From 4399f07d8ff64f19d8cc802bd48327fbf5cb234b Mon Sep 17 00:00:00 2001 From: zuohuaijun Date: Sun, 30 Jun 2024 15:30:59 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=98=8E=E5=A2=9E=E5=8A=A0vxe-table?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E5=8F=8A=E6=A0=B7=E5=BC=8F=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SeedData/SysConfigSeedData.cs | 6 +- Web/package.json | 8 +- Web/src/components/highLightKeyword/index.vue | 19 ++ Web/src/hooks/dateTimeShortCust.ts | 25 ++ Web/src/hooks/setupVXETableHook.ts | 109 ++++++++ Web/src/hooks/vxeTableOptionsHook.ts | 89 ++++++ Web/src/layout/component/columnsAside.vue | 2 +- Web/src/layout/footer/index.vue | 5 +- Web/src/layout/lockScreen/index.vue | 3 +- Web/src/layout/logo/index.vue | 2 +- .../layout/navBars/tagsView/contextmenu.vue | 2 +- Web/src/layout/navBars/tagsView/tagsView.vue | 52 ++-- Web/src/layout/navBars/topBar/breadcrumb.vue | 6 +- Web/src/layout/navBars/topBar/settings.vue | 18 +- Web/src/layout/navBars/topBar/user.vue | 8 +- Web/src/layout/navBars/topBar/userNews.vue | 11 +- Web/src/layout/navMenu/subItem.vue | 12 +- Web/src/main.ts | 26 +- Web/src/stores/themeConfig.ts | 16 +- Web/src/theme/app.scss | 20 +- Web/src/theme/dark.scss | 12 + Web/src/theme/element.scss | 53 ++-- Web/src/theme/index.scss | 1 + Web/src/theme/vxe.scss | 69 +++++ Web/src/utils/authFunction.ts | 28 ++ Web/src/utils/formatTime.ts | 3 +- Web/src/views/system/onlineUser/index.vue | 2 +- .../views/system/role/component/baseApi.vue | 2 +- .../views/system/role/component/grantApi.vue | 2 +- .../views/system/role/component/grantData.vue | 2 +- Web/src/views/system/role/index.vue | 257 ++++++++++-------- 31 files changed, 664 insertions(+), 206 deletions(-) create mode 100644 Web/src/components/highLightKeyword/index.vue create mode 100644 Web/src/hooks/dateTimeShortCust.ts create mode 100644 Web/src/hooks/setupVXETableHook.ts create mode 100644 Web/src/hooks/vxeTableOptionsHook.ts create mode 100644 Web/src/theme/vxe.scss diff --git a/Admin.NET/Admin.NET.Core/SeedData/SysConfigSeedData.cs b/Admin.NET/Admin.NET.Core/SeedData/SysConfigSeedData.cs index 3b2a8dab..a0928390 100644 --- a/Admin.NET/Admin.NET.Core/SeedData/SysConfigSeedData.cs +++ b/Admin.NET/Admin.NET.Core/SeedData/SysConfigSeedData.cs @@ -32,10 +32,10 @@ public class SysConfigSeedData : ISqlSugarEntitySeedData new SysConfig{ Id=1300000000201, Name="发送异常日志邮件", Code="sys_error_mail", Value="True", SysFlag=YesNoEnum.Y, Remark="是否发送异常日志邮件", OrderNo=110, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysConfig{ Id=1300000000211, Name="开启域登录验证", Code="sys_domain_login", Value="False", SysFlag=YesNoEnum.Y, Remark="是否开启域登录验证", OrderNo=120, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysConfig{ Id=1300000000221, Name="开启数据校验日志", Code="sys_validation_log", Value="True", SysFlag=YesNoEnum.Y, Remark="是否数据校验日志", OrderNo=130, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, - new SysConfig{ Id=1300000000301, Name="系统主标题", Code="sys_web_title", Value="Admin.NET", SysFlag=YesNoEnum.Y, Remark="系统主标题", OrderNo=300, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, - new SysConfig{ Id=1300000000311, Name="系统副标题", Code="sys_web_viceTitle", Value="Admin.NET", SysFlag=YesNoEnum.Y, Remark="系统副标题", OrderNo=310, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, + new SysConfig{ Id=1300000000301, Name="系统主标题", Code="sys_web_title", Value="Admin.NET.Pro", SysFlag=YesNoEnum.Y, Remark="系统主标题", OrderNo=300, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, + new SysConfig{ Id=1300000000311, Name="系统副标题", Code="sys_web_viceTitle", Value="Admin.NET.Pro", SysFlag=YesNoEnum.Y, Remark="系统副标题", OrderNo=310, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysConfig{ Id=1300000000321, Name="系统描述", Code="sys_web_viceDesc", Value="站在巨人肩膀上的 .NET 通用权限开发框架", SysFlag=YesNoEnum.Y, Remark="系统描述", OrderNo=320, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, - new SysConfig{ Id=1300000000331, Name="水印内容", Code="sys_web_watermark", Value="Admin.NET", SysFlag=YesNoEnum.Y, Remark="水印内容", OrderNo=330, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, + new SysConfig{ Id=1300000000331, Name="水印内容", Code="sys_web_watermark", Value="Admin.NET.Pro", SysFlag=YesNoEnum.Y, Remark="水印内容", OrderNo=330, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysConfig{ Id=1300000000341, Name="版权说明", Code="sys_web_copyright", Value="Copyright © 2021-present Admin.NET All rights reserved.", SysFlag=YesNoEnum.Y, Remark="版权说明", OrderNo=340, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysConfig{ Id=1300000000351, Name="系统图标", Code="sys_web_logo", Value="/Upload/logo.png", SysFlag=YesNoEnum.Y, Remark="系统图标", OrderNo=350, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysConfig{ Id=1300000000361, Name="ICP备案号", Code="sys_web_icp", Value="省ICP备12345678号", SysFlag=YesNoEnum.Y, Remark="ICP备案号", OrderNo=360, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, diff --git a/Web/package.json b/Web/package.json index 840c0780..fbf1ffb7 100644 --- a/Web/package.json +++ b/Web/package.json @@ -32,6 +32,7 @@ "echarts-gl": "^2.0.9", "echarts-wordcloud": "^2.1.0", "element-plus": "^2.7.6", + "exceljs": "^4.4.0", "ezuikit": "^1.0.0", "ezuikit-js": "^8.0.5", "gcoord": "^1.0.6", @@ -67,6 +68,11 @@ "vue-signature-pad": "^3.0.2", "vue3-tree-org": "^4.2.2", "vuedraggable": "4.0.3", + "vxe-pc-ui": "^4.0.42", + "vxe-table": "^4.7.39", + "vxe-table-plugin-element": "^4.0.4", + "vxe-table-plugin-export-xlsx": "^4.0.4", + "xe-utils": "^3.5.27", "xlsx-js-style": "^1.2.0" }, "devDependencies": { @@ -81,7 +87,7 @@ "@vitejs/plugin-vue-jsx": "^4.0.0", "@vue/compiler-sfc": "^3.4.31", "code-inspector-plugin": "^0.14.2", - "eslint": "^9.5.0", + "eslint": "^9.6.0", "eslint-plugin-vue": "^9.26.0", "less": "^4.2.0", "prettier": "^3.3.2", diff --git a/Web/src/components/highLightKeyword/index.vue b/Web/src/components/highLightKeyword/index.vue new file mode 100644 index 00000000..bd661321 --- /dev/null +++ b/Web/src/components/highLightKeyword/index.vue @@ -0,0 +1,19 @@ + + + diff --git a/Web/src/hooks/dateTimeShortCust.ts b/Web/src/hooks/dateTimeShortCust.ts new file mode 100644 index 00000000..52e63c85 --- /dev/null +++ b/Web/src/hooks/dateTimeShortCust.ts @@ -0,0 +1,25 @@ +/** + * 日期时间设置快捷选项 + * @returns + */ +export const useDateTimeShortCust = () => { + return [ + { text: '今天', value: new Date() }, + { + text: '昨天', + value: () => { + const date = new Date(); + date.setTime(date.getTime() - 3600 * 1000 * 24); + return date; + }, + }, + { + text: '上周', + value: () => { + const date = new Date(); + date.setTime(date.getTime() - 3600 * 1000 * 24 * 7); + return date; + }, + }, + ]; +}; diff --git a/Web/src/hooks/setupVXETableHook.ts b/Web/src/hooks/setupVXETableHook.ts new file mode 100644 index 00000000..045063cc --- /dev/null +++ b/Web/src/hooks/setupVXETableHook.ts @@ -0,0 +1,109 @@ +import App from '/@/App.vue'; +// VXETable +import VxeUITable from 'vxe-table'; +import VXETablePluginElement from 'vxe-table-plugin-element'; +import VXETablePluginExportXLSX from 'vxe-table-plugin-export-xlsx'; +// import 'vxe-table/lib/style.css'; // 已在theme/vxe.scss引入 +import 'vxe-table-plugin-element/dist/style.css'; +// Vxe UI 组件库 +import VxeUI from 'vxe-pc-ui'; +import ExcelJS from 'exceljs'; + +export const setupVXETable = (app: App) => { + // 加载插件 + VxeUITable.use(VXETablePluginElement); + VxeUITable.use(VXETablePluginExportXLSX, { ExcelJS: ExcelJS }); + // VXETable全局配置https://vxetable.cn/v4.7/#/table/start/global + VxeUITable.setConfig({ + theme: 'light', // 主题颜色 + size: 'mini', // 全局尺寸 + // i18n: (key, args) => i18n.global.t(key, args), + // zIndex: 999, // 全局 zIndex 起始值,如果项目的的 z-index 样式值过大时就需要跟随设置更大,避免被遮挡 + // version: 0, // 版本号,对于某些带数据缓存的功能有用到,上升版本号可以用于重置数据 + // loadingText: '加载中...', // 全局loading提示内容,如果为null则不显示文本 + table: { + border: true, // 是否带有边框 + stripe: true, // 是否带有斑马纹 + // keepSource: false,// 保持原始值的状态,被某些功能所依赖,比如编辑状态、还原数据等(开启后影响性能,具体取决于数据量) + showOverflow: true, // 设置所有内容过长时显示为省略号(如果是固定列建议设置该值,提升渲染速度) + size: 'mini', // 表格的尺寸[medium, small, mini] + autoResize: true, // 自动监听父元素的变化去重新计算表格(对于父元素可能存在动态变化、显示隐藏的容器中、列宽异常等场景中的可能会用到) + round: false, // 是否为圆角边框 + emptyText: '暂无数据', // + columnConfig: { + isCurrent: true, // 当鼠标点击列头时,是否要高亮当前列 + isHover: true, // 当鼠标移到列头时,是否要高亮当前头 + resizable: true, // 每一列是否启用列宽调整 + minWidth: 70, // 每一列的最小宽度(auto, px, %) + }, + rowConfig: { + isCurrent: false, // 当鼠标点击行时,是否要高亮当前行 + isHover: true, // 当鼠标移到行时,是否要高亮当前行 + }, + radioConfig: { + strict: true, // 严格模式,选中后不能取消 + highlight: true, // 高亮选中行 + }, + checkboxConfig: { + strict: true, // 严格模式,当数据为空或全部禁用时,列头的复选框为禁用状态 + highlight: true, // 高亮勾选行 + range: true, // 开启复选框范围选择功能(启用后通过鼠标在复选框的列内滑动选中或取消指定行)***全局配置貌似不生效*** + trigger: 'default', // 触发方式(注:当多种功能重叠时,会同时触发)default(默认), cell(点击单元格触发), row(点击行触发) + }, + exportConfig: { + remote: false, // 是否服务端导出 + types: ['xlsx', 'csv', 'html', 'xml', 'txt'], // 可选文件类型列表 + modes: ['current', 'selected', 'all'], // 输出数据的方式 + }, + printConfig: { modes: ['current', 'selected', 'all'] }, // 输出数据的方式 + tooltipConfig: { + showAll: false, // 所有单元格开启工具提示 + enterable: true, // 鼠标是否可进入到工具提示中 + theme: 'dark', + }, + customConfig: { + // 貌似全局设置不生效,须要单独设置 + storage: { + // 是否启用 localStorage 本地保存,会将列操作状态保留在本地(需要有 id) + visible: true, // 启用显示/隐藏列状态 + resizable: true, // 启用列宽状态 + }, + }, + scrollX: { + enabled: true, // 是否默认开启横向虚拟滚动 + gt: 30, // 指定大于指定列时自动启动横向虚拟滚动 + }, + scrollY: { + scrollToTopOnChange: true, // 当数据源被更改时,自动将纵向滚动条滚动到顶部 + enabled: true, // 是否默认开启纵向虚拟滚动 + gt: 50, // 当数据大于指定数量时自动触发启用虚拟滚动 + }, + }, + grid: { + size: 'mini', + toolbarConfig: { + size: 'mini', // 尺寸 medium, small, mini + perfect: false, // 配套的样式 + }, + zoomConfig: { escRestore: true }, // 是否允许通过按下 ESC 键还原 + }, + pager: { + size: 'mini', + background: true, // 带背景颜色 + perfect: false, // 配套的样式 + autoHidden: false, // 当只有一页时自动隐藏 + pageSize: 50, // 每页大小 + pagerCount: 10, // 显示页码按钮的数量 + pageSizes: [50, 100, 200, 500], // 每页大小选项列表 + layouts: ['PrevJump', 'PrevPage', 'JumpNumber', 'NextPage', 'NextJump', 'Sizes', 'FullJump', 'PageCount', 'Total'], // 自定义布局 + }, + }); + // 安装UI组件 + app.use(VxeUI); + app.use(VxeUITable); + // 给 vue 实例挂载内部对象,例如: + // app.config.globalProperties.$XModal = VxeUI.modal + // app.config.globalProperties.$XPrint = VxeUI.print + // app.config.globalProperties.$XSaveFile = VxeUI.saveFile + // app.config.globalProperties.$XReadFile = VxeUI.readFile +}; diff --git a/Web/src/hooks/vxeTableOptionsHook.ts b/Web/src/hooks/vxeTableOptionsHook.ts new file mode 100644 index 00000000..9099390e --- /dev/null +++ b/Web/src/hooks/vxeTableOptionsHook.ts @@ -0,0 +1,89 @@ +import { dayjs } from 'element-plus'; +import { reactive } from 'vue'; +import { VxeGridProps, VxeGridPropTypes } from 'vxe-table'; + +/** + * @param {String} id 表格唯一标识,为空时自动随机产生; + * @param {String} id name:表格名称,与导出文件名有关; + * @param {VxeGridPropTypes.Columns} columns 列配置; + * @param {boolean} enableExport 是否显示导出按钮; + * @param {boolean} remoteExport 是否为服务器导出; + * @param {Function} searchCallback 查询回调方法; + * @param {Function} queryAllCallback 查询所有回调方法; + * @param {Function} remoteExportCallback 服务器导出回调方法; + */ +interface iVxeOption { + id?: string; + name?: string; + columns: VxeGridPropTypes.Columns; + enableExport?: boolean; + remoteExport?: boolean; + searchCallback: Function; + queryAllCallback?: Function; + remoteExportCallback?: Function; +} + +/** + * Vxe表格参数化Hook + * @param {iVxeOption} opt 参数 + * @param {VxeGridProps} extras 要覆盖的参数 + * @returns + */ +export const useVxeTable = (opt: iVxeOption, extras?: VxeGridProps = null) => { + // 默认参数 + 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: 'mini', + loading: false, + align: 'center', // 自动监听父元素的变化去重新计算表格(对于父元素可能存在动态变化、显示隐藏的容器中、列宽异常等场景中的可能会用到) + // data: [] as Array, + columns: opt.columns, + toolbarConfig: { + size: 'small', + slots: { buttons: 'toolbar_buttons', tools: 'toolbar_tools' }, + refresh: { + queryMethod: () => opt.searchCallback(), + }, + export: opt.enableExport, + print: true, + zoom: true, + custom: true, + }, + checkboxConfig: { range: true }, + sortConfig: { trigger: 'cell', remote: true }, + exportConfig: { + remote: opt.remoteExport, // 设置使用服务端导出 + filename: `${opt.name}导出_${dayjs().format('YYMMDDHHmmss')}`, + exportMethod: ({ options }) => { + if (opt.remoteExportCallback) opt.remoteExportCallback(options); + }, //服务器导出方法 + }, + printConfig: { sheetName: '' }, + proxyConfig: { + props: { + list: 'data.result.items', // 不分页时 + // result: 'data.result.items', // 分页时 + total: 'data.result.total', + message: 'data.message', + }, + ajax: { + query: () => Promise.resolve(), // 不加会报错 + queryAll: opt.queryAllCallback, + }, + }, + customConfig: { + storage: { + // 是否启用 localStorage 本地保存,会将列操作状态保留在本地(需要有 id) + visible: true, // 启用显示/隐藏列状态 + resizable: true, // 启用列宽状态 + }, + }, + }); + return extras ? Object.assign(options, extras) : options; +}; diff --git a/Web/src/layout/component/columnsAside.vue b/Web/src/layout/component/columnsAside.vue index 9a8e59a4..7eaf2603 100644 --- a/Web/src/layout/component/columnsAside.vue +++ b/Web/src/layout/component/columnsAside.vue @@ -283,7 +283,7 @@ watch( width: var(--el-columnsMenuRoundWidth); transform: translateX(-50%); z-index: 0; - transition: 0.3s ease-in-out; + transition: 0.5s ease-in-out; border-radius: 5px; } .columns-card { diff --git a/Web/src/layout/footer/index.vue b/Web/src/layout/footer/index.vue index 9db8046a..e46fecd6 100644 --- a/Web/src/layout/footer/index.vue +++ b/Web/src/layout/footer/index.vue @@ -1,8 +1,7 @@ diff --git a/Web/src/layout/lockScreen/index.vue b/Web/src/layout/lockScreen/index.vue index 13e4cb48..69776cb9 100644 --- a/Web/src/layout/lockScreen/index.vue +++ b/Web/src/layout/lockScreen/index.vue @@ -205,7 +205,6 @@ const onLockScreenSubmit = async () => { const password = sm2.doEncrypt(state.lockScreenPassword, publicKey, 1); const [err, res] = await feature(getAPI(SysAuthApi).apiSysAuthUnLockScreenPost(password)); if (err) { - console.log(err); state.message = err.message; state.showMessage = true; state.lockScreenPassword = ''; @@ -245,7 +244,7 @@ onMounted(() => { state.moveDifference = state.moveDifference - 10; onMove(); //超过600像素则结束 - if (state.moveDifference < -600) clearInterval(moveInterval); + if (state.moveDifference < -410 && moveInterval) clearInterval(moveInterval); }, 5); } //当显示消息时,按ENTER切到密码输入 diff --git a/Web/src/layout/logo/index.vue b/Web/src/layout/logo/index.vue index 9c3eff2e..3688ca8b 100644 --- a/Web/src/layout/logo/index.vue +++ b/Web/src/layout/logo/index.vue @@ -69,7 +69,7 @@ const onThemeConfigChange = () => { cursor: pointer; animation: logoAnimation 0.3s ease-in-out; &-img { - width: 20px; + width: 35px; margin: auto; } &:hover { diff --git a/Web/src/layout/navBars/tagsView/contextmenu.vue b/Web/src/layout/navBars/tagsView/contextmenu.vue index 58da2f0f..856c1d83 100644 --- a/Web/src/layout/navBars/tagsView/contextmenu.vue +++ b/Web/src/layout/navBars/tagsView/contextmenu.vue @@ -1,5 +1,5 @@