diff --git a/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj b/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj index 40a42f83..9bb9cd9e 100644 --- a/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj +++ b/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj @@ -17,17 +17,17 @@ - - - - + + + + - + @@ -37,7 +37,7 @@ - + @@ -56,9 +56,9 @@ - - - + + + diff --git a/Admin.NET/Admin.NET.Core/Entity/SysWechatRefund.cs b/Admin.NET/Admin.NET.Core/Entity/SysWechatRefund.cs index 94b33c53..d4ef92a3 100644 --- a/Admin.NET/Admin.NET.Core/Entity/SysWechatRefund.cs +++ b/Admin.NET/Admin.NET.Core/Entity/SysWechatRefund.cs @@ -63,7 +63,7 @@ public class SysWechatRefund : EntityBase /// 退款资金来源, 可不传,默认使用未结算资金退款(仅对老资金流商户适用) /// [SugarColumn(ColumnDescription = "退款资金来源", Length = 32)] - public string FundsAccount { get; set; } + public string? FundsAccount { get; set; } /// /// 关联的商户订单号 diff --git a/Admin.NET/Admin.NET.Core/Service/Cache/SysCacheService.cs b/Admin.NET/Admin.NET.Core/Service/Cache/SysCacheService.cs index 89d79784..6ddead17 100644 --- a/Admin.NET/Admin.NET.Core/Service/Cache/SysCacheService.cs +++ b/Admin.NET/Admin.NET.Core/Service/Cache/SysCacheService.cs @@ -62,6 +62,17 @@ public class SysCacheService : IDynamicApiController, ISingleton return _cacheProvider.Cache.Set($"{_cacheOptions.Prefix}{key}", value, expire); } + /// + /// 获取缓存的剩余生存时间 + /// + /// + /// + [NonAction] + public TimeSpan GetExpire(string key) + { + return _cacheProvider.Cache.GetExpire(key); + } + /// /// 获取缓存 /// diff --git a/Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenService.cs b/Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenService.cs index 3cc5e5ae..822df72c 100644 --- a/Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenService.cs +++ b/Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenService.cs @@ -42,6 +42,7 @@ public class SysCodeGenService : IDynamicApiController, ITransient return await _db.Queryable() .WhereIF(!string.IsNullOrWhiteSpace(input.TableName), u => u.TableName.Contains(input.TableName.Trim())) .WhereIF(!string.IsNullOrWhiteSpace(input.BusName), u => u.BusName.Contains(input.BusName.Trim())) + .OrderBy(u => u.Id, OrderByType.Desc) .ToPagedListAsync(input.Page, input.PageSize); } diff --git a/Admin.NET/Admin.NET.Core/Service/Config/SysConfigService.cs b/Admin.NET/Admin.NET.Core/Service/Config/SysConfigService.cs index c6640026..3a0b1b12 100644 --- a/Admin.NET/Admin.NET.Core/Service/Config/SysConfigService.cs +++ b/Admin.NET/Admin.NET.Core/Service/Config/SysConfigService.cs @@ -14,12 +14,15 @@ public class SysConfigService : IDynamicApiController, ITransient { private readonly SysCacheService _sysCacheService; private readonly SqlSugarRepository _sysConfigRep; + private readonly UserManager _userManager; public SysConfigService(SysCacheService sysCacheService, - SqlSugarRepository sysConfigRep) + SqlSugarRepository sysConfigRep, + UserManager userManager) { _sysCacheService = sysCacheService; _sysConfigRep = sysConfigRep; + _userManager = userManager; } /// @@ -31,7 +34,7 @@ public class SysConfigService : IDynamicApiController, ITransient public async Task> Page(PageConfigInput input) { return await _sysConfigRep.AsQueryable() - .Where(u => u.GroupCode != "WebConfig") // 不显示 WebConfig 分组 + .WhereIF(!_userManager.SuperAdmin, u => u.GroupCode != "WebConfig") // 若非超管,不显示 WebConfig 分组 .WhereIF(!string.IsNullOrWhiteSpace(input.Name?.Trim()), u => u.Name.Contains(input.Name)) .WhereIF(!string.IsNullOrWhiteSpace(input.Code?.Trim()), u => u.Code.Contains(input.Code)) .WhereIF(!string.IsNullOrWhiteSpace(input.GroupCode?.Trim()), u => u.GroupCode.Equals(input.GroupCode)) diff --git a/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/index.vue.vm b/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/index.vue.vm index ce4bbe98..de62f3c7 100644 --- a/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/index.vue.vm +++ b/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/index.vue.vm @@ -20,7 +20,7 @@ } else if(@column.EffectType == "DatePicker") { @: } } @@ -227,19 +227,19 @@ import ModifyRecord from '/@@/components/table/modifyRecord.vue'; @if (@Model.IsApiService) { // 接口函数 -import { getAPI } from '/@@/utils/axios-utils'; +@:import { getAPI } from '/@@/utils/axios-utils'; // 接口 -import { @(@Model.ClassName)Api } from '/@@/api-services/api'; +@:import { @(@Model.ClassName)Api } from '/@@/api-services/api'; // 模型 -import { @(@Model.ClassName), @(@Model.ClassName)Input, @(@Model.ClassName)Output } from '/@@/api-services/models'; +@:import { @(@Model.ClassName), @(@Model.ClassName)Input, @(@Model.ClassName)Output } from '/@@/api-services/models'; } else { -@:import { page@(@Model.ClassName), delete@(@Model.ClassName) } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerEntityName)'; +@:import { page@(@Model.ClassName), delete@(@Model.ClassName) } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)'; foreach (var column in Model.QueryWhetherList){ if(@column.EffectType == "fk"){ - @:import { get@(@column.FkEntityName)@(@column.PropertyName)Dropdown } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerEntityName)'; + @:import { get@(@column.FkEntityName)@(@column.PropertyName)Dropdown } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)'; } } } diff --git a/Web/package.json b/Web/package.json index efcffd08..15fca79c 100644 --- a/Web/package.json +++ b/Web/package.json @@ -2,7 +2,7 @@ "name": "admin.net.pro", "type": "module", "version": "2.4.33", - "lastBuildTime": "2024.07.09", + "lastBuildTime": "2024.07.10", "description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架", "author": "zuohuaijun", "license": "MIT", @@ -16,7 +16,7 @@ "@element-plus/icons-vue": "^2.3.1", "@logicflow/core": "^1.2.27", "@logicflow/extension": "^1.2.27", - "@microsoft/signalr": "^8.0.0", + "@microsoft/signalr": "^8.0.7", "@vue-office/docx": "^1.6.2", "@vue-office/excel": "^1.7.8", "@vue-office/pdf": "^2.0.2", @@ -49,10 +49,10 @@ "print-js": "^1.6.0", "push.js": "^1.0.12", "qrcodejs2-fixes": "^0.0.2", - "qs": "^6.12.2", + "qs": "^6.12.3", "relation-graph": "^2.2.2", "screenfull": "^6.0.2", - "sm-crypto-v2": "^1.9.0", + "sm-crypto-v2": "^1.9.1", "sortablejs": "^1.15.2", "splitpanes": "^3.1.5", "vcrontab-3": "^3.3.22", @@ -68,8 +68,8 @@ "vue-signature-pad": "^3.0.2", "vue3-tree-org": "^4.2.2", "vuedraggable": "4.0.3", - "vxe-pc-ui": "^4.0.51", - "vxe-table": "^4.7.45", + "vxe-pc-ui": "^4.0.58", + "vxe-table": "^4.7.47", "vxe-table-plugin-element": "^4.0.4", "vxe-table-plugin-export-xlsx": "^4.0.5", "xe-utils": "^3.5.28", @@ -93,8 +93,8 @@ "less": "^4.2.0", "prettier": "^3.3.2", "rollup-plugin-visualizer": "^5.12.0", - "sass": "^1.77.6", - "terser": "^5.31.1", + "sass": "^1.77.7", + "terser": "^5.31.2", "typescript": "^5.5.3", "vite": "^5.3.3", "vite-plugin-cdn-import": "^1.0.1", diff --git a/Web/src/hooks/setupVXETableHook.ts b/Web/src/hooks/setupVXETableHook.ts index 8c699285..332873da 100644 --- a/Web/src/hooks/setupVXETableHook.ts +++ b/Web/src/hooks/setupVXETableHook.ts @@ -8,10 +8,10 @@ import 'vxe-table-plugin-element/dist/style.css'; // Vxe UI 组件库 import VxeUI, { VxeComponentSizeType } from 'vxe-pc-ui'; import ExcelJS from 'exceljs'; -import { Local } from '../utils/storage'; +import { useThemeConfig } from '/@/stores/themeConfig'; +const vxeSize: VxeComponentSizeType = useThemeConfig().themeConfig.globalComponentSize == 'small' ? 'mini' : useThemeConfig().themeConfig.globalComponentSize == 'default' ? 'small' : 'medium'; export const setupVXETable = (app: App) => { - let vxeSize = getVxeTableSize(); // 加载插件 VxeUITable.use(VXETablePluginElement); VxeUITable.use(VXETablePluginExportXLSX, { ExcelJS: ExcelJS }); @@ -109,18 +109,3 @@ export const setupVXETable = (app: App) => { // app.config.globalProperties.$XSaveFile = VxeUI.saveFile // app.config.globalProperties.$XReadFile = VxeUI.readFile }; - -// 从全局主题里面获取组件大小模式 -function getVxeTableSize() { - let vxeSize: VxeComponentSizeType = 'mini'; - - let themeConfig = Local.get('themeConfig'); - if (themeConfig == null || themeConfig == undefined) return vxeSize; - - let size = themeConfig.globalComponentSize; - if (size == 'large') vxeSize = 'medium'; - else if (size == 'default') vxeSize = 'small'; - else if (size == 'small') vxeSize = 'mini'; - - return vxeSize; -} diff --git a/Web/src/hooks/useVxeTableOptionsHook.ts b/Web/src/hooks/useVxeTableOptionsHook.ts new file mode 100644 index 00000000..e8f0b0f7 --- /dev/null +++ b/Web/src/hooks/useVxeTableOptionsHook.ts @@ -0,0 +1,84 @@ +import { dayjs } from 'element-plus'; +import { reactive } from 'vue'; +import { VxeGridProps, VxeGridPropTypes, VxeComponentSizeType } from 'vxe-table'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { merge } from 'lodash-es'; + +const vxeSize: VxeComponentSizeType = useThemeConfig().themeConfig.globalComponentSize == 'small' ? 'mini' : useThemeConfig().themeConfig.globalComponentSize == 'default' ? 'small' : 'medium'; + +/** + * @param {String} id 表格唯一标识,为空时自动随机产生; + * @param {String} id name:表格名称,与导出文件名有关; + * @param {VxeGridPropTypes.Columns} columns 列配置; + */ +interface iVxeOption { + id?: string; + name?: string; + columns: VxeGridPropTypes.Columns; +} + +/** + * Vxe表格参数化Hook + * @param {iVxeOption} opt 参数 + * @param {VxeGridProps} extras 要覆盖的参数 + * @returns + */ +export const useVxeTable = (opt: iVxeOption, extras?: VxeGridProps) => { + // 默认参数 + opt = Object.assign({ enableExport: true, remoteExport: false }, opt); + // 创建tableId,表格id固定才可以记录调整列宽,再次刷新仍有效。 + opt.id = opt.id ? opt.id : String(new Date().getTime()); + // console.log(opt); + const options = reactive({ + id: opt.id, + height: 'auto', + autoResize: true, + size: vxeSize, + loading: false, + align: 'center', // 自动监听父元素的变化去重新计算表格(对于父元素可能存在动态变化、显示隐藏的容器中、列宽异常等场景中的可能会用到) + // data: [] as Array, + columns: opt.columns, + toolbarConfig: { + size: vxeSize, + slots: { buttons: 'toolbar_buttons', tools: 'toolbar_tools' }, + refresh: { + code: 'query', + }, + export: true, + print: true, + zoom: true, + custom: true, + }, + checkboxConfig: { range: true }, + sortConfig: { trigger: 'cell', remote: true }, + exportConfig: { + remote: false, // 设置使用服务端导出 + filename: `${opt.name}导出_${dayjs().format('YYMMDDHHmmss')}`, + }, + pagerConfig: { + enabled: true, + size: vxeSize, + pageSize: 20, + }, // 分页 + printConfig: { sheetName: '' }, + proxyConfig: { + enabled: true, + autoLoad: false, + sort: true, + props: { + list: 'data.result', // 不分页时 + result: 'data.result.items', // 分页时 + total: 'data.result.total', + message: 'data.message', + }, + }, + customConfig: { + storage: { + // 是否启用 localStorage 本地保存,会将列操作状态保留在本地(需要有 id) + visible: true, // 启用显示/隐藏列状态 + resizable: true, // 启用列宽状态 + }, + }, + }); + return extras ? merge(options, extras) : options; +}; diff --git a/Web/src/theme/element.scss b/Web/src/theme/element.scss index 83daf5b7..47524694 100644 --- a/Web/src/theme/element.scss +++ b/Web/src/theme/element.scss @@ -376,13 +376,13 @@ /* Table 表格 element plus 2.2.0 版本 ------------------------------- */ .el-table { + // 表头背景色 + --el-table-header-bg-color: var(--next-bg-main-color); + .el-button.is-text { padding: 0; } - // 表头背景色 - --el-table-header-bg-color: var(--next-bg-main-color); - // 表头字体颜色 thead { color: var(--el-text-color-regular); diff --git a/Web/src/theme/vxeTable.scss b/Web/src/theme/vxeTable.scss index 2482ce3b..a1be7244 100644 --- a/Web/src/theme/vxeTable.scss +++ b/Web/src/theme/vxeTable.scss @@ -36,10 +36,11 @@ .vxe-cell { padding-left: 5px !important; padding-right: 5px !important; + user-select: text !important; + .el-button { padding: 0 !important; } - user-select: text !important; } .vxe-pager.size--mini { diff --git a/Web/src/views/login/component/account.vue b/Web/src/views/login/component/account.vue index 1407af75..a22804a5 100644 --- a/Web/src/views/login/component/account.vue +++ b/Web/src/views/login/component/account.vue @@ -283,6 +283,8 @@ defineExpose({ saveTokenAndInitRoutes });