Browse Source

Merge pull request #1010 from colinin/dev

Merge dev to master
pull/1050/head
yx lin 1 year ago
committed by GitHub
parent
commit
28ad4d67ce
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      .github/workflows/publish.yml
  2. 4
      .github/workflows/release.yml
  3. 4
      Directory.Packages.props
  4. 18
      apps/vue/src/components/Table/src/BasicTable.vue
  5. 16
      apps/vue/src/components/Table/src/components/AdvancedSearch.vue
  6. 15
      apps/vue/src/components/Table/src/hooks/useDataSource.ts
  7. 2
      aspnet-core/framework/dynamic-queryable/LINGYUN.Abp.Dynamic.Queryable.Application.Contracts/LINGYUN/Abp/Dynamic/Queryable/IDynamicQueryableAppService.cs
  8. 2
      aspnet-core/framework/dynamic-queryable/LINGYUN.Abp.Dynamic.Queryable.Application/LINGYUN/Abp/Dynamic/Queryable/DynamicQueryableAppService.cs
  9. 4
      aspnet-core/framework/dynamic-queryable/LINGYUN.Abp.Dynamic.Queryable.HttpApi/LINGYUN/Abp/Dynamic/Queryable/DynamicQueryableControllerBase.cs
  10. 3
      aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application.Contracts/LINGYUN/Abp/LocalizationManagement/LanguageCreateOrUpdateDto.cs
  11. 6
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs
  12. 14
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs
  13. 3
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json
  14. 3
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json
  15. 42
      aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/BackgroundJobLogAppService.cs
  16. 32
      aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/System/Linq/Expressions/ExpressionFuncExtensions.cs
  17. 35
      aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobLogFilter.cs
  18. 18
      aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/IBackgroundJobLogRepository.cs
  19. 31
      aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/EfCoreBackgroundJobLogRepository.cs
  20. 4
      common.props

2
.github/workflows/publish.yml

@ -2,7 +2,7 @@ name: "Publish"
on: on:
push: push:
branches: [ rel-8.2.1 ] branches: [ rel-8.2.2 ]
env: env:
DOTNET_VERSION: "8.0.200" DOTNET_VERSION: "8.0.200"

4
.github/workflows/release.yml

@ -2,7 +2,7 @@ name: "Tagged Release"
on: on:
push: push:
branches: [ rel-8.2.1 ] branches: [ rel-8.2.2 ]
jobs: jobs:
tagged-release: tagged-release:
@ -14,4 +14,4 @@ jobs:
with: with:
repo_token: "${{ secrets.GITHUB_TOKEN }}" repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: false prerelease: false
automatic_release_tag: "8.2.1" automatic_release_tag: "8.2.2"

4
Directory.Packages.props

@ -2,8 +2,8 @@
<PropertyGroup> <PropertyGroup>
<DotNetCoreCAPPackageVersion>8.2.0</DotNetCoreCAPPackageVersion> <DotNetCoreCAPPackageVersion>8.2.0</DotNetCoreCAPPackageVersion>
<ElsaPackageVersion>2.14.1</ElsaPackageVersion> <ElsaPackageVersion>2.14.1</ElsaPackageVersion>
<VoloAbpPackageVersion>8.2.1</VoloAbpPackageVersion> <VoloAbpPackageVersion>8.2.2</VoloAbpPackageVersion>
<LINGYUNAbpPackageVersion>8.2.1</LINGYUNAbpPackageVersion> <LINGYUNAbpPackageVersion>8.2.2</LINGYUNAbpPackageVersion>
<MicrosoftExtensionsPackageVersion>8.0.0</MicrosoftExtensionsPackageVersion> <MicrosoftExtensionsPackageVersion>8.0.0</MicrosoftExtensionsPackageVersion>
<MicrosoftAspNetCorePackageVersion>8.0.0</MicrosoftAspNetCorePackageVersion> <MicrosoftAspNetCorePackageVersion>8.0.0</MicrosoftAspNetCorePackageVersion>
<MicrosoftEntityFrameworkCorePackageVersion>8.0.0</MicrosoftEntityFrameworkCorePackageVersion> <MicrosoftEntityFrameworkCorePackageVersion>8.0.0</MicrosoftEntityFrameworkCorePackageVersion>

18
apps/vue/src/components/Table/src/BasicTable.vue

@ -15,14 +15,15 @@
<slot :name="item" v-bind="data || {}"></slot> <slot :name="item" v-bind="data || {}"></slot>
</template> </template>
<template #advanceBefore> <template #advanceBefore>
<Badge v-if="getAdvancedSearchProps?.useAdvancedSearch" :count="advancedSearchInput?.paramters.length">
<Button <Button
v-if="getAdvancedSearchProps?.useAdvancedSearch"
type="link" type="link"
size="small" size="small"
@click="handleAdvanceSearch" @click="handleAdvanceSearch"
> >
{{ t('component.table.advancedSearch.title') }} {{ t('component.table.advancedSearch.title') }}
</Button> </Button>
</Badge>
</template> </template>
</BasicForm> </BasicForm>
@ -55,7 +56,7 @@
ref="advancedSearchRef" ref="advancedSearchRef"
@register="registerAdSearchModal" @register="registerAdSearchModal"
v-bind="getAdvancedSearchProps" v-bind="getAdvancedSearchProps"
@change="handleAdvanceSearchChange" @change="handleAdvanceSearchChanged"
@search="handleAdvanceSearchInfoChange" @search="handleAdvanceSearchInfoChange"
/> />
</div> </div>
@ -70,13 +71,14 @@
} from './types/table'; } from './types/table';
import { defineComponent, ref, reactive, computed, unref, toRaw, inject, watchEffect, nextTick } from 'vue'; import { defineComponent, ref, reactive, computed, unref, toRaw, inject, watchEffect, nextTick } from 'vue';
import { Button, Table } from 'ant-design-vue'; import { Badge, Button, Table } from 'ant-design-vue';
import { BasicForm, useForm } from '/@/components/Form/index'; import { BasicForm, useForm } from '/@/components/Form/index';
import { useModal } from '/@/components/Modal/index'; import { useModal } from '/@/components/Modal/index';
import { PageWrapperFixedHeightKey } from '/@/components/Page'; import { PageWrapperFixedHeightKey } from '/@/components/Page';
import HeaderCell from './components/HeaderCell.vue'; import HeaderCell from './components/HeaderCell.vue';
import AdvancedSearch from './components/AdvancedSearch.vue'; import AdvancedSearch from './components/AdvancedSearch.vue';
import { InnerHandlers } from './types/table'; import { InnerHandlers } from './types/table';
import { DynamicQueryable } from './types/advancedSearch';
import { usePagination } from './hooks/usePagination'; import { usePagination } from './hooks/usePagination';
import { useColumns } from './hooks/useColumns'; import { useColumns } from './hooks/useColumns';
@ -105,6 +107,7 @@
name: 'BasicTable', name: 'BasicTable',
components: { components: {
Table, Table,
Badge,
BasicForm, BasicForm,
Button, Button,
HeaderCell, HeaderCell,
@ -137,6 +140,7 @@
const wrapRef = ref(null); const wrapRef = ref(null);
const formRef = ref(null); const formRef = ref(null);
const advancedSearchRef = ref<any>(null); const advancedSearchRef = ref<any>(null);
const advancedSearchInput = ref<DynamicQueryable>();
const innerPropsRef = ref<Partial<BasicTableProps>>(); const innerPropsRef = ref<Partial<BasicTableProps>>();
const { prefixCls } = useDesign('basic-table'); const { prefixCls } = useDesign('basic-table');
@ -276,6 +280,11 @@
getDataSourceRef, getDataSourceRef,
); );
function handleAdvanceSearchChanged(queryable: DynamicQueryable) {
advancedSearchInput.value = queryable;
handleAdvanceSearchChange(queryable);
}
const { const {
getFormProps, getFormProps,
getAdvancedSearchProps, getAdvancedSearchProps,
@ -401,12 +410,13 @@
formRef, formRef,
tableElRef, tableElRef,
advancedSearchRef, advancedSearchRef,
advancedSearchInput,
getBindValues, getBindValues,
getLoading, getLoading,
registerForm, registerForm,
handleSearchInfoChange, handleSearchInfoChange,
registerAdSearchModal, registerAdSearchModal,
handleAdvanceSearchChange, handleAdvanceSearchChanged,
handleAdvanceSearchInfoChange, handleAdvanceSearchInfoChange,
handleSearchInfoReset, handleSearchInfoReset,
handleAdvanceSearch, handleAdvanceSearch,

16
apps/vue/src/components/Table/src/components/AdvancedSearch.vue

@ -330,7 +330,7 @@
function handleDelField(paramter) { function handleDelField(paramter) {
const index = formMdel.paramters.findIndex(p => p.field === paramter.field); const index = formMdel.paramters.findIndex(p => p.field === paramter.field);
formMdel.paramters.splice(index, 1); formMdel.paramters.splice(index, 1);
emits('change', getSearchInput()); emits('change', formMdel);
} }
function handleFieldChange(field, record) { function handleFieldChange(field, record) {
@ -344,26 +344,18 @@
if (defineParam.javaScriptType === 'boolean') { if (defineParam.javaScriptType === 'boolean') {
record.value = false; record.value = false;
} }
emits('change', getSearchInput()); emits('change', formMdel);
} }
} }
function handleSubmit() { function handleSubmit() {
emits('search', getSearchInput()); emits('search', formMdel);
closeModal(); closeModal();
} }
function resetFields() { function resetFields() {
formMdel.paramters = []; formMdel.paramters = [];
emits('change', getSearchInput()); emits('change', formMdel);
}
function getSearchInput() {
const searchInput = {
//
paramters: formMdel.paramters.filter(p => p.value !== undefined)
};
return searchInput;
} }
function setLoading(loading: boolean) { function setLoading(loading: boolean) {

15
apps/vue/src/components/Table/src/hooks/useDataSource.ts

@ -242,13 +242,18 @@ export function useDataSource(
} = unref(propsRef); } = unref(propsRef);
let fetchApi = api; let fetchApi = api;
// 高级查询条件支持 // 高级查询条件支持
const searchInput = cloneDeep(getFieldsValue());
if (advancedSearchConfig?.useAdvancedSearch) { if (advancedSearchConfig?.useAdvancedSearch) {
const searchInput = getFieldsValue(); if (Reflect.has(searchInput, 'queryable')
if (Reflect.has(searchInput, 'queryable') && && searchInput?.queryable?.paramters
Array.isArray(searchInput.queryable?.paramters) && && Array.isArray(searchInput.queryable?.paramters)) {
searchInput.queryable.paramters.length > 0) searchInput.queryable.paramters = searchInput.queryable.paramters
.filter((p) => p.value !== undefined);
if (searchInput.queryable.paramters.length > 0) {
fetchApi = advancedSearchConfig?.fetchApi; fetchApi = advancedSearchConfig?.fetchApi;
} }
}
}
if (!fetchApi || !isFunction(fetchApi)) return; if (!fetchApi || !isFunction(fetchApi)) return;
try { try {
if (clearSelectOnPageChange) { if (clearSelectOnPageChange) {
@ -275,7 +280,7 @@ export function useDataSource(
let params: Recordable = merge( let params: Recordable = merge(
pageParams, pageParams,
useSearchForm ? getFieldsValue() : {}, useSearchForm ? searchInput : {},
searchInfo, searchInfo,
opt?.searchInfo ?? {}, opt?.searchInfo ?? {},
defSort, defSort,

2
aspnet-core/framework/dynamic-queryable/LINGYUN.Abp.Dynamic.Queryable.Application.Contracts/LINGYUN/Abp/Dynamic/Queryable/IDynamicQueryableAppService.cs

@ -15,5 +15,5 @@ public interface IDynamicQueryableAppService<TEntityDto>
/// </summary> /// </summary>
/// <param name="dynamicInput"></param> /// <param name="dynamicInput"></param>
/// <returns></returns> /// <returns></returns>
Task<PagedResultDto<TEntityDto>> GetListAsync(GetListByDynamicQueryableInput dynamicInput); Task<PagedResultDto<TEntityDto>> SearchAsync(GetListByDynamicQueryableInput dynamicInput);
} }

2
aspnet-core/framework/dynamic-queryable/LINGYUN.Abp.Dynamic.Queryable.Application/LINGYUN/Abp/Dynamic/Queryable/DynamicQueryableAppService.cs

@ -84,7 +84,7 @@ public abstract class DynamicQueryableAppService<TEntity, TEntityDto> : Applicat
/// </summary> /// </summary>
/// <param name="dynamicInput"></param> /// <param name="dynamicInput"></param>
/// <returns></returns> /// <returns></returns>
public async virtual Task<PagedResultDto<TEntityDto>> GetListAsync(GetListByDynamicQueryableInput dynamicInput) public async virtual Task<PagedResultDto<TEntityDto>> SearchAsync(GetListByDynamicQueryableInput dynamicInput)
{ {
Expression<Func<TEntity, bool>> condition = (e) => true; Expression<Func<TEntity, bool>> condition = (e) => true;

4
aspnet-core/framework/dynamic-queryable/LINGYUN.Abp.Dynamic.Queryable.HttpApi/LINGYUN/Abp/Dynamic/Queryable/DynamicQueryableControllerBase.cs

@ -24,8 +24,8 @@ public abstract class DynamicQueryableControllerBase<TEntityDto> : AbpController
[HttpPost] [HttpPost]
[Route("search")] [Route("search")]
public Task<PagedResultDto<TEntityDto>> GetListAsync(GetListByDynamicQueryableInput dynamicInput) public Task<PagedResultDto<TEntityDto>> SearchAsync(GetListByDynamicQueryableInput dynamicInput)
{ {
return DynamicQueryableAppService.GetListAsync(dynamicInput); return DynamicQueryableAppService.SearchAsync(dynamicInput);
} }
} }

3
aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application.Contracts/LINGYUN/Abp/LocalizationManagement/LanguageCreateOrUpdateDto.cs

@ -7,7 +7,4 @@ public abstract class LanguageCreateOrUpdateDto
[Required] [Required]
[DynamicStringLength(typeof(LanguageConsts), nameof(LanguageConsts.MaxDisplayNameLength))] [DynamicStringLength(typeof(LanguageConsts), nameof(LanguageConsts.MaxDisplayNameLength))]
public string DisplayName { get; set; } public string DisplayName { get; set; }
[DynamicStringLength(typeof(LanguageConsts), nameof(LanguageConsts.MaxTwoLetterISOLanguageNameLength))]
public string FlagIcon { get; set; }
} }

6
aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs

@ -39,7 +39,8 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService
var tenant = await TenantRepository.FindAsync(id); var tenant = await TenantRepository.FindAsync(id);
if (tenant == null) if (tenant == null)
{ {
throw new UserFriendlyException(L["TenantNotFoundById", id]); throw new BusinessException(AbpSaasErrorCodes.TenantIdOrNameNotFound)
.WithData("Tenant", id);
} }
return ObjectMapper.Map<Tenant, TenantDto>(tenant); return ObjectMapper.Map<Tenant, TenantDto>(tenant);
@ -50,7 +51,8 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService
var tenant = await TenantRepository.FindByNameAsync(name); var tenant = await TenantRepository.FindByNameAsync(name);
if (tenant == null) if (tenant == null)
{ {
throw new UserFriendlyException(L["TenantNotFoundByName", name]); throw new BusinessException(AbpSaasErrorCodes.TenantIdOrNameNotFound)
.WithData("Tenant", name);
} }
return ObjectMapper.Map<Tenant, TenantDto>(tenant); return ObjectMapper.Map<Tenant, TenantDto>(tenant);
} }

14
aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs

@ -3,11 +3,23 @@
public static class AbpSaasErrorCodes public static class AbpSaasErrorCodes
{ {
public const string Namespace = "Saas"; public const string Namespace = "Saas";
/// <summary>
/// 已经存在名为 {DisplayName} 的版本!
/// </summary>
public const string DuplicateEditionDisplayName = Namespace + ":010001"; public const string DuplicateEditionDisplayName = Namespace + ":010001";
/// <summary>
/// 试图删除正在使用的版本: {DisplayName}!
/// </summary>
public const string DeleteUsedEdition = Namespace + ":010002"; public const string DeleteUsedEdition = Namespace + ":010002";
/// <summary>
/// 已经存在名为 {Name} 的租户!
/// </summary>
public const string DuplicateTenantName = Namespace + ":020001"; public const string DuplicateTenantName = Namespace + ":020001";
/// <summary> /// <summary>
/// 租户: {Tenant} 不存在!
/// </summary>
public const string TenantIdOrNameNotFound = Namespace + ":020002";
/// <summary>
/// 无效的默认连接字符串 /// 无效的默认连接字符串
/// </summary> /// </summary>
public const string InvalidDefaultConnectionString = Namespace + ":020101"; public const string InvalidDefaultConnectionString = Namespace + ":020101";

3
aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json

@ -4,6 +4,7 @@
"Saas:010001": "Unable to create duplicate editions {DisplayName}!", "Saas:010001": "Unable to create duplicate editions {DisplayName}!",
"Saas:010002": "Tried to delete the edition in use: {DisplayName}!", "Saas:010002": "Tried to delete the edition in use: {DisplayName}!",
"Saas:020001": "Unable to create duplicate tenants {Name}!", "Saas:020001": "Unable to create duplicate tenants {Name}!",
"Saas:020002": "Tenant: {Tenant} not found!",
"Saas:020101": "The default connection string cannot open a connection to the database!", "Saas:020101": "The default connection string cannot open a connection to the database!",
"Saas:020102": "The database pointed to by the default connection string already exists!", "Saas:020102": "The database pointed to by the default connection string already exists!",
"Saas:020103": "Unable to open the database connection pointed to by {Name}!", "Saas:020103": "Unable to open the database connection pointed to by {Name}!",
@ -47,8 +48,6 @@
"Features:ExpirationReminderDaysDesc": "Send a reminder to the administrator when the resource has how many days left to expire", "Features:ExpirationReminderDaysDesc": "Send a reminder to the administrator when the resource has how many days left to expire",
"Features:ExpiredRecoveryTime": "Expired Recovery Time", "Features:ExpiredRecoveryTime": "Expired Recovery Time",
"Features:ExpiredRecoveryTimeDesc": "If the resource expiration is not handled for a long time, tenant resources will be reclaimed", "Features:ExpiredRecoveryTimeDesc": "If the resource expiration is not handled for a long time, tenant resources will be reclaimed",
"TenantNotFoundById": "Tenant: {0} not found!",
"TenantNotFoundByName": "Tenant: {0} not found!",
"UnActived": "UnActived", "UnActived": "UnActived",
"RecycleStrategy:Reserve": "Reserve", "RecycleStrategy:Reserve": "Reserve",
"RecycleStrategy:Recycle": "Recycle" "RecycleStrategy:Recycle": "Recycle"

3
aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json

@ -4,6 +4,7 @@
"Saas:010001": "已经存在名为 {DisplayName} 的版本!", "Saas:010001": "已经存在名为 {DisplayName} 的版本!",
"Saas:010002": "试图删除正在使用的版本: {DisplayName}!", "Saas:010002": "试图删除正在使用的版本: {DisplayName}!",
"Saas:020001": "已经存在名为 {Name} 的租户!", "Saas:020001": "已经存在名为 {Name} 的租户!",
"Saas:020002": "租户: {Tenant} 不存在!",
"Saas:020101": "无法打开默认连接字符串指向的数据库连接!", "Saas:020101": "无法打开默认连接字符串指向的数据库连接!",
"Saas:020102": "默认连接字符串指向的数据库已经存在!", "Saas:020102": "默认连接字符串指向的数据库已经存在!",
"Saas:020103": "无法打开 {Name} 指向的数据库连接!", "Saas:020103": "无法打开 {Name} 指向的数据库连接!",
@ -47,8 +48,6 @@
"Features:ExpirationReminderDaysDesc": "当资源还有多少天过期时, 给管理员发送提醒", "Features:ExpirationReminderDaysDesc": "当资源还有多少天过期时, 给管理员发送提醒",
"Features:ExpiredRecoveryTime": "过期回收时长", "Features:ExpiredRecoveryTime": "过期回收时长",
"Features:ExpiredRecoveryTimeDesc": "当资源超期多久没有处理, 将回收租户资源", "Features:ExpiredRecoveryTimeDesc": "当资源超期多久没有处理, 将回收租户资源",
"TenantNotFoundById": "租户: {0} 不存在!",
"TenantNotFoundByName": "租户: {0} 不存在!",
"UnActived": "未启用", "UnActived": "未启用",
"RecycleStrategy:Reserve": "保留", "RecycleStrategy:Reserve": "保留",
"RecycleStrategy:Recycle": "回收" "RecycleStrategy:Recycle": "回收"

42
aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/BackgroundJobLogAppService.cs

@ -1,6 +1,8 @@
using LINGYUN.Abp.TaskManagement.Permissions; using LINGYUN.Abp.TaskManagement.Permissions;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
@ -32,22 +34,38 @@ public class BackgroundJobLogAppService : TaskManagementApplicationService, IBac
public async virtual Task<PagedResultDto<BackgroundJobLogDto>> GetListAsync(BackgroundJobLogGetListInput input) public async virtual Task<PagedResultDto<BackgroundJobLogDto>> GetListAsync(BackgroundJobLogGetListInput input)
{ {
var filter = new BackgroundJobLogFilter var specification = new BackgroundJobLogGetListSpecification(input);
{
BeginRunTime = input.BeginRunTime,
EndRunTime = input.EndRunTime,
HasExceptions = input.HasExceptions,
Filter = input.Filter,
Group = input.Group,
Name = input.Name,
Type = input.Type
};
var totalCount = await BackgroundJobLogRepository.GetCountAsync(filter, input.JobId); var totalCount = await BackgroundJobLogRepository.GetCountAsync(specification);
var backgroundJobLogs = await BackgroundJobLogRepository.GetListAsync( var backgroundJobLogs = await BackgroundJobLogRepository.GetListAsync(
filter, input.JobId, input.Sorting, input.MaxResultCount, input.SkipCount); specification, input.Sorting, input.MaxResultCount, input.SkipCount);
return new PagedResultDto<BackgroundJobLogDto>(totalCount, return new PagedResultDto<BackgroundJobLogDto>(totalCount,
ObjectMapper.Map<List<BackgroundJobLog>, List<BackgroundJobLogDto>>(backgroundJobLogs)); ObjectMapper.Map<List<BackgroundJobLog>, List<BackgroundJobLogDto>>(backgroundJobLogs));
} }
private class BackgroundJobLogGetListSpecification : Volo.Abp.Specifications.Specification<BackgroundJobLog>
{
protected BackgroundJobLogGetListInput Input { get; }
public BackgroundJobLogGetListSpecification(BackgroundJobLogGetListInput input)
{
Input = input;
}
public override Expression<Func<BackgroundJobLog, bool>> ToExpression()
{
Expression<Func<BackgroundJobLog, bool>> expression = _ => true;
return expression
.AndIf(!Input.JobId.IsNullOrWhiteSpace(), x => x.JobId.Equals(Input.JobId))
.AndIf(!Input.Type.IsNullOrWhiteSpace(), x => x.JobType.Contains(Input.Type))
.AndIf(!Input.Group.IsNullOrWhiteSpace(), x => x.JobGroup.Equals(Input.Group))
.AndIf(!Input.Name.IsNullOrWhiteSpace(), x => x.JobName.Equals(Input.Name))
.AndIf(!Input.Filter.IsNullOrWhiteSpace(), x => x.JobName.Contains(Input.Filter) ||
x.JobGroup.Contains(Input.Filter) || x.JobType.Contains(Input.Filter) || x.Message.Contains(Input.Filter))
.AndIf(Input.HasExceptions.HasValue, x => !string.IsNullOrWhiteSpace(x.Exception))
.AndIf(Input.BeginRunTime.HasValue, x => x.RunTime >= Input.BeginRunTime)
.AndIf(Input.EndRunTime.HasValue, x => x.RunTime <= Input.EndRunTime);
}
}
} }

32
aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/System/Linq/Expressions/ExpressionFuncExtensions.cs

@ -0,0 +1,32 @@
using Volo.Abp.Specifications;
namespace System.Linq.Expressions;
internal static class ExpressionFuncExtensions
{
public static Expression<Func<T, bool>> AndIf<T>(
this Expression<Func<T, bool>> first,
bool condition,
Expression<Func<T, bool>> second)
{
if (condition)
{
return ExpressionFuncExtender.And(first, second);
}
return first;
}
public static Expression<Func<T, bool>> OrIf<T>(
this Expression<Func<T, bool>> first,
bool condition,
Expression<Func<T, bool>> second)
{
if (condition)
{
return ExpressionFuncExtender.Or(first, second);
}
return first;
}
}

35
aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobLogFilter.cs

@ -1,35 +0,0 @@
using System;
namespace LINGYUN.Abp.TaskManagement;
public class BackgroundJobLogFilter
{
/// <summary>
/// 其他过滤条件
/// </summary>
public string Filter { get; set; }
/// <summary>
/// 存在异常
/// </summary>
public bool? HasExceptions { get; set; }
/// <summary>
/// 任务名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 任务分组
/// </summary>
public string Group { get; set; }
/// <summary>
/// 任务类型
/// </summary>
public string Type { get; set; }
/// <summary>
/// 开始触发时间
/// </summary>
public DateTime? BeginRunTime { get; set; }
/// <summary>
/// 结束触发时间
/// </summary>
public DateTime? EndRunTime { get; set; }
}

18
aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/IBackgroundJobLogRepository.cs

@ -1,8 +1,8 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Volo.Abp.Specifications;
namespace LINGYUN.Abp.TaskManagement; namespace LINGYUN.Abp.TaskManagement;
@ -11,28 +11,24 @@ public interface IBackgroundJobLogRepository : IRepository<BackgroundJobLog, lon
/// <summary> /// <summary>
/// 获取过滤后的任务日志数量 /// 获取过滤后的任务日志数量
/// </summary> /// </summary>
/// <param name="filter"></param> /// <param name="specification"></param>
/// <param name="jobId"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
Task<int> GetCountAsync( Task<int> GetCountAsync(
BackgroundJobLogFilter filter, ISpecification<BackgroundJobLog> specification,
string jobId = null,
CancellationToken cancellationToken = default); CancellationToken cancellationToken = default);
/// <summary> /// <summary>
/// 获取过滤后的任务日志列表 /// 获取过滤后的任务日志列表
/// </summary> /// </summary>
/// <param name="filter"></param> /// <param name="specification"></param>
/// <param name="jobId"></param>
/// <param name="sorting"></param> /// <param name="sorting"></param>
/// <param name="maxResultCount"></param> /// <param name="maxResultCount"></param>
/// <param name="skipCount"></param> /// <param name="skipCount"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
Task<List<BackgroundJobLog>> GetListAsync( Task<List<BackgroundJobLog>> GetListAsync(
BackgroundJobLogFilter filter, ISpecification<BackgroundJobLog> specification,
string jobId = null, string sorting = $"{nameof(BackgroundJobLog.RunTime)} DESC",
string sorting = nameof(BackgroundJobLog.RunTime),
int maxResultCount = 10, int maxResultCount = 10,
int skipCount = 0, int skipCount = 0,
CancellationToken cancellationToken = default); CancellationToken cancellationToken = default);

31
aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/EfCoreBackgroundJobLogRepository.cs

@ -7,6 +7,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Specifications;
namespace LINGYUN.Abp.TaskManagement.EntityFrameworkCore; namespace LINGYUN.Abp.TaskManagement.EntityFrameworkCore;
@ -21,45 +22,27 @@ public class EfCoreBackgroundJobLogRepository :
} }
public async virtual Task<int> GetCountAsync( public async virtual Task<int> GetCountAsync(
BackgroundJobLogFilter filter, ISpecification<BackgroundJobLog> specification,
string jobId = null,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
return await (await GetDbSetAsync()) return await (await GetDbSetAsync())
.WhereIf(!jobId.IsNullOrWhiteSpace(), x => x.JobId.Equals(jobId)) .Where(specification.ToExpression())
.WhereIf(!filter.Type.IsNullOrWhiteSpace(), x => x.JobType.Contains(filter.Type))
.WhereIf(!filter.Group.IsNullOrWhiteSpace(), x => x.JobGroup.Equals(filter.Group))
.WhereIf(!filter.Name.IsNullOrWhiteSpace(), x => x.JobName.Equals(filter.Name))
.WhereIf(!filter.Filter.IsNullOrWhiteSpace(), x => x.JobName.Contains(filter.Filter) ||
x.JobGroup.Contains(filter.Filter) || x.JobType.Contains(filter.Filter) || x.Message.Contains(filter.Filter))
.WhereIf(filter.HasExceptions.HasValue, x => !string.IsNullOrWhiteSpace(x.Exception))
.WhereIf(filter.BeginRunTime.HasValue, x => x.RunTime.CompareTo(filter.BeginRunTime.Value) >= 0)
.WhereIf(filter.EndRunTime.HasValue, x => x.RunTime.CompareTo(filter.EndRunTime.Value) <= 0)
.CountAsync(GetCancellationToken(cancellationToken)); .CountAsync(GetCancellationToken(cancellationToken));
} }
public async virtual Task<List<BackgroundJobLog>> GetListAsync( public async virtual Task<List<BackgroundJobLog>> GetListAsync(
BackgroundJobLogFilter filter, ISpecification<BackgroundJobLog> specification,
string jobId = null, string sorting = $"{nameof(BackgroundJobLog.RunTime)} DESC",
string sorting = nameof(BackgroundJobLog.RunTime),
int maxResultCount = 10, int maxResultCount = 10,
int skipCount = 0, int skipCount = 0,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
if (sorting.IsNullOrWhiteSpace()) if (sorting.IsNullOrWhiteSpace())
{ {
sorting = $"{nameof(BackgroundJobLog.RunTime)}"; sorting = $"{nameof(BackgroundJobLog.RunTime)} DESC";
} }
return await (await GetDbSetAsync()) return await (await GetDbSetAsync())
.WhereIf(!jobId.IsNullOrWhiteSpace(), x => x.JobId.Equals(jobId)) .Where(specification.ToExpression())
.WhereIf(!filter.Type.IsNullOrWhiteSpace(), x => x.JobType.Contains(filter.Type))
.WhereIf(!filter.Group.IsNullOrWhiteSpace(), x => x.JobGroup.Equals(filter.Group))
.WhereIf(!filter.Name.IsNullOrWhiteSpace(), x => x.JobName.Equals(filter.Name))
.WhereIf(!filter.Filter.IsNullOrWhiteSpace(), x => x.JobName.Contains(filter.Filter) ||
x.JobGroup.Contains(filter.Filter) || x.JobType.Contains(filter.Filter) || x.Message.Contains(filter.Filter))
.WhereIf(filter.HasExceptions.HasValue, x => !string.IsNullOrWhiteSpace(x.Exception))
.WhereIf(filter.BeginRunTime.HasValue, x => x.RunTime.CompareTo(filter.BeginRunTime.Value) >= 0)
.WhereIf(filter.EndRunTime.HasValue, x => x.RunTime.CompareTo(filter.EndRunTime.Value) <= 0)
.OrderBy(sorting) .OrderBy(sorting)
.PageBy(skipCount, maxResultCount) .PageBy(skipCount, maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken)); .ToListAsync(GetCancellationToken(cancellationToken));

4
common.props

@ -1,12 +1,12 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<Version>8.2.1</Version> <Version>8.2.2</Version>
<Authors>colin</Authors> <Authors>colin</Authors>
<NoWarn>$(NoWarn);CS1591;CS0436;CS8618;NU1803</NoWarn> <NoWarn>$(NoWarn);CS1591;CS0436;CS8618;NU1803</NoWarn>
<PackageProjectUrl>https://github.com/colinin/abp-next-admin</PackageProjectUrl> <PackageProjectUrl>https://github.com/colinin/abp-next-admin</PackageProjectUrl>
<PackageOutputPath>$(SolutionDir)LocalNuget</PackageOutputPath> <PackageOutputPath>$(SolutionDir)LocalNuget</PackageOutputPath>
<PackageVersion>8.2.1</PackageVersion> <PackageVersion>8.2.2</PackageVersion>
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/colinin/abp-next-admin</RepositoryUrl> <RepositoryUrl>https://github.com/colinin/abp-next-admin</RepositoryUrl>

Loading…
Cancel
Save