兰宝车间质量管理系统-前端
疯狂的狮子Li
2023-04-03 1595cb282aab5399862fac6406b5de550863e3b6
update 调整代码格式
已添加7个文件
已删除7个文件
已修改181个文件
6629 ■■■■ 文件已修改
.eslintrc-auto-import.json 补丁 | 查看 | 原始文档 | blame | 历史
.eslintrc.js 补丁 | 查看 | 原始文档 | blame | 历史
.prettierrc.cjs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
README.md 119 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Vite/plugins/auto-import.ts 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Vite/plugins/components.ts 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Vite/plugins/compression.ts 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Vite/plugins/icons.ts 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Vite/plugins/index.ts 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Vite/plugins/svg-icon.ts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Vite/plugins/unocss.ts 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
commitlint.config.js 补丁 | 查看 | 原始文档 | blame | 历史
html/ie.html 补丁 | 查看 | 原始文档 | blame | 历史
index.html 补丁 | 查看 | 原始文档 | blame | 历史
package.json 补丁 | 查看 | 原始文档 | blame | 历史
src/App.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/animate.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/demo/demo.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/demo/tree.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/demo/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/login.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/menu.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/monitor/cache/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/monitor/cache/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/monitor/loginInfo/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/monitor/loginInfo/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/monitor/online/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/monitor/online/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/monitor/operlog/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/monitor/operlog/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/config/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/config/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/dept/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/dept/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/dict/data/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/dict/data/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/dict/type/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/dict/type/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/menu/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/menu/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/notice/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/notice/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/oss/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/oss/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/ossConfig/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/ossConfig/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/post/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/post/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/role/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/role/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/tenant/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/tenant/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/tenantPackage/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/tenantPackage/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/user/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/user/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/tool/gen/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/tool/gen/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/api/types.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/btn.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/element-ui.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/mixin.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/ruoyi.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/sidebar.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/transition.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/variables.module.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Breadcrumb/index.vue 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/DictTag/index.vue 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Editor/index.vue 56 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/FileUpload/index.vue 88 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Hamburger/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/components/HeaderSearch/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/components/IconSelect/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/components/IconSelect/requireIcons.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/components/ImagePreview/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/components/ImageUpload/index.vue 78 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Pagination/index.vue 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/ParentView/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/components/RightToolbar/index.vue 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/RuoYiDoc/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/components/RuoYiGit/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Screenfull/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/components/SizeSelect/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/components/SvgIcon/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/components/TopNav/index.vue 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/TreeSelect/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/components/iFrame/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/directive/common/copyText.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/directive/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/directive/permission/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/enums/MenuTypeEnum.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/enums/RespEnum.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/enums/SettingTypeEnum.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/enums/layout/LayoutEnum.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/lang/en.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/lang/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/lang/zh-cn.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/AppMain.vue 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/IframeToggle/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/InnerLink/index.vue 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Navbar.vue 130 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Settings/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Sidebar/Link.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Sidebar/Logo.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Sidebar/SidebarItem.vue 62 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Sidebar/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/TagsView/ScrollPane.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/TagsView/index.vue 62 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/permission.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/plugins/auth.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/plugins/cache.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/plugins/download.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/plugins/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/plugins/modal.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/plugins/svgicon.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/plugins/tab.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/settings.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/app.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/dict.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/permission.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/settings.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/tagsView.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/user.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/types/auto-imports.d.ts 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/types/axios.d.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/types/components.d.ts 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/types/env.d.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/types/global.d.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/types/module.d.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/types/router.d.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/types/setting.d.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/dict.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/dynamicTitle.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/errorCode.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/i18n.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/jsencrypt.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/permission.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/request.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/ruoyi.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/scroll-to.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/theme.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/validate.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/views/demo/demo/index.vue 294 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/demo/tree/index.vue 214 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/error/401.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/views/error/404.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/views/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login.vue 92 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/admin/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/cache/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/logininfor/index.vue 196 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/online/index.vue 102 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/operlog/index.vue 263 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/xxljob/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/views/redirect/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/views/register.vue 114 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/config/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/dept/index.vue 260 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/dict/data.vue 266 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/dict/index.vue 244 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/menu/index.vue 314 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/notice/index.vue 237 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/oss/config.vue 261 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/oss/index.vue 264 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/post/index.vue 212 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/role/authUser.vue 144 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/role/index.vue 386 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/role/selectUser.vue 90 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/tenant/index.vue 280 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/tenantPackage/index.vue 198 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/user/authRole.vue 112 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/user/index.vue 574 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/user/profile/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/user/profile/resetPwd.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/user/profile/userAvatar.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/user/profile/userInfo.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/build/index.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/gen/basicInfoForm.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/gen/editTable.vue 152 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/gen/genInfoForm.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/gen/importTable.vue 68 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/gen/index.vue 216 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
tsconfig.json 补丁 | 查看 | 原始文档 | blame | 历史
vite.config.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite/plugins/auto-import.ts 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite/plugins/components.ts 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite/plugins/compression.ts 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite/plugins/icons.ts 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite/plugins/index.ts 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite/plugins/svg-icon.ts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite/plugins/unocss.ts 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.eslintrc-auto-import.json
.eslintrc.js
.prettierrc.cjs
@@ -7,7 +7,7 @@
    // æŒ‡å®šæ¯ä¸ªç¼©è¿›çº§åˆ«çš„空格数
    tabWidth: 2,
    // ä½¿ç”¨åˆ¶è¡¨ç¬¦è€Œä¸æ˜¯ç©ºæ ¼ç¼©è¿›è¡Œ
    useTabs: true,
    useTabs: false,
    // åœ¨è¯­å¥æœ«å°¾æ˜¯å¦éœ€è¦åˆ†å·
    semi: true,
    // æ˜¯å¦ä½¿ç”¨å•引号
README.md
@@ -1,11 +1,9 @@
## å¹³å°ç®€ä»‹
## å¹³å°ç®€ä»‹
- æœ¬ä»“库为前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) ç‰ˆæœ¬ã€‚
- é…å¥—后端代码仓库地址
- [RuoYi-Vue-Plus 5.X(注意版本号)](https://gitee.com/dromara/RuoYi-Vue-Plus)
- [RuoYi-Cloud-Plus 2.X(注意版本号)](https://gitee.com/dromara/RuoYi-Cloud-Plus)
* æœ¬ä»“库为前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [TS](https://www.typescriptlang.org/) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) ç‰ˆæœ¬ã€‚
* é…å¥—后端代码仓库地址
* [RuoYi-Vue-Plus 5.X(注意版本号)](https://gitee.com/dromara/RuoYi-Vue-Plus)
* [RuoYi-Cloud-Plus 2.X(注意版本号)](https://gitee.com/dromara/RuoYi-Cloud-Plus)
## å‰ç«¯è¿è¡Œ
@@ -19,7 +17,6 @@
# å¯åŠ¨æœåŠ¡
npm run dev
# æž„建测试环境 yarn build:stage
# æž„建生产环境 yarn build:prod
# å‰ç«¯è®¿é—®åœ°å€ http://localhost:80
```
@@ -27,7 +24,7 @@
## æœ¬æ¡†æž¶ä¸Ž RuoYi çš„业务差异
| ä¸šåŠ¡         | åŠŸèƒ½è¯´æ˜Ž                                                        | æœ¬æ¡†æž¶ | RuoYi                          |
| ------------ | --------------------------------------------------------------- | ------ | ------------------------------ |
|--------|-----------------------------------------|-----|------------------|
| ç§Ÿæˆ·ç®¡ç†     | ç³»ç»Ÿå†…租户的管理 å¦‚:租户套餐、过期时间、用户数量、企业信息等    | æ”¯æŒ   | æ—                              |
| ç§Ÿæˆ·å¥—餐管理 | ç³»ç»Ÿå†…租户所能使用的套餐管理 å¦‚:套餐内所包含的菜单等            | æ”¯æŒ   | æ—                              |
| ç”¨æˆ·ç®¡ç†     | ç”¨æˆ·çš„管理配置 å¦‚:新增用户、分配用户所属部门、角色、岗位等      | æ”¯æŒ   | æ”¯æŒ                           |
@@ -51,88 +48,26 @@
| åœ¨çº¿æž„建器   | æ‹–动表单元素生成相应的 HTML ä»£ç ã€‚                              | æ”¯æŒ   | æ”¯æŒ                           |
| ä½¿ç”¨æ¡ˆä¾‹     | ç³»ç»Ÿçš„一些功能案例                                              | æ”¯æŒ   | ä¸æ”¯æŒ                         |
## æ¼”示图
## æ¼”示图例
- æœ¬ä»“库为前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) ç‰ˆæœ¬ã€‚
- é…å¥—后端代码仓库地址
- [RuoYi-Vue-Plus 5.X(注意版本号)](https://gitee.com/dromara/RuoYi-Vue-Plus)
- [RuoYi-Cloud-Plus 2.X(注意版本号)](https://gitee.com/dromara/RuoYi-Cloud-Plus)
## å‰ç«¯è¿è¡Œ
```bash
# å…‹éš†é¡¹ç›®
git clone https://gitee.com/JavaLionLi/plus-ui.git
# å®‰è£…依赖
npm install --registry=https://registry.npmmirror.com
# å¯åŠ¨æœåŠ¡
npm run dev
# æž„建测试环境 yarn build:stage
# æž„建生产环境 yarn build:prod
# å‰ç«¯è®¿é—®åœ°å€ http://localhost:80
```
## åŽç«¯æ”¹é€ 
参考后端代码内 `ruoyi-gen/resources/vm/vue/v3/readme.txt` è¯´æ˜Ž
## å†…置功能
1. ç§Ÿæˆ·ç®¡ç†ï¼šé…ç½®ç³»ç»Ÿç§Ÿæˆ·ï¼Œæ”¯æŒ SaaS åœºæ™¯ä¸‹çš„多租户功能。
2. ç”¨æˆ·ç®¡ç†ï¼šç”¨æˆ·æ˜¯ç³»ç»Ÿæ“ä½œè€…,该功能主要完成系统用户配置。
3. éƒ¨é—¨ç®¡ç†ï¼šé…ç½®ç³»ç»Ÿç»„织机构(公司、部门、小组),树结构展现支持数据权限。
4. å²—位管理:配置系统用户所属担任职务。
5. èœå•管理:配置系统菜单,操作权限,按钮权限标识等。
6. è§’色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
7. å­—典管理:对系统中经常使用的一些较为固定的数据进行维护。
8. å‚数管理:对系统动态配置常用参数。
9. é€šçŸ¥å…¬å‘Šï¼šç³»ç»Ÿé€šçŸ¥å…¬å‘Šä¿¡æ¯å‘布维护。
10. æ“ä½œæ—¥å¿—:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
11. ç™»å½•日志:系统登录日志记录查询包含登录异常。
12. åœ¨çº¿ç”¨æˆ·ï¼šå½“前系统中活跃用户状态监控。
13. å®šæ—¶ä»»åŠ¡ï¼šåœ¨çº¿ï¼ˆæ·»åŠ ã€ä¿®æ”¹ã€åˆ é™¤)任务调度包含执行结果日志。
14. ä»£ç ç”Ÿæˆï¼šå‰åŽç«¯ä»£ç çš„生成(java、html、xml、sql)支持 CRUD ä¸‹è½½ ã€‚
15. ç³»ç»ŸæŽ¥å£ï¼šæ ¹æ®ä¸šåŠ¡ä»£ç è‡ªåŠ¨ç”Ÿæˆç›¸å…³çš„ api æŽ¥å£æ–‡æ¡£ã€‚
16. æœåŠ¡ç›‘æŽ§ï¼šç›‘è§†å½“å‰ç³»ç»Ÿ CPU、内存、磁盘、堆栈等相关信息。
17. ç¼“存监控:对系统的缓存信息查询,命令统计等。
18. åœ¨çº¿æž„建器:拖动表单元素生成相应的 HTML ä»£ç ã€‚
## æ¼”示图
<table>
    <tr>
        <td><img src="https://oscimg.oschina.net/oscnet/cd1f90be5f2684f4560c9519c0f2a232ee8.jpg"/></td>
        <td><img src="https://oscimg.oschina.net/oscnet/1cbcf0e6f257c7d3a063c0e3f2ff989e4b3.jpg"/></td>
    </tr>
    <tr>
        <td><img src="https://oscimg.oschina.net/oscnet/up-8074972883b5ba0622e13246738ebba237a.png"/></td>
        <td><img src="https://oscimg.oschina.net/oscnet/up-9f88719cdfca9af2e58b352a20e23d43b12.png"/></td>
    </tr>
    <tr>
        <td><img src="https://oscimg.oschina.net/oscnet/up-39bf2584ec3a529b0d5a3b70d15c9b37646.png"/></td>
        <td><img src="https://oscimg.oschina.net/oscnet/up-936ec82d1f4872e1bc980927654b6007307.png"/></td>
    </tr>
    <tr>
        <td><img src="https://oscimg.oschina.net/oscnet/up-b2d62ceb95d2dd9b3fbe157bb70d26001e9.png"/></td>
        <td><img src="https://oscimg.oschina.net/oscnet/up-d67451d308b7a79ad6819723396f7c3d77a.png"/></td>
    </tr>
    <tr>
        <td><img src="https://oscimg.oschina.net/oscnet/5e8c387724954459291aafd5eb52b456f53.jpg"/></td>
        <td><img src="https://oscimg.oschina.net/oscnet/644e78da53c2e92a95dfda4f76e6d117c4b.jpg"/></td>
    </tr>
    <tr>
        <td><img src="https://oscimg.oschina.net/oscnet/up-8370a0d02977eebf6dbf854c8450293c937.png"/></td>
        <td><img src="https://oscimg.oschina.net/oscnet/up-49003ed83f60f633e7153609a53a2b644f7.png"/></td>
    </tr>
    <tr>
        <td><img src="https://oscimg.oschina.net/oscnet/up-d4fe726319ece268d4746602c39cffc0621.png"/></td>
        <td><img src="https://oscimg.oschina.net/oscnet/up-c195234bbcd30be6927f037a6755e6ab69c.png"/></td>
    </tr>
    <tr>
        <td><img src="https://oscimg.oschina.net/oscnet/b6115bc8c31de52951982e509930b20684a.jpg"/></td>
        <td><img src="https://oscimg.oschina.net/oscnet/up-5e4daac0bb59612c5038448acbcef235e3a.png"/></td>
    </tr>
</table>
|                                                                                            |                                                                                            |
|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|
| ![输入图片说明](https://foruda.gitee.com/images/1680077524361362822/270bb429_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680077619939771291/989bf9b6_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680077681751513929/1c27c5bd_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680077721559267315/74d63e23_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680077765638904515/1b75d4a6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078026375951297/eded7a4b_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078237104531207/0eb1b6a7_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078254306078709/5931e22f_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078287971528493/0b9af60a_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078308138770249/8d3b6696_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078352553634393/db5ef880_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078378238393374/601e4357_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078414983206024/2aae27c1_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078446738419874/ecce7d59_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078475971341775/149e8634_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078491666717143/3fadece7_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078558863188826/fb8ced2a_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078574561685461/ae68a0b2_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078594932772013/9d8bfec6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078626493093532/fcfe4ff6_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078643608812515/0295bd4f_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078685196286463/d7612c81_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078703877318597/56fce0bc_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078716586545643/b6dbd68f_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078734103217688/eb1e6aa6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078759131415480/73c525d8_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078779416197879/75e3ed02_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078802329118061/77e10915_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078893627848351/34a1c342_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078928175016986/f126ec4a_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078941718318363/b68a0f72_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078963175518631/3bb769a1_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078982294090567/b31c343d_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079000642440444/77ca82a9_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680079020995074177/03b7d52e_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079039367822173/76811806_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680079274333484664/4dfdc7c0_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079290467458224/d6715fcf_1766278.png "屏幕截图") |
Vite/plugins/auto-import.ts
ÎļþÒÑɾ³ý
Vite/plugins/components.ts
ÎļþÒÑɾ³ý
Vite/plugins/compression.ts
ÎļþÒÑɾ³ý
Vite/plugins/icons.ts
ÎļþÒÑɾ³ý
Vite/plugins/index.ts
ÎļþÒÑɾ³ý
Vite/plugins/svg-icon.ts
ÎļþÒÑɾ³ý
Vite/plugins/unocss.ts
ÎļþÒÑɾ³ý
commitlint.config.js
html/ie.html
index.html
package.json
src/App.vue
src/animate.ts
src/api/demo/demo.ts
src/api/demo/tree.ts
src/api/demo/types.ts
src/api/login.ts
src/api/menu.ts
src/api/monitor/cache/index.ts
src/api/monitor/cache/types.ts
src/api/monitor/loginInfo/index.ts
src/api/monitor/loginInfo/types.ts
src/api/monitor/online/index.ts
src/api/monitor/online/types.ts
src/api/monitor/operlog/index.ts
src/api/monitor/operlog/types.ts
src/api/system/config/index.ts
src/api/system/config/types.ts
src/api/system/dept/index.ts
src/api/system/dept/types.ts
src/api/system/dict/data/index.ts
src/api/system/dict/data/types.ts
src/api/system/dict/type/index.ts
src/api/system/dict/type/types.ts
src/api/system/menu/index.ts
src/api/system/menu/types.ts
src/api/system/notice/index.ts
src/api/system/notice/types.ts
src/api/system/oss/index.ts
src/api/system/oss/types.ts
src/api/system/ossConfig/index.ts
src/api/system/ossConfig/types.ts
src/api/system/post/index.ts
src/api/system/post/types.ts
src/api/system/role/index.ts
src/api/system/role/types.ts
src/api/system/tenant/index.ts
src/api/system/tenant/types.ts
src/api/system/tenantPackage/index.ts
src/api/system/tenantPackage/types.ts
src/api/system/user/index.ts
src/api/system/user/types.ts
src/api/tool/gen/index.ts
src/api/tool/gen/types.ts
src/api/types.ts
src/assets/styles/btn.scss
src/assets/styles/element-ui.scss
src/assets/styles/index.scss
src/assets/styles/mixin.scss
src/assets/styles/ruoyi.scss
src/assets/styles/sidebar.scss
src/assets/styles/transition.scss
src/assets/styles/variables.module.scss
src/components/Breadcrumb/index.vue
@@ -1,3 +1,15 @@
<template>
  <el-breadcrumb class="app-breadcrumb" separator="/">
    <transition-group name="breadcrumb">
      <el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
        <span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{
          item.meta?.title }}</span>
        <a v-else @click.prevent="handleLink(item)">{{ item.meta?.title }}</a>
      </el-breadcrumb-item>
    </transition-group>
  </el-breadcrumb>
</template>
<script setup lang="ts">
import { RouteLocationMatched } from 'vue-router'
@@ -36,18 +48,6 @@
  getBreadcrumb();
})
</script>
<template>
    <el-breadcrumb class="app-breadcrumb" separator="/">
        <transition-group name="breadcrumb">
            <el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
                <span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{
          item.meta?.title }}</span>
                <a v-else @click.prevent="handleLink(item)">{{ item.meta?.title }}</a>
            </el-breadcrumb-item>
        </transition-group>
    </el-breadcrumb>
</template>
<style lang="scss" scoped>
.app-breadcrumb.el-breadcrumb {
src/components/DictTag/index.vue
@@ -1,25 +1,3 @@
<script setup lang="ts">
import { PropType } from 'vue';
const props = defineProps({
  // æ•°æ®
  options: {
    type: Array as PropType<DictDataOption[]>,
    default: null,
  },
  // å½“前的值
  value: [Number, String, Array],
})
const values = computed(() => {
    if (props.value !== null && typeof props.value !== 'undefined') {
        return Array.isArray(props.value) ? props.value : [String(props.value)];
    } else {
        return [];
    }
})
</script>
<template>
    <div>
        <template v-for="(item, index) in options">
@@ -45,6 +23,28 @@
    </div>
</template>
<script setup lang="ts">
import { PropType } from 'vue';
const props = defineProps({
    // æ•°æ®
    options: {
        type: Array as PropType<DictDataOption[]>,
        default: null,
    },
    // å½“前的值
    value: [Number, String, Array],
})
const values = computed(() => {
    if (props.value !== null && typeof props.value !== 'undefined') {
        return Array.isArray(props.value) ? props.value : [String(props.value)];
    } else {
        return [];
    }
})
</script>
<style scoped>
.el-tag + .el-tag {
  margin-left: 10px;
src/components/Editor/index.vue
@@ -1,3 +1,31 @@
<template>
  <div>
    <el-upload
      :action="upload.url"
      :before-upload="handleBeforeUpload"
      :on-success="handleUploadSuccess"
      :on-error="handleUploadError"
      class="editor-img-uploader"
      name="file"
      :show-file-list="false"
      :headers="upload.headers"
      style="display: none"
      v-if="type === 'url'"
    >
    </el-upload>
    <div class="editor">
      <quill-editor
        ref="myQuillEditor"
        v-model:content="content"
        contentType="html"
        @textChange="(e: any) => $emit('update:modelValue', content)"
        :options="options"
        :style="styles"
      />
    </div>
  </div>
</template>
<script setup lang="ts">
import { QuillEditor, Quill } from '@vueup/vue-quill';
import '@vueup/vue-quill/dist/vue-quill.snow.css';
@@ -136,34 +164,6 @@
  proxy?.$modal.msgError('上传文件失败');
}
</script>
<template>
    <div>
        <el-upload
            :action="upload.url"
            :before-upload="handleBeforeUpload"
            :on-success="handleUploadSuccess"
            :on-error="handleUploadError"
            class="editor-img-uploader"
            name="file"
            :show-file-list="false"
            :headers="upload.headers"
            style="display: none"
            v-if="type === 'url'"
        >
        </el-upload>
        <div class="editor">
            <quill-editor
                ref="myQuillEditor"
                v-model:content="content"
                contentType="html"
                @textChange="(e: any) => $emit('update:modelValue', content)"
                :options="options"
                :style="styles"
            />
        </div>
    </div>
</template>
<style>
.editor, .ql-toolbar {
src/components/FileUpload/index.vue
@@ -1,3 +1,47 @@
<template>
  <div class="upload-file">
    <el-upload
      multiple
      :action="uploadFileUrl"
      :before-upload="handleBeforeUpload"
      :file-list="fileList"
      :limit="limit"
      :on-error="handleUploadError"
      :on-exceed="handleExceed"
      :on-success="handleUploadSuccess"
      :show-file-list="false"
      :headers="headers"
      class="upload-file-uploader"
      ref="fileUploadRef"
    >
      <!-- ä¸Šä¼ æŒ‰é’® -->
      <el-button type="primary">选取文件</el-button>
    </el-upload>
    <!-- ä¸Šä¼ æç¤º -->
    <div class="el-upload__tip" v-if="showTip">
      è¯·ä¸Šä¼ 
      <template v-if="fileSize">
        å¤§å°ä¸è¶…过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
      </template>
      <template v-if="fileType">
        æ ¼å¼ä¸º <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
      </template>
      çš„æ–‡ä»¶
    </div>
    <!-- æ–‡ä»¶åˆ—表 -->
    <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
      <li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
        <el-link :href="`${file.url}`" :underline="false" target="_blank">
          <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
        </el-link>
        <div class="ele-upload-list__item-content-action">
          <el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
        </div>
      </li>
    </transition-group>
  </div>
</template>
<script setup lang="ts">
import { getToken } from "@/utils/auth";
import { listByIds, delOss } from "@/api/system/oss";
@@ -160,50 +204,6 @@
  return strs != "" ? strs.substring(0, strs.length - 1) : "";
}
</script>
<template>
    <div class="upload-file">
        <el-upload
            multiple
            :action="uploadFileUrl"
            :before-upload="handleBeforeUpload"
            :file-list="fileList"
            :limit="limit"
            :on-error="handleUploadError"
            :on-exceed="handleExceed"
            :on-success="handleUploadSuccess"
            :show-file-list="false"
            :headers="headers"
            class="upload-file-uploader"
            ref="fileUploadRef"
        >
            <!-- ä¸Šä¼ æŒ‰é’® -->
            <el-button type="primary">选取文件</el-button>
        </el-upload>
        <!-- ä¸Šä¼ æç¤º -->
        <div class="el-upload__tip" v-if="showTip">
            è¯·ä¸Šä¼ 
            <template v-if="fileSize">
                å¤§å°ä¸è¶…过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
            </template>
            <template v-if="fileType">
                æ ¼å¼ä¸º <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
            </template>
            çš„æ–‡ä»¶
        </div>
        <!-- æ–‡ä»¶åˆ—表 -->
        <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
            <li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
                <el-link :href="`${file.url}`" :underline="false" target="_blank">
                    <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
                </el-link>
                <div class="ele-upload-list__item-content-action">
                    <el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
                </div>
            </li>
        </transition-group>
    </div>
</template>
<style scoped lang="scss">
.upload-file-uploader {
src/components/Hamburger/index.vue
src/components/HeaderSearch/index.vue
src/components/IconSelect/index.vue
src/components/IconSelect/requireIcons.ts
src/components/ImagePreview/index.vue
src/components/ImageUpload/index.vue
@@ -1,3 +1,42 @@
<template>
  <div class="component-upload-image">
    <el-upload
      multiple
      :action="uploadImgUrl"
      list-type="picture-card"
      :on-success="handleUploadSuccess"
      :before-upload="handleBeforeUpload"
      :limit="limit"
      :on-error="handleUploadError"
      :on-exceed="handleExceed"
      ref="imageUpload"
      :before-remove="handleDelete"
      :show-file-list="true"
      :headers="headers"
      :file-list="fileList"
      :on-preview="handlePictureCardPreview"
      :class="{ hide: fileList.length >= limit }"
    >
      <el-icon class="avatar-uploader-icon"><plus /></el-icon>
    </el-upload>
    <!-- ä¸Šä¼ æç¤º -->
    <div class="el-upload__tip" v-if="showTip">
      è¯·ä¸Šä¼ 
      <template v-if="fileSize">
        å¤§å°ä¸è¶…过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
      </template>
      <template v-if="fileType">
        æ ¼å¼ä¸º <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
      </template>
      çš„æ–‡ä»¶
    </div>
    <el-dialog v-model="dialogVisible" title="预览" width="800px" append-to-body>
      <img :src="dialogImageUrl" style="display: block; max-width: 100%; margin: 0 auto" />
    </el-dialog>
  </div>
</template>
<script setup lang="ts">
import { getToken } from "@/utils/auth";
import { listByIds, delOss } from "@/api/system/oss";
@@ -175,45 +214,6 @@
  return strs != "" ? strs.substring(0, strs.length - 1) : "";
}
</script>
<template>
    <div class="component-upload-image">
        <el-upload
            multiple
            :action="uploadImgUrl"
            list-type="picture-card"
            :on-success="handleUploadSuccess"
            :before-upload="handleBeforeUpload"
            :limit="limit"
            :on-error="handleUploadError"
            :on-exceed="handleExceed"
            ref="imageUpload"
            :before-remove="handleDelete"
            :show-file-list="true"
            :headers="headers"
            :file-list="fileList"
            :on-preview="handlePictureCardPreview"
            :class="{ hide: fileList.length >= limit }"
        >
            <el-icon class="avatar-uploader-icon"><plus /></el-icon>
        </el-upload>
        <!-- ä¸Šä¼ æç¤º -->
        <div class="el-upload__tip" v-if="showTip">
            è¯·ä¸Šä¼ 
            <template v-if="fileSize">
                å¤§å°ä¸è¶…过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
            </template>
            <template v-if="fileType">
                æ ¼å¼ä¸º <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
            </template>
            çš„æ–‡ä»¶
        </div>
        <el-dialog v-model="dialogVisible" title="预览" width="800px" append-to-body>
            <img :src="dialogImageUrl" style="display: block; max-width: 100%; margin: 0 auto" />
        </el-dialog>
    </div>
</template>
<style scoped lang="scss">
// .el-upload--picture-card æŽ§åˆ¶åŠ å·éƒ¨åˆ†
src/components/Pagination/index.vue
@@ -1,3 +1,19 @@
<template>
  <div :class="{ 'hidden': hidden }" class="pagination-container">
    <el-pagination
      :background="background"
      v-model:current-page="currentPage"
      v-model:page-size="pageSize"
      :layout="layout"
      :page-sizes="pageSizes"
      :pager-count="pagerCount"
      :total="total"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
    />
  </div>
</template>
<script lang="ts">
export default {
  name: 'Pagination'
@@ -87,22 +103,6 @@
  }
}
</script>
<template>
    <div :class="{ 'hidden': hidden }" class="pagination-container">
        <el-pagination
            :background="background"
            v-model:current-page="currentPage"
            v-model:page-size="pageSize"
            :layout="layout"
            :page-sizes="pageSizes"
            :pager-count="pagerCount"
            :total="total"
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
        />
    </div>
</template>
<style lang="scss" scoped>
.pagination-container {
src/components/ParentView/index.vue
src/components/RightToolbar/index.vue
@@ -1,3 +1,22 @@
<template>
  <div class="top-right-btn" :style="style">
    <el-row>
      <el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top" v-if="search">
        <el-button circle icon="Search" @click="toggleSearch()" />
      </el-tooltip>
      <el-tooltip class="item" effect="dark" content="刷新" placement="top">
        <el-button circle icon="Refresh" @click="refresh()" />
      </el-tooltip>
      <el-tooltip class="item" effect="dark" content="显隐列" placement="top" v-if="columns">
        <el-button circle icon="Menu" @click="showColumn()" />
      </el-tooltip>
    </el-row>
    <el-dialog :title="title" v-model="open" append-to-body>
      <el-transfer :titles="['显示', '隐藏']" v-model="value" :data="columns" @change="dataChange"></el-transfer>
    </el-dialog>
  </div>
</template>
<script setup lang="ts">
import { TransferKey } from "element-plus";
import { PropType } from "vue";
@@ -68,25 +87,6 @@
  })
})
</script>
<template>
    <div class="top-right-btn" :style="style">
        <el-row>
            <el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top" v-if="search">
                <el-button circle icon="Search" @click="toggleSearch()" />
            </el-tooltip>
            <el-tooltip class="item" effect="dark" content="刷新" placement="top">
                <el-button circle icon="Refresh" @click="refresh()" />
            </el-tooltip>
            <el-tooltip class="item" effect="dark" content="显隐列" placement="top" v-if="columns">
                <el-button circle icon="Menu" @click="showColumn()" />
            </el-tooltip>
        </el-row>
        <el-dialog :title="title" v-model="open" append-to-body>
            <el-transfer :titles="['显示', '隐藏']" v-model="value" :data="columns" @change="dataChange"></el-transfer>
        </el-dialog>
    </div>
</template>
<style lang="scss" scoped>
:deep(.el-transfer__button) {
src/components/RuoYiDoc/index.vue
src/components/RuoYiGit/index.vue
src/components/Screenfull/index.vue
src/components/SizeSelect/index.vue
src/components/SvgIcon/index.vue
src/components/TopNav/index.vue
@@ -1,3 +1,23 @@
<template>
    <el-menu :default-active="activeMenu" mode="horizontal" @select="handleSelect" :ellipsis="false">
        <template v-for="(item, index) in topMenus">
            <el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber"
            ><svg-icon :icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item
            >
        </template>
        <!-- é¡¶éƒ¨èœå•超出数量折叠 -->
        <el-sub-menu :style="{'--theme': theme}" index="more" v-if="topMenus.length > visibleNumber">
            <template #title>更多菜单</template>
            <template v-for="(item, index) in topMenus">
                <el-menu-item :index="item.path" :key="index" v-if="index >= visibleNumber"
                ><svg-icon :icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item
                >
            </template>
        </el-sub-menu>
    </el-menu>
</template>
<script setup lang="ts">
import { constantRoutes } from '@/router';
import { isHttp } from '@/utils/validate';
@@ -129,26 +149,6 @@
  setVisibleNumber()
})
</script>
<template>
    <el-menu :default-active="activeMenu" mode="horizontal" @select="handleSelect" :ellipsis="false">
        <template v-for="(item, index) in topMenus">
            <el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber"
                ><svg-icon :icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item
            >
        </template>
        <!-- é¡¶éƒ¨èœå•超出数量折叠 -->
        <el-sub-menu :style="{'--theme': theme}" index="more" v-if="topMenus.length > visibleNumber">
            <template #title>更多菜单</template>
            <template v-for="(item, index) in topMenus">
                <el-menu-item :index="item.path" :key="index" v-if="index >= visibleNumber"
                    ><svg-icon :icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item
                >
            </template>
        </el-sub-menu>
    </el-menu>
</template>
<style lang="scss">
.topmenu-container.el-menu--horizontal > .el-menu-item {
src/components/TreeSelect/index.vue
src/components/iFrame/index.vue
src/directive/common/copyText.ts
src/directive/index.ts
src/directive/permission/index.ts
src/enums/MenuTypeEnum.ts
src/enums/RespEnum.ts
src/enums/SettingTypeEnum.ts
src/enums/layout/LayoutEnum.ts
src/lang/en.ts
src/lang/index.ts
src/lang/zh-cn.ts
src/layout/components/AppMain.vue
@@ -1,3 +1,16 @@
<template>
  <section class="app-main">
    <router-view v-slot="{ Component, route }">
      <transition :enter-active-class="animante" mode="out-in">
        <keep-alive :include="tagsViewStore.cachedViews">
          <component v-if="!route.meta.link" :is="Component" :key="route.path" />
        </keep-alive>
      </transition>
    </router-view>
    <iframe-toggle />
  </section>
</template>
<script lang="ts">
export default {
  name: 'AppMin'
@@ -24,19 +37,6 @@
  }
}, { immediate: true });
</script>
<template>
    <section class="app-main">
        <router-view v-slot="{ Component, route }">
            <transition :enter-active-class="animante" mode="out-in">
                <keep-alive :include="tagsViewStore.cachedViews">
                    <component v-if="!route.meta.link" :is="Component" :key="route.path" />
                </keep-alive>
            </transition>
        </router-view>
        <iframe-toggle />
    </section>
</template>
<style lang="scss" scoped>
.app-main {
src/layout/components/IframeToggle/index.vue
src/layout/components/InnerLink/index.vue
@@ -1,3 +1,9 @@
<template>
  <div :style="'height:' + height">
    <iframe :id="iframeId" style="width: 100%; height: 100%" :src="src" frameborder="no"></iframe>
  </div>
</template>
<script setup lang="ts">
const props = defineProps({
  src: {
@@ -10,9 +16,3 @@
});
const height = ref(document.documentElement.clientHeight - 94.5 + "px");
</script>
<template>
    <div :style="'height:' + height">
        <iframe :id="iframeId" style="width: 100%; height: 100%" :src="src" frameborder="no"></iframe>
    </div>
</template>
src/layout/components/Navbar.vue
@@ -1,3 +1,68 @@
<template>
  <div class="navbar">
    <hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
    <breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!settingsStore.topNav" />
    <top-nav id="topmenu-container" class="topmenu-container" v-if="settingsStore.topNav" />
    <div class="right-menu flex align-center">
      <template v-if="appStore.device !== 'mobile'">
        <el-select
          v-model="companyName"
          clearable
          filterable
          reserve-keyword
          placeholder="请选择租户"
          v-if="userId === 1 && tenantEnabled"
          @change="dynamicTenantEvent"
          @clear="dynamicClearEvent"
        >
          <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option>
          <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
        </el-select>
        <header-search id="header-search" class="right-menu-item" />
        <el-tooltip content="源码地址" effect="dark" placement="bottom">
          <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
        </el-tooltip>
        <el-tooltip content="文档地址" effect="dark" placement="bottom">
          <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
        </el-tooltip>
        <el-tooltip content="全屏" effect="dark" placement="bottom">
          <screenfull id="screenfull" class="right-menu-item hover-effect" />
        </el-tooltip>
        <el-tooltip content="布局大小" effect="dark" placement="bottom">
          <size-select id="size-select" class="right-menu-item hover-effect" />
        </el-tooltip>
      </template>
      <div class="avatar-container">
        <el-dropdown @command="handleCommand" class="right-menu-item hover-effect" trigger="click">
          <div class="avatar-wrapper">
            <img :src="userStore.avatar" class="user-avatar" />
            <el-icon><caret-bottom /></el-icon>
          </div>
          <template #dropdown>
            <el-dropdown-menu>
              <router-link to="/user/profile" v-if="!dynamic">
                <el-dropdown-item>个人中心</el-dropdown-item>
              </router-link>
              <el-dropdown-item command="setLayout">
                <span>布局设置</span>
              </el-dropdown-item>
              <el-dropdown-item divided command="logout">
                <span>退出登录</span>
              </el-dropdown-item>
            </el-dropdown-menu>
          </template>
        </el-dropdown>
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
import useAppStore from '@/store/modules/app'
import useUserStore from '@/store/modules/user'
@@ -81,71 +146,6 @@
  }
}
</script>
<template>
    <div class="navbar">
        <hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
        <breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!settingsStore.topNav" />
        <top-nav id="topmenu-container" class="topmenu-container" v-if="settingsStore.topNav" />
        <div class="right-menu flex align-center">
            <template v-if="appStore.device !== 'mobile'">
                <el-select
                    v-model="companyName"
                    clearable
                    filterable
                    reserve-keyword
                    placeholder="请选择租户"
                    v-if="userId === 1 && tenantEnabled"
                    @change="dynamicTenantEvent"
                    @clear="dynamicClearEvent"
                >
                    <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option>
                    <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
                </el-select>
                <header-search id="header-search" class="right-menu-item" />
                <el-tooltip content="源码地址" effect="dark" placement="bottom">
                    <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
                </el-tooltip>
                <el-tooltip content="文档地址" effect="dark" placement="bottom">
                    <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
                </el-tooltip>
                <el-tooltip content="全屏" effect="dark" placement="bottom">
                    <screenfull id="screenfull" class="right-menu-item hover-effect" />
                </el-tooltip>
                <el-tooltip content="布局大小" effect="dark" placement="bottom">
                    <size-select id="size-select" class="right-menu-item hover-effect" />
                </el-tooltip>
            </template>
            <div class="avatar-container">
                <el-dropdown @command="handleCommand" class="right-menu-item hover-effect" trigger="click">
                    <div class="avatar-wrapper">
                        <img :src="userStore.avatar" class="user-avatar" />
                        <el-icon><caret-bottom /></el-icon>
                    </div>
                    <template #dropdown>
                        <el-dropdown-menu>
                            <router-link to="/user/profile" v-if="!dynamic">
                                <el-dropdown-item>个人中心</el-dropdown-item>
                            </router-link>
                            <el-dropdown-item command="setLayout">
                                <span>布局设置</span>
                            </el-dropdown-item>
                            <el-dropdown-item divided command="logout">
                                <span>退出登录</span>
                            </el-dropdown-item>
                        </el-dropdown-menu>
                    </template>
                </el-dropdown>
            </div>
        </div>
    </div>
</template>
<style lang="scss" scoped>
src/layout/components/Settings/index.vue
src/layout/components/Sidebar/Link.vue
src/layout/components/Sidebar/Logo.vue
src/layout/components/Sidebar/SidebarItem.vue
@@ -1,3 +1,34 @@
<template>
  <div v-if="!item.hidden">
    <template v-if="hasOneShowingChild(item.children, item) && (!onlyOneChild.children || onlyOneChild.noShowingChildren) && !item.alwaysShow">
      <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path, onlyOneChild.query)">
        <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{ 'submenu-title-noDropdown': !isNest }">
          <svg-icon :icon-class="onlyOneChild.meta.icon || (item.meta && item.meta.icon)" />
          <template #title>
            <span class="menu-title" :title="hasTitle(onlyOneChild.meta.title)">{{ onlyOneChild.meta.title }}</span>
          </template>
        </el-menu-item>
      </app-link>
    </template>
    <el-sub-menu v-else ref="subMenu" :index="resolvePath(item.path)" teleported>
      <template v-if="item.meta" #title>
        <svg-icon :icon-class="item.meta ? item.meta.icon : '' " />
        <span class="menu-title" :title="hasTitle(item.meta?.title)">{{ item.meta?.title }}</span>
      </template>
      <sidebar-item
        v-for="child in item.children"
        :key="child.path"
        :is-nest="true"
        :item="child as RouteOption"
        :base-path="resolvePath(child.path)"
        class="nest-menu"
      />
    </el-sub-menu>
  </div>
</template>
<script setup lang="ts">
import { isExternal } from '@/utils/validate'
import AppLink from './Link.vue'
@@ -72,34 +103,3 @@
  return title;
}
</script>
<template>
    <div v-if="!item.hidden">
        <template v-if="hasOneShowingChild(item.children, item) && (!onlyOneChild.children || onlyOneChild.noShowingChildren) && !item.alwaysShow">
            <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path, onlyOneChild.query)">
                <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{ 'submenu-title-noDropdown': !isNest }">
                    <svg-icon :icon-class="onlyOneChild.meta.icon || (item.meta && item.meta.icon)" />
                    <template #title>
                        <span class="menu-title" :title="hasTitle(onlyOneChild.meta.title)">{{ onlyOneChild.meta.title }}</span>
                    </template>
                </el-menu-item>
            </app-link>
        </template>
        <el-sub-menu v-else ref="subMenu" :index="resolvePath(item.path)" teleported>
            <template v-if="item.meta" #title>
                <svg-icon :icon-class="item.meta ? item.meta.icon : '' " />
                <span class="menu-title" :title="hasTitle(item.meta?.title)">{{ item.meta?.title }}</span>
            </template>
            <sidebar-item
                v-for="child in item.children"
                :key="child.path"
                :is-nest="true"
                :item="child as RouteOption"
                :base-path="resolvePath(child.path)"
                class="nest-menu"
            />
        </el-sub-menu>
    </div>
</template>
src/layout/components/Sidebar/index.vue
src/layout/components/TagsView/ScrollPane.vue
src/layout/components/TagsView/index.vue
@@ -1,3 +1,34 @@
<template>
  <div id="tags-view-container" class="tags-view-container">
    <scroll-pane ref="scrollPaneRef" class="tags-view-wrapper" @scroll="handleScroll">
      <router-link
        v-for="tag in visitedViews"
        :key="tag.path"
        :data-path="tag.path"
        :class="isActive(tag) ? 'active' : ''"
        :to="{ path: tag.path ? tag.path : '', query: tag.query, fullPath: tag.fullPath ? tag.fullPath : '' }"
        class="tags-view-item"
        :style="activeStyle(tag)"
        @click.middle="!isAffix(tag) ? closeSelectedTag(tag) : ''"
        @contextmenu.prevent="openMenu(tag, $event)"
      >
        {{ tag.title }}
        <span v-if="!isAffix(tag)" @click.prevent.stop="closeSelectedTag(tag)">
          <close class="el-icon-close" style="width: 1em; height: 1em;vertical-align: middle;" />
        </span>
      </router-link>
    </scroll-pane>
    <ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="contextmenu">
      <li @click="refreshSelectedTag(selectedTag)"><refresh-right style="width: 1em; height: 1em;" /> åˆ·æ–°é¡µé¢</li>
      <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"><close style="width: 1em; height: 1em;" /> å…³é—­å½“前</li>
      <li @click="closeOthersTags"><circle-close style="width: 1em; height: 1em;" /> å…³é—­å…¶ä»–</li>
      <li v-if="!isFirstView()" @click="closeLeftTags"><back style="width: 1em; height: 1em;" /> å…³é—­å·¦ä¾§</li>
      <li v-if="!isLastView()" @click="closeRightTags"><right style="width: 1em; height: 1em;" /> å…³é—­å³ä¾§</li>
      <li @click="closeAllTags(selectedTag)"><circle-close style="width: 1em; height: 1em;" /> å…¨éƒ¨å…³é—­</li>
    </ul>
  </div>
</template>
<script setup lang="ts">
import ScrollPane from './ScrollPane.vue'
import { getNormalPath } from '@/utils/ruoyi'
@@ -201,37 +232,6 @@
  addTags();
})
</script>
<template>
    <div id="tags-view-container" class="tags-view-container">
        <scroll-pane ref="scrollPaneRef" class="tags-view-wrapper" @scroll="handleScroll">
            <router-link
                v-for="tag in visitedViews"
                :key="tag.path"
                :data-path="tag.path"
                :class="isActive(tag) ? 'active' : ''"
                :to="{ path: tag.path ? tag.path : '', query: tag.query, fullPath: tag.fullPath ? tag.fullPath : '' }"
                class="tags-view-item"
                :style="activeStyle(tag)"
                @click.middle="!isAffix(tag) ? closeSelectedTag(tag) : ''"
                @contextmenu.prevent="openMenu(tag, $event)"
            >
                {{ tag.title }}
                <span v-if="!isAffix(tag)" @click.prevent.stop="closeSelectedTag(tag)">
                    <close class="el-icon-close" style="width: 1em; height: 1em;vertical-align: middle;" />
                </span>
            </router-link>
        </scroll-pane>
        <ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="contextmenu">
            <li @click="refreshSelectedTag(selectedTag)"><refresh-right style="width: 1em; height: 1em;" /> åˆ·æ–°é¡µé¢</li>
            <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"><close style="width: 1em; height: 1em;" /> å…³é—­å½“前</li>
            <li @click="closeOthersTags"><circle-close style="width: 1em; height: 1em;" /> å…³é—­å…¶ä»–</li>
            <li v-if="!isFirstView()" @click="closeLeftTags"><back style="width: 1em; height: 1em;" /> å…³é—­å·¦ä¾§</li>
            <li v-if="!isLastView()" @click="closeRightTags"><right style="width: 1em; height: 1em;" /> å…³é—­å³ä¾§</li>
            <li @click="closeAllTags(selectedTag)"><circle-close style="width: 1em; height: 1em;" /> å…¨éƒ¨å…³é—­</li>
        </ul>
    </div>
</template>
<style lang="scss" scoped>
.tags-view-container {
src/layout/index.vue
src/permission.ts
src/plugins/auth.ts
src/plugins/cache.ts
src/plugins/download.ts
src/plugins/index.ts
src/plugins/modal.ts
src/plugins/svgicon.ts
src/plugins/tab.ts
src/router/index.ts
src/settings.ts
src/store/modules/app.ts
src/store/modules/dict.ts
src/store/modules/permission.ts
src/store/modules/settings.ts
src/store/modules/tagsView.ts
src/store/modules/user.ts
src/types/auto-imports.d.ts
@@ -2,13 +2,11 @@
export {}
declare global {
  const EffectScope: typeof import('vue')['EffectScope']
  const ElForm: typeof import('element-plus/es')['ElForm']
  const ElLoading: typeof import('element-plus/es')['ElLoading']
  const ElMessage: typeof import('element-plus/es')['ElMessage']
  const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
  const ElNotification: typeof import('element-plus/es')['ElNotification']
  const ElSelect: typeof import('element-plus/es')['ElSelect']
  const ElTable: typeof import('element-plus/es')['ElTable']
  const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
  const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
  const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
@@ -288,13 +286,11 @@
declare module 'vue' {
  interface ComponentCustomProperties {
    readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
    readonly ElForm: UnwrapRef<typeof import('element-plus/es')['ElForm']>
    readonly ElLoading: UnwrapRef<typeof import('element-plus/es')['ElLoading']>
    readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']>
    readonly ElMessageBox: UnwrapRef<typeof import('element-plus/es')['ElMessageBox']>
    readonly ElNotification: UnwrapRef<typeof import('element-plus/es')['ElNotification']>
    readonly ElSelect: UnwrapRef<typeof import('element-plus/es')['ElSelect']>
    readonly ElTable: UnwrapRef<typeof import('element-plus/es')['ElTable']>
    readonly acceptHMRUpdate: UnwrapRef<typeof import('pinia')['acceptHMRUpdate']>
    readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
    readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']>
src/types/axios.d.ts
src/types/components.d.ts
@@ -14,7 +14,6 @@
    ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
    ElButton: typeof import('element-plus/es')['ElButton']
    ElCard: typeof import('element-plus/es')['ElCard']
    ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
    ElCol: typeof import('element-plus/es')['ElCol']
    ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
    ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
@@ -25,42 +24,26 @@
    ElDropdown: typeof import('element-plus/es')['ElDropdown']
    ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
    ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
    ElForm: typeof import('element-plus/es')['ElForm']
    ElFormItem: typeof import('element-plus/es')['ElFormItem']
    ElIcon: typeof import('element-plus/es')['ElIcon']
    ElImage: typeof import('element-plus/es')['ElImage']
    ElInput: typeof import('element-plus/es')['ElInput']
    ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
    ElLink: typeof import('element-plus/es')['ElLink']
    ElMenu: typeof import('element-plus/es')['ElMenu']
    ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
    ElOption: typeof import('element-plus/es')['ElOption']
    ElPagination: typeof import('element-plus/es')['ElPagination']
    ElPopover: typeof import('element-plus/es')['ElPopover']
    ElRadio: typeof import('element-plus/es')['ElRadio']
    ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
    ElRow: typeof import('element-plus/es')['ElRow']
    ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
    ElSelect: typeof import('element-plus/es')['ElSelect']
    ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
    ElSwitch: typeof import('element-plus/es')['ElSwitch']
    ElTable: typeof import('element-plus/es')['ElTable']
    ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
    ElTabPane: typeof import('element-plus/es')['ElTabPane']
    ElTabs: typeof import('element-plus/es')['ElTabs']
    ElTag: typeof import('element-plus/es')['ElTag']
    ElTooltip: typeof import('element-plus/es')['ElTooltip']
    ElTransfer: typeof import('element-plus/es')['ElTransfer']
    ElTree: typeof import('element-plus/es')['ElTree']
    ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
    ElUpload: typeof import('element-plus/es')['ElUpload']
    FileUpload: typeof import('./../components/FileUpload/index.vue')['default']
    Hamburger: typeof import('./../components/Hamburger/index.vue')['default']
    HeaderSearch: typeof import('./../components/HeaderSearch/index.vue')['default']
    IconSelect: typeof import('./../components/IconSelect/index.vue')['default']
    IEpCaretBottom: typeof import('~icons/ep/caret-bottom')['default']
    IEpCaretTop: typeof import('~icons/ep/caret-top')['default']
    IEpUploadFilled: typeof import('~icons/ep/upload-filled')['default']
    IFrame: typeof import('./../components/iFrame/index.vue')['default']
    ImagePreview: typeof import('./../components/ImagePreview/index.vue')['default']
    ImageUpload: typeof import('./../components/ImageUpload/index.vue')['default']
src/types/env.d.ts
src/types/global.d.ts
src/types/module.d.ts
src/types/router.d.ts
src/types/setting.d.ts
src/utils/dict.ts
src/utils/dynamicTitle.ts
src/utils/errorCode.ts
src/utils/i18n.ts
src/utils/index.ts
src/utils/jsencrypt.ts
src/utils/permission.ts
src/utils/request.ts
src/utils/ruoyi.ts
src/utils/scroll-to.ts
src/utils/theme.ts
src/utils/validate.ts
src/views/demo/demo/index.vue
@@ -1,3 +1,150 @@
<template>
  <div class="p-2">
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div class="search" v-show="showSearch">
        <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
          <el-form-item label="key键" prop="testKey">
            <el-input v-model="queryParams.testKey" placeholder="请输入key键" clearable style="width: 200px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="值" prop="value">
            <el-input v-model="queryParams.value" placeholder="请输入值" clearable style="width: 200px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="创建时间">
            <el-date-picker
              v-model="daterangeCreateTime"
              value-format="YYYY-MM-DD HH:mm:ss"
              type="daterange"
              range-separator="-"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
            ></el-date-picker>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
            <el-button type="primary" icon="search" @click="handlePage">搜索(自定义分页接口)</el-button>
            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </transition>
    <el-card shadow="never">
      <template #header>
        <el-row :gutter="10" class="mb8">
          <el-col :span="1.5">
            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['demo:demo:add']">新增</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['demo:demo:edit']">修改</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['demo:demo:remove']">
              åˆ é™¤
            </el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="info" plain icon="Upload" @click="handleImport" v-hasPermi="['demo:demo:import']">导入(校验)</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['demo:demo:export']">导出</el-button>
          </el-col>
          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
        </el-row>
      </template>
      <el-table v-loading="loading" :data="demoList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="主键" align="center" prop="id" v-if="columns[0].visible" />
        <el-table-column label="部门id" align="center" prop="deptId" v-if="columns[1].visible" />
        <el-table-column label="用户id" align="center" prop="userId" v-if="columns[2].visible" />
        <el-table-column label="排序号" align="center" prop="orderNum" v-if="columns[3].visible" />
        <el-table-column label="key键" align="center" prop="testKey" v-if="columns[4].visible" />
        <el-table-column label="值" align="center" prop="value" v-if="columns[5].visible" />
        <el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="180">
          <template #default="scope">
            <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
          </template>
        </el-table-column>
        <el-table-column label="创建人" align="center" prop="createByName" v-if="columns[7].visible" />
        <el-table-column label="更新时间" align="center" prop="updateTime" v-if="columns[8].visible" width="180">
          <template #default="scope">
            <span>{{ parseTime(scope.row.updateTime, '{y}-{m}-{d}') }}</span>
          </template>
        </el-table-column>
        <el-table-column label="更新人" align="center" prop="updateByName" v-if="columns[9].visible" />
        <el-table-column label="操作" fixed="right" align="center" width="150" class-name="small-padding fixed-width">
          <template #default="scope">
            <el-tooltip content="修改" placement="top">
              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['demo:demo:edit']"></el-button>
            </el-tooltip>
            <el-tooltip content="修改" placement="top">
              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['demo:demo:remove']"></el-button>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
    </el-card>
    <!-- æ·»åŠ æˆ–ä¿®æ”¹æµ‹è¯•å•è¡¨å¯¹è¯æ¡† -->
    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
      <el-form ref="demoFormRef" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="部门id" prop="deptId">
          <el-input v-model="form.deptId" placeholder="请输入部门id" />
        </el-form-item>
        <el-form-item label="用户id" prop="userId">
          <el-input v-model="form.userId" placeholder="请输入用户id" />
        </el-form-item>
        <el-form-item label="排序号" prop="orderNum">
          <el-input v-model="form.orderNum" placeholder="请输入排序号" />
        </el-form-item>
        <el-form-item label="key键" prop="testKey">
          <el-input v-model="form.testKey" placeholder="请输入key键" />
        </el-form-item>
        <el-form-item label="值" prop="value">
          <el-input v-model="form.value" placeholder="请输入值" />
        </el-form-item>
        <el-form-item label="创建时间" prop="createTime">
          <el-date-picker clearable v-model="form.createTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="选择创建时间">
          </el-date-picker>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button :loading="buttonLoading" type="primary" @click="submitForm">ç¡® å®š</el-button>
          <el-button @click="cancel">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
    <!-- ç”¨æˆ·å¯¼å…¥å¯¹è¯æ¡† -->
    <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
      <el-upload
        ref="uploadRef"
        :limit="1"
        accept=".xlsx, .xls"
        :headers="upload.headers"
        :action="upload.url + '?updateSupport=' + upload.updateSupport"
        :disabled="upload.isUploading"
        :on-progress="handleFileUploadProgress"
        :on-success="handleFileSuccess"
        :auto-upload="false"
        drag
      >
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
      </el-upload>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitFileForm">ç¡® å®š</el-button>
          <el-button @click="upload.open = false">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup name="Demo" lang="ts">
import { listDemo, pageDemo, getDemo, delDemo, addDemo, updateDemo } from "@/api/demo/demo";
import { getToken } from "@/utils/auth";
@@ -208,150 +355,3 @@
    getPage()
})
</script>
<template>
    <div class="p-2">
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
            <div class="search" v-show="showSearch">
                <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
                    <el-form-item label="key键" prop="testKey">
                        <el-input v-model="queryParams.testKey" placeholder="请输入key键" clearable style="width: 200px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="值" prop="value">
                        <el-input v-model="queryParams.value" placeholder="请输入值" clearable style="width: 200px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="创建时间">
                        <el-date-picker
                            v-model="daterangeCreateTime"
                            value-format="YYYY-MM-DD HH:mm:ss"
                            type="daterange"
                            range-separator="-"
                            start-placeholder="开始日期"
                            end-placeholder="结束日期"
                            :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
                        ></el-date-picker>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
                        <el-button type="primary" icon="search" @click="handlePage">搜索(自定义分页接口)</el-button>
                        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
                    </el-form-item>
                </el-form>
            </div>
        </transition>
        <el-card shadow="never">
            <template #header>
                <el-row :gutter="10" class="mb8">
                    <el-col :span="1.5">
                        <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['demo:demo:add']">新增</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['demo:demo:edit']">修改</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['demo:demo:remove']">
                            åˆ é™¤
                        </el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="info" plain icon="Upload" @click="handleImport" v-hasPermi="['demo:demo:import']">导入(校验)</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['demo:demo:export']">导出</el-button>
                    </el-col>
                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
                </el-row>
            </template>
            <el-table v-loading="loading" :data="demoList" @selection-change="handleSelectionChange">
                <el-table-column type="selection" width="55" align="center" />
                <el-table-column label="主键" align="center" prop="id" v-if="columns[0].visible" />
                <el-table-column label="部门id" align="center" prop="deptId" v-if="columns[1].visible" />
                <el-table-column label="用户id" align="center" prop="userId" v-if="columns[2].visible" />
                <el-table-column label="排序号" align="center" prop="orderNum" v-if="columns[3].visible" />
                <el-table-column label="key键" align="center" prop="testKey" v-if="columns[4].visible" />
                <el-table-column label="值" align="center" prop="value" v-if="columns[5].visible" />
                <el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="180">
                    <template #default="scope">
                        <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
                    </template>
                </el-table-column>
                <el-table-column label="创建人" align="center" prop="createByName" v-if="columns[7].visible" />
                <el-table-column label="更新时间" align="center" prop="updateTime" v-if="columns[8].visible" width="180">
                    <template #default="scope">
                        <span>{{ parseTime(scope.row.updateTime, '{y}-{m}-{d}') }}</span>
                    </template>
                </el-table-column>
                <el-table-column label="更新人" align="center" prop="updateByName" v-if="columns[9].visible" />
                <el-table-column label="操作" fixed="right" align="center" width="150" class-name="small-padding fixed-width">
                    <template #default="scope">
                        <el-tooltip content="修改" placement="top">
                            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['demo:demo:edit']"></el-button>
                        </el-tooltip>
                        <el-tooltip content="修改" placement="top">
                            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['demo:demo:remove']"></el-button>
                        </el-tooltip>
                    </template>
                </el-table-column>
            </el-table>
            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
        </el-card>
        <!-- æ·»åŠ æˆ–ä¿®æ”¹æµ‹è¯•å•è¡¨å¯¹è¯æ¡† -->
        <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
            <el-form ref="demoFormRef" :model="form" :rules="rules" label-width="80px">
                <el-form-item label="部门id" prop="deptId">
                    <el-input v-model="form.deptId" placeholder="请输入部门id" />
                </el-form-item>
                <el-form-item label="用户id" prop="userId">
                    <el-input v-model="form.userId" placeholder="请输入用户id" />
                </el-form-item>
                <el-form-item label="排序号" prop="orderNum">
                    <el-input v-model="form.orderNum" placeholder="请输入排序号" />
                </el-form-item>
                <el-form-item label="key键" prop="testKey">
                    <el-input v-model="form.testKey" placeholder="请输入key键" />
                </el-form-item>
                <el-form-item label="值" prop="value">
                    <el-input v-model="form.value" placeholder="请输入值" />
                </el-form-item>
                <el-form-item label="创建时间" prop="createTime">
                    <el-date-picker clearable v-model="form.createTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="选择创建时间">
                    </el-date-picker>
                </el-form-item>
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <el-button :loading="buttonLoading" type="primary" @click="submitForm">ç¡® å®š</el-button>
                    <el-button @click="cancel">取 æ¶ˆ</el-button>
                </div>
            </template>
        </el-dialog>
        <!-- ç”¨æˆ·å¯¼å…¥å¯¹è¯æ¡† -->
        <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
            <el-upload
                ref="uploadRef"
                :limit="1"
                accept=".xlsx, .xls"
                :headers="upload.headers"
                :action="upload.url + '?updateSupport=' + upload.updateSupport"
                :disabled="upload.isUploading"
                :on-progress="handleFileUploadProgress"
                :on-success="handleFileSuccess"
                :auto-upload="false"
                drag
            >
                <i class="el-icon-upload"></i>
                <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
            </el-upload>
            <template #footer>
                <div class="dialog-footer">
                    <el-button type="primary" @click="submitFileForm">ç¡® å®š</el-button>
                    <el-button @click="upload.open = false">取 æ¶ˆ</el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>
src/views/demo/tree/index.vue
@@ -1,3 +1,110 @@
<template>
  <div class="p-2">
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div class="search" v-show="showSearch">
        <el-form :model="queryParams" ref="qeuryFormRef" :inline="true" label-width="68px">
          <el-form-item label="树节点名" prop="treeName">
            <el-input v-model="queryParams.treeName" placeholder="请输入树节点名" clearable style="width: 200px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="创建时间">
            <el-date-picker
              v-model="daterangeCreateTime"
              value-format="YYYY-MM-DD HH:mm:ss"
              type="daterange"
              range-separator="-"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
            ></el-date-picker>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </transition>
    <el-card shadow="never">
      <template #header>
        <el-row :gutter="10">
          <el-col :span="1.5">
            <el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['demo:tree:add']">新增</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
          </el-col>
          <right-toolbar :columns="columns" v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
        </el-row>
      </template>
      <el-table
        v-if="refreshTable"
        v-loading="loading"
        :data="treeList"
        row-key="id"
        :default-expand-all="isExpandAll"
        :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
        ref="demoTreeTableRef"
      >
        <el-table-column label="父id" prop="parentId" v-if="columns[0].visible" />
        <el-table-column label="部门id" align="center" prop="deptId" v-if="columns[1].visible" />
        <el-table-column label="用户id" align="center" prop="userId" v-if="columns[2].visible" />
        <el-table-column label="树节点名" align="center" prop="treeName" v-if="columns[3].visible" />
        <el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[4].visible" width="180">
          <template #default="scope">
            <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
          </template>
        </el-table-column>
        <el-table-column label="操作" fixed="right" align="center" width="150" class-name="small-padding fixed-width">
          <template #default="scope">
            <el-tooltip content="修改" placement="top">
              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['demo:tree:edit']"></el-button>
            </el-tooltip>
            <el-tooltip content="新增" placement="top">
              <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['demo:tree:add']"></el-button>
            </el-tooltip>
            <el-tooltip content="删除" placement="top">
              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['demo:tree:remove']"></el-button>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
    <!-- æ·»åŠ æˆ–ä¿®æ”¹æµ‹è¯•æ ‘è¡¨å¯¹è¯æ¡† -->
    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
      <el-form ref="treeRef" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="父id" prop="parentId">
          <el-tree-select
            v-model="form.parentId"
            :data="treeOptions"
            :props="{ value: 'id', label: 'treeName', children: 'children' }"
            value-key="id"
            check-strictly
            placeholder="请选择父id"
          />
        </el-form-item>
        <el-form-item label="部门id" prop="deptId">
          <el-input v-model="form.deptId" placeholder="请输入部门id" />
        </el-form-item>
        <el-form-item label="用户id" prop="userId">
          <el-input v-model="form.userId" placeholder="请输入用户id" />
        </el-form-item>
        <el-form-item label="树节点名" prop="treeName">
          <el-input v-model="form.treeName" placeholder="请输入树节点名" />
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button :loading="buttonLoading" type="primary" @click="submitForm">ç¡® å®š</el-button>
          <el-button @click="cancel">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup name="Tree" lang="ts">
import { listTree, getTree, delTree, addTree, updateTree } from '@/api/demo/tree';
import { DemoTreeVO, DemoTreeForm, DemoTreeOptionsType, DemoTreeQuery } from '@/api/demo/types';
@@ -184,110 +291,3 @@
  getList()
})
</script>
<template>
    <div class="p-2">
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
            <div class="search" v-show="showSearch">
                <el-form :model="queryParams" ref="qeuryFormRef" :inline="true" label-width="68px">
                    <el-form-item label="树节点名" prop="treeName">
                        <el-input v-model="queryParams.treeName" placeholder="请输入树节点名" clearable style="width: 200px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="创建时间">
                        <el-date-picker
                            v-model="daterangeCreateTime"
                            value-format="YYYY-MM-DD HH:mm:ss"
                            type="daterange"
                            range-separator="-"
                            start-placeholder="开始日期"
                            end-placeholder="结束日期"
                            :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
                        ></el-date-picker>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
                        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
                    </el-form-item>
                </el-form>
            </div>
        </transition>
        <el-card shadow="never">
            <template #header>
                <el-row :gutter="10">
                    <el-col :span="1.5">
                        <el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['demo:tree:add']">新增</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
                    </el-col>
                    <right-toolbar :columns="columns" v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
                </el-row>
            </template>
            <el-table
                v-if="refreshTable"
                v-loading="loading"
                :data="treeList"
                row-key="id"
                :default-expand-all="isExpandAll"
                :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
                ref="demoTreeTableRef"
            >
                <el-table-column label="父id" prop="parentId" v-if="columns[0].visible" />
                <el-table-column label="部门id" align="center" prop="deptId" v-if="columns[1].visible" />
                <el-table-column label="用户id" align="center" prop="userId" v-if="columns[2].visible" />
                <el-table-column label="树节点名" align="center" prop="treeName" v-if="columns[3].visible" />
                <el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[4].visible" width="180">
                    <template #default="scope">
                        <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
                    </template>
                </el-table-column>
                <el-table-column label="操作" fixed="right" align="center" width="150" class-name="small-padding fixed-width">
                    <template #default="scope">
                        <el-tooltip content="修改" placement="top">
                            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['demo:tree:edit']"></el-button>
                        </el-tooltip>
                        <el-tooltip content="新增" placement="top">
                            <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['demo:tree:add']"></el-button>
                        </el-tooltip>
                        <el-tooltip content="删除" placement="top">
                            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['demo:tree:remove']"></el-button>
                        </el-tooltip>
                    </template>
                </el-table-column>
            </el-table>
        </el-card>
        <!-- æ·»åŠ æˆ–ä¿®æ”¹æµ‹è¯•æ ‘è¡¨å¯¹è¯æ¡† -->
        <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
            <el-form ref="treeRef" :model="form" :rules="rules" label-width="80px">
                <el-form-item label="父id" prop="parentId">
                    <el-tree-select
                        v-model="form.parentId"
                        :data="treeOptions"
                        :props="{ value: 'id', label: 'treeName', children: 'children' }"
                        value-key="id"
                        check-strictly
                        placeholder="请选择父id"
                    />
                </el-form-item>
                <el-form-item label="部门id" prop="deptId">
                    <el-input v-model="form.deptId" placeholder="请输入部门id" />
                </el-form-item>
                <el-form-item label="用户id" prop="userId">
                    <el-input v-model="form.userId" placeholder="请输入用户id" />
                </el-form-item>
                <el-form-item label="树节点名" prop="treeName">
                    <el-input v-model="form.treeName" placeholder="请输入树节点名" />
                </el-form-item>
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <el-button :loading="buttonLoading" type="primary" @click="submitForm">ç¡® å®š</el-button>
                    <el-button @click="cancel">取 æ¶ˆ</el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>
src/views/error/401.vue
src/views/error/404.vue
src/views/index.vue
src/views/login.vue
@@ -1,3 +1,49 @@
<template>
  <div class="login">
    <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
      <h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3>
      <el-form-item prop="tenantId" v-if="tenantEnabled">
        <el-select v-model="loginForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%">
          <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option>
          <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
        </el-select>
      </el-form-item>
      <el-form-item prop="username">
        <el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" placeholder="账号">
          <template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
        </el-input>
      </el-form-item>
      <el-form-item prop="password">
        <el-input v-model="loginForm.password" type="password" size="large" auto-complete="off" placeholder="密码" @keyup.enter="handleLogin">
          <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
        </el-input>
      </el-form-item>
      <el-form-item prop="code" v-if="captchaEnabled">
        <el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleLogin">
          <template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
        </el-input>
        <div class="login-code">
          <img :src="codeUrl" @click="getCode" class="login-code-img" />
        </div>
      </el-form-item>
      <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
      <el-form-item style="width:100%;">
        <el-button :loading="loading" size="large" type="primary" style="width:100%;" @click.prevent="handleLogin">
          <span v-if="!loading">登 å½•</span>
          <span v-else>登 å½• ä¸­...</span>
        </el-button>
        <div style="float: right;" v-if="register">
          <router-link class="link-type" :to="'/register'">立即注册</router-link>
        </div>
      </el-form-item>
    </el-form>
    <!--  åº•部  -->
    <div class="el-login-footer">
      <span>Copyright Â© 2018-2023 ç–¯ç‹‚的狮子Li All Rights Reserved.</span>
    </div>
  </div>
</template>
<script setup lang="ts">
import { getCodeImg, getTenantList } from '@/api/login';
import Cookies from 'js-cookie';
@@ -123,52 +169,6 @@
  getCookie();
});
</script>
<template>
    <div class="login">
        <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
            <h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3>
            <el-form-item prop="tenantId" v-if="tenantEnabled">
                <el-select v-model="loginForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%">
                    <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option>
                    <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
                </el-select>
            </el-form-item>
            <el-form-item prop="username">
                <el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" placeholder="账号">
                    <template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
                </el-input>
            </el-form-item>
            <el-form-item prop="password">
                <el-input v-model="loginForm.password" type="password" size="large" auto-complete="off" placeholder="密码" @keyup.enter="handleLogin">
                    <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
                </el-input>
            </el-form-item>
            <el-form-item prop="code" v-if="captchaEnabled">
                <el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleLogin">
                    <template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
                </el-input>
                <div class="login-code">
                    <img :src="codeUrl" @click="getCode" class="login-code-img" />
                </div>
            </el-form-item>
            <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
            <el-form-item style="width:100%;">
                <el-button :loading="loading" size="large" type="primary" style="width:100%;" @click.prevent="handleLogin">
                    <span v-if="!loading">登 å½•</span>
                    <span v-else>登 å½• ä¸­...</span>
                </el-button>
                <div style="float: right;" v-if="register">
                    <router-link class="link-type" :to="'/register'">立即注册</router-link>
                </div>
            </el-form-item>
        </el-form>
        <!--  åº•部  -->
        <div class="el-login-footer">
            <span>Copyright Â© 2018-2023 ç–¯ç‹‚的狮子Li All Rights Reserved.</span>
        </div>
    </div>
</template>
<style lang="scss" scoped>
.login {
src/views/monitor/admin/index.vue
src/views/monitor/cache/index.vue
src/views/monitor/logininfor/index.vue
@@ -1,3 +1,101 @@
<template>
  <div class="p-2">
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div class="search" v-show="showSearch">
        <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
          <el-form-item label="登录地址" prop="ipaddr">
            <el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable style="width: 240px;" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="用户名称" prop="userName">
            <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px;" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="状态" prop="status">
            <el-select v-model="queryParams.status" placeholder="登录状态" clearable style="width: 240px">
              <el-option v-for="dict in sys_common_status" :key="dict.value" :label="dict.label" :value="dict.value" />
            </el-select>
          </el-form-item>
          <el-form-item label="登录时间" style="width: 308px">
            <el-date-picker
              v-model="dateRange"
              value-format="YYYY-MM-DD HH:mm:ss"
              type="daterange"
              range-separator="-"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
            ></el-date-picker>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </transition>
    <el-card shadow="never">
      <template #header>
        <el-row :gutter="10" class="mb8">
          <el-col :span="1.5">
            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['monitor:logininfor:remove']">
              åˆ é™¤
            </el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="danger" plain icon="Delete" @click="handleClean" v-hasPermi="['monitor:logininfor:remove']">清空</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="primary" plain icon="Unlock" :disabled="single" @click="handleUnlock" v-hasPermi="['monitor:logininfor:unlock']">
              è§£é”
            </el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['monitor:logininfor:export']">导出</el-button>
          </el-col>
          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
        </el-row>
      </template>
      <el-table
        ref="loginInfoTableRef"
        v-loading="loading"
        :data="loginInfoList"
        @selection-change="handleSelectionChange"
        :default-sort="defaultSort"
        @sort-change="handleSortChange"
      >
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="访问编号" align="center" prop="infoId" />
        <el-table-column
          label="用户名称"
          align="center"
          prop="userName"
          :show-overflow-tooltip="true"
          sortable="custom"
          :sort-orders="['descending', 'ascending']"
        />
        <el-table-column label="地址" align="center" prop="ipaddr" :show-overflow-tooltip="true" />
        <el-table-column label="登录地点" align="center" prop="loginLocation" :show-overflow-tooltip="true" />
        <el-table-column label="操作系统" align="center" prop="os" :show-overflow-tooltip="true" />
        <el-table-column label="浏览器" align="center" prop="browser" :show-overflow-tooltip="true" />
        <el-table-column label="登录状态" align="center" prop="status">
          <template #default="scope">
            <dict-tag :options="sys_common_status" :value="scope.row.status" />
          </template>
        </el-table-column>
        <el-table-column label="描述" align="center" prop="msg" :show-overflow-tooltip="true" />
        <el-table-column label="访问时间" align="center" prop="loginTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="180">
          <template #default="scope">
            <span>{{ parseTime(scope.row.loginTime) }}</span>
          </template>
        </el-table-column>
      </el-table>
      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
    </el-card>
  </div>
</template>
<script setup name="Logininfor" lang="ts">
import { list, delLoginInfo, cleanLoginInfo, unlockLoginInfo } from "@/api/monitor/loginInfo";
import { ComponentInternalInstance } from "vue";
@@ -97,101 +195,3 @@
  getList();
})
</script>
<template>
    <div class="p-2">
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
            <div class="search" v-show="showSearch">
                <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
                    <el-form-item label="登录地址" prop="ipaddr">
                        <el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable style="width: 240px;" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="用户名称" prop="userName">
                        <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px;" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="状态" prop="status">
                        <el-select v-model="queryParams.status" placeholder="登录状态" clearable style="width: 240px">
                            <el-option v-for="dict in sys_common_status" :key="dict.value" :label="dict.label" :value="dict.value" />
                        </el-select>
                    </el-form-item>
                    <el-form-item label="登录时间" style="width: 308px">
                        <el-date-picker
                            v-model="dateRange"
                            value-format="YYYY-MM-DD HH:mm:ss"
                            type="daterange"
                            range-separator="-"
                            start-placeholder="开始日期"
                            end-placeholder="结束日期"
                            :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
                        ></el-date-picker>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
                    </el-form-item>
                </el-form>
            </div>
        </transition>
        <el-card shadow="never">
            <template #header>
                <el-row :gutter="10" class="mb8">
                    <el-col :span="1.5">
                        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['monitor:logininfor:remove']">
                            åˆ é™¤
                        </el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="danger" plain icon="Delete" @click="handleClean" v-hasPermi="['monitor:logininfor:remove']">清空</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="primary" plain icon="Unlock" :disabled="single" @click="handleUnlock" v-hasPermi="['monitor:logininfor:unlock']">
                            è§£é”
                        </el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['monitor:logininfor:export']">导出</el-button>
                    </el-col>
                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
                </el-row>
            </template>
            <el-table
                ref="loginInfoTableRef"
                v-loading="loading"
                :data="loginInfoList"
                @selection-change="handleSelectionChange"
                :default-sort="defaultSort"
                @sort-change="handleSortChange"
            >
                <el-table-column type="selection" width="55" align="center" />
                <el-table-column label="访问编号" align="center" prop="infoId" />
                <el-table-column
                    label="用户名称"
                    align="center"
                    prop="userName"
                    :show-overflow-tooltip="true"
                    sortable="custom"
                    :sort-orders="['descending', 'ascending']"
                />
                <el-table-column label="地址" align="center" prop="ipaddr" :show-overflow-tooltip="true" />
                <el-table-column label="登录地点" align="center" prop="loginLocation" :show-overflow-tooltip="true" />
                <el-table-column label="操作系统" align="center" prop="os" :show-overflow-tooltip="true" />
                <el-table-column label="浏览器" align="center" prop="browser" :show-overflow-tooltip="true" />
                <el-table-column label="登录状态" align="center" prop="status">
                    <template #default="scope">
                        <dict-tag :options="sys_common_status" :value="scope.row.status" />
                    </template>
                </el-table-column>
                <el-table-column label="描述" align="center" prop="msg" :show-overflow-tooltip="true" />
                <el-table-column label="访问时间" align="center" prop="loginTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="180">
                    <template #default="scope">
                        <span>{{ parseTime(scope.row.loginTime) }}</span>
                    </template>
                </el-table-column>
            </el-table>
            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
        </el-card>
    </div>
</template>
src/views/monitor/online/index.vue
@@ -1,54 +1,3 @@
<script setup name="Online" lang="ts">
import { forceLogout, list as initData } from "@/api/monitor/online";
import { ComponentInternalInstance } from "vue";
import { OnlineQuery, OnlineVO } from "@/api/monitor/online/types";
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const onlineList = ref<OnlineVO[]>([]);
const loading = ref(true);
const total = ref(0);
const queryFormRef = ref(ElForm);
const queryParams = ref<OnlineQuery>({
    pageNum: 1,
    pageSize: 10,
    ipaddr: '',
    userName: ''
});
/** æŸ¥è¯¢ç™»å½•日志列表 */
const getList = async () => {
    loading.value = true;
    const res = await initData(queryParams.value);
    onlineList.value = res.rows;
    total.value = res.total;
    loading.value = false;
}
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
    queryParams.value.pageNum = 1;
    getList();
}
/** é‡ç½®æŒ‰é’®æ“ä½œ */
const resetQuery = () => {
    queryFormRef.value.resetFields();
    handleQuery();
}
/** å¼ºé€€æŒ‰é’®æ“ä½œ */
const handleForceLogout = async (row: OnlineVO) => {
    await proxy?.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?');
    await forceLogout(row.tokenId);
    getList();
    proxy?.$modal.msgSuccess("删除成功");
}
onMounted(() => {
    getList();
})
</script>
<template>
    <div class="p-2">
        <div class="search">
@@ -102,3 +51,54 @@
        </div>
    </div>
</template>
<script setup name="Online" lang="ts">
import { forceLogout, list as initData } from "@/api/monitor/online";
import { ComponentInternalInstance } from "vue";
import { OnlineQuery, OnlineVO } from "@/api/monitor/online/types";
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const onlineList = ref<OnlineVO[]>([]);
const loading = ref(true);
const total = ref(0);
const queryFormRef = ref(ElForm);
const queryParams = ref<OnlineQuery>({
    pageNum: 1,
    pageSize: 10,
    ipaddr: '',
    userName: ''
});
/** æŸ¥è¯¢ç™»å½•日志列表 */
const getList = async () => {
    loading.value = true;
    const res = await initData(queryParams.value);
    onlineList.value = res.rows;
    total.value = res.total;
    loading.value = false;
}
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
    queryParams.value.pageNum = 1;
    getList();
}
/** é‡ç½®æŒ‰é’®æ“ä½œ */
const resetQuery = () => {
    queryFormRef.value.resetFields();
    handleQuery();
}
/** å¼ºé€€æŒ‰é’®æ“ä½œ */
const handleForceLogout = async (row: OnlineVO) => {
    await proxy?.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?');
    await forceLogout(row.tokenId);
    getList();
    proxy?.$modal.msgSuccess("删除成功");
}
onMounted(() => {
    getList();
})
</script>
src/views/monitor/operlog/index.vue
@@ -1,134 +1,3 @@
<script setup name="Operlog" lang="ts">
import { list, delOperlog, cleanOperlog } from '@/api/monitor/operlog';
import { ComponentInternalInstance } from 'vue';
import { OperLogForm, OperLogQuery, OperLogVO } from '@/api/monitor/operlog/types';
import { DateModelType } from 'element-plus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_oper_type, sys_common_status } = toRefs<any>(proxy?.useDict("sys_oper_type","sys_common_status"));
const operlogList = ref<OperLogVO[]>([]);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<number | string>>([]);
const multiple = ref(true);
const total = ref(0);
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
const defaultSort = ref<any>({ prop: "operTime", order: "descending" });
const operLogTableRef = ref(ElTable);
const queryFormRef = ref(ElForm);
const dialog = reactive<DialogOption>({
  visible: false,
  title: ''
});
const data = reactive<PageData<OperLogForm, OperLogQuery>>({
  form: {
    operId: undefined,
    tenantId: undefined,
    title: '',
    businessType: 0,
    businessTypes: undefined,
    method: '',
    requestMethod: '',
    operatorType: 0,
    operName: '',
    deptName: '',
    operUrl: '',
    operIp: '',
    operLocation: '',
    operParam: '',
    jsonResult: '',
    status: 0,
    errorMsg: '',
    operTime: '',
    costTime: 0
  },
  queryParams: {
    pageNum: 1,
    pageSize: 10,
    title: '',
    operName: '',
    businessType: '',
    status: '',
    orderByColumn: defaultSort.value.prop,
    isAsc: defaultSort.value.order
  },
  rules: {}
});
const { queryParams, form } = toRefs(data);
/** æŸ¥è¯¢ç™»å½•日志 */
const getList = async () => {
  loading.value = true;
    const res = await list(proxy?.addDateRange(queryParams.value, dateRange.value));
    operlogList.value = res.rows;
    total.value = res.total;
    loading.value = false;
}
/** æ“ä½œæ—¥å¿—类型字典翻译 */
const typeFormat = (row: OperLogForm) => {
  return proxy?.selectDictLabel(sys_oper_type.value, row.businessType);
}
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
  queryParams.value.pageNum = 1;
  getList();
}
/** é‡ç½®æŒ‰é’®æ“ä½œ */
const resetQuery = () => {
  dateRange.value = ['', ''];
  queryFormRef.value.resetFields();
  queryParams.value.pageNum = 1;
  operLogTableRef.value.sort(defaultSort.value.prop, defaultSort.value.order);
}
/** å¤šé€‰æ¡†é€‰ä¸­æ•°æ® */
const handleSelectionChange = (selection: OperLogVO[]) => {
  ids.value = selection.map(item => item.operId);
  multiple.value = !selection.length;
}
/** æŽ’序触发事件 */
const handleSortChange = (column: any) => {
  queryParams.value.orderByColumn = column.prop;
  queryParams.value.isAsc = column.order;
  getList();
}
/** è¯¦ç»†æŒ‰é’®æ“ä½œ */
const handleView = (row: OperLogVO) => {
  dialog.visible = true;
  form.value = row;
}
/** åˆ é™¤æŒ‰é’®æ“ä½œ */
const handleDelete = async (row?: OperLogVO) => {
  const operIds = row?.operId || ids.value;
    await proxy?.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?');
    await delOperlog(operIds);
    getList();
    proxy?.$modal.msgSuccess("删除成功");
}
/** æ¸…空按钮操作 */
const handleClean = async () => {
    await proxy?.$modal.confirm("是否确认清空所有操作日志数据项?");
    await cleanOperlog();
    getList();
    proxy?.$modal.msgSuccess("清空成功");
}
/** å¯¼å‡ºæŒ‰é’®æ“ä½œ */
const handleExport = () => {
  proxy?.download("monitor/operlog/export", {
    ...queryParams.value,
  }, `config_${new Date().getTime()}.xlsx`);
}
onMounted(() => {
  getList();
})
</script>
<template>
    <div class="p-2">
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
@@ -293,3 +162,135 @@
        </el-dialog>
    </div>
</template>
<script setup name="Operlog" lang="ts">
import { list, delOperlog, cleanOperlog } from '@/api/monitor/operlog';
import { ComponentInternalInstance } from 'vue';
import { OperLogForm, OperLogQuery, OperLogVO } from '@/api/monitor/operlog/types';
import { DateModelType } from 'element-plus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_oper_type, sys_common_status } = toRefs<any>(proxy?.useDict("sys_oper_type","sys_common_status"));
const operlogList = ref<OperLogVO[]>([]);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<number | string>>([]);
const multiple = ref(true);
const total = ref(0);
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
const defaultSort = ref<any>({ prop: "operTime", order: "descending" });
const operLogTableRef = ref(ElTable);
const queryFormRef = ref(ElForm);
const dialog = reactive<DialogOption>({
    visible: false,
    title: ''
});
const data = reactive<PageData<OperLogForm, OperLogQuery>>({
    form: {
        operId: undefined,
        tenantId: undefined,
        title: '',
        businessType: 0,
        businessTypes: undefined,
        method: '',
        requestMethod: '',
        operatorType: 0,
        operName: '',
        deptName: '',
        operUrl: '',
        operIp: '',
        operLocation: '',
        operParam: '',
        jsonResult: '',
        status: 0,
        errorMsg: '',
        operTime: '',
        costTime: 0
    },
    queryParams: {
        pageNum: 1,
        pageSize: 10,
        title: '',
        operName: '',
        businessType: '',
        status: '',
        orderByColumn: defaultSort.value.prop,
        isAsc: defaultSort.value.order
    },
    rules: {}
});
const { queryParams, form } = toRefs(data);
/** æŸ¥è¯¢ç™»å½•日志 */
const getList = async () => {
    loading.value = true;
    const res = await list(proxy?.addDateRange(queryParams.value, dateRange.value));
    operlogList.value = res.rows;
    total.value = res.total;
    loading.value = false;
}
/** æ“ä½œæ—¥å¿—类型字典翻译 */
const typeFormat = (row: OperLogForm) => {
    return proxy?.selectDictLabel(sys_oper_type.value, row.businessType);
}
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
    queryParams.value.pageNum = 1;
    getList();
}
/** é‡ç½®æŒ‰é’®æ“ä½œ */
const resetQuery = () => {
    dateRange.value = ['', ''];
    queryFormRef.value.resetFields();
    queryParams.value.pageNum = 1;
    operLogTableRef.value.sort(defaultSort.value.prop, defaultSort.value.order);
}
/** å¤šé€‰æ¡†é€‰ä¸­æ•°æ® */
const handleSelectionChange = (selection: OperLogVO[]) => {
    ids.value = selection.map(item => item.operId);
    multiple.value = !selection.length;
}
/** æŽ’序触发事件 */
const handleSortChange = (column: any) => {
    queryParams.value.orderByColumn = column.prop;
    queryParams.value.isAsc = column.order;
    getList();
}
/** è¯¦ç»†æŒ‰é’®æ“ä½œ */
const handleView = (row: OperLogVO) => {
    dialog.visible = true;
    form.value = row;
}
/** åˆ é™¤æŒ‰é’®æ“ä½œ */
const handleDelete = async (row?: OperLogVO) => {
    const operIds = row?.operId || ids.value;
    await proxy?.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?');
    await delOperlog(operIds);
    getList();
    proxy?.$modal.msgSuccess("删除成功");
}
/** æ¸…空按钮操作 */
const handleClean = async () => {
    await proxy?.$modal.confirm("是否确认清空所有操作日志数据项?");
    await cleanOperlog();
    getList();
    proxy?.$modal.msgSuccess("清空成功");
}
/** å¯¼å‡ºæŒ‰é’®æ“ä½œ */
const handleExport = () => {
    proxy?.download("monitor/operlog/export", {
        ...queryParams.value,
    }, `config_${new Date().getTime()}.xlsx`);
}
onMounted(() => {
    getList();
})
</script>
src/views/monitor/xxljob/index.vue
src/views/redirect/index.vue
src/views/register.vue
@@ -1,3 +1,60 @@
<template>
  <div class="register">
    <el-form ref="registerRef" :model="registerForm" :rules="registerRules" class="register-form">
      <h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3>
      <el-form-item prop="tenantId" v-if="tenantEnabled">
        <el-select v-model="registerForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%">
          <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option>
          <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
        </el-select>
      </el-form-item>
      <el-form-item prop="username">
        <el-input v-model="registerForm.username" type="text" size="large" auto-complete="off" placeholder="账号">
          <template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
        </el-input>
      </el-form-item>
      <el-form-item prop="password">
        <el-input v-model="registerForm.password" type="password" size="large" auto-complete="off" placeholder="密码" @keyup.enter="handleRegister">
          <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
        </el-input>
      </el-form-item>
      <el-form-item prop="confirmPassword">
        <el-input
          v-model="registerForm.confirmPassword"
          type="password"
          size="large"
          auto-complete="off"
          placeholder="确认密码"
          @keyup.enter="handleRegister"
        >
          <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
        </el-input>
      </el-form-item>
      <el-form-item prop="code" v-if="captchaEnabled">
        <el-input size="large" v-model="registerForm.code" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleRegister">
          <template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
        </el-input>
        <div class="register-code">
          <img :src="codeUrl" @click="getCode" class="register-code-img" />
        </div>
      </el-form-item>
      <el-form-item style="width:100%;">
        <el-button :loading="loading" size="large" type="primary" style="width:100%;" @click.prevent="handleRegister">
          <span v-if="!loading">注 å†Œ</span>
          <span v-else>注 å†Œ ä¸­...</span>
        </el-button>
        <div style="float: right;">
          <router-link class="link-type" :to="'/login'">使用已有账户登录</router-link>
        </div>
      </el-form-item>
    </el-form>
    <!--  åº•部  -->
    <div class="el-register-footer">
      <span>Copyright Â© 2018-2023 ç–¯ç‹‚的狮子Li All Rights Reserved.</span>
    </div>
  </div>
</template>
<script setup lang="ts">
import { getCodeImg, register, getTenantList } from '@/api/login';
import { RegisterForm, TenantVO } from '@/api/types';
@@ -100,63 +157,6 @@
  initTenantList();
})
</script>
<template>
    <div class="register">
        <el-form ref="registerRef" :model="registerForm" :rules="registerRules" class="register-form">
            <h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3>
            <el-form-item prop="tenantId" v-if="tenantEnabled">
                <el-select v-model="registerForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%">
                    <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option>
                    <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
                </el-select>
            </el-form-item>
            <el-form-item prop="username">
                <el-input v-model="registerForm.username" type="text" size="large" auto-complete="off" placeholder="账号">
                    <template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
                </el-input>
            </el-form-item>
            <el-form-item prop="password">
                <el-input v-model="registerForm.password" type="password" size="large" auto-complete="off" placeholder="密码" @keyup.enter="handleRegister">
                    <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
                </el-input>
            </el-form-item>
            <el-form-item prop="confirmPassword">
                <el-input
                    v-model="registerForm.confirmPassword"
                    type="password"
                    size="large"
                    auto-complete="off"
                    placeholder="确认密码"
                    @keyup.enter="handleRegister"
                >
                    <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
                </el-input>
            </el-form-item>
            <el-form-item prop="code" v-if="captchaEnabled">
                <el-input size="large" v-model="registerForm.code" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleRegister">
                    <template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
                </el-input>
                <div class="register-code">
                    <img :src="codeUrl" @click="getCode" class="register-code-img" />
                </div>
            </el-form-item>
            <el-form-item style="width:100%;">
                <el-button :loading="loading" size="large" type="primary" style="width:100%;" @click.prevent="handleRegister">
                    <span v-if="!loading">注 å†Œ</span>
                    <span v-else>注 å†Œ ä¸­...</span>
                </el-button>
                <div style="float: right;">
                    <router-link class="link-type" :to="'/login'">使用已有账户登录</router-link>
                </div>
            </el-form-item>
        </el-form>
        <!--  åº•部  -->
        <div class="el-register-footer">
            <span>Copyright Â© 2018-2023 ç–¯ç‹‚的狮子Li All Rights Reserved.</span>
        </div>
    </div>
</template>
<style lang="scss" scoped>
.register {
src/views/system/config/index.vue
src/views/system/dept/index.vue
@@ -1,3 +1,133 @@
<template>
  <div class="p-2">
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div class="search" v-show="showSearch">
        <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
          <el-form-item label="菜单名称" prop="menuName">
            <el-input v-model="queryParams.deptName" placeholder="请输入部门名称" clearable @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="状态" prop="status">
            <el-select v-model="queryParams.status" placeholder="部门状态" clearable>
              <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
            </el-select>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </transition>
    <el-card shadow="never">
      <template #header>
        <el-row :gutter="10">
          <el-col :span="1.5">
            <el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['system:dept:add']">新增 </el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
          </el-col>
          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
        </el-row>
      </template>
      <el-table
        v-loading="loading"
        :data="deptList"
        row-key="deptId"
        :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
        ref="deptTableRef"
        :default-expand-all="isExpandAll"
      >
        <el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
        <el-table-column prop="orderNum" align="center" label="排序" width="200"></el-table-column>
        <el-table-column prop="status" align="center" label="状态" width="100">
          <template #default="scope">
            <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
          </template>
        </el-table-column>
        <el-table-column label="创建时间" align="center" prop="createTime" width="200">
          <template #default="scope">
            <span>{{ parseTime(scope.row.createTime) }}</span>
          </template>
        </el-table-column>
        <el-table-column fixed="right" align="center" label="操作">
          <template #default="scope">
            <el-tooltip content="修改" placement="top">
              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dept:edit']" />
            </el-tooltip>
            <el-tooltip content="新增" placement="top">
              <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:dept:add']" />
            </el-tooltip>
            <el-tooltip content="删除" placement="top">
              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dept:remove']" />
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
    <el-dialog :title="dialog.title" v-model="dialog.visible" destroy-on-close append-to-bod width="600px">
      <el-form ref="deptFormRef" :model="form" :rules="rules" label-width="80px">
        <el-row>
          <el-col :span="24" v-if="form.parentId !== 0">
            <el-form-item label="上级部门" prop="parentId">
              <el-tree-select
                v-model="form.parentId"
                :data="deptOptions"
                :props="{ value: 'deptId', label: 'deptName', children: 'children' }"
                value-key="deptId"
                placeholder="选择上级部门"
                check-strictly
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="部门名称" prop="deptName">
              <el-input v-model="form.deptName" placeholder="请输入部门名称" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="显示排序" prop="orderNum">
              <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="负责人" prop="leader">
              <el-input v-model="form.leader" placeholder="请输入负责人" maxlength="20" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="联系电话" prop="phone">
              <el-input v-model="form.phone" placeholder="请输入联系电话" maxlength="11" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="邮箱" prop="email">
              <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="部门状态">
              <el-radio-group v-model="form.status">
                <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label
                }}</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
          <el-button @click="cancel">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup name="Dept" lang="ts">
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from "@/api/system/dept"
import { ComponentInternalInstance } from 'vue';
@@ -160,133 +290,3 @@
  getList();
});
</script>
<template>
    <div class="p-2">
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
            <div class="search" v-show="showSearch">
                <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
                    <el-form-item label="菜单名称" prop="menuName">
                        <el-input v-model="queryParams.deptName" placeholder="请输入部门名称" clearable @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="状态" prop="status">
                        <el-select v-model="queryParams.status" placeholder="部门状态" clearable>
                            <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
                        </el-select>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
                    </el-form-item>
                </el-form>
            </div>
        </transition>
        <el-card shadow="never">
            <template #header>
                <el-row :gutter="10">
                    <el-col :span="1.5">
                        <el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['system:dept:add']">新增 </el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
                    </el-col>
                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
                </el-row>
            </template>
            <el-table
                v-loading="loading"
                :data="deptList"
                row-key="deptId"
                :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
                ref="deptTableRef"
                :default-expand-all="isExpandAll"
            >
                <el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
                <el-table-column prop="orderNum" align="center" label="排序" width="200"></el-table-column>
                <el-table-column prop="status" align="center" label="状态" width="100">
                    <template #default="scope">
                        <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
                    </template>
                </el-table-column>
                <el-table-column label="创建时间" align="center" prop="createTime" width="200">
                    <template #default="scope">
                        <span>{{ parseTime(scope.row.createTime) }}</span>
                    </template>
                </el-table-column>
                <el-table-column fixed="right" align="center" label="操作">
                    <template #default="scope">
                        <el-tooltip content="修改" placement="top">
                            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dept:edit']" />
                        </el-tooltip>
                        <el-tooltip content="新增" placement="top">
                            <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:dept:add']" />
                        </el-tooltip>
                        <el-tooltip content="删除" placement="top">
                            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dept:remove']" />
                        </el-tooltip>
                    </template>
                </el-table-column>
            </el-table>
        </el-card>
        <el-dialog :title="dialog.title" v-model="dialog.visible" destroy-on-close append-to-bod width="600px">
            <el-form ref="deptFormRef" :model="form" :rules="rules" label-width="80px">
                <el-row>
                    <el-col :span="24" v-if="form.parentId !== 0">
                        <el-form-item label="上级部门" prop="parentId">
                            <el-tree-select
                                v-model="form.parentId"
                                :data="deptOptions"
                                :props="{ value: 'deptId', label: 'deptName', children: 'children' }"
                                value-key="deptId"
                                placeholder="选择上级部门"
                                check-strictly
                            />
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="部门名称" prop="deptName">
                            <el-input v-model="form.deptName" placeholder="请输入部门名称" />
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="显示排序" prop="orderNum">
                            <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="负责人" prop="leader">
                            <el-input v-model="form.leader" placeholder="请输入负责人" maxlength="20" />
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="联系电话" prop="phone">
                            <el-input v-model="form.phone" placeholder="请输入联系电话" maxlength="11" />
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="邮箱" prop="email">
                            <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="部门状态">
                            <el-radio-group v-model="form.status">
                                <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label
                                }}</el-radio>
                            </el-radio-group>
                        </el-form-item>
                    </el-col>
                </el-row>
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
                    <el-button @click="cancel">取 æ¶ˆ</el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>
src/views/system/dict/data.vue
@@ -1,3 +1,136 @@
<template>
  <div class="p-2">
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div class="search" v-show="showSearch">
        <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
          <el-form-item label="字典名称" prop="dictType">
            <el-select v-model="queryParams.dictType" style="width: 200px">
              <el-option v-for="item in typeOptions" :key="item.dictId" :label="item.dictName" :value="item.dictType" />
            </el-select>
          </el-form-item>
          <el-form-item label="字典标签" prop="dictLabel">
            <el-input v-model="queryParams.dictLabel" placeholder="请输入字典标签" clearable style="width: 200px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="状态" prop="status">
            <el-select v-model="queryParams.status" placeholder="数据状态" clearable style="width: 200px">
              <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
            </el-select>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </transition>
    <el-card shadow="never">
      <template #header>
        <el-row :gutter="10" class="mb8">
          <el-col :span="1.5">
            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:dict:add']">新增</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:dict:edit']">修改</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:dict:remove']">
              åˆ é™¤
            </el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:dict:export']">导出</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="warning" plain icon="Close" @click="handleClose">关闭</el-button>
          </el-col>
          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
        </el-row>
      </template>
      <el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="字典编码" align="center" prop="dictCode" v-if="false" />
        <el-table-column label="字典标签" align="center" prop="dictLabel">
          <template #default="scope">
            <span v-if="scope.row.listClass === '' || scope.row.listClass === 'default'">{{ scope.row.dictLabel }}</span>
            <el-tag v-else :type="scope.row.listClass === 'primary' ? '' : scope.row.listClass">{{ scope.row.dictLabel
            }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="字典键值" align="center" prop="dictValue" />
        <el-table-column label="字典排序" align="center" prop="dictSort" />
        <el-table-column label="状态" align="center" prop="status">
          <template #default="scope">
            <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
          </template>
        </el-table-column>
        <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
        <el-table-column label="创建时间" align="center" prop="createTime" width="180">
          <template #default="scope">
            <span>{{ parseTime(scope.row.createTime) }}</span>
          </template>
        </el-table-column>
        <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
          <template #default="scope">
            <el-tooltip content="修改" placement="top">
              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dict:edit']"></el-button>
            </el-tooltip>
            <el-tooltip content="删除" placement="top">
              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dict:remove']"></el-button>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
    </el-card>
    <!-- æ·»åŠ æˆ–ä¿®æ”¹å‚æ•°é…ç½®å¯¹è¯æ¡† -->
    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
      <el-form ref="dataFormRef" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="字典类型">
          <el-input v-model="form.dictType" :disabled="true" />
        </el-form-item>
        <el-form-item label="数据标签" prop="dictLabel">
          <el-input v-model="form.dictLabel" placeholder="请输入数据标签" />
        </el-form-item>
        <el-form-item label="数据键值" prop="dictValue">
          <el-input v-model="form.dictValue" placeholder="请输入数据键值" />
        </el-form-item>
        <el-form-item label="样式属性" prop="cssClass">
          <el-input v-model="form.cssClass" placeholder="请输入样式属性" />
        </el-form-item>
        <el-form-item label="显示排序" prop="dictSort">
          <el-input-number v-model="form.dictSort" controls-position="right" :min="0" />
        </el-form-item>
        <el-form-item label="回显样式" prop="listClass">
          <el-select v-model="form.listClass">
            <el-option
              v-for="item in listClassOptions"
              :key="item.value"
              :label="item.label + '(' + item.value + ')'"
              :value="item.value"
            ></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="状态" prop="status">
          <el-radio-group v-model="form.status">
            <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
          <el-button @click="cancel">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup name="Data" lang="ts">
import useDictStore from '@/store/modules/dict'
import { optionselect as getDictOptionselect, getType } from "@/api/system/dict/type";
@@ -177,136 +310,3 @@
    getTypeList();
})
</script>
<template>
    <div class="p-2">
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
            <div class="search" v-show="showSearch">
                <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
                    <el-form-item label="字典名称" prop="dictType">
                        <el-select v-model="queryParams.dictType" style="width: 200px">
                            <el-option v-for="item in typeOptions" :key="item.dictId" :label="item.dictName" :value="item.dictType" />
                        </el-select>
                    </el-form-item>
                    <el-form-item label="字典标签" prop="dictLabel">
                        <el-input v-model="queryParams.dictLabel" placeholder="请输入字典标签" clearable style="width: 200px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="状态" prop="status">
                        <el-select v-model="queryParams.status" placeholder="数据状态" clearable style="width: 200px">
                            <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
                        </el-select>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
                    </el-form-item>
                </el-form>
            </div>
        </transition>
        <el-card shadow="never">
            <template #header>
                <el-row :gutter="10" class="mb8">
                    <el-col :span="1.5">
                        <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:dict:add']">新增</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:dict:edit']">修改</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:dict:remove']">
                            åˆ é™¤
                        </el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:dict:export']">导出</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="warning" plain icon="Close" @click="handleClose">关闭</el-button>
                    </el-col>
                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
                </el-row>
            </template>
            <el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
                <el-table-column type="selection" width="55" align="center" />
                <el-table-column label="字典编码" align="center" prop="dictCode" v-if="false" />
                <el-table-column label="字典标签" align="center" prop="dictLabel">
                    <template #default="scope">
                        <span v-if="scope.row.listClass === '' || scope.row.listClass === 'default'">{{ scope.row.dictLabel }}</span>
                        <el-tag v-else :type="scope.row.listClass === 'primary' ? '' : scope.row.listClass">{{ scope.row.dictLabel
                        }}</el-tag>
                    </template>
                </el-table-column>
                <el-table-column label="字典键值" align="center" prop="dictValue" />
                <el-table-column label="字典排序" align="center" prop="dictSort" />
                <el-table-column label="状态" align="center" prop="status">
                    <template #default="scope">
                        <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
                    </template>
                </el-table-column>
                <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
                <el-table-column label="创建时间" align="center" prop="createTime" width="180">
                    <template #default="scope">
                        <span>{{ parseTime(scope.row.createTime) }}</span>
                    </template>
                </el-table-column>
                <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
                    <template #default="scope">
                        <el-tooltip content="修改" placement="top">
                            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dict:edit']"></el-button>
                        </el-tooltip>
                        <el-tooltip content="删除" placement="top">
                            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dict:remove']"></el-button>
                        </el-tooltip>
                    </template>
                </el-table-column>
            </el-table>
            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
        </el-card>
        <!-- æ·»åŠ æˆ–ä¿®æ”¹å‚æ•°é…ç½®å¯¹è¯æ¡† -->
        <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
            <el-form ref="dataFormRef" :model="form" :rules="rules" label-width="80px">
                <el-form-item label="字典类型">
                    <el-input v-model="form.dictType" :disabled="true" />
                </el-form-item>
                <el-form-item label="数据标签" prop="dictLabel">
                    <el-input v-model="form.dictLabel" placeholder="请输入数据标签" />
                </el-form-item>
                <el-form-item label="数据键值" prop="dictValue">
                    <el-input v-model="form.dictValue" placeholder="请输入数据键值" />
                </el-form-item>
                <el-form-item label="样式属性" prop="cssClass">
                    <el-input v-model="form.cssClass" placeholder="请输入样式属性" />
                </el-form-item>
                <el-form-item label="显示排序" prop="dictSort">
                    <el-input-number v-model="form.dictSort" controls-position="right" :min="0" />
                </el-form-item>
                <el-form-item label="回显样式" prop="listClass">
                    <el-select v-model="form.listClass">
                        <el-option
                            v-for="item in listClassOptions"
                            :key="item.value"
                            :label="item.label + '(' + item.value + ')'"
                            :value="item.value"
                        ></el-option>
                    </el-select>
                </el-form-item>
                <el-form-item label="状态" prop="status">
                    <el-radio-group v-model="form.status">
                        <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
                    </el-radio-group>
                </el-form-item>
                <el-form-item label="备注" prop="remark">
                    <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
                </el-form-item>
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
                    <el-button @click="cancel">取 æ¶ˆ</el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>
src/views/system/dict/index.vue
@@ -1,3 +1,125 @@
<template>
  <div class="p-2">
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div class="search" v-show="showSearch">
        <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
          <el-form-item label="字典名称" prop="dictName">
            <el-input v-model="queryParams.dictName" placeholder="请输入字典名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="字典类型" prop="dictType">
            <el-input v-model="queryParams.dictType" placeholder="请输入字典类型" clearable style="width: 240px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="状态" prop="status">
            <el-select v-model="queryParams.status" placeholder="字典状态" clearable style="width: 240px">
              <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
            </el-select>
          </el-form-item>
          <el-form-item label="创建时间" style="width: 308px">
            <el-date-picker
              v-model="dateRange"
              value-format="YYYY-MM-DD HH:mm:ss"
              type="daterange"
              range-separator="-"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
            ></el-date-picker>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </transition>
    <el-card shadow="never">
      <template #header>
        <el-row :gutter="10" class="mb8">
          <el-col :span="1.5">
            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:dict:add']">新增</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:dict:edit']">修改</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:dict:remove']">
              åˆ é™¤
            </el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:dict:export']">导出</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="danger" plain icon="Refresh" @click="handleRefreshCache" v-hasPermi="['system:dict:remove']">刷新缓存</el-button>
          </el-col>
          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
        </el-row>
      </template>
      <el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="字典编号" align="center" prop="dictId" v-if="false" />
        <el-table-column label="字典名称" align="center" prop="dictName" :show-overflow-tooltip="true" />
        <el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
          <template #default="scope">
            <router-link :to="'/system/dict-data/index/' + scope.row.dictId" class="link-type">
              <span>{{ scope.row.dictType }}</span>
            </router-link>
          </template>
        </el-table-column>
        <el-table-column label="状态" align="center" prop="status">
          <template #default="scope">
            <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
          </template>
        </el-table-column>
        <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
        <el-table-column label="创建时间" align="center" prop="createTime" width="180">
          <template #default="scope">
            <span>{{ parseTime(scope.row.createTime) }}</span>
          </template>
        </el-table-column>
        <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
          <template #default="scope">
            <el-tooltip content="修改" placement="top">
              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dict:edit']"></el-button>
            </el-tooltip>
            <el-tooltip content="删除" placement="top">
              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dict:remove']"></el-button>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
    </el-card>
    <!-- æ·»åŠ æˆ–ä¿®æ”¹å‚æ•°é…ç½®å¯¹è¯æ¡† -->
    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
      <el-form ref="dictFormRef" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="字典名称" prop="dictName">
          <el-input v-model="form.dictName" placeholder="请输入字典名称" />
        </el-form-item>
        <el-form-item label="字典类型" prop="dictType">
          <el-input v-model="form.dictType" placeholder="请输入字典类型" />
        </el-form-item>
        <el-form-item label="状态" prop="status">
          <el-radio-group v-model="form.status">
            <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
          <el-button @click="cancel">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup name="Dict" lang="ts">
import useDictStore from '@/store/modules/dict'
import { listType, getType, delType, addType, updateType, refreshCache } from "@/api/system/dict/type";
@@ -142,125 +264,3 @@
  getList();
})
</script>
<template>
    <div class="p-2">
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
            <div class="search" v-show="showSearch">
                <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
                    <el-form-item label="字典名称" prop="dictName">
                        <el-input v-model="queryParams.dictName" placeholder="请输入字典名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="字典类型" prop="dictType">
                        <el-input v-model="queryParams.dictType" placeholder="请输入字典类型" clearable style="width: 240px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="状态" prop="status">
                        <el-select v-model="queryParams.status" placeholder="字典状态" clearable style="width: 240px">
                            <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
                        </el-select>
                    </el-form-item>
                    <el-form-item label="创建时间" style="width: 308px">
                        <el-date-picker
                            v-model="dateRange"
                            value-format="YYYY-MM-DD HH:mm:ss"
                            type="daterange"
                            range-separator="-"
                            start-placeholder="开始日期"
                            end-placeholder="结束日期"
                            :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
                        ></el-date-picker>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
                    </el-form-item>
                </el-form>
            </div>
        </transition>
        <el-card shadow="never">
            <template #header>
                <el-row :gutter="10" class="mb8">
                    <el-col :span="1.5">
                        <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:dict:add']">新增</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:dict:edit']">修改</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:dict:remove']">
                            åˆ é™¤
                        </el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:dict:export']">导出</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="danger" plain icon="Refresh" @click="handleRefreshCache" v-hasPermi="['system:dict:remove']">刷新缓存</el-button>
                    </el-col>
                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
                </el-row>
            </template>
            <el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange">
                <el-table-column type="selection" width="55" align="center" />
                <el-table-column label="字典编号" align="center" prop="dictId" v-if="false" />
                <el-table-column label="字典名称" align="center" prop="dictName" :show-overflow-tooltip="true" />
                <el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
                    <template #default="scope">
                        <router-link :to="'/system/dict-data/index/' + scope.row.dictId" class="link-type">
                            <span>{{ scope.row.dictType }}</span>
                        </router-link>
                    </template>
                </el-table-column>
                <el-table-column label="状态" align="center" prop="status">
                    <template #default="scope">
                        <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
                    </template>
                </el-table-column>
                <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
                <el-table-column label="创建时间" align="center" prop="createTime" width="180">
                    <template #default="scope">
                        <span>{{ parseTime(scope.row.createTime) }}</span>
                    </template>
                </el-table-column>
                <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
                    <template #default="scope">
                        <el-tooltip content="修改" placement="top">
                            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dict:edit']"></el-button>
                        </el-tooltip>
                        <el-tooltip content="删除" placement="top">
                            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dict:remove']"></el-button>
                        </el-tooltip>
                    </template>
                </el-table-column>
            </el-table>
            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
        </el-card>
        <!-- æ·»åŠ æˆ–ä¿®æ”¹å‚æ•°é…ç½®å¯¹è¯æ¡† -->
        <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
            <el-form ref="dictFormRef" :model="form" :rules="rules" label-width="80px">
                <el-form-item label="字典名称" prop="dictName">
                    <el-input v-model="form.dictName" placeholder="请输入字典名称" />
                </el-form-item>
                <el-form-item label="字典类型" prop="dictType">
                    <el-input v-model="form.dictType" placeholder="请输入字典类型" />
                </el-form-item>
                <el-form-item label="状态" prop="status">
                    <el-radio-group v-model="form.status">
                        <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
                    </el-radio-group>
                </el-form-item>
                <el-form-item label="备注" prop="remark">
                    <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
                </el-form-item>
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
                    <el-button @click="cancel">取 æ¶ˆ</el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>
src/views/system/menu/index.vue
@@ -1,160 +1,3 @@
<script setup name="Menu" lang="ts">
import { addMenu, delMenu, getMenu, listMenu, updateMenu } from '@/api/system/menu';
import { MenuForm, MenuQuery, MenuVO } from '@/api/system/menu/types';
import { ComponentInternalInstance } from 'vue';
import { MenuTypeEnum } from '@/enums/MenuTypeEnum';
import { ElTable, ElForm } from 'element-plus';
interface MenuOptionsType {
    menuId: number;
    menuName: string;
    children: MenuOptionsType[] | undefined;
}
const { proxy } = getCurrentInstance() as ComponentInternalInstance
const { sys_show_hide, sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_show_hide", "sys_normal_disable"));
const menuList = ref<MenuVO[]>([])
const loading = ref(true)
const showSearch = ref(true)
const menuOptions = ref<MenuOptionsType[]>([])
const isExpandAll = ref(false)
const dialog = reactive<DialogOption>({
    visible: false,
    title: ''
});
const queryFormRef = ref(ElForm);
const menuFormRef = ref(ElForm);
const initFormData = {
    path: '',
    menuId: undefined,
    parentId: 0,
    menuName: '',
    icon: '',
    menuType: MenuTypeEnum.M,
    orderNum: 1,
    isFrame: "1",
    isCache: "0",
    visible: "0",
    status: "0"
}
const data = reactive<PageData<MenuForm, MenuQuery>>({
    form: { ...initFormData },
    queryParams: {
        menuName: undefined,
        status: undefined
    },
    rules: {
        menuName: [{ required: true, message: "菜单名称不能为空", trigger: "blur" }],
        orderNum: [{ required: true, message: "菜单顺序不能为空", trigger: "blur" }],
        path: [{ required: true, message: "路由地址不能为空", trigger: "blur" }]
    },
})
const menuTableRef = ref(ElTable);
const { queryParams, form, rules } = toRefs<PageData<MenuForm, MenuQuery>>(data)
/** æŸ¥è¯¢èœå•列表 */
const getList = async () => {
    loading.value = true
    const res = await listMenu(queryParams.value);
    const data = proxy?.handleTree<MenuVO>(res.data, "menuId")
    if (data) {
        menuList.value = data
    }
    loading.value = false
}
/** æŸ¥è¯¢èœå•下拉树结构 */
const getTreeselect = async () => {
    menuOptions.value = []
    const response = await listMenu();
    const menu: MenuOptionsType = { menuId: 0, menuName: "主类目", children: [] }
    menu.children = proxy?.handleTree<MenuOptionsType>(response.data, "menuId")
    menuOptions.value.push(menu)
}
/** å–消按钮 */
const cancel = () => {
    reset()
    dialog.visible = false
}
/** è¡¨å•重置 */
const reset = () => {
    form.value = { ...initFormData };
    menuFormRef.value.resetFields();
}
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
    getList();
}
/** é‡ç½®æŒ‰é’®æ“ä½œ */
const resetQuery = () => {
    queryFormRef.value.resetFields();
    handleQuery();
}
/** æ–°å¢žæŒ‰é’®æ“ä½œ */
const handleAdd = (row?: MenuVO) => {
    dialog.visible = true;
    dialog.title = "添加菜单";
    getTreeselect();
    nextTick(() => {
        reset();
        row && row.menuId ? form.value.parentId = row.menuId : form.value.parentId = 0;
    })
}
/** å±•å¼€/折叠操作 */
const handleToggleExpandAll = () => {
    isExpandAll.value = !isExpandAll.value;
    toggleExpandAll(menuList.value, isExpandAll.value)
}
/** å±•å¼€/折叠所有 */
const toggleExpandAll = (data: MenuVO[], status: boolean) => {
    data.forEach((item: MenuVO) => {
        menuTableRef.value.toggleRowExpansion(item, status)
        if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
    })
}
/** ä¿®æ”¹æŒ‰é’®æ“ä½œ */
const handleUpdate = async (row: MenuVO) => {
    await getTreeselect();
    dialog.visible = true;
    dialog.title = "修改菜单";
    await nextTick(async () => {
        if (row.menuId) {
            const { data } = await getMenu(row.menuId);
            reset();
            form.value = data;
        }
    })
}
/** æäº¤æŒ‰é’® */
const submitForm = () => {
    menuFormRef.value.validate(async (valid: boolean) => {
        if (valid) {
            form.value.menuId ? await updateMenu(form.value) : await addMenu(form.value);
            proxy?.$modal.msgSuccess("操作成功");
            dialog.visible = false;
            getList();
        }
    })
}
/** åˆ é™¤æŒ‰é’®æ“ä½œ */
const handleDelete = async (row: MenuVO) => {
    await proxy?.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?');
    await delMenu(row.menuId);
    getList();
    proxy?.$modal.msgSuccess("删除成功");
}
onMounted(() => {
    getList();
});
</script>
<template>
    <div class="p-2">
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
@@ -415,3 +258,160 @@
        </el-dialog>
    </div>
</template>
<script setup name="Menu" lang="ts">
import { addMenu, delMenu, getMenu, listMenu, updateMenu } from '@/api/system/menu';
import { MenuForm, MenuQuery, MenuVO } from '@/api/system/menu/types';
import { ComponentInternalInstance } from 'vue';
import { MenuTypeEnum } from '@/enums/MenuTypeEnum';
import { ElTable, ElForm } from 'element-plus';
interface MenuOptionsType {
    menuId: number;
    menuName: string;
    children: MenuOptionsType[] | undefined;
}
const { proxy } = getCurrentInstance() as ComponentInternalInstance
const { sys_show_hide, sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_show_hide", "sys_normal_disable"));
const menuList = ref<MenuVO[]>([])
const loading = ref(true)
const showSearch = ref(true)
const menuOptions = ref<MenuOptionsType[]>([])
const isExpandAll = ref(false)
const dialog = reactive<DialogOption>({
    visible: false,
    title: ''
});
const queryFormRef = ref(ElForm);
const menuFormRef = ref(ElForm);
const initFormData = {
    path: '',
    menuId: undefined,
    parentId: 0,
    menuName: '',
    icon: '',
    menuType: MenuTypeEnum.M,
    orderNum: 1,
    isFrame: "1",
    isCache: "0",
    visible: "0",
    status: "0"
}
const data = reactive<PageData<MenuForm, MenuQuery>>({
    form: { ...initFormData },
    queryParams: {
        menuName: undefined,
        status: undefined
    },
    rules: {
        menuName: [{ required: true, message: "菜单名称不能为空", trigger: "blur" }],
        orderNum: [{ required: true, message: "菜单顺序不能为空", trigger: "blur" }],
        path: [{ required: true, message: "路由地址不能为空", trigger: "blur" }]
    },
})
const menuTableRef = ref(ElTable);
const { queryParams, form, rules } = toRefs<PageData<MenuForm, MenuQuery>>(data)
/** æŸ¥è¯¢èœå•列表 */
const getList = async () => {
    loading.value = true
    const res = await listMenu(queryParams.value);
    const data = proxy?.handleTree<MenuVO>(res.data, "menuId")
    if (data) {
        menuList.value = data
    }
    loading.value = false
}
/** æŸ¥è¯¢èœå•下拉树结构 */
const getTreeselect = async () => {
    menuOptions.value = []
    const response = await listMenu();
    const menu: MenuOptionsType = { menuId: 0, menuName: "主类目", children: [] }
    menu.children = proxy?.handleTree<MenuOptionsType>(response.data, "menuId")
    menuOptions.value.push(menu)
}
/** å–消按钮 */
const cancel = () => {
    reset()
    dialog.visible = false
}
/** è¡¨å•重置 */
const reset = () => {
    form.value = { ...initFormData };
    menuFormRef.value.resetFields();
}
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
    getList();
}
/** é‡ç½®æŒ‰é’®æ“ä½œ */
const resetQuery = () => {
    queryFormRef.value.resetFields();
    handleQuery();
}
/** æ–°å¢žæŒ‰é’®æ“ä½œ */
const handleAdd = (row?: MenuVO) => {
    dialog.visible = true;
    dialog.title = "添加菜单";
    getTreeselect();
    nextTick(() => {
        reset();
        row && row.menuId ? form.value.parentId = row.menuId : form.value.parentId = 0;
    })
}
/** å±•å¼€/折叠操作 */
const handleToggleExpandAll = () => {
    isExpandAll.value = !isExpandAll.value;
    toggleExpandAll(menuList.value, isExpandAll.value)
}
/** å±•å¼€/折叠所有 */
const toggleExpandAll = (data: MenuVO[], status: boolean) => {
    data.forEach((item: MenuVO) => {
        menuTableRef.value.toggleRowExpansion(item, status)
        if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
    })
}
/** ä¿®æ”¹æŒ‰é’®æ“ä½œ */
const handleUpdate = async (row: MenuVO) => {
    await getTreeselect();
    dialog.visible = true;
    dialog.title = "修改菜单";
    await nextTick(async () => {
        if (row.menuId) {
            const { data } = await getMenu(row.menuId);
            reset();
            form.value = data;
        }
    })
}
/** æäº¤æŒ‰é’® */
const submitForm = () => {
    menuFormRef.value.validate(async (valid: boolean) => {
        if (valid) {
            form.value.menuId ? await updateMenu(form.value) : await addMenu(form.value);
            proxy?.$modal.msgSuccess("操作成功");
            dialog.visible = false;
            getList();
        }
    })
}
/** åˆ é™¤æŒ‰é’®æ“ä½œ */
const handleDelete = async (row: MenuVO) => {
    await proxy?.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?');
    await delMenu(row.menuId);
    getList();
    proxy?.$modal.msgSuccess("删除成功");
}
onMounted(() => {
    getList();
});
</script>
src/views/system/notice/index.vue
@@ -1,3 +1,122 @@
<template>
  <div class="p-2">
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div class="search" v-show="showSearch">
        <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
          <el-form-item label="公告标题" prop="noticeTitle">
            <el-input v-model="queryParams.noticeTitle" placeholder="请输入公告标题" clearable style="width: 200px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="操作人员" prop="createByName">
            <el-input v-model="queryParams.createByName" placeholder="请输入操作人员" clearable style="width: 200px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="类型" prop="noticeType">
            <el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable style="width: 200px">
              <el-option v-for="dict in sys_notice_type" :key="dict.value" :label="dict.label" :value="dict.value" />
            </el-select>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </transition>
    <el-card shadow="never">
      <template #header>
        <el-row :gutter="10" class="mb8">
          <el-col :span="1.5">
            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:notice:add']">新增</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:notice:edit']"
              >修改</el-button
            >
          </el-col>
          <el-col :span="1.5">
            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:notice:remove']">
              åˆ é™¤
            </el-button>
          </el-col>
          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
        </el-row>
      </template>
      <el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="序号" align="center" prop="noticeId" width="100" v-if="false" />
        <el-table-column label="公告标题" align="center" prop="noticeTitle" :show-overflow-tooltip="true" />
        <el-table-column label="公告类型" align="center" prop="noticeType" width="100">
          <template #default="scope">
            <dict-tag :options="sys_notice_type" :value="scope.row.noticeType" />
          </template>
        </el-table-column>
        <el-table-column label="状态" align="center" prop="status" width="100">
          <template #default="scope">
            <dict-tag :options="sys_notice_status" :value="scope.row.status" />
          </template>
        </el-table-column>
        <el-table-column label="创建者" align="center" prop="createByName" width="100" />
        <el-table-column label="创建时间" align="center" prop="createTime" width="100">
          <template #default="scope">
            <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
          </template>
        </el-table-column>
        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
          <template #default="scope">
            <el-tooltip content="修改" placement="top">
              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:notice:edit']"></el-button>
            </el-tooltip>
            <el-tooltip content="删除" placement="top">
              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:notice:remove']"></el-button>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
    </el-card>
    <!-- æ·»åŠ æˆ–ä¿®æ”¹å…¬å‘Šå¯¹è¯æ¡† -->
    <el-dialog :title="dialog.title" v-model="dialog.visible" width="780px" append-to-body>
      <el-form ref="noticeFormRef" :model="form" :rules="rules" label-width="80px">
        <el-row>
          <el-col :span="12">
            <el-form-item label="公告标题" prop="noticeTitle">
              <el-input v-model="form.noticeTitle" placeholder="请输入公告标题" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="公告类型" prop="noticeType">
              <el-select v-model="form.noticeType" placeholder="请选择">
                <el-option v-for="dict in sys_notice_type" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="状态">
              <el-radio-group v-model="form.status">
                <el-radio v-for="dict in sys_notice_status" :key="dict.value" :label="dict.value">{{ dict.label
                }}</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="内容">
              <editor v-model="form.noticeContent" :min-height="192" />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
          <el-button @click="cancel">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup name="Notice" lang="ts">
import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice";
import { ComponentInternalInstance } from "vue";
@@ -128,121 +247,3 @@
    getList();
})
</script>
<template>
    <div class="p-2">
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
            <div class="search" v-show="showSearch">
                <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
                    <el-form-item label="公告标题" prop="noticeTitle">
                        <el-input v-model="queryParams.noticeTitle" placeholder="请输入公告标题" clearable style="width: 200px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="操作人员" prop="createByName">
                        <el-input v-model="queryParams.createByName" placeholder="请输入操作人员" clearable style="width: 200px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="类型" prop="noticeType">
                        <el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable style="width: 200px">
                            <el-option v-for="dict in sys_notice_type" :key="dict.value" :label="dict.label" :value="dict.value" />
                        </el-select>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
                    </el-form-item>
                </el-form>
            </div>
        </transition>
        <el-card shadow="never">
            <template #header>
                <el-row :gutter="10" class="mb8">
                    <el-col :span="1.5">
                        <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:notice:add']">新增</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:notice:edit']"
                            >修改</el-button
                        >
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:notice:remove']">
                            åˆ é™¤
                        </el-button>
                    </el-col>
                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
                </el-row>
            </template>
            <el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
                <el-table-column type="selection" width="55" align="center" />
                <el-table-column label="序号" align="center" prop="noticeId" width="100" v-if="false" />
                <el-table-column label="公告标题" align="center" prop="noticeTitle" :show-overflow-tooltip="true" />
                <el-table-column label="公告类型" align="center" prop="noticeType" width="100">
                    <template #default="scope">
                        <dict-tag :options="sys_notice_type" :value="scope.row.noticeType" />
                    </template>
                </el-table-column>
                <el-table-column label="状态" align="center" prop="status" width="100">
                    <template #default="scope">
                        <dict-tag :options="sys_notice_status" :value="scope.row.status" />
                    </template>
                </el-table-column>
                <el-table-column label="创建者" align="center" prop="createByName" width="100" />
                <el-table-column label="创建时间" align="center" prop="createTime" width="100">
                    <template #default="scope">
                        <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
                    </template>
                </el-table-column>
                <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
                    <template #default="scope">
                        <el-tooltip content="修改" placement="top">
                            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:notice:edit']"></el-button>
                        </el-tooltip>
                        <el-tooltip content="删除" placement="top">
                            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:notice:remove']"></el-button>
                        </el-tooltip>
                    </template>
                </el-table-column>
            </el-table>
            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
        </el-card>
        <!-- æ·»åŠ æˆ–ä¿®æ”¹å…¬å‘Šå¯¹è¯æ¡† -->
        <el-dialog :title="dialog.title" v-model="dialog.visible" width="780px" append-to-body>
            <el-form ref="noticeFormRef" :model="form" :rules="rules" label-width="80px">
                <el-row>
                    <el-col :span="12">
                        <el-form-item label="公告标题" prop="noticeTitle">
                            <el-input v-model="form.noticeTitle" placeholder="请输入公告标题" />
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="公告类型" prop="noticeType">
                            <el-select v-model="form.noticeType" placeholder="请选择">
                                <el-option v-for="dict in sys_notice_type" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24">
                        <el-form-item label="状态">
                            <el-radio-group v-model="form.status">
                                <el-radio v-for="dict in sys_notice_status" :key="dict.value" :label="dict.value">{{ dict.label
                                }}</el-radio>
                            </el-radio-group>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24">
                        <el-form-item label="内容">
                            <editor v-model="form.noticeContent" :min-height="192" />
                        </el-form-item>
                    </el-col>
                </el-row>
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
                    <el-button @click="cancel">取 æ¶ˆ</el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>
src/views/system/oss/config.vue
@@ -1,3 +1,134 @@
<template>
  <div class="p-2">
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div class="search" v-show="showSearch">
        <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
          <el-form-item label="配置key" prop="configKey">
            <el-input v-model="queryParams.configKey" placeholder="配置key" clearable style="width: 200px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="桶名称" prop="bucketName">
            <el-input v-model="queryParams.bucketName" placeholder="请输入桶名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="是否默认" prop="status">
            <el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width: 200px">
              <el-option key="0" label="是" value="0" />
              <el-option key="1" label="否" value="1" />
            </el-select>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </transition>
    <el-card shadow="never">
      <template #header>
        <el-row :gutter="10" class="mb8">
          <el-col :span="1.5">
            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:oss:add']">新增</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:oss:edit']">修改</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:oss:remove']">
              åˆ é™¤
            </el-button>
          </el-col>
          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
        </el-row>
      </template>
      <el-table v-loading="loading" :data="ossConfigList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="主建" align="center" prop="ossConfigId" v-if="columns[0].visible" />
        <el-table-column label="配置key" align="center" prop="configKey" v-if="columns[1].visible" />
        <el-table-column label="访问站点" align="center" prop="endpoint" v-if="columns[2].visible" width="200" />
        <el-table-column label="自定义域名" align="center" prop="domain" v-if="columns[3].visible" width="200" />
        <el-table-column label="桶名称" align="center" prop="bucketName" v-if="columns[4].visible" />
        <el-table-column label="前缀" align="center" prop="prefix" v-if="columns[5].visible" />
        <el-table-column label="域" align="center" prop="region" v-if="columns[6].visible" />
        <el-table-column label="桶权限类型" align="center" prop="accessPolicy" v-if="columns[7].visible">
          <template #default="scope">
            <el-tag type="warning" v-if="scope.row.accessPolicy === '0'">private</el-tag>
            <el-tag type="success" v-if="scope.row.accessPolicy === '1'">public</el-tag>
            <el-tag type="info" v-if="scope.row.accessPolicy === '2'">custom</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="是否默认" align="center" prop="status" v-if="columns[8].visible">
          <template #default="scope">
            <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
          </template>
        </el-table-column>
        <el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
          <template #default="scope">
            <el-tooltip content="修改" placement="top">
              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:oss:edit']"></el-button>
            </el-tooltip>
            <el-tooltip content="删除" placement="top">
              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:oss:remove']"></el-button>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
    </el-card>
    <!-- æ·»åŠ æˆ–ä¿®æ”¹å¯¹è±¡å­˜å‚¨é…ç½®å¯¹è¯æ¡† -->
    <el-dialog :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
      <el-form ref="ossConfigFormRef" :model="form" :rules="rules" label-width="120px">
        <el-form-item label="配置key" prop="configKey">
          <el-input v-model="form.configKey" placeholder="请输入配置key" />
        </el-form-item>
        <el-form-item label="访问站点" prop="endpoint">
          <el-input v-model="form.endpoint" placeholder="请输入访问站点" />
        </el-form-item>
        <el-form-item label="自定义域名" prop="domain">
          <el-input v-model="form.domain" placeholder="请输入自定义域名" />
        </el-form-item>
        <el-form-item label="accessKey" prop="accessKey">
          <el-input v-model="form.accessKey" placeholder="请输入accessKey" />
        </el-form-item>
        <el-form-item label="secretKey" prop="secretKey">
          <el-input v-model="form.secretKey" placeholder="请输入秘钥" show-password />
        </el-form-item>
        <el-form-item label="桶名称" prop="bucketName">
          <el-input v-model="form.bucketName" placeholder="请输入桶名称" />
        </el-form-item>
        <el-form-item label="前缀" prop="prefix">
          <el-input v-model="form.prefix" placeholder="请输入前缀" />
        </el-form-item>
        <el-form-item label="是否HTTPS">
          <el-radio-group v-model="form.isHttps">
            <el-radio v-for="dict in sys_yes_no" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="桶权限类型">
          <el-radio-group v-model="form.accessPolicy">
            <el-radio label="0">private</el-radio>
            <el-radio label="1">public</el-radio>
            <el-radio label="2">custom</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="域" prop="region">
          <el-input v-model="form.region" placeholder="请输入域" />
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button :loading="buttonLoading" type="primary" @click="submitForm">ç¡® å®š</el-button>
          <el-button @click="cancel">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup name="OssConfig" lang="ts">
import {
  listOssConfig,
@@ -214,133 +345,3 @@
  getList();
})
</script>
<template>
    <div class="p-2">
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
            <div class="search" v-show="showSearch">
                <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
                    <el-form-item label="配置key" prop="configKey">
                        <el-input v-model="queryParams.configKey" placeholder="配置key" clearable style="width: 200px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="桶名称" prop="bucketName">
                        <el-input v-model="queryParams.bucketName" placeholder="请输入桶名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="是否默认" prop="status">
                        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width: 200px">
                            <el-option key="0" label="是" value="0" />
                            <el-option key="1" label="否" value="1" />
                        </el-select>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
                        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
                    </el-form-item>
                </el-form>
            </div>
        </transition>
        <el-card shadow="never">
            <template #header>
                <el-row :gutter="10" class="mb8">
                    <el-col :span="1.5">
                        <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:oss:add']">新增</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:oss:edit']">修改</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:oss:remove']">
                            åˆ é™¤
                        </el-button>
                    </el-col>
                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
                </el-row>
            </template>
            <el-table v-loading="loading" :data="ossConfigList" @selection-change="handleSelectionChange">
                <el-table-column type="selection" width="55" align="center" />
                <el-table-column label="主建" align="center" prop="ossConfigId" v-if="columns[0].visible" />
                <el-table-column label="配置key" align="center" prop="configKey" v-if="columns[1].visible" />
                <el-table-column label="访问站点" align="center" prop="endpoint" v-if="columns[2].visible" width="200" />
                <el-table-column label="自定义域名" align="center" prop="domain" v-if="columns[3].visible" width="200" />
                <el-table-column label="桶名称" align="center" prop="bucketName" v-if="columns[4].visible" />
                <el-table-column label="前缀" align="center" prop="prefix" v-if="columns[5].visible" />
                <el-table-column label="域" align="center" prop="region" v-if="columns[6].visible" />
                <el-table-column label="桶权限类型" align="center" prop="accessPolicy" v-if="columns[7].visible">
                    <template #default="scope">
                        <el-tag type="warning" v-if="scope.row.accessPolicy === '0'">private</el-tag>
                        <el-tag type="success" v-if="scope.row.accessPolicy === '1'">public</el-tag>
                        <el-tag type="info" v-if="scope.row.accessPolicy === '2'">custom</el-tag>
                    </template>
                </el-table-column>
                <el-table-column label="是否默认" align="center" prop="status" v-if="columns[8].visible">
                    <template #default="scope">
                        <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
                    </template>
                </el-table-column>
                <el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
                    <template #default="scope">
                        <el-tooltip content="修改" placement="top">
                            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:oss:edit']"></el-button>
                        </el-tooltip>
                        <el-tooltip content="删除" placement="top">
                            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:oss:remove']"></el-button>
                        </el-tooltip>
                    </template>
                </el-table-column>
            </el-table>
            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
        </el-card>
        <!-- æ·»åŠ æˆ–ä¿®æ”¹å¯¹è±¡å­˜å‚¨é…ç½®å¯¹è¯æ¡† -->
        <el-dialog :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
            <el-form ref="ossConfigFormRef" :model="form" :rules="rules" label-width="120px">
                <el-form-item label="配置key" prop="configKey">
                    <el-input v-model="form.configKey" placeholder="请输入配置key" />
                </el-form-item>
                <el-form-item label="访问站点" prop="endpoint">
                    <el-input v-model="form.endpoint" placeholder="请输入访问站点" />
                </el-form-item>
                <el-form-item label="自定义域名" prop="domain">
                    <el-input v-model="form.domain" placeholder="请输入自定义域名" />
                </el-form-item>
                <el-form-item label="accessKey" prop="accessKey">
                    <el-input v-model="form.accessKey" placeholder="请输入accessKey" />
                </el-form-item>
                <el-form-item label="secretKey" prop="secretKey">
                    <el-input v-model="form.secretKey" placeholder="请输入秘钥" show-password />
                </el-form-item>
                <el-form-item label="桶名称" prop="bucketName">
                    <el-input v-model="form.bucketName" placeholder="请输入桶名称" />
                </el-form-item>
                <el-form-item label="前缀" prop="prefix">
                    <el-input v-model="form.prefix" placeholder="请输入前缀" />
                </el-form-item>
                <el-form-item label="是否HTTPS">
                    <el-radio-group v-model="form.isHttps">
                        <el-radio v-for="dict in sys_yes_no" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
                    </el-radio-group>
                </el-form-item>
                <el-form-item label="桶权限类型">
                    <el-radio-group v-model="form.accessPolicy">
                        <el-radio label="0">private</el-radio>
                        <el-radio label="1">public</el-radio>
                        <el-radio label="2">custom</el-radio>
                    </el-radio-group>
                </el-form-item>
                <el-form-item label="域" prop="region">
                    <el-input v-model="form.region" placeholder="请输入域" />
                </el-form-item>
                <el-form-item label="备注" prop="remark">
                    <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
                </el-form-item>
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <el-button :loading="buttonLoading" type="primary" @click="submitForm">ç¡® å®š</el-button>
                    <el-button @click="cancel">取 æ¶ˆ</el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>
src/views/system/oss/index.vue
@@ -1,3 +1,135 @@
<template>
  <div class="p-2">
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div class="search" v-show="showSearch">
        <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
          <el-form-item label="文件名" prop="fileName">
            <el-input v-model="queryParams.fileName" placeholder="请输入文件名" clearable style="width: 200px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="原名" prop="originalName">
            <el-input v-model="queryParams.originalName" placeholder="请输入原名" clearable style="width: 200px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="文件后缀" prop="fileSuffix">
            <el-input v-model="queryParams.fileSuffix" placeholder="请输入文件后缀" clearable style="width: 200px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="创建时间">
            <el-date-picker
              v-model="daterangeCreateTime"
              value-format="YYYY-MM-DD HH:mm:ss"
              type="daterange"
              range-separator="-"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
            ></el-date-picker>
          </el-form-item>
          <el-form-item label="服务商" prop="service">
            <el-input v-model="queryParams.service" placeholder="请输入服务商" clearable style="width: 200px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </transition>
    <el-card shadow="never">
      <template #header>
        <el-row :gutter="10" class="mb8">
          <el-col :span="1.5">
            <el-button type="primary" plain icon="Upload" @click="handleFile" v-hasPermi="['system:oss:upload']">上传文件</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="primary" plain icon="Upload" @click="handleImage" v-hasPermi="['system:oss:upload']">上传图片</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:oss:remove']">
              åˆ é™¤
            </el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button
              :type="previewListResource ? 'danger' : 'warning'"
              plain
              @click="handlePreviewListResource(!previewListResource)"
              v-hasPermi="['system:oss:edit']"
              >预览开关 :
              {{
                previewListResource ? "禁用" : "启用" }}</el-button
            >
          </el-col>
          <el-col :span="1.5">
            <el-button type="info" plain icon="Operation" @click="handleOssConfig" v-hasPermi="['system:oss:list']">配置管理</el-button>
          </el-col>
          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
        </el-row>
      </template>
      <el-table
        v-loading="loading"
        :data="ossList"
        @selection-change="handleSelectionChange"
        :header-cell-class-name="handleHeaderClass"
        @header-click="handleHeaderCLick"
        v-if="showTable"
      >
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="对象存储主键" align="center" prop="ossId" v-if="false" />
        <el-table-column label="文件名" align="center" prop="fileName" />
        <el-table-column label="原名" align="center" prop="originalName" />
        <el-table-column label="文件后缀" align="center" prop="fileSuffix" />
        <el-table-column label="文件展示" align="center" prop="url">
          <template #default="scope">
            <ImagePreview
              v-if="previewListResource && checkFileSuffix(scope.row.fileSuffix)"
              :width="100"
              :height="100"
              :src="scope.row.url"
              :preview-src-list="[scope.row.url]"
            />
            <span v-text="scope.row.url" v-if="!checkFileSuffix(scope.row.fileSuffix) || !previewListResource" />
          </template>
        </el-table-column>
        <el-table-column label="创建时间" align="center" prop="createTime" width="180" sortable="custom">
          <template #default="scope">
            <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
          </template>
        </el-table-column>
        <el-table-column label="上传人" align="center" prop="createByName" />
        <el-table-column label="服务商" align="center" prop="service" sortable="custom" />
        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
          <template #default="scope">
            <el-tooltip content="下载" placement="top">
              <el-button link type="primary" icon="Download" @click="handleDownload(scope.row)" v-hasPermi="['system:oss:download']"></el-button>
            </el-tooltip>
            <el-tooltip content="删除" placement="top">
              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:oss:remove']"></el-button>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
    </el-card>
    <!-- æ·»åŠ æˆ–ä¿®æ”¹OSS对象存储对话框 -->
    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
      <el-form ref="ossFormRef" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="文件名">
          <fileUpload v-model="form.file" v-if="type === 0" />
          <imageUpload v-model="form.file" v-if="type === 1" />
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button :loading="buttonLoading" type="primary" @click="submitForm">ç¡® å®š</el-button>
          <el-button @click="cancel">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup name="Oss" lang="ts">
import { listOss, delOss } from "@/api/system/oss";
import ImagePreview from "@/components/ImagePreview/index.vue";
@@ -208,135 +340,3 @@
    getList();
})
</script>
<template>
    <div class="p-2">
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
            <div class="search" v-show="showSearch">
                <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
                    <el-form-item label="文件名" prop="fileName">
                        <el-input v-model="queryParams.fileName" placeholder="请输入文件名" clearable style="width: 200px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="原名" prop="originalName">
                        <el-input v-model="queryParams.originalName" placeholder="请输入原名" clearable style="width: 200px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="文件后缀" prop="fileSuffix">
                        <el-input v-model="queryParams.fileSuffix" placeholder="请输入文件后缀" clearable style="width: 200px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="创建时间">
                        <el-date-picker
                            v-model="daterangeCreateTime"
                            value-format="YYYY-MM-DD HH:mm:ss"
                            type="daterange"
                            range-separator="-"
                            start-placeholder="开始日期"
                            end-placeholder="结束日期"
                            :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
                        ></el-date-picker>
                    </el-form-item>
                    <el-form-item label="服务商" prop="service">
                        <el-input v-model="queryParams.service" placeholder="请输入服务商" clearable style="width: 200px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
                        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
                    </el-form-item>
                </el-form>
            </div>
        </transition>
        <el-card shadow="never">
            <template #header>
                <el-row :gutter="10" class="mb8">
                    <el-col :span="1.5">
                        <el-button type="primary" plain icon="Upload" @click="handleFile" v-hasPermi="['system:oss:upload']">上传文件</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="primary" plain icon="Upload" @click="handleImage" v-hasPermi="['system:oss:upload']">上传图片</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:oss:remove']">
                            åˆ é™¤
                        </el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button
                            :type="previewListResource ? 'danger' : 'warning'"
                            plain
                            @click="handlePreviewListResource(!previewListResource)"
                            v-hasPermi="['system:oss:edit']"
                            >预览开关 :
                            {{
                                previewListResource ? "禁用" : "启用" }}</el-button
                        >
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="info" plain icon="Operation" @click="handleOssConfig" v-hasPermi="['system:oss:list']">配置管理</el-button>
                    </el-col>
                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
                </el-row>
            </template>
            <el-table
                v-loading="loading"
                :data="ossList"
                @selection-change="handleSelectionChange"
                :header-cell-class-name="handleHeaderClass"
                @header-click="handleHeaderCLick"
                v-if="showTable"
            >
                <el-table-column type="selection" width="55" align="center" />
                <el-table-column label="对象存储主键" align="center" prop="ossId" v-if="false" />
                <el-table-column label="文件名" align="center" prop="fileName" />
                <el-table-column label="原名" align="center" prop="originalName" />
                <el-table-column label="文件后缀" align="center" prop="fileSuffix" />
                <el-table-column label="文件展示" align="center" prop="url">
                    <template #default="scope">
                        <ImagePreview
                            v-if="previewListResource && checkFileSuffix(scope.row.fileSuffix)"
                            :width="100"
                            :height="100"
                            :src="scope.row.url"
                            :preview-src-list="[scope.row.url]"
                        />
                        <span v-text="scope.row.url" v-if="!checkFileSuffix(scope.row.fileSuffix) || !previewListResource" />
                    </template>
                </el-table-column>
                <el-table-column label="创建时间" align="center" prop="createTime" width="180" sortable="custom">
                    <template #default="scope">
                        <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
                    </template>
                </el-table-column>
                <el-table-column label="上传人" align="center" prop="createByName" />
                <el-table-column label="服务商" align="center" prop="service" sortable="custom" />
                <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
                    <template #default="scope">
                        <el-tooltip content="下载" placement="top">
                            <el-button link type="primary" icon="Download" @click="handleDownload(scope.row)" v-hasPermi="['system:oss:download']"></el-button>
                        </el-tooltip>
                        <el-tooltip content="删除" placement="top">
                            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:oss:remove']"></el-button>
                        </el-tooltip>
                    </template>
                </el-table-column>
            </el-table>
            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
        </el-card>
        <!-- æ·»åŠ æˆ–ä¿®æ”¹OSS对象存储对话框 -->
        <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
            <el-form ref="ossFormRef" :model="form" :rules="rules" label-width="80px">
                <el-form-item label="文件名">
                    <fileUpload v-model="form.file" v-if="type === 0" />
                    <imageUpload v-model="form.file" v-if="type === 1" />
                </el-form-item>
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <el-button :loading="buttonLoading" type="primary" @click="submitForm">ç¡® å®š</el-button>
                    <el-button @click="cancel">取 æ¶ˆ</el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>
src/views/system/post/index.vue
@@ -1,3 +1,109 @@
<template>
  <div class="p-2">
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div class="search" v-show="showSearch">
        <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="70">
          <el-form-item label="岗位编码" prop="postCode">
            <el-input v-model="queryParams.postCode" placeholder="请输入岗位编码" clearable style="width: 200px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="岗位名称" prop="postName">
            <el-input v-model="queryParams.postName" placeholder="请输入岗位名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="状态" prop="status">
            <el-select v-model="queryParams.status" placeholder="岗位状态" clearable style="width: 200px">
              <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
            </el-select>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </transition>
    <el-card shadow="never">
      <template #header>
        <el-row :gutter="10" class="mb8">
          <el-col :span="1.5">
            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:post:add']">新增</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:post:edit']">修改</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:post:remove']">
              åˆ é™¤
            </el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:post:export']">导出</el-button>
          </el-col>
          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
        </el-row>
      </template>
      <el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="岗位编号" align="center" prop="postId" v-if="false" />
        <el-table-column label="岗位编码" align="center" prop="postCode" />
        <el-table-column label="岗位名称" align="center" prop="postName" />
        <el-table-column label="岗位排序" align="center" prop="postSort" />
        <el-table-column label="状态" align="center" prop="status">
          <template #default="scope">
            <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
          </template>
        </el-table-column>
        <el-table-column label="创建时间" align="center" prop="createTime" width="180">
          <template #default="scope">
            <span>{{ parseTime(scope.row.createTime) }}</span>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
          <template #default="scope">
            <el-tooltip content="修改" placement="top">
              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:post:edit']"></el-button>
            </el-tooltip>
            <el-tooltip content="删除" placement="top">
              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:post:remove']"></el-button>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
    </el-card>
    <!-- æ·»åŠ æˆ–ä¿®æ”¹å²—ä½å¯¹è¯æ¡† -->
    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
      <el-form ref="postFormRef" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="岗位名称" prop="postName">
          <el-input v-model="form.postName" placeholder="请输入岗位名称" />
        </el-form-item>
        <el-form-item label="岗位编码" prop="postCode">
          <el-input v-model="form.postCode" placeholder="请输入编码名称" />
        </el-form-item>
        <el-form-item label="岗位顺序" prop="postSort">
          <el-input-number v-model="form.postSort" controls-position="right" :min="0" />
        </el-form-item>
        <el-form-item label="岗位状态" prop="status">
          <el-radio-group v-model="form.status">
            <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
          <el-button @click="cancel">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup name="Post" lang="ts">
import { listPost, addPost, delPost, getPost, updatePost } from "@/api/system/post";
import { PostForm, PostQuery, PostVO } from "@/api/system/post/types";
@@ -132,109 +238,3 @@
    getList();
});
</script>
<template>
    <div class="p-2">
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
            <div class="search" v-show="showSearch">
                <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="70">
                    <el-form-item label="岗位编码" prop="postCode">
                        <el-input v-model="queryParams.postCode" placeholder="请输入岗位编码" clearable style="width: 200px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="岗位名称" prop="postName">
                        <el-input v-model="queryParams.postName" placeholder="请输入岗位名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="状态" prop="status">
                        <el-select v-model="queryParams.status" placeholder="岗位状态" clearable style="width: 200px">
                            <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
                        </el-select>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
                    </el-form-item>
                </el-form>
            </div>
        </transition>
        <el-card shadow="never">
            <template #header>
                <el-row :gutter="10" class="mb8">
                    <el-col :span="1.5">
                        <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:post:add']">新增</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:post:edit']">修改</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:post:remove']">
                            åˆ é™¤
                        </el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:post:export']">导出</el-button>
                    </el-col>
                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
                </el-row>
            </template>
            <el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange">
                <el-table-column type="selection" width="55" align="center" />
                <el-table-column label="岗位编号" align="center" prop="postId" v-if="false" />
                <el-table-column label="岗位编码" align="center" prop="postCode" />
                <el-table-column label="岗位名称" align="center" prop="postName" />
                <el-table-column label="岗位排序" align="center" prop="postSort" />
                <el-table-column label="状态" align="center" prop="status">
                    <template #default="scope">
                        <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
                    </template>
                </el-table-column>
                <el-table-column label="创建时间" align="center" prop="createTime" width="180">
                    <template #default="scope">
                        <span>{{ parseTime(scope.row.createTime) }}</span>
                    </template>
                </el-table-column>
                <el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
                    <template #default="scope">
                        <el-tooltip content="修改" placement="top">
                            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:post:edit']"></el-button>
                        </el-tooltip>
                        <el-tooltip content="删除" placement="top">
                            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:post:remove']"></el-button>
                        </el-tooltip>
                    </template>
                </el-table-column>
            </el-table>
            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
        </el-card>
        <!-- æ·»åŠ æˆ–ä¿®æ”¹å²—ä½å¯¹è¯æ¡† -->
        <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
            <el-form ref="postFormRef" :model="form" :rules="rules" label-width="80px">
                <el-form-item label="岗位名称" prop="postName">
                    <el-input v-model="form.postName" placeholder="请输入岗位名称" />
                </el-form-item>
                <el-form-item label="岗位编码" prop="postCode">
                    <el-input v-model="form.postCode" placeholder="请输入编码名称" />
                </el-form-item>
                <el-form-item label="岗位顺序" prop="postSort">
                    <el-input-number v-model="form.postSort" controls-position="right" :min="0" />
                </el-form-item>
                <el-form-item label="岗位状态" prop="status">
                    <el-radio-group v-model="form.status">
                        <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
                    </el-radio-group>
                </el-form-item>
                <el-form-item label="备注" prop="remark">
                    <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
                </el-form-item>
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
                    <el-button @click="cancel">取 æ¶ˆ</el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>
src/views/system/role/authUser.vue
@@ -1,3 +1,75 @@
<template>
  <div class="p-2">
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div class="search" v-show="showSearch">
        <el-form :model="queryParams" ref="queryFormRef" :inline="true">
          <el-form-item label="用户名称" prop="userName">
            <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="手机号码" prop="phonenumber">
            <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </transition>
    <el-card shadow="never">
      <template #header>
        <el-row :gutter="10">
          <el-col :span="1.5">
            <el-button type="primary" plain icon="Plus" @click="openSelectUser" v-hasPermi="['system:role:add']">添加用户</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="danger" plain icon="CircleClose" :disabled="multiple" @click="cancelAuthUserAll" v-hasPermi="['system:role:remove']">
              æ‰¹é‡å–消授权
            </el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="warning" plain icon="Close" @click="handleClose">关闭</el-button>
          </el-col>
          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :search="true"></right-toolbar>
        </el-row>
      </template>
      <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
        <el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
        <el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
        <el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
        <el-table-column label="状态" align="center" prop="status">
          <template #default="scope">
            <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
          </template>
        </el-table-column>
        <el-table-column label="创建时间" align="center" prop="createTime" width="180">
          <template #default="scope">
            <span>{{ scope.row.createTime }}</span>
          </template>
        </el-table-column>
        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
          <template #default="scope">
            <el-tooltip content="取消授权" placement="top">
              <el-button link type="primary" icon="CircleClose" @click="cancelAuthUser(scope.row)" v-hasPermi="['system:role:remove']"> </el-button>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        v-show="total > 0"
        :total="total"
        v-model:page="queryParams.pageNum"
        v-model:limit="queryParams.pageSize"
        @pagination="handleQuery"
      />
      <select-user ref="selectRef" :roleId="queryParams.roleId" @ok="handleQuery" />
    </el-card>
  </div>
</template>
<script setup name="AuthUser" lang="ts">
import { allocatedUserList, authUserCancel, authUserCancelAll } from "@/api/system/role";
import { UserQuery } from "@/api/system/user/types";
@@ -82,77 +154,5 @@
  getList();
});
</script>
<template>
    <div class="p-2">
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
            <div class="search" v-show="showSearch">
                <el-form :model="queryParams" ref="queryFormRef" :inline="true">
                    <el-form-item label="用户名称" prop="userName">
                        <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="手机号码" prop="phonenumber">
                        <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
                    </el-form-item>
                </el-form>
            </div>
        </transition>
        <el-card shadow="never">
            <template #header>
                <el-row :gutter="10">
                    <el-col :span="1.5">
                        <el-button type="primary" plain icon="Plus" @click="openSelectUser" v-hasPermi="['system:role:add']">添加用户</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="danger" plain icon="CircleClose" :disabled="multiple" @click="cancelAuthUserAll" v-hasPermi="['system:role:remove']">
                            æ‰¹é‡å–消授权
                        </el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="warning" plain icon="Close" @click="handleClose">关闭</el-button>
                    </el-col>
                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :search="true"></right-toolbar>
                </el-row>
            </template>
            <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
                <el-table-column type="selection" width="55" align="center" />
                <el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
                <el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
                <el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
                <el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
                <el-table-column label="状态" align="center" prop="status">
                    <template #default="scope">
                        <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
                    </template>
                </el-table-column>
                <el-table-column label="创建时间" align="center" prop="createTime" width="180">
                    <template #default="scope">
                        <span>{{ scope.row.createTime }}</span>
                    </template>
                </el-table-column>
                <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
                    <template #default="scope">
                        <el-tooltip content="取消授权" placement="top">
                            <el-button link type="primary" icon="CircleClose" @click="cancelAuthUser(scope.row)" v-hasPermi="['system:role:remove']"> </el-button>
                        </el-tooltip>
                    </template>
                </el-table-column>
            </el-table>
            <pagination
                v-show="total > 0"
                :total="total"
                v-model:page="queryParams.pageNum"
                v-model:limit="queryParams.pageSize"
                @pagination="handleQuery"
            />
            <select-user ref="selectRef" :roleId="queryParams.roleId" @ok="handleQuery" />
        </el-card>
    </div>
</template>
<style lang="scss" scoped></style>
src/views/system/role/index.vue
@@ -1,3 +1,196 @@
<template>
  <div class="p-2">
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div class="search" v-show="showSearch">
        <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
          <el-form-item label="角色名称" prop="roleName">
            <el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="权限字符" prop="roleKey">
            <el-input v-model="queryParams.roleKey" placeholder="请输入权限字符" clearable style="width: 240px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="状态" prop="status">
            <el-select v-model="queryParams.status" placeholder="角色状态" clearable style="width: 240px">
              <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
            </el-select>
          </el-form-item>
          <el-form-item label="创建时间" style="width: 308px">
            <el-date-picker
              v-model="dateRange"
              value-format="YYYY-MM-DD"
              type="daterange"
              range-separator="-"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
            ></el-date-picker>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="handleQuery" icon="Search">搜索</el-button>
            <el-button @click="resetQuery" icon="Refresh">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </transition>
    <el-card shadow="never">
      <template #header>
        <el-row :gutter="10">
          <el-col :span="1.5">
            <el-button type="primary" plain @click="handleAdd()" icon="Plus" v-hasPermi="['system:role:add']">新增</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="success" plain @click="handleUpdate()" :disabled="single" icon="Edit" v-hasPermi="['system:role:edit']">修改</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="danger" plain :disabled="ids.length === 0" @click="handleDelete()" v-hasPermi="['system:role:delete']">删除</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:role:export']">导出</el-button>
          </el-col>
          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
        </el-row>
      </template>
      <el-table ref="roleTableRef" v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="角色编号" prop="roleId" width="120" v-if="false" />
        <el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
        <el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="200" />
        <el-table-column label="显示顺序" prop="roleSort" width="100" />
        <el-table-column label="状态" align="center" width="100">
          <template #default="scope">
            <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
          </template>
        </el-table-column>
        <el-table-column label="创建时间" align="center" prop="createTime">
          <template #default="scope">
            <span>{{ parseTime(scope.row.createTime) }}</span>
          </template>
        </el-table-column>
        <el-table-column fixed="right" label="操作" width="180">
          <template #default="scope">
            <el-tooltip content="修改" placement="top" v-if="scope.row.roleId !== 1">
              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
            </el-tooltip>
            <el-tooltip content="删除" placement="top" v-if="scope.row.roleId !== 1">
              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:role:remove']"></el-button>
            </el-tooltip>
            <el-tooltip content="数据权限" placement="top" v-if="scope.row.roleId !== 1">
              <el-button link type="primary" icon="CircleCheck" @click="handleDataScope(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
            </el-tooltip>
            <el-tooltip content="分配用户" placement="top" v-if="scope.row.roleId !== 1">
              <el-button link type="primary" icon="User" @click="handleAuthUser(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        v-if="total > 0"
        v-model:total="total"
        v-model:page="queryParams.pageNum"
        v-model:limit="queryParams.pageSize"
        @pagination="handleQuery"
      />
    </el-card>
    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
      <el-form ref="roleFormRef" :model="form" :rules="rules" label-width="100px">
        <el-form-item label="角色名称" prop="roleName">
          <el-input v-model="form.roleName" placeholder="请输入角色名称" />
        </el-form-item>
        <el-form-item prop="roleKey">
          <template #label>
            <span>
              <el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)" placement="top">
                <el-icon><question-filled /></el-icon>
              </el-tooltip>
              æƒé™å­—符
            </span>
          </template>
          <el-input v-model="form.roleKey" placeholder="请输入权限字符" />
        </el-form-item>
        <el-form-item label="角色顺序" prop="roleSort">
          <el-input-number v-model="form.roleSort" controls-position="right" :min="0" />
        </el-form-item>
        <el-form-item label="状态">
          <el-radio-group v-model="form.status">
            <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{
                dict.label
            }}</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="菜单权限">
          <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
          <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
          <el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
          <el-tree
            class="tree-border"
            :data="menuOptions"
            show-checkbox
            ref="menuRef"
            node-key="id"
            :check-strictly="!form.menuCheckStrictly"
            empty-text="加载中,请稍候"
            :props="{ label: 'label', children: 'children' }"
          ></el-tree>
        </el-form-item>
        <el-form-item label="备注">
          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
          <el-button @click="cancel">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
    <!-- åˆ†é…è§’色数据权限对话框 -->
    <el-dialog :title="dialog.title" v-model="openDataScope" width="500px" append-to-body>
      <el-form :model="form" label-width="80px" ref="dataScopeRef">
        <el-form-item label="角色名称">
          <el-input v-model="form.roleName" :disabled="true" />
        </el-form-item>
        <el-form-item label="权限字符">
          <el-input v-model="form.roleKey" :disabled="true" />
        </el-form-item>
        <el-form-item label="权限范围">
          <el-select v-model="form.dataScope" @change="dataScopeSelectChange">
            <el-option v-for="item in dataScopeOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="数据权限" v-show="form.dataScope === 2">
          <el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
          <el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
          <el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
          <el-tree
            class="tree-border"
            :data="deptOptions"
            show-checkbox
            default-expand-all
            ref="deptRef"
            node-key="id"
            :check-strictly="!form.deptCheckStrictly"
            empty-text="加载中,请稍候"
            :props="{ label: 'label', children: 'children' }"
          ></el-tree>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitDataScope">ç¡® å®š</el-button>
          <el-button @click="cancelDataScope">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup name="Role" lang="ts">
import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updateRole, deptTreeSelect } from "@/api/system/role";
import { roleMenuTreeselect, treeselect as menuTreeselect } from '@/api/system/menu/index';
@@ -313,196 +506,3 @@
  getList();
});
</script>
<template>
    <div class="p-2">
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
            <div class="search" v-show="showSearch">
                <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
                    <el-form-item label="角色名称" prop="roleName">
                        <el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="权限字符" prop="roleKey">
                        <el-input v-model="queryParams.roleKey" placeholder="请输入权限字符" clearable style="width: 240px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="状态" prop="status">
                        <el-select v-model="queryParams.status" placeholder="角色状态" clearable style="width: 240px">
                            <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
                        </el-select>
                    </el-form-item>
                    <el-form-item label="创建时间" style="width: 308px">
                        <el-date-picker
                            v-model="dateRange"
                            value-format="YYYY-MM-DD"
                            type="daterange"
                            range-separator="-"
                            start-placeholder="开始日期"
                            end-placeholder="结束日期"
                            :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
                        ></el-date-picker>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" @click="handleQuery" icon="Search">搜索</el-button>
                        <el-button @click="resetQuery" icon="Refresh">重置</el-button>
                    </el-form-item>
                </el-form>
            </div>
        </transition>
        <el-card shadow="never">
            <template #header>
                <el-row :gutter="10">
                    <el-col :span="1.5">
                        <el-button type="primary" plain @click="handleAdd()" icon="Plus" v-hasPermi="['system:role:add']">新增</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="success" plain @click="handleUpdate()" :disabled="single" icon="Edit" v-hasPermi="['system:role:edit']">修改</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="danger" plain :disabled="ids.length === 0" @click="handleDelete()" v-hasPermi="['system:role:delete']">删除</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:role:export']">导出</el-button>
                    </el-col>
                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
                </el-row>
            </template>
            <el-table ref="roleTableRef" v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
                <el-table-column type="selection" width="55" align="center" />
                <el-table-column label="角色编号" prop="roleId" width="120" v-if="false" />
                <el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
                <el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="200" />
                <el-table-column label="显示顺序" prop="roleSort" width="100" />
                <el-table-column label="状态" align="center" width="100">
                    <template #default="scope">
                        <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
                    </template>
                </el-table-column>
                <el-table-column label="创建时间" align="center" prop="createTime">
                    <template #default="scope">
                        <span>{{ parseTime(scope.row.createTime) }}</span>
                    </template>
                </el-table-column>
                <el-table-column fixed="right" label="操作" width="180">
                    <template #default="scope">
                        <el-tooltip content="修改" placement="top" v-if="scope.row.roleId !== 1">
                            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
                        </el-tooltip>
                        <el-tooltip content="删除" placement="top" v-if="scope.row.roleId !== 1">
                            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:role:remove']"></el-button>
                        </el-tooltip>
                        <el-tooltip content="数据权限" placement="top" v-if="scope.row.roleId !== 1">
                            <el-button link type="primary" icon="CircleCheck" @click="handleDataScope(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
                        </el-tooltip>
                        <el-tooltip content="分配用户" placement="top" v-if="scope.row.roleId !== 1">
                            <el-button link type="primary" icon="User" @click="handleAuthUser(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
                        </el-tooltip>
                    </template>
                </el-table-column>
            </el-table>
            <pagination
                v-if="total > 0"
                v-model:total="total"
                v-model:page="queryParams.pageNum"
                v-model:limit="queryParams.pageSize"
                @pagination="handleQuery"
            />
        </el-card>
        <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
            <el-form ref="roleFormRef" :model="form" :rules="rules" label-width="100px">
                <el-form-item label="角色名称" prop="roleName">
                    <el-input v-model="form.roleName" placeholder="请输入角色名称" />
                </el-form-item>
                <el-form-item prop="roleKey">
                    <template #label>
                        <span>
                            <el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)" placement="top">
                                <el-icon><question-filled /></el-icon>
                            </el-tooltip>
                            æƒé™å­—符
                        </span>
                    </template>
                    <el-input v-model="form.roleKey" placeholder="请输入权限字符" />
                </el-form-item>
                <el-form-item label="角色顺序" prop="roleSort">
                    <el-input-number v-model="form.roleSort" controls-position="right" :min="0" />
                </el-form-item>
                <el-form-item label="状态">
                    <el-radio-group v-model="form.status">
                        <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{
                dict.label
                        }}</el-radio>
                    </el-radio-group>
                </el-form-item>
                <el-form-item label="菜单权限">
                    <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
                    <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
                    <el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
                    <el-tree
                        class="tree-border"
                        :data="menuOptions"
                        show-checkbox
                        ref="menuRef"
                        node-key="id"
                        :check-strictly="!form.menuCheckStrictly"
                        empty-text="加载中,请稍候"
                        :props="{ label: 'label', children: 'children' }"
                    ></el-tree>
                </el-form-item>
                <el-form-item label="备注">
                    <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
                </el-form-item>
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
                    <el-button @click="cancel">取 æ¶ˆ</el-button>
                </div>
            </template>
        </el-dialog>
        <!-- åˆ†é…è§’色数据权限对话框 -->
        <el-dialog :title="dialog.title" v-model="openDataScope" width="500px" append-to-body>
            <el-form :model="form" label-width="80px" ref="dataScopeRef">
                <el-form-item label="角色名称">
                    <el-input v-model="form.roleName" :disabled="true" />
                </el-form-item>
                <el-form-item label="权限字符">
                    <el-input v-model="form.roleKey" :disabled="true" />
                </el-form-item>
                <el-form-item label="权限范围">
                    <el-select v-model="form.dataScope" @change="dataScopeSelectChange">
                        <el-option v-for="item in dataScopeOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
                    </el-select>
                </el-form-item>
                <el-form-item label="数据权限" v-show="form.dataScope === 2">
                    <el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
                    <el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
                    <el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
                    <el-tree
                        class="tree-border"
                        :data="deptOptions"
                        show-checkbox
                        default-expand-all
                        ref="deptRef"
                        node-key="id"
                        :check-strictly="!form.deptCheckStrictly"
                        empty-text="加载中,请稍候"
                        :props="{ label: 'label', children: 'children' }"
                    ></el-tree>
                </el-form-item>
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <el-button type="primary" @click="submitDataScope">ç¡® å®š</el-button>
                    <el-button @click="cancelDataScope">取 æ¶ˆ</el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>
src/views/system/role/selectUser.vue
@@ -1,3 +1,48 @@
<template>
  <el-row>
    <el-dialog title="选择用户" v-model="visible" width="800px" top="5vh" append-to-body>
      <el-form :model="queryParams" ref="queryFormRef" :inline="true">
        <el-form-item label="用户名称" prop="userName">
          <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
        </el-form-item>
        <el-form-item label="手机号码" prop="phonenumber">
          <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable @keyup.enter="handleQuery" />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
          <el-button icon="Refresh" @click="resetQuery">重置</el-button>
        </el-form-item>
      </el-form>
      <el-row>
        <el-table @row-click="clickRow" ref="tableRef" :data="userList" @selection-change="handleSelectionChange" height="260px">
          <el-table-column type="selection" width="55"></el-table-column>
          <el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
          <el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
          <el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
          <el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
          <el-table-column label="状态" align="center" prop="status">
            <template #default="scope">
              <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
            </template>
          </el-table-column>
          <el-table-column label="创建时间" align="center" prop="createTime" width="180">
            <template #default="scope">
              <span>{{ parseTime(scope.row.createTime) }}</span>
            </template>
          </el-table-column>
        </el-table>
        <pagination v-if="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
      </el-row>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="handleSelectUser">ç¡® å®š</el-button>
          <el-button @click="visible = false">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
  </el-row>
</template>
<script setup name="SelectUser" lang="ts">
import { authUserSelectAll, unallocatedUserList } from "@/api/system/role";
import { UserVO } from '@/api/system/user/types';
@@ -84,50 +129,5 @@
  show,
});
</script>
<template>
    <el-row>
        <el-dialog title="选择用户" v-model="visible" width="800px" top="5vh" append-to-body>
            <el-form :model="queryParams" ref="queryFormRef" :inline="true">
                <el-form-item label="用户名称" prop="userName">
                    <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
                </el-form-item>
                <el-form-item label="手机号码" prop="phonenumber">
                    <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable @keyup.enter="handleQuery" />
                </el-form-item>
                <el-form-item>
                    <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                    <el-button icon="Refresh" @click="resetQuery">重置</el-button>
                </el-form-item>
            </el-form>
            <el-row>
                <el-table @row-click="clickRow" ref="tableRef" :data="userList" @selection-change="handleSelectionChange" height="260px">
                    <el-table-column type="selection" width="55"></el-table-column>
                    <el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
                    <el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
                    <el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
                    <el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
                    <el-table-column label="状态" align="center" prop="status">
                        <template #default="scope">
                            <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
                        </template>
                    </el-table-column>
                    <el-table-column label="创建时间" align="center" prop="createTime" width="180">
                        <template #default="scope">
                            <span>{{ parseTime(scope.row.createTime) }}</span>
                        </template>
                    </el-table-column>
                </el-table>
                <pagination v-if="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
            </el-row>
            <template #footer>
                <div class="dialog-footer">
                    <el-button type="primary" @click="handleSelectUser">ç¡® å®š</el-button>
                    <el-button @click="visible = false">取 æ¶ˆ</el-button>
                </div>
            </template>
        </el-dialog>
    </el-row>
</template>
<style scoped></style>
src/views/system/tenant/index.vue
@@ -1,3 +1,143 @@
<template>
  <div class="p-2">
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div class="search" v-show="showSearch">
        <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
          <el-form-item label="租户编号" prop="tenantId">
            <el-input v-model="queryParams.tenantId" placeholder="请输入租户编号" clearable @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="联系人" prop="contactUserName">
            <el-input v-model="queryParams.contactUserName" placeholder="请输入联系人" clearable @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="联系电话" prop="contactPhone">
            <el-input v-model="queryParams.contactPhone" placeholder="请输入联系电话" clearable @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="企业名称" prop="companyName">
            <el-input v-model="queryParams.companyName" placeholder="请输入企业名称" clearable @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </transition>
    <el-card shadow="never">
      <template #header>
        <el-row :gutter="10" class="mb8">
          <el-col :span="1.5">
            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:tenant:add']">新增</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:tenant:edit']"
              >修改</el-button
            >
          </el-col>
          <el-col :span="1.5">
            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:tenant:remove']">
              åˆ é™¤
            </el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:tenant:export']">导出</el-button>
          </el-col>
          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
        </el-row>
      </template>
      <el-table v-loading="loading" :data="tenantList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="id" align="center" prop="id" v-if="false" />
        <el-table-column label="租户编号" align="center" prop="tenantId" />
        <el-table-column label="联系人" align="center" prop="contactUserName" />
        <el-table-column label="联系电话" align="center" prop="contactPhone" />
        <el-table-column label="企业名称" align="center" prop="companyName" />
        <el-table-column label="社会信用代码" align="center" prop="licenseNumber" />
        <el-table-column label="过期时间" align="center" prop="expireTime" width="180">
          <template #default="scope">
            <span>{{ parseTime(scope.row.expireTime, '{y}-{m}-{d}') }}</span>
          </template>
        </el-table-column>
        <el-table-column label="租户状态" align="center" prop="status">
          <template #default="scope">
            <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
          </template>
        </el-table-column>
        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
          <template #default="scope">
            <el-tooltip content="修改" placement="top">
              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:tenant:edit']"></el-button>
            </el-tooltip>
            <el-tooltip content="同步套餐" placement="top">
              <el-button link type="primary" icon="Refresh" @click="handleSyncTenantPackage(scope.row)" v-hasPermi="['system:tenant:edit']">
              </el-button>
            </el-tooltip>
            <el-tooltip content="删除" placement="top">
              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:tenant:remove']"></el-button>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
      <pagination v-show="total>0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
    </el-card>
    <!-- æ·»åŠ æˆ–ä¿®æ”¹ç§Ÿæˆ·å¯¹è¯æ¡† -->
    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
      <el-form ref="tenantFormRef" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="企业名称" prop="companyName">
          <el-input v-model="form.companyName" placeholder="请输入企业名称" />
        </el-form-item>
        <el-form-item label="联系人" prop="contactUserName">
          <el-input v-model="form.contactUserName" placeholder="请输入联系人" />
        </el-form-item>
        <el-form-item label="联系电话" prop="contactPhone">
          <el-input v-model="form.contactPhone" placeholder="请输入联系电话" />
        </el-form-item>
        <el-form-item v-if="!form.id" label="用户名" prop="username">
          <el-input v-model="form.username" placeholder="请输入系统用户名" maxlength="30" />
        </el-form-item>
        <el-form-item v-if="!form.id" label="用户密码" prop="password">
          <el-input type="password" v-model="form.password" placeholder="请输入系统用户密码" maxlength="20" />
        </el-form-item>
        <el-form-item label="租户套餐" prop="packageId">
          <el-select v-model="form.packageId" :disabled="!!form.tenantId" placeholder="请选择租户套餐" clearable style="width: 100%">
            <el-option v-for="item in packageList" :key="item.packageId" :label="item.packageName" :value="item.packageId" />
          </el-select>
        </el-form-item>
        <el-form-item label="过期时间" prop="expireTime">
          <el-date-picker clearable v-model="form.expireTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择过期时间">
          </el-date-picker>
        </el-form-item>
        <el-form-item label="用户数量" prop="accountCount">
          <el-input v-model="form.accountCount" placeholder="请输入用户数量" />
        </el-form-item>
        <el-form-item label="绑定域名" prop="domain">
          <el-input v-model="form.domain" placeholder="请输入绑定域名" />
        </el-form-item>
        <el-form-item label="企业地址" prop="address">
          <el-input v-model="form.address" placeholder="请输入企业地址" />
        </el-form-item>
        <el-form-item label="企业代码" prop="licenseNumber">
          <el-input v-model="form.licenseNumber" placeholder="请输入统一社会信用代码" />
        </el-form-item>
        <el-form-item label="企业简介" prop="intro">
          <el-input type="textarea" v-model="form.intro" placeholder="请输入企业简介" />
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="form.remark" placeholder="请输入备注" />
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button :loading="buttonLoading" type="primary" @click="submitForm">ç¡® å®š</el-button>
          <el-button @click="cancel">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup name="Tenant" lang="ts">
import { listTenant, getTenant, delTenant, addTenant, updateTenant, changeTenantStatus, syncTenantPackage} from '@/api/system/tenant';
import { listTenantPackage } from '@/api/system/tenantPackage';
@@ -212,143 +352,3 @@
  getList();
})
</script>
<template>
    <div class="p-2">
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
            <div class="search" v-show="showSearch">
                <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
                    <el-form-item label="租户编号" prop="tenantId">
                        <el-input v-model="queryParams.tenantId" placeholder="请输入租户编号" clearable @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="联系人" prop="contactUserName">
                        <el-input v-model="queryParams.contactUserName" placeholder="请输入联系人" clearable @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="联系电话" prop="contactPhone">
                        <el-input v-model="queryParams.contactPhone" placeholder="请输入联系电话" clearable @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="企业名称" prop="companyName">
                        <el-input v-model="queryParams.companyName" placeholder="请输入企业名称" clearable @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
                    </el-form-item>
                </el-form>
            </div>
        </transition>
        <el-card shadow="never">
            <template #header>
                <el-row :gutter="10" class="mb8">
                    <el-col :span="1.5">
                        <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:tenant:add']">新增</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:tenant:edit']"
                            >修改</el-button
                        >
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:tenant:remove']">
                            åˆ é™¤
                        </el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:tenant:export']">导出</el-button>
                    </el-col>
                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
                </el-row>
            </template>
            <el-table v-loading="loading" :data="tenantList" @selection-change="handleSelectionChange">
                <el-table-column type="selection" width="55" align="center" />
                <el-table-column label="id" align="center" prop="id" v-if="false" />
                <el-table-column label="租户编号" align="center" prop="tenantId" />
                <el-table-column label="联系人" align="center" prop="contactUserName" />
                <el-table-column label="联系电话" align="center" prop="contactPhone" />
                <el-table-column label="企业名称" align="center" prop="companyName" />
                <el-table-column label="社会信用代码" align="center" prop="licenseNumber" />
                <el-table-column label="过期时间" align="center" prop="expireTime" width="180">
                    <template #default="scope">
                        <span>{{ parseTime(scope.row.expireTime, '{y}-{m}-{d}') }}</span>
                    </template>
                </el-table-column>
                <el-table-column label="租户状态" align="center" prop="status">
                    <template #default="scope">
                        <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
                    </template>
                </el-table-column>
                <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
                    <template #default="scope">
                        <el-tooltip content="修改" placement="top">
                            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:tenant:edit']"></el-button>
                        </el-tooltip>
                        <el-tooltip content="同步套餐" placement="top">
                            <el-button link type="primary" icon="Refresh" @click="handleSyncTenantPackage(scope.row)" v-hasPermi="['system:tenant:edit']">
                            </el-button>
                        </el-tooltip>
                        <el-tooltip content="删除" placement="top">
                            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:tenant:remove']"></el-button>
                        </el-tooltip>
                    </template>
                </el-table-column>
            </el-table>
            <pagination v-show="total>0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
        </el-card>
        <!-- æ·»åŠ æˆ–ä¿®æ”¹ç§Ÿæˆ·å¯¹è¯æ¡† -->
        <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
            <el-form ref="tenantFormRef" :model="form" :rules="rules" label-width="80px">
                <el-form-item label="企业名称" prop="companyName">
                    <el-input v-model="form.companyName" placeholder="请输入企业名称" />
                </el-form-item>
                <el-form-item label="联系人" prop="contactUserName">
                    <el-input v-model="form.contactUserName" placeholder="请输入联系人" />
                </el-form-item>
                <el-form-item label="联系电话" prop="contactPhone">
                    <el-input v-model="form.contactPhone" placeholder="请输入联系电话" />
                </el-form-item>
                <el-form-item v-if="!form.id" label="用户名" prop="username">
                    <el-input v-model="form.username" placeholder="请输入系统用户名" maxlength="30" />
                </el-form-item>
                <el-form-item v-if="!form.id" label="用户密码" prop="password">
                    <el-input type="password" v-model="form.password" placeholder="请输入系统用户密码" maxlength="20" />
                </el-form-item>
                <el-form-item label="租户套餐" prop="packageId">
                    <el-select v-model="form.packageId" :disabled="!!form.tenantId" placeholder="请选择租户套餐" clearable style="width: 100%">
                        <el-option v-for="item in packageList" :key="item.packageId" :label="item.packageName" :value="item.packageId" />
                    </el-select>
                </el-form-item>
                <el-form-item label="过期时间" prop="expireTime">
                    <el-date-picker clearable v-model="form.expireTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择过期时间">
                    </el-date-picker>
                </el-form-item>
                <el-form-item label="用户数量" prop="accountCount">
                    <el-input v-model="form.accountCount" placeholder="请输入用户数量" />
                </el-form-item>
                <el-form-item label="绑定域名" prop="domain">
                    <el-input v-model="form.domain" placeholder="请输入绑定域名" />
                </el-form-item>
                <el-form-item label="企业地址" prop="address">
                    <el-input v-model="form.address" placeholder="请输入企业地址" />
                </el-form-item>
                <el-form-item label="企业代码" prop="licenseNumber">
                    <el-input v-model="form.licenseNumber" placeholder="请输入统一社会信用代码" />
                </el-form-item>
                <el-form-item label="企业简介" prop="intro">
                    <el-input type="textarea" v-model="form.intro" placeholder="请输入企业简介" />
                </el-form-item>
                <el-form-item label="备注" prop="remark">
                    <el-input v-model="form.remark" placeholder="请输入备注" />
                </el-form-item>
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <el-button :loading="buttonLoading" type="primary" @click="submitForm">ç¡® å®š</el-button>
                    <el-button @click="cancel">取 æ¶ˆ</el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>
src/views/system/tenantPackage/index.vue
@@ -1,3 +1,102 @@
<template>
  <div class="p-2">
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div class="search" v-show="showSearch">
        <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
          <el-form-item label="套餐名称" prop="packageName">
            <el-input v-model="queryParams.packageName" placeholder="请输入套餐名称" clearable @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </transition>
    <el-card shadow="never">
      <template #header>
        <el-row :gutter="10" class="mb8">
          <el-col :span="1.5">
            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:tenantPackage:add']">新增</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:tenantPackage:edit']"
              >修改</el-button
            >
          </el-col>
          <el-col :span="1.5">
            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:tenantPackage:remove']"
              >删除</el-button
            >
          </el-col>
          <el-col :span="1.5">
            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:tenantPackage:export']">导出</el-button>
          </el-col>
          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
        </el-row>
      </template>
      <el-table v-loading="loading" :data="tenantPackageList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="租户套餐id" align="center" prop="packageId" v-if="false" />
        <el-table-column label="套餐名称" align="center" prop="packageName" />
        <el-table-column label="备注" align="center" prop="remark" />
        <el-table-column label="状态" align="center" prop="status">
          <template #default="scope">
            <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @click="handleStatusChange(scope.row)"></el-switch>
          </template>
        </el-table-column>
        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
          <template #default="scope">
            <el-tooltip content="修改" placement="top">
              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:tenantPackage:edit']"></el-button>
            </el-tooltip>
            <el-tooltip content="删除" placement="top">
              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:tenantPackage:remove']"> </el-button>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
      <pagination v-show="total>0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
    </el-card>
    <!-- æ·»åŠ æˆ–ä¿®æ”¹ç§Ÿæˆ·å¥—é¤å¯¹è¯æ¡† -->
    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
      <el-form ref="tenantPackageFormRef" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="套餐名称" prop="packageName">
          <el-input v-model="form.packageName" placeholder="请输入套餐名称" />
        </el-form-item>
        <el-form-item label="关联菜单">
          <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
          <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
          <el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
          <el-tree
            class="tree-border"
            :data="menuOptions"
            show-checkbox
            ref="menuTreeRef"
            node-key="id"
            :check-strictly="!form.menuCheckStrictly"
            empty-text="加载中,请稍候"
            :props="{ label: 'label', children: 'children' }"
          ></el-tree>
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="form.remark" placeholder="请输入备注" />
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button :loading="buttonLoading" type="primary" @click="submitForm">ç¡® å®š</el-button>
          <el-button @click="cancel">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup name="TenantPackage" lang="ts">
import { listTenantPackage, getTenantPackage, delTenantPackage, addTenantPackage, updateTenantPackage, changePackageStatus } from "@/api/system/tenantPackage";
import { treeselect as menuTreeselect, tenantPackageMenuTreeselect } from "@/api/system/menu";
@@ -232,102 +331,3 @@
  getList();
})
</script>
<template>
    <div class="p-2">
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
            <div class="search" v-show="showSearch">
                <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
                    <el-form-item label="套餐名称" prop="packageName">
                        <el-input v-model="queryParams.packageName" placeholder="请输入套餐名称" clearable @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
                    </el-form-item>
                </el-form>
            </div>
        </transition>
        <el-card shadow="never">
            <template #header>
                <el-row :gutter="10" class="mb8">
                    <el-col :span="1.5">
                        <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:tenantPackage:add']">新增</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:tenantPackage:edit']"
                            >修改</el-button
                        >
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:tenantPackage:remove']"
                            >删除</el-button
                        >
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:tenantPackage:export']">导出</el-button>
                    </el-col>
                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
                </el-row>
            </template>
            <el-table v-loading="loading" :data="tenantPackageList" @selection-change="handleSelectionChange">
                <el-table-column type="selection" width="55" align="center" />
                <el-table-column label="租户套餐id" align="center" prop="packageId" v-if="false" />
                <el-table-column label="套餐名称" align="center" prop="packageName" />
                <el-table-column label="备注" align="center" prop="remark" />
                <el-table-column label="状态" align="center" prop="status">
                    <template #default="scope">
                        <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @click="handleStatusChange(scope.row)"></el-switch>
                    </template>
                </el-table-column>
                <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
                    <template #default="scope">
                        <el-tooltip content="修改" placement="top">
                            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:tenantPackage:edit']"></el-button>
                        </el-tooltip>
                        <el-tooltip content="删除" placement="top">
                            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:tenantPackage:remove']"> </el-button>
                        </el-tooltip>
                    </template>
                </el-table-column>
            </el-table>
            <pagination v-show="total>0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
        </el-card>
        <!-- æ·»åŠ æˆ–ä¿®æ”¹ç§Ÿæˆ·å¥—é¤å¯¹è¯æ¡† -->
        <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
            <el-form ref="tenantPackageFormRef" :model="form" :rules="rules" label-width="80px">
                <el-form-item label="套餐名称" prop="packageName">
                    <el-input v-model="form.packageName" placeholder="请输入套餐名称" />
                </el-form-item>
                <el-form-item label="关联菜单">
                    <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
                    <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
                    <el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
                    <el-tree
                        class="tree-border"
                        :data="menuOptions"
                        show-checkbox
                        ref="menuTreeRef"
                        node-key="id"
                        :check-strictly="!form.menuCheckStrictly"
                        empty-text="加载中,请稍候"
                        :props="{ label: 'label', children: 'children' }"
                    ></el-tree>
                </el-form-item>
                <el-form-item label="备注" prop="remark">
                    <el-input v-model="form.remark" placeholder="请输入备注" />
                </el-form-item>
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <el-button :loading="buttonLoading" type="primary" @click="submitForm">ç¡® å®š</el-button>
                    <el-button @click="cancel">取 æ¶ˆ</el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>
src/views/system/user/authRole.vue
@@ -1,3 +1,59 @@
<template>
  <div class="p-2">
    <div class="panel">
      <h4 class="panel-title">基本信息</h4>
      <el-form :model="form" label-width="80px" :inline="true">
        <el-row :gutter="10">
          <el-col :span="2.5">
            <el-form-item label="用户昵称" prop="nickName">
              <el-input v-model="form.nickName" disabled />
            </el-form-item>
          </el-col>
          <el-col :span="2.5">
            <el-form-item label="登录账号" prop="userName">
              <el-input v-model="form.userName" disabled />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    </div>
    <div class="panel">
      <h4 class="panel-title">角色信息</h4>
      <div>
        <el-table
          v-loading="loading"
          :row-key="getRowKey"
          @row-click="clickRow"
          ref="tableRef"
          @selection-change="handleSelectionChange"
          :data="roles.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
        >
          <el-table-column label="序号" width="55" type="index" align="center">
            <template #default="scope">
              <span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
            </template>
          </el-table-column>
          <el-table-column type="selection" :reserve-selection="true" width="55"></el-table-column>
          <el-table-column label="角色编号" align="center" prop="roleId" />
          <el-table-column label="角色名称" align="center" prop="roleName" />
          <el-table-column label="权限字符" align="center" prop="roleKey" />
          <el-table-column label="创建时间" align="center" prop="createTime" width="180">
            <template #default="scope">
              <span>{{ parseTime(scope.row.createTime) }}</span>
            </template>
          </el-table-column>
        </el-table>
        <pagination v-show="total > 0" :total="total" v-model:page="pageNum" v-model:limit="pageSize" />
        <div style="text-align: center;margin-left:-120px;margin-top:30px;">
          <el-button type="primary" @click="submitForm()">提交</el-button>
          <el-button @click="close()">返回</el-button>
        </div>
        <div></div>
      </div>
    </div>
  </div>
</template>
<script setup name="AuthRole" lang="ts">
import { RoleVO } from '@/api/system/role/types';
import { getAuthRole, updateAuthRole } from '@/api/system/user';
@@ -69,59 +125,3 @@
  getList();
})
</script>
<template>
    <div class="p-2">
        <div class="panel">
            <h4 class="panel-title">基本信息</h4>
            <el-form :model="form" label-width="80px" :inline="true">
                <el-row :gutter="10">
                    <el-col :span="2.5">
                        <el-form-item label="用户昵称" prop="nickName">
                            <el-input v-model="form.nickName" disabled />
                        </el-form-item>
                    </el-col>
                    <el-col :span="2.5">
                        <el-form-item label="登录账号" prop="userName">
                            <el-input v-model="form.userName" disabled />
                        </el-form-item>
                    </el-col>
                </el-row>
            </el-form>
        </div>
        <div class="panel">
            <h4 class="panel-title">角色信息</h4>
            <div>
                <el-table
                    v-loading="loading"
                    :row-key="getRowKey"
                    @row-click="clickRow"
                    ref="tableRef"
                    @selection-change="handleSelectionChange"
                    :data="roles.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
                >
                    <el-table-column label="序号" width="55" type="index" align="center">
                        <template #default="scope">
                            <span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
                        </template>
                    </el-table-column>
                    <el-table-column type="selection" :reserve-selection="true" width="55"></el-table-column>
                    <el-table-column label="角色编号" align="center" prop="roleId" />
                    <el-table-column label="角色名称" align="center" prop="roleName" />
                    <el-table-column label="权限字符" align="center" prop="roleKey" />
                    <el-table-column label="创建时间" align="center" prop="createTime" width="180">
                        <template #default="scope">
                            <span>{{ parseTime(scope.row.createTime) }}</span>
                        </template>
                    </el-table-column>
                </el-table>
                <pagination v-show="total > 0" :total="total" v-model:page="pageNum" v-model:limit="pageSize" />
                <div style="text-align: center;margin-left:-120px;margin-top:30px;">
                    <el-button type="primary" @click="submitForm()">提交</el-button>
                    <el-button @click="close()">返回</el-button>
                </div>
                <div></div>
            </div>
        </div>
    </div>
</template>
src/views/system/user/index.vue
@@ -1,3 +1,290 @@
<template>
  <div class="p-2">
    <el-row :gutter="20">
      <!-- éƒ¨é—¨æ ‘ -->
      <el-col :lg="4" :xs="24" style="">
        <el-card shadow="never">
          <el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
          <el-tree
            class="mt-2"
            ref="deptTreeRef"
            :data="deptOptions"
            :props="{ label: 'label', children: 'children' }"
            :expand-on-click-node="false"
            :filter-node-method="filterNode"
            highlight-current
            default-expand-all
            @node-click="handleNodeClick"
          ></el-tree>
        </el-card>
      </el-col>
      <el-col :lg="20" :xs="24">
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
          <div class="search" v-show="showSearch">
            <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
              <el-form-item label="用户名称" prop="userName">
                <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
              </el-form-item>
              <el-form-item label="手机号码" prop="phonenumber">
                <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter="handleQuery" />
              </el-form-item>
              <el-form-item label="状态" prop="status">
                <el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 240px">
                  <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
                </el-select>
              </el-form-item>
              <el-form-item label="创建时间" style="width: 308px;">
                <el-date-picker
                  v-model="dateRange"
                  value-format="YYYY-MM-DD"
                  type="daterange"
                  range-separator="-"
                  start-placeholder="开始日期"
                  end-placeholder="结束日期"
                ></el-date-picker>
              </el-form-item>
              <el-form-item>
                <el-button type="primary" @click="handleQuery" icon="Search">搜索</el-button>
                <el-button @click="resetQuery" icon="Refresh">重置</el-button>
              </el-form-item>
            </el-form>
          </div>
        </transition>
        <el-card shadow="never">
          <template #header>
            <el-row :gutter="10">
              <el-col :span="1.5">
                <el-button type="primary" plain @click="handleAdd()" v-has-permi="['sys:user:add']" icon="Plus">新增</el-button>
              </el-col>
              <el-col :span="1.5">
                <el-button type="success" plain @click="handleUpdate()" :disabled="single" v-has-permi="['sys:user:add']" icon="Edit">修改</el-button>
              </el-col>
              <el-col :span="1.5">
                <el-button type="danger" plain @click="handleDelete()" :disabled="multiple" v-has-permi="['sys:user:delete']" icon="Delete">
                  åˆ é™¤
                </el-button>
              </el-col>
              <el-col :span="1.5">
                <el-dropdown class="mt-[1px]">
                  <el-button plain type="info">
                    æ›´å¤š
                    <el-icon class="el-icon--right"><arrow-down /></el-icon
                  ></el-button>
                  <template #dropdown>
                    <el-dropdown-menu>
                      <el-dropdown-item @click="importTemplate" icon="Download">下载模板</el-dropdown-item>
                      <el-dropdown-item @click="handleImport" icon="Top"> å¯¼å…¥æ•°æ®</el-dropdown-item>
                      <el-dropdown-item @click="handleExport" icon="Download"> å¯¼å‡ºæ•°æ®</el-dropdown-item>
                    </el-dropdown-menu>
                  </template>
                </el-dropdown>
              </el-col>
              <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns" :search="true"></right-toolbar>
            </el-row>
          </template>
          <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
            <el-table-column type="selection" width="50" align="center" />
            <el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
            <el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
            <el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
            <el-table-column
              label="部门"
              align="center"
              key="deptName"
              prop="dept.deptName"
              v-if="columns[3].visible"
              :show-overflow-tooltip="true"
            />
            <el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
            <el-table-column label="状态" align="center" key="status" v-if="columns[5].visible">
              <template #default="scope">
                <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
              </template>
            </el-table-column>
            <el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
              <template #default="scope">
                <span>{{ scope.row.createTime }}</span>
              </template>
            </el-table-column>
            <el-table-column label="操作" fixed="right" width="180" class-name="small-padding fixed-width">
              <template #default="scope">
                <el-tooltip content="修改" placement="top" v-if="scope.row.userId !== 1">
                  <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:user:edit']"></el-button>
                </el-tooltip>
                <el-tooltip content="删除" placement="top" v-if="scope.row.userId !== 1">
                  <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:user:remove']"></el-button>
                </el-tooltip>
                <el-tooltip content="重置密码" placement="top" v-if="scope.row.userId !== 1">
                  <el-button link type="primary" icon="Key" @click="handleResetPwd(scope.row)" v-hasPermi="['system:user:resetPwd']"></el-button>
                </el-tooltip>
                <el-tooltip content="分配角色" placement="top" v-if="scope.row.userId !== 1">
                  <el-button link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)" v-hasPermi="['system:user:edit']"></el-button>
                </el-tooltip>
              </template>
            </el-table-column>
          </el-table>
          <pagination
            v-show="total > 0"
            :total="total"
            v-model:page="queryParams.pageNum"
            v-model:limit="queryParams.pageSize"
            @pagination="handleQuery"
          />
        </el-card>
      </el-col>
    </el-row>
    <!-- æ·»åŠ æˆ–ä¿®æ”¹ç”¨æˆ·é…ç½®å¯¹è¯æ¡† -->
    <el-dialog :title="dialog.title" v-model="dialog.visible" width="600px" append-to-body @close="closeDialog">
      <el-form :model="form" :rules="rules" ref="userFormRef" label-width="80px">
        <el-row>
          <el-col :span="12">
            <el-form-item label="用户昵称" prop="nickName">
              <el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="归属部门" prop="deptId">
              <el-tree-select
                v-model="form.deptId"
                :data="deptOptions"
                :props="{ value: 'id', label: 'label', children: 'children' }"
                value-key="id"
                placeholder="请选择归属部门"
                check-strictly
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="手机号码" prop="phonenumber">
              <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="邮箱" prop="email">
              <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
              <el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
              <el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="用户性别">
              <el-select v-model="form.sex" placeholder="请选择">
                <el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="状态">
              <el-radio-group v-model="form.status">
                <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{
                    dict.label }}</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="岗位">
              <el-select v-model="form.postIds" multiple placeholder="请选择">
                <el-option
                  v-for="item in postOptions"
                  :key="item.postId"
                  :label="item.postName"
                  :value="item.postId"
                  :disabled="item.status == '1'"
                ></el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="角色">
              <el-select v-model="form.roleIds" multiple placeholder="请选择">
                <el-option
                  v-for="item in roleOptions"
                  :key="item.roleId"
                  :label="item.roleName"
                  :value="item.roleId"
                  :disabled="item.status == '1'"
                ></el-option>
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="备注">
              <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
          <el-button @click="cancel()">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
    <!-- ç”¨æˆ·å¯¼å…¥å¯¹è¯æ¡† -->
    <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
      <el-upload
        ref="uploadRef"
        :limit="1"
        accept=".xlsx, .xls"
        :headers="upload.headers"
        :action="upload.url + '?updateSupport=' + upload.updateSupport"
        :disabled="upload.isUploading"
        :on-progress="handleFileUploadProgress"
        :on-success="handleFileSuccess"
        :auto-upload="false"
        drag
      >
        <el-icon class="el-icon--upload">
          <i-ep-upload-filled />
        </el-icon>
        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
        <template #tip>
          <div class="text-center el-upload__tip">
            <div class="el-upload__tip"><el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据</div>
            <span>仅允许导入xls、xlsx格式文件。</span>
            <el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;" @click="importTemplate">下载模板</el-link>
          </div>
        </template>
      </el-upload>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitFileForm">ç¡® å®š</el-button>
          <el-button @click="upload.open = false">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup name="User" lang="ts">
import {
  changeUserStatus,
@@ -331,292 +618,5 @@
  getList() // åˆå§‹åŒ–列表数据
});
</script>
<template>
    <div class="p-2">
        <el-row :gutter="20">
            <!-- éƒ¨é—¨æ ‘ -->
            <el-col :lg="4" :xs="24" style="">
                <el-card shadow="never">
                    <el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
                    <el-tree
                        class="mt-2"
                        ref="deptTreeRef"
                        :data="deptOptions"
                        :props="{ label: 'label', children: 'children' }"
                        :expand-on-click-node="false"
                        :filter-node-method="filterNode"
                        highlight-current
                        default-expand-all
                        @node-click="handleNodeClick"
                    ></el-tree>
                </el-card>
            </el-col>
            <el-col :lg="20" :xs="24">
                <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
                    <div class="search" v-show="showSearch">
                        <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
                            <el-form-item label="用户名称" prop="userName">
                                <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
                            </el-form-item>
                            <el-form-item label="手机号码" prop="phonenumber">
                                <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter="handleQuery" />
                            </el-form-item>
                            <el-form-item label="状态" prop="status">
                                <el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 240px">
                                    <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
                                </el-select>
                            </el-form-item>
                            <el-form-item label="创建时间" style="width: 308px;">
                                <el-date-picker
                                    v-model="dateRange"
                                    value-format="YYYY-MM-DD"
                                    type="daterange"
                                    range-separator="-"
                                    start-placeholder="开始日期"
                                    end-placeholder="结束日期"
                                ></el-date-picker>
                            </el-form-item>
                            <el-form-item>
                                <el-button type="primary" @click="handleQuery" icon="Search">搜索</el-button>
                                <el-button @click="resetQuery" icon="Refresh">重置</el-button>
                            </el-form-item>
                        </el-form>
                    </div>
                </transition>
                <el-card shadow="never">
                    <template #header>
                        <el-row :gutter="10">
                            <el-col :span="1.5">
                                <el-button type="primary" plain @click="handleAdd()" v-has-permi="['sys:user:add']" icon="Plus">新增</el-button>
                            </el-col>
                            <el-col :span="1.5">
                                <el-button type="success" plain @click="handleUpdate()" :disabled="single" v-has-permi="['sys:user:add']" icon="Edit">修改</el-button>
                            </el-col>
                            <el-col :span="1.5">
                                <el-button type="danger" plain @click="handleDelete()" :disabled="multiple" v-has-permi="['sys:user:delete']" icon="Delete">
                                    åˆ é™¤
                                </el-button>
                            </el-col>
                            <el-col :span="1.5">
                                <el-dropdown class="mt-[1px]">
                                    <el-button plain type="info">
                                        æ›´å¤š
                                        <el-icon class="el-icon--right"><arrow-down /></el-icon
                                    ></el-button>
                                    <template #dropdown>
                                        <el-dropdown-menu>
                                            <el-dropdown-item @click="importTemplate" icon="Download">下载模板</el-dropdown-item>
                                            <el-dropdown-item @click="handleImport" icon="Top"> å¯¼å…¥æ•°æ®</el-dropdown-item>
                                            <el-dropdown-item @click="handleExport" icon="Download"> å¯¼å‡ºæ•°æ®</el-dropdown-item>
                                        </el-dropdown-menu>
                                    </template>
                                </el-dropdown>
                            </el-col>
                            <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns" :search="true"></right-toolbar>
                        </el-row>
                    </template>
                    <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
                        <el-table-column type="selection" width="50" align="center" />
                        <el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
                        <el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
                        <el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
                        <el-table-column
                            label="部门"
                            align="center"
                            key="deptName"
                            prop="dept.deptName"
                            v-if="columns[3].visible"
                            :show-overflow-tooltip="true"
                        />
                        <el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
                        <el-table-column label="状态" align="center" key="status" v-if="columns[5].visible">
                            <template #default="scope">
                                <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
                            </template>
                        </el-table-column>
                        <el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
                            <template #default="scope">
                                <span>{{ scope.row.createTime }}</span>
                            </template>
                        </el-table-column>
                        <el-table-column label="操作" fixed="right" width="180" class-name="small-padding fixed-width">
                            <template #default="scope">
                                <el-tooltip content="修改" placement="top" v-if="scope.row.userId !== 1">
                                    <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:user:edit']"></el-button>
                                </el-tooltip>
                                <el-tooltip content="删除" placement="top" v-if="scope.row.userId !== 1">
                                    <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:user:remove']"></el-button>
                                </el-tooltip>
                                <el-tooltip content="重置密码" placement="top" v-if="scope.row.userId !== 1">
                                    <el-button link type="primary" icon="Key" @click="handleResetPwd(scope.row)" v-hasPermi="['system:user:resetPwd']"></el-button>
                                </el-tooltip>
                                <el-tooltip content="分配角色" placement="top" v-if="scope.row.userId !== 1">
                                    <el-button link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)" v-hasPermi="['system:user:edit']"></el-button>
                                </el-tooltip>
                            </template>
                        </el-table-column>
                    </el-table>
                    <pagination
                        v-show="total > 0"
                        :total="total"
                        v-model:page="queryParams.pageNum"
                        v-model:limit="queryParams.pageSize"
                        @pagination="handleQuery"
                    />
                </el-card>
            </el-col>
        </el-row>
        <!-- æ·»åŠ æˆ–ä¿®æ”¹ç”¨æˆ·é…ç½®å¯¹è¯æ¡† -->
        <el-dialog :title="dialog.title" v-model="dialog.visible" width="600px" append-to-body @close="closeDialog">
            <el-form :model="form" :rules="rules" ref="userFormRef" label-width="80px">
                <el-row>
                    <el-col :span="12">
                        <el-form-item label="用户昵称" prop="nickName">
                            <el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" />
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="归属部门" prop="deptId">
                            <el-tree-select
                                v-model="form.deptId"
                                :data="deptOptions"
                                :props="{ value: 'id', label: 'label', children: 'children' }"
                                value-key="id"
                                placeholder="请选择归属部门"
                                check-strictly
                            />
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row>
                    <el-col :span="12">
                        <el-form-item label="手机号码" prop="phonenumber">
                            <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="邮箱" prop="email">
                            <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row>
                    <el-col :span="12">
                        <el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
                            <el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
                            <el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row>
                    <el-col :span="12">
                        <el-form-item label="用户性别">
                            <el-select v-model="form.sex" placeholder="请选择">
                                <el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="状态">
                            <el-radio-group v-model="form.status">
                                <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{
                    dict.label }}</el-radio>
                            </el-radio-group>
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row>
                    <el-col :span="12">
                        <el-form-item label="岗位">
                            <el-select v-model="form.postIds" multiple placeholder="请选择">
                                <el-option
                                    v-for="item in postOptions"
                                    :key="item.postId"
                                    :label="item.postName"
                                    :value="item.postId"
                                    :disabled="item.status == '1'"
                                ></el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="角色">
                            <el-select v-model="form.roleIds" multiple placeholder="请选择">
                                <el-option
                                    v-for="item in roleOptions"
                                    :key="item.roleId"
                                    :label="item.roleName"
                                    :value="item.roleId"
                                    :disabled="item.status == '1'"
                                ></el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row>
                    <el-col :span="24">
                        <el-form-item label="备注">
                            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
                        </el-form-item>
                    </el-col>
                </el-row>
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
                    <el-button @click="cancel()">取 æ¶ˆ</el-button>
                </div>
            </template>
        </el-dialog>
        <!-- ç”¨æˆ·å¯¼å…¥å¯¹è¯æ¡† -->
        <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
            <el-upload
                ref="uploadRef"
                :limit="1"
                accept=".xlsx, .xls"
                :headers="upload.headers"
                :action="upload.url + '?updateSupport=' + upload.updateSupport"
                :disabled="upload.isUploading"
                :on-progress="handleFileUploadProgress"
                :on-success="handleFileSuccess"
                :auto-upload="false"
                drag
            >
                <el-icon class="el-icon--upload">
                    <i-ep-upload-filled />
                </el-icon>
                <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
                <template #tip>
                    <div class="text-center el-upload__tip">
                        <div class="el-upload__tip"><el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据</div>
                        <span>仅允许导入xls、xlsx格式文件。</span>
                        <el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;" @click="importTemplate">下载模板</el-link>
                    </div>
                </template>
            </el-upload>
            <template #footer>
                <div class="dialog-footer">
                    <el-button type="primary" @click="submitFileForm">ç¡® å®š</el-button>
                    <el-button @click="upload.open = false">取 æ¶ˆ</el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>
<style lang="scss" scoped></style>
src/views/system/user/profile/index.vue
src/views/system/user/profile/resetPwd.vue
src/views/system/user/profile/userAvatar.vue
src/views/system/user/profile/userInfo.vue
src/views/tool/build/index.vue
src/views/tool/gen/basicInfoForm.vue
src/views/tool/gen/editTable.vue
@@ -1,79 +1,3 @@
<script setup name="GenEdit" lang="ts">
import { getGenTable, updateGenTable } from '@/api/tool/gen';
import { DbColumnVO, DbTableVO } from '@/api/tool/gen/types';
import { optionselect as getDictOptionselect } from '@/api/system/dict/type';
import { DictTypeVO } from '@/api/system/dict/type/types';
import basicInfoForm from './basicInfoForm.vue';
import genInfoForm from "./genInfoForm.vue";
import { ComponentInternalInstance } from "vue";
const route = useRoute();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const activeName = ref('columnInfo');
const tableHeight = ref(document.documentElement.scrollHeight - 245 + 'px');
const tables = ref<DbTableVO[]>([]);
const columns = ref<DbColumnVO[]>([]);
const dictOptions = ref<DictTypeVO[]>([]);
const info = ref<Partial<DbTableVO>>({});
const basicInfo = ref(basicInfoForm);
const genInfo = ref(genInfoForm);
/** æäº¤æŒ‰é’® */
const submitForm = () => {
  const basicForm = basicInfo.value.$refs.basicInfoForm;
  const genForm = genInfo.value.$refs.genInfoForm;
  Promise.all([basicForm, genForm].map(getFormPromise)).then(async res => {
    const validateResult = res.every(item => !!item);
    if (validateResult) {
      const genTable: any = Object.assign({}, info.value);
      genTable.columns = columns.value;
      genTable.params = {
        treeCode: info.value?.treeCode,
        treeName: info.value.treeName,
        treeParentCode: info.value.treeParentCode,
        parentMenuId: info.value.parentMenuId
            };
            console.log(genTable)
            const response = await updateGenTable(genTable);
            proxy?.$modal.msgSuccess(response.msg);
            if (response.code === 200) {
                close();
            }
    } else {
      proxy?.$modal.msgError("表单校验未通过,请重新检查提交内容");
    }
  });
}
const getFormPromise = (form: any) => {
  return new Promise(resolve => {
    form.validate((res: any) => {
      resolve(res);
    });
  });
}
const close = () => {
  const obj = { path: "/tool/gen", query: { t: Date.now(), pageNum: route.query.pageNum } };
  proxy?.$tab.closeOpenPage(obj);
}
(async () => {
  const tableId = route.params && route.params.tableId as string;
  if (tableId) {
    // èŽ·å–è¡¨è¯¦ç»†ä¿¡æ¯
        const res = await getGenTable(tableId);
        columns.value = res.data.rows;
        info.value = res.data.info;
        tables.value = res.data.tables;
    /** æŸ¥è¯¢å­—典下拉列表 */
        const response = await getDictOptionselect();
        dictOptions.value = response.data;
  }
})();
</script>
<template>
    <el-card>
        <el-tabs v-model="activeName">
@@ -187,3 +111,79 @@
        </el-form>
    </el-card>
</template>
<script setup name="GenEdit" lang="ts">
import { getGenTable, updateGenTable } from '@/api/tool/gen';
import { DbColumnVO, DbTableVO } from '@/api/tool/gen/types';
import { optionselect as getDictOptionselect } from '@/api/system/dict/type';
import { DictTypeVO } from '@/api/system/dict/type/types';
import basicInfoForm from './basicInfoForm.vue';
import genInfoForm from "./genInfoForm.vue";
import { ComponentInternalInstance } from "vue";
const route = useRoute();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const activeName = ref('columnInfo');
const tableHeight = ref(document.documentElement.scrollHeight - 245 + 'px');
const tables = ref<DbTableVO[]>([]);
const columns = ref<DbColumnVO[]>([]);
const dictOptions = ref<DictTypeVO[]>([]);
const info = ref<Partial<DbTableVO>>({});
const basicInfo = ref(basicInfoForm);
const genInfo = ref(genInfoForm);
/** æäº¤æŒ‰é’® */
const submitForm = () => {
    const basicForm = basicInfo.value.$refs.basicInfoForm;
    const genForm = genInfo.value.$refs.genInfoForm;
    Promise.all([basicForm, genForm].map(getFormPromise)).then(async res => {
        const validateResult = res.every(item => !!item);
        if (validateResult) {
            const genTable: any = Object.assign({}, info.value);
            genTable.columns = columns.value;
            genTable.params = {
                treeCode: info.value?.treeCode,
                treeName: info.value.treeName,
                treeParentCode: info.value.treeParentCode,
                parentMenuId: info.value.parentMenuId
            };
            console.log(genTable)
            const response = await updateGenTable(genTable);
            proxy?.$modal.msgSuccess(response.msg);
            if (response.code === 200) {
                close();
            }
        } else {
            proxy?.$modal.msgError("表单校验未通过,请重新检查提交内容");
        }
    });
}
const getFormPromise = (form: any) => {
    return new Promise(resolve => {
        form.validate((res: any) => {
            resolve(res);
        });
    });
}
const close = () => {
    const obj = { path: "/tool/gen", query: { t: Date.now(), pageNum: route.query.pageNum } };
    proxy?.$tab.closeOpenPage(obj);
}
(async () => {
    const tableId = route.params && route.params.tableId as string;
    if (tableId) {
        // èŽ·å–è¡¨è¯¦ç»†ä¿¡æ¯
        const res = await getGenTable(tableId);
        columns.value = res.data.rows;
        info.value = res.data.info;
        tables.value = res.data.tables;
        /** æŸ¥è¯¢å­—典下拉列表 */
        const response = await getDictOptionselect();
        dictOptions.value = response.data;
    }
})();
</script>
src/views/tool/gen/genInfoForm.vue
src/views/tool/gen/importTable.vue
@@ -1,3 +1,37 @@
<template>
  <!-- å¯¼å…¥è¡¨ -->
  <el-dialog title="导入表" v-model="visible" width="800px" top="5vh" append-to-body>
    <el-form :model="queryParams" ref="queryFormRef" :inline="true">
      <el-form-item label="表名称" prop="tableName">
        <el-input v-model="queryParams.tableName" placeholder="请输入表名称" clearable @keyup.enter="handleQuery" />
      </el-form-item>
      <el-form-item label="表描述" prop="tableComment">
        <el-input v-model="queryParams.tableComment" placeholder="请输入表描述" clearable @keyup.enter="handleQuery" />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>
    <el-row>
      <el-table @row-click="clickRow" ref="tableRef" :data="dbTableList" @selection-change="handleSelectionChange" height="260px">
        <el-table-column type="selection" width="55"></el-table-column>
        <el-table-column prop="tableName" label="表名称" :show-overflow-tooltip="true"></el-table-column>
        <el-table-column prop="tableComment" label="表描述" :show-overflow-tooltip="true"></el-table-column>
        <el-table-column prop="createTime" label="创建时间"></el-table-column>
        <el-table-column prop="updateTime" label="更新时间"></el-table-column>
      </el-table>
      <pagination v-show="total>0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
    </el-row>
    <template #footer>
      <div class="dialog-footer">
        <el-button type="primary" @click="handleImportTable">ç¡® å®š</el-button>
        <el-button @click="visible = false">取 æ¶ˆ</el-button>
      </div>
    </template>
  </el-dialog>
</template>
<script setup lang="ts">
import { listDbTable, importTable } from '@/api/tool/gen';
import { DbTableQuery, DbTableVO } from '@/api/tool/gen/types';
@@ -70,37 +104,3 @@
  show,
});
</script>
<template>
    <!-- å¯¼å…¥è¡¨ -->
    <el-dialog title="导入表" v-model="visible" width="800px" top="5vh" append-to-body>
        <el-form :model="queryParams" ref="queryFormRef" :inline="true">
            <el-form-item label="表名称" prop="tableName">
                <el-input v-model="queryParams.tableName" placeholder="请输入表名称" clearable @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="表描述" prop="tableComment">
                <el-input v-model="queryParams.tableComment" placeholder="请输入表描述" clearable @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item>
                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
            </el-form-item>
        </el-form>
        <el-row>
            <el-table @row-click="clickRow" ref="tableRef" :data="dbTableList" @selection-change="handleSelectionChange" height="260px">
                <el-table-column type="selection" width="55"></el-table-column>
                <el-table-column prop="tableName" label="表名称" :show-overflow-tooltip="true"></el-table-column>
                <el-table-column prop="tableComment" label="表描述" :show-overflow-tooltip="true"></el-table-column>
                <el-table-column prop="createTime" label="创建时间"></el-table-column>
                <el-table-column prop="updateTime" label="更新时间"></el-table-column>
            </el-table>
            <pagination v-show="total>0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
        </el-row>
        <template #footer>
            <div class="dialog-footer">
                <el-button type="primary" @click="handleImportTable">ç¡® å®š</el-button>
                <el-button @click="visible = false">取 æ¶ˆ</el-button>
            </div>
        </template>
    </el-dialog>
</template>
src/views/tool/gen/index.vue
@@ -1,3 +1,111 @@
<template>
  <div class="p-2">
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div class="search" v-show="showSearch">
        <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
          <el-form-item label="数据源" prop="dataName">
            <el-input v-model="queryParams.dataName" placeholder="请输入数据源名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="表名称" prop="tableName">
            <el-input v-model="queryParams.tableName" placeholder="请输入表名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="表描述" prop="tableComment">
            <el-input v-model="queryParams.tableComment" placeholder="请输入表描述" clearable style="width: 200px" @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="创建时间" style="width: 308px">
            <el-date-picker
              v-model="dateRange"
              value-format="YYYY-MM-DD"
              type="daterange"
              range-separator="-"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
            ></el-date-picker>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </transition>
    <el-card shadow="never">
      <template #header>
        <el-row :gutter="10" class="mb8">
          <el-col :span="1.5">
            <el-button type="primary" plain icon="Download" @click="handleGenTable()" v-hasPermi="['tool:gen:code']">生成</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="info" plain icon="Upload" @click="openImportTable" v-hasPermi="['tool:gen:import']">导入</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleEditTable()" v-hasPermi="['tool:gen:edit']">修改</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['tool:gen:remove']">
              åˆ é™¤
            </el-button>
          </el-col>
          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
        </el-row>
      </template>
      <el-table v-loading="loading" :data="tableList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" align="center" width="55"></el-table-column>
        <el-table-column label="序号" type="index" width="50" align="center">
          <template #default="scope">
            <span>{{ (queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1 }}</span>
          </template>
        </el-table-column>
        <el-table-column label="表名称" align="center" prop="tableName" :show-overflow-tooltip="true" />
        <el-table-column label="表描述" align="center" prop="tableComment" :show-overflow-tooltip="true" />
        <el-table-column label="实体" align="center" prop="className" :show-overflow-tooltip="true" />
        <el-table-column label="创建时间" align="center" prop="createTime" width="160" />
        <el-table-column label="更新时间" align="center" prop="updateTime" width="160" />
        <el-table-column label="操作" align="center" width="330" class-name="small-padding fixed-width">
          <template #default="scope">
            <el-tooltip content="预览" placement="top">
              <el-button link type="primary" icon="View" @click="handlePreview(scope.row)" v-hasPermi="['tool:gen:preview']"></el-button>
            </el-tooltip>
            <el-tooltip content="编辑" placement="top">
              <el-button link type="primary" icon="Edit" @click="handleEditTable(scope.row)" v-hasPermi="['tool:gen:edit']"></el-button>
            </el-tooltip>
            <el-tooltip content="删除" placement="top">
              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['tool:gen:remove']"></el-button>
            </el-tooltip>
            <el-tooltip content="同步" placement="top">
              <el-button link type="primary" icon="Refresh" @click="handleSynchDb(scope.row)" v-hasPermi="['tool:gen:edit']"></el-button>
            </el-tooltip>
            <el-tooltip content="生成代码" placement="top">
              <el-button link type="primary" icon="Download" @click="handleGenTable(scope.row)" v-hasPermi="['tool:gen:code']"></el-button>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
    </el-card>
    <!-- é¢„览界面 -->
    <el-dialog :title="dialog.title" v-model="dialog.visible" width="80%" top="5vh" append-to-body class="scrollbar">
      <el-tabs v-model="preview.activeName">
        <el-tab-pane
          v-for="(value, key) in preview.data"
          :label="(key as any).substring((key as any).lastIndexOf('/') + 1, (key as any).indexOf('.vm'))"
          :name="(key as any).substring((key as any).lastIndexOf('/') + 1, (key as any).indexOf('.vm'))"
          :key="value"
        >
          <el-link :underline="false" icon="DocumentCopy" v-copyText="value" v-copyText:callback="copyTextSuccess" style="float:right"
            >&nbsp;复制</el-link
          >
          <pre>{{ value }}</pre>
        </el-tab-pane>
      </el-tabs>
    </el-dialog>
    <import-table ref="importRef" @ok="handleQuery" />
  </div>
</template>
<script setup name="Gen" lang="ts">
import { listTable, previewTable, delTable, genCode, synchDb } from '@/api/tool/gen';
import { TableQuery, TableVO } from '@/api/tool/gen/types';
@@ -134,111 +242,3 @@
    getList();
})
</script>
<template>
    <div class="p-2">
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
            <div class="search" v-show="showSearch">
                <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
                    <el-form-item label="数据源" prop="dataName">
                        <el-input v-model="queryParams.dataName" placeholder="请输入数据源名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="表名称" prop="tableName">
                        <el-input v-model="queryParams.tableName" placeholder="请输入表名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="表描述" prop="tableComment">
                        <el-input v-model="queryParams.tableComment" placeholder="请输入表描述" clearable style="width: 200px" @keyup.enter="handleQuery" />
                    </el-form-item>
                    <el-form-item label="创建时间" style="width: 308px">
                        <el-date-picker
                            v-model="dateRange"
                            value-format="YYYY-MM-DD"
                            type="daterange"
                            range-separator="-"
                            start-placeholder="开始日期"
                            end-placeholder="结束日期"
                        ></el-date-picker>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
                    </el-form-item>
                </el-form>
            </div>
        </transition>
        <el-card shadow="never">
            <template #header>
                <el-row :gutter="10" class="mb8">
                    <el-col :span="1.5">
                        <el-button type="primary" plain icon="Download" @click="handleGenTable()" v-hasPermi="['tool:gen:code']">生成</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="info" plain icon="Upload" @click="openImportTable" v-hasPermi="['tool:gen:import']">导入</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleEditTable()" v-hasPermi="['tool:gen:edit']">修改</el-button>
                    </el-col>
                    <el-col :span="1.5">
                        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['tool:gen:remove']">
                            åˆ é™¤
                        </el-button>
                    </el-col>
                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
                </el-row>
            </template>
            <el-table v-loading="loading" :data="tableList" @selection-change="handleSelectionChange">
                <el-table-column type="selection" align="center" width="55"></el-table-column>
                <el-table-column label="序号" type="index" width="50" align="center">
                    <template #default="scope">
                        <span>{{ (queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1 }}</span>
                    </template>
                </el-table-column>
                <el-table-column label="表名称" align="center" prop="tableName" :show-overflow-tooltip="true" />
                <el-table-column label="表描述" align="center" prop="tableComment" :show-overflow-tooltip="true" />
                <el-table-column label="实体" align="center" prop="className" :show-overflow-tooltip="true" />
                <el-table-column label="创建时间" align="center" prop="createTime" width="160" />
                <el-table-column label="更新时间" align="center" prop="updateTime" width="160" />
                <el-table-column label="操作" align="center" width="330" class-name="small-padding fixed-width">
                    <template #default="scope">
                        <el-tooltip content="预览" placement="top">
                            <el-button link type="primary" icon="View" @click="handlePreview(scope.row)" v-hasPermi="['tool:gen:preview']"></el-button>
                        </el-tooltip>
                        <el-tooltip content="编辑" placement="top">
                            <el-button link type="primary" icon="Edit" @click="handleEditTable(scope.row)" v-hasPermi="['tool:gen:edit']"></el-button>
                        </el-tooltip>
                        <el-tooltip content="删除" placement="top">
                            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['tool:gen:remove']"></el-button>
                        </el-tooltip>
                        <el-tooltip content="同步" placement="top">
                            <el-button link type="primary" icon="Refresh" @click="handleSynchDb(scope.row)" v-hasPermi="['tool:gen:edit']"></el-button>
                        </el-tooltip>
                        <el-tooltip content="生成代码" placement="top">
                            <el-button link type="primary" icon="Download" @click="handleGenTable(scope.row)" v-hasPermi="['tool:gen:code']"></el-button>
                        </el-tooltip>
                    </template>
                </el-table-column>
            </el-table>
            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
        </el-card>
        <!-- é¢„览界面 -->
        <el-dialog :title="dialog.title" v-model="dialog.visible" width="80%" top="5vh" append-to-body class="scrollbar">
            <el-tabs v-model="preview.activeName">
                <el-tab-pane
                    v-for="(value, key) in preview.data"
                    :label="(key as any).substring((key as any).lastIndexOf('/') + 1, (key as any).indexOf('.vm'))"
                    :name="(key as any).substring((key as any).lastIndexOf('/') + 1, (key as any).indexOf('.vm'))"
                    :key="value"
                >
                    <el-link :underline="false" icon="DocumentCopy" v-copyText="value" v-copyText:callback="copyTextSuccess" style="float:right"
                        >&nbsp;复制</el-link
                    >
                    <pre>{{ value }}</pre>
                </el-tab-pane>
            </el-tabs>
        </el-dialog>
        <import-table ref="importRef" @ok="handleQuery" />
    </div>
</template>
tsconfig.json
vite.config.ts
@@ -1,6 +1,6 @@
import { UserConfig, ConfigEnv, loadEnv, defineConfig } from 'vite';
import createPlugins from './Vite/plugins';
import createPlugins from './vite/plugins';
import path from 'path';
export default defineConfig(({ mode, command }: ConfigEnv): UserConfig => {
vite/plugins/auto-import.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
import AutoImport from 'unplugin-auto-import/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
import IconsResolver from 'unplugin-icons/resolver';
export default (path: any) => {
  return AutoImport({
    // è‡ªåЍ坼入 Vue ç›¸å…³å‡½æ•°
    imports: ['vue', 'vue-router', '@vueuse/core', 'pinia'],
    eslintrc: {
      enabled: false,
      filepath: './.eslintrc-auto-import.json',
      globalsPropValue: true
    },
    resolvers: [
      // è‡ªåЍ坼入 Element Plus ç›¸å…³å‡½æ•°ElMessage, ElMessageBox... (带样式)
      ElementPlusResolver(),
      IconsResolver({
        prefix: 'Icon'
      })
    ],
    vueTemplate: true, // æ˜¯å¦åœ¨ vue æ¨¡æ¿ä¸­è‡ªåЍ坼入
    dts: path.resolve(path.resolve(__dirname, '../../src'), 'types', 'auto-imports.d.ts')
  });
};
vite/plugins/components.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
import Components from 'unplugin-vue-components/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
import IconsResolver from 'unplugin-icons/resolver';
export default (path: any) => {
  return Components({
    resolvers: [
      // è‡ªåЍ坼入 Element Plus ç»„ä»¶
      ElementPlusResolver(),
      // è‡ªåŠ¨æ³¨å†Œå›¾æ ‡ç»„ä»¶
      IconsResolver({
        enabledCollections: ['ep']
      })
    ],
    dts: path.resolve(path.resolve(__dirname, '../../src'), 'types', 'components.d.ts')
  });
};
vite/plugins/compression.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
import compression from 'vite-plugin-compression';
export default function createCompression(env: any) {
  const { VITE_BUILD_COMPRESS } = env;
  const plugin: any[] = [];
  if (VITE_BUILD_COMPRESS) {
    const compressList = VITE_BUILD_COMPRESS.split(',');
    if (compressList.includes('gzip')) {
      // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件
      plugin.push(
        compression({
          ext: '.gz',
          deleteOriginFile: false
        })
      );
    }
    if (compressList.includes('brotli')) {
      plugin.push(
        compression({
          ext: '.br',
          algorithm: 'brotliCompress',
          deleteOriginFile: false
        })
      );
    }
  }
  return plugin;
}
vite/plugins/icons.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
import Icons from 'unplugin-icons/vite';
export default () => {
  return Icons({
    // è‡ªåŠ¨å®‰è£…å›¾æ ‡åº“
    autoInstall: true
  });
};
vite/plugins/index.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
import vue from '@vitejs/plugin-vue';
import createUnoCss from './unocss';
import createAutoImport from './auto-import';
import createComponents from './components';
import createIcons from './icons';
import createSvgIconsPlugin from './svg-icon';
import createCompression from './compression';
import path from 'path';
export default (viteEnv: any, isBuild = false): [] => {
  const vitePlusgins: any = [];
  vitePlusgins.push(vue());
  vitePlusgins.push(createUnoCss());
  vitePlusgins.push(createAutoImport(path));
  vitePlusgins.push(createComponents(path));
  vitePlusgins.push(createCompression(viteEnv));
  vitePlusgins.push(createIcons());
  vitePlusgins.push(createSvgIconsPlugin(path, isBuild));
  return vitePlusgins;
};
vite/plugins/svg-icon.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,10 @@
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
export default (path: any, isBuild: boolean) => {
  return createSvgIconsPlugin({
    // æŒ‡å®šéœ€è¦ç¼“存的图标文件夹
    iconDirs: [path.resolve(path.resolve(__dirname, '../../src'), 'assets/icons/svg')],
    // æŒ‡å®šsymbolId格式
    symbolId: 'icon-[dir]-[name]',
    svgoOptions: isBuild
  });
};
vite/plugins/unocss.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
import UnoCss from 'unocss/vite';
import { presetUno, presetAttributify, presetIcons } from 'unocss';
export default () => {
  return UnoCss({
    presets: [presetUno(), presetAttributify(), presetIcons()],
    // rules: [['search', {}]],
    shortcuts: {
      'panel-title':
        'pb-[5px] font-sans leading-[1.1] font-medium text-base text-[#6379bb] border-b border-b-solid border-[var(--el-border-color-light)] mb-5 mt-0'
    }
  });
};