44 Commits

Author SHA1 Message Date
003c43140b chore(projects): 更换图标 2025-08-16 13:34:25 +08:00
6850347b89 Merge branch 'master' into tauri 2025-08-16 11:56:14 +08:00
4e625111ce chore(projects): release v1.1.3 2025-08-16 11:14:41 +08:00
AN
8524ae7666 Merge branch 'dev' of https://gitee.com/xlsea/ruoyi-plus-soybean into dev 2025-08-15 17:49:07 +08:00
AN
d6ae85d218 fix(projects): 修复新增用户未查询角色列表问题 2025-08-15 17:45:11 +08:00
89719abe34 Merge remote-tracking branch 'Soybean/main' into dev
# Conflicts:
#	README.en_US.md
#	README.md
2025-08-14 18:10:28 +08:00
8d7f91dccf chore(other): update the ESLint validation configuration to support more file types. 2025-08-13 10:10:10 +08:00
33ade53904 chore(readme): remove DartNode sponsorship badge from README files 2025-08-11 10:46:15 +08:00
AN
ab9c84d831 Merge branch 'dev' of https://gitee.com/xlsea/ruoyi-plus-soybean into dev 2025-08-11 09:42:59 +08:00
AN
7651816495 typo(projects): 去除console打印 2025-08-11 09:22:05 +08:00
4539fe01fb fix(projects): Fix the icon size in the image preview toolbar 2025-08-08 17:17:23 +08:00
AN
4e9839bd48 fix(projects): 修复用户导入功能无法更新问题 2025-08-07 20:29:56 +08:00
AN
a15b683b1d fix(projects): 修复用户新增时角色下拉包含超级管理员问题 2025-08-06 09:12:24 +08:00
9df8d2f55f Merge remote-tracking branch 'origin/dev' into dev 2025-07-31 13:55:10 +08:00
710374398a fix(projects): 修复登录过期事件监听未被重置 2025-07-31 13:52:07 +08:00
AN
52318c106d fix(projects): 修复日期搜索条件清除问题 2025-07-31 13:30:51 +08:00
9027632bef !25 fix(project): 关闭多租户功能后仍然遍历租户列表导致控制台报错的问题
Merge pull request !25 from littleghost2016/dev
2025-07-30 12:43:44 +00:00
b96c46baa9 fix(project): 关闭多租户功能后仍然遍历租户列表导致控制台报错的问题 2025-07-30 18:02:24 +08:00
AN
2d31d7dc62 fix(hooks): 修复oss下载时未转码问题 2025-07-28 17:56:12 +08:00
e538355f2b refactor(projects): 菜单列表新增禁用菜单样式 2025-07-26 12:55:19 +08:00
f89835578c fix(hooks): 非安全环境下不使用流式下载 2025-07-26 12:43:10 +08:00
4eb77eac78 !24 refactor(menu): 菜单管理中隐藏的菜单显示灰色
Merge pull request !24 from NicholasLD/N/A
2025-07-25 07:27:35 +00:00
adca2e26be refactor(menu): 菜单管理中隐藏的菜单显示灰色
Signed-off-by: NicholasLD <nicholasld505@gmail.com>
2025-07-25 03:51:09 +00:00
AN
ff576f3f42 Merge branch 'dev' of https://gitee.com/xlsea/ruoyi-plus-soybean into dev 2025-07-25 10:31:57 +08:00
AN
8fcc70d73d fix(projects): 修复一级菜单隐藏失效问题 2025-07-25 10:25:50 +08:00
fb5a59d81b Merge branch 'master' into tauri
# Conflicts:
#	package.json
#	pnpm-lock.yaml
2025-07-24 17:49:12 +08:00
48f603ed32 chore(projects): release v1.1.2 2025-07-24 17:44:45 +08:00
f4038a2dc0 fix(projects): 修复菜单结构变动后路由无法进入问题 2025-07-24 17:36:52 +08:00
923eb98a5c fix(readme): update GitHub stars and forks links for gitee 2025-07-20 01:12:19 +08:00
AN
a1336d1536 optimize(projects): 优化搜索框FormItem 2025-07-19 12:21:53 +08:00
AN
cc29ea85c1 style(projects): 搜索FormItem占比调整 2025-07-17 21:44:00 +08:00
AN
2edd4bc9f1 Merge branch 'dev' of https://gitee.com/xlsea/ruoyi-plus-soybean into dev 2025-07-17 16:02:29 +08:00
AN
e485f680c7 fix(projects): 修复登录过期不弹窗问题 2025-07-17 16:00:50 +08:00
2f8797eb98 docs(projects): 修改更新日志 2025-07-17 11:06:52 +08:00
2a3f3a4812 Merge remote-tracking branch 'Soybean/main' into dev
# Conflicts:
#	package.json
#	pnpm-lock.yaml
2025-07-17 10:57:54 +08:00
AN
2587f8cbfa fix(projects): 修复刷新时跳转至登录页问题 2025-07-15 16:09:34 +08:00
2036391c41 !17 fix: 修复 api.d.ts.vm 代码生成模板bug
Merge pull request !17 from 月祈风华/dev
2025-07-14 04:12:42 +00:00
e89b86ce56 chore(deps): update deps 2025-07-14 00:44:44 +08:00
4e8c8715ae fix: 修复 api.d.ts.vm 代码生成模板bug 2025-07-13 01:42:21 +08:00
8147f1652e chore(release): release tauri v1.1.0 2025-07-01 10:53:41 +08:00
d5be9dc08e Merge branch 'master' into tauri 2025-06-05 22:16:58 +08:00
2f9576f53d Merge branch 'master' into tauri 2025-05-21 11:02:20 +08:00
ba7395ac18 Merge branch 'dev' into tauri 2025-05-17 20:17:20 +08:00
d49728a796 feat: 新增 tauri 适配 2025-05-16 17:50:23 +08:00
91 changed files with 12628 additions and 619 deletions

13
.vscode/settings.json vendored
View File

@ -4,7 +4,18 @@
"source.organizeImports": "never"
},
"editor.formatOnSave": false,
"eslint.validate": ["html", "css", "scss", "json", "jsonc"],
"eslint.validate": [
"html",
"css",
"scss",
"json",
"jsonc",
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue"
],
"i18n-ally.displayLanguage": "zh-cn",
"i18n-ally.enabledParsers": ["ts"],
"i18n-ally.enabledFrameworks": ["vue"],

View File

@ -1,63 +1,127 @@
# Changelog
# 更新日志
## [v1.1.3](https://gitee.com/xlsea/ruoyi-plus-soybean/compare/v1.1.2...v1.1.3) (2025-08-16)
### &nbsp;&nbsp;&nbsp;🐞 Bug 修复
- **hooks**:
- 非安全环境下不使用流式下载 &nbsp;-&nbsp; by @m-xlsea [<samp>(f8983)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/f8983557)
- 修复oss下载时未转码问题 &nbsp;-&nbsp; by **AN** [<samp>(2d31d)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/2d31d7dc)
- **project**:
- 关闭多租户功能后仍然遍历租户列表导致控制台报错的问题 &nbsp;-&nbsp; by **wang_rui** [<samp>(b96c4)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/b96c46ba)
- 关闭多租户功能后仍然遍历租户列表导致控制台报错的问题 Merge pull request !25 from littleghost2016/dev &nbsp;-&nbsp; by **不寻俗** [<samp>(90276)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/9027632b)
- **projects**:
- 修复一级菜单隐藏失效问题 &nbsp;-&nbsp; by **AN** [<samp>(8fcc7)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/8fcc70d7)
- 修复日期搜索条件清除问题 &nbsp;-&nbsp; by **AN** [<samp>(52318)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/52318c10)
- 修复登录过期事件监听未被重置 &nbsp;-&nbsp; by @m-xlsea [<samp>(71037)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/71037439)
- 修复用户新增时角色下拉包含超级管理员问题 &nbsp;-&nbsp; by **AN** [<samp>(a15b6)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/a15b683b)
- 修复用户导入功能无法更新问题 &nbsp;-&nbsp; by **AN** [<samp>(4e983)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/4e9839bd)
- Fix the icon size in the image preview toolbar &nbsp;-&nbsp; by @m-xlsea [<samp>(4539f)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/4539fe01)
- 修复新增用户未查询角色列表问题 &nbsp;-&nbsp; by **AN** [<samp>(d6ae8)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/d6ae85d2)
- **readme**:
- update GitHub stars and forks links for gitee &nbsp;-&nbsp; by @soybeanjs [<samp>(923eb)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/923eb98a)
### &nbsp;&nbsp;&nbsp;💅 重构
- **menu**:
- 菜单管理中隐藏的菜单显示灰色 &nbsp;-&nbsp; by **NicholasLD** [<samp>(adca2)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/adca2e26)
- 菜单管理中隐藏的菜单显示灰色 Merge pull request !24 from NicholasLD/N/A &nbsp;-&nbsp; by **不寻俗** [<samp>(4eb77)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/4eb77eac)
- **projects**:
- 菜单列表新增禁用菜单样式 &nbsp;-&nbsp; by @m-xlsea [<samp>(e5383)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/e538355f)
### &nbsp;&nbsp;&nbsp;🏡 杂项
- **other**: update the ESLint validation configuration to support more file types. &nbsp;-&nbsp; by **Azir-11** [<samp>(8d7f9)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/8d7f91dc)
- **readme**: remove DartNode sponsorship badge from README files &nbsp;-&nbsp; by @soybeanjs [<samp>(33ade)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/33ade539)
### &nbsp;&nbsp;&nbsp;❤️ 贡献者
[![soybeanjs](https://github.com/soybeanjs.png?size=48)](https://github.com/soybeanjs)&nbsp;&nbsp;[![m-xlsea](https://github.com/m-xlsea.png?size=48)](https://github.com/m-xlsea)&nbsp;&nbsp;[![Elio-An](https://github.com/Elio-An.png?size=48)](https://gitee.com/elio-an)&nbsp;&nbsp;[![Azir-11](https://github.com/Azir-11.png?size=48)](https://github.com/Azir-11)&nbsp;&nbsp;[![Azir-11](https://github.com/NicholasLD.png?size=48)](https://github.com/NicholasLD)&nbsp;&nbsp;
[wang_rui](mailto:wrr1996@163.com)
## [v1.1.2](https://gitee.com/xlsea/ruoyi-plus-soybean/compare/v1.1.1...v1.1.2) (2025-07-24)
### &nbsp;&nbsp;&nbsp;🐞 Bug 修复
- 修复 api.d.ts.vm 代码生成模板bug &nbsp;-&nbsp; by **zygalaxy** [<samp>(4e8c8)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/4e8c8715)
- **projects**:
- 修复刷新时跳转至登录页问题 &nbsp;-&nbsp; by **AN** [<samp>(2587f)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/2587f8cb)
- 修复登录过期不弹窗问题 &nbsp;-&nbsp; by **AN** [<samp>(e485f)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/e485f680)
- 修复菜单结构变动后路由无法进入问题 &nbsp;-&nbsp; by @m-xlsea [<samp>(f4038)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/f4038a2d)
### &nbsp;&nbsp;&nbsp;🛠 优化
- **projects**: 优化搜索框FormItem &nbsp;-&nbsp; by **AN** [<samp>(a1336)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/a1336d15)
### &nbsp;&nbsp;&nbsp;🏡 杂项
- **deps**: update deps &nbsp;-&nbsp; by @soybeanjs [<samp>(e89b8)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/e89b86ce)
### &nbsp;&nbsp;&nbsp;🎨 样式
- **projects**: 搜索FormItem占比调整 &nbsp;-&nbsp; by **AN** [<samp>(cc29e)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/cc29ea85)
### &nbsp;&nbsp;&nbsp;❤️ 贡献者
[![m-xlsea](https://github.com/m-xlsea.png?size=48)](https://github.com/m-xlsea)&nbsp;&nbsp;[![Elio-An](https://github.com/Elio-An.png?size=48)](https://gitee.com/elio-an)&nbsp;&nbsp;[![soybeanjs](https://github.com/soybeanjs.png?size=48)](https://github.com/soybeanjs)&nbsp;&nbsp;
[zygalaxy](mailto:zygalaxy@qq.com)
## [v1.1.1](https://gitee.com/xlsea/ruoyi-plus-soybean/compare/v1.1.0...v1.1.1) (2025-07-11)
### &nbsp;&nbsp;&nbsp;🚀 新功能
- **hooks**:
- 重构下载方法,支持流式下载 &nbsp;-&nbsp; by @m-xlsea [<samp>(65067)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/650673e2)
- 重构下载方法,支持流式下载 &nbsp;-&nbsp; by @m-xlsea [<samp>(65067)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/650673e2)
- **projects**:
- 角色分配用户新增部门与时间查询条件 &nbsp;-&nbsp; by @m-xlsea [<samp>(ad48d)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/ad48d8e8)
- 修改操作后列表查询方式 &nbsp;-&nbsp; by @m-xlsea [<samp>(d8542)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/d85424ee)
- 角色分配用户新增部门与时间查询条件 &nbsp;-&nbsp; by @m-xlsea [<samp>(ad48d)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/ad48d8e8)
- 修改操作后列表查询方式 &nbsp;-&nbsp; by @m-xlsea [<samp>(d8542)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/d85424ee)
### &nbsp;&nbsp;&nbsp;🐞 Bug 修复
- **hooks**:
- 解决 streamsaver 访问不到 Github 资源问题 &nbsp;-&nbsp; by @m-xlsea [<samp>(566b2)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/566b2c2d)
- 解决 streamsaver 访问不到 Github 资源问题 &nbsp;-&nbsp; by @m-xlsea [<samp>(566b2)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/566b2c2d)
- **other**:
- 修复代码生成类型定义文件重复问题 &nbsp;-&nbsp; by @m-xlsea [<samp>(f7c7f)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/f7c7fc41)
- 修复代码生成类型定义文件重复问题 &nbsp;-&nbsp; by @m-xlsea [<samp>(f7c7f)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/f7c7fc41)
- **packages**:
- 修复 cleanup 会删除富文本编辑器资源问题 &nbsp;-&nbsp; by @m-xlsea [<samp>(9ca7c)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/9ca7ca8f)
- 修复 cleanup 会删除富文本编辑器资源问题 &nbsp;-&nbsp; by @m-xlsea [<samp>(9ca7c)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/9ca7ca8f)
- **projects**:
- 修复字典数据重复获取问题 &nbsp;-&nbsp; by @m-xlsea [<samp>(3628c)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/3628c249)
- 修改强退在线设备接口 &nbsp;-&nbsp; by **AN** [<samp>(dbcf8)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/dbcf8d42)
- 修复代码生成逻辑判断问题 &nbsp;-&nbsp; by **AN** [<samp>(6fc7b)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/6fc7b11b)
- 修复部门字典 sys_normal_disable 重复获取 Merge pull request !11 from 素还真/N/A &nbsp;-&nbsp; by @m-xlsea [<samp>(ad938)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/ad9386eb)
- 修复未清空文件列表,上传回显问题 &nbsp;-&nbsp; by **AN** [<samp>(229e0)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/229e0044)
- Fix i18n-ally not working when setting moduleResolution to bundler. fixed #780 &nbsp;-&nbsp; by @xiaobao0505 in https://github.com/m-xlsea/ruoyi-plus-soybean/issues/780 [<samp>(41191)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/41191d54)
- 修复角色列表操作栏展示不全问题 &nbsp;-&nbsp; by @m-xlsea [<samp>(62f2c)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/62f2c6d5)
- 修复用户导入结果信息未渲染标签问题 &nbsp;-&nbsp; by **AN** [<samp>(efc95)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/efc953c0)
- 修复角色用户分配未调用接口问题 &nbsp;-&nbsp; by @m-xlsea [<samp>(ff874)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/ff87415d)
- 修复字典数据重复获取问题 &nbsp;-&nbsp; by @m-xlsea [<samp>(3628c)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/3628c249)
- 修改强退在线设备接口 &nbsp;-&nbsp; by **AN** [<samp>(dbcf8)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/dbcf8d42)
- 修复代码生成逻辑判断问题 &nbsp;-&nbsp; by **AN** [<samp>(6fc7b)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/6fc7b11b)
- 修复部门字典 sys_normal_disable 重复获取 Merge pull request !11 from 素还真/N/A &nbsp;-&nbsp; by @m-xlsea [<samp>(ad938)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/ad9386eb)
- 修复未清空文件列表,上传回显问题 &nbsp;-&nbsp; by **AN** [<samp>(229e0)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/229e0044)
- Fix i18n-ally not working when setting moduleResolution to bundler. fixed #780 &nbsp;-&nbsp; by @xiaobao0505 in https://gitee.com/xlsea/ruoyi-plus-soybean/issues/780 [<samp>(41191)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/41191d54)
- 修复角色列表操作栏展示不全问题 &nbsp;-&nbsp; by @m-xlsea [<samp>(62f2c)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/62f2c6d5)
- 修复用户导入结果信息未渲染标签问题 &nbsp;-&nbsp; by **AN** [<samp>(efc95)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/efc953c0)
- 修复角色用户分配未调用接口问题 &nbsp;-&nbsp; by @m-xlsea [<samp>(ff874)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/ff87415d)
- **styles**:
- 修复登录页平板界面滚动问题 &nbsp;-&nbsp; by @m-xlsea [<samp>(90145)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/90145fa5)
- 修复登录页平板界面滚动问题 &nbsp;-&nbsp; by @m-xlsea [<samp>(90145)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/90145fa5)
- **utils**:
- 修复isNull和IsNotNull判断方法潜在问题 &nbsp;-&nbsp; by **AN** [<samp>(90d32)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/90d32ee2)
- 修复isNull和IsNotNull判断方法潜在问题 &nbsp;-&nbsp; by **AN** [<samp>(90d32)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/90d32ee2)
### &nbsp;&nbsp;&nbsp;💅 重构
- **projects**: 调整租户套餐菜单接口 &nbsp;-&nbsp; by **AN** [<samp>(b9999)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/b9999935)
- **projects**: 调整租户套餐菜单接口 &nbsp;-&nbsp; by **AN** [<samp>(b9999)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/b9999935)
### &nbsp;&nbsp;&nbsp;📖 文档
- **other**: 修改文档内容 &nbsp;-&nbsp; by @m-xlsea [<samp>(3ae99)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/3ae9922d)
- **projects**: 优化 cursor 规则及 mcp &nbsp;-&nbsp; by @m-xlsea [<samp>(a3199)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/a31994dc)
- **readme**: 更新 README.md 文件 &nbsp;-&nbsp; by @m-xlsea [<samp>(99675)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/99675cbc)
- **other**: 修改文档内容 &nbsp;-&nbsp; by @m-xlsea [<samp>(3ae99)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/3ae9922d)
- **projects**: 优化 cursor 规则及 mcp &nbsp;-&nbsp; by @m-xlsea [<samp>(a3199)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/a31994dc)
- **readme**: 更新 README.md 文件 &nbsp;-&nbsp; by @m-xlsea [<samp>(99675)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/99675cbc)
### &nbsp;&nbsp;&nbsp;🏡 杂项
- **deps**:
- update NodeJS and pnpm version requirements in package.json and documentation &nbsp;-&nbsp; by **Junior25306** [<samp>(a5c4b)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/a5c4b4e3)
- update deps &nbsp;-&nbsp; by @soybeanjs [<samp>(5cb1c)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/5cb1cebd)
- update deps &nbsp;-&nbsp; by @soybeanjs [<samp>(aeb63)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/aeb63690)
- update deps &nbsp;-&nbsp; by @m-xlsea [<samp>(89c71)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/89c716e1)
- update NodeJS and pnpm version requirements in package.json and documentation &nbsp;-&nbsp; by **Junior25306** [<samp>(a5c4b)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/a5c4b4e3)
- update deps &nbsp;-&nbsp; by @soybeanjs [<samp>(5cb1c)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/5cb1cebd)
- update deps &nbsp;-&nbsp; by @soybeanjs [<samp>(aeb63)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/aeb63690)
- update deps &nbsp;-&nbsp; by @m-xlsea [<samp>(89c71)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/89c716e1)
- **packages**:
- update Vite version to 7 in package.json and documentation. &nbsp;-&nbsp; by **Azir** [<samp>(03dd6)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/03dd64c5)
- update Vite version to 7 in package.json and documentation. &nbsp;-&nbsp; by **Azir** [<samp>(03dd6)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/03dd64c5)
- **projects**:
- update pnpm-lock.yaml &nbsp;-&nbsp; by @m-xlsea [<samp>(7c6ca)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/7c6ca91e)
- update pnpm-lock.yaml &nbsp;-&nbsp; by @m-xlsea [<samp>(7c6ca)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/7c6ca91e)
- **vscode**:
- remove unused vue.server.hybridMode setting from .vscode/settings.json &nbsp;-&nbsp; by @soybeanjs [<samp>(13319)</samp>](https://github.com/m-xlsea/ruoyi-plus-soybean/commit/133196f3)
- remove unused vue.server.hybridMode setting from .vscode/settings.json &nbsp;-&nbsp; by @soybeanjs [<samp>(13319)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/133196f3)
### &nbsp;&nbsp;&nbsp;❤️ 贡献值

View File

@ -22,13 +22,12 @@
# 📢 重要通知
1.1.1 版本已发布,但仍然建议:
1.1.3 版本已经正式发布(工作流版本请切换 [flow](https://gitee.com/xlsea/ruoyi-plus-soybean/tree/flow/) 分支查看),但仍然建议:
- 在生产环境使用前进行充分测试
- 关注项目更新,及时获取最新版本
- 积极反馈问题,帮助我们快速迭代
**后续规划**
- 工作流引擎集成
- 多语言国际化完善
- 性能优化和稳定性提升
@ -41,6 +40,11 @@
<p style="font-weight: bold; font-size: 24px;">后端需要替换代码生成模板与菜单 SQL详细请看 <a href="#代码生成与菜单更新">代码生成与菜单更新</a></p>
# 💎 友情链接
- [Snail Job Pro](https://pro.snailjob.opensnail.com/home) - 灵活,可靠和快速的分布式任务重试和分布式任务调度平台
- [AiZuDa - 爱组搭(飞龙工作流企业版)](https://naiveui.aizuda.com) - 像搭积木一样进行低代码甚至零代码快速构建应用
## 📋 项目概述
RuoYi-Plus-Soybean 是一个现代化的企业级多租户管理系统,它结合了 RuoYi-Vue-Plus 的强大后端功能和 Soybean Admin 的现代化前端特性,为开发者提供了完整的企业管理解决方案。

View File

@ -1,44 +1,51 @@
#set($BaseEntity = ['createDept', 'createBy', 'createTime', 'updateBy', 'updateTime'])
#set($ModuleName = $moduleName.substring(0, 1).toUpperCase() + $moduleName.substring(1))
/**
* namespace ${ModuleName}
* Namespace Api
*
* backend api module: "${ModuleName}"
* All backend api type
*/
namespace ${ModuleName} {
/** ${businessname} */
type ${BusinessName} = Common.CommonRecord<{
#foreach($column in $columns)#if(!$BaseEntity.contains($column.javaField))
/** $column.columnComment */
$column.javaField:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) CommonType.IdType; #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number; #elseif($column.javaType == 'Boolean') boolean; #else string; #end
#end#end
}>;
declare namespace Api {
/**
* namespace ${ModuleName}
*
* backend api module: "${ModuleName}"
*/
namespace ${ModuleName} {
/** ${businessname} */
type ${BusinessName} = Common.CommonRecord<{
#foreach($column in $columns)#if(!$BaseEntity.contains($column.javaField))
/** $column.columnComment */
$column.javaField:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) CommonType.IdType; #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number; #elseif($column.javaType == 'Boolean') boolean; #else string; #end
#end#end
}>;
/** ${businessname} search params */
type ${BusinessName}SearchParams = CommonType.RecordNullable<
Pick<
Api.${ModuleName}.${BusinessName},
#foreach($column in $columns)
#if($column.query && $column.queryType != 'BETWEEN')
| '${column.javaField}'
#end
#end
> &
Api.Common.CommonSearchParams
>;
/** ${businessname} search params */
type ${BusinessName}SearchParams = CommonType.RecordNullable<
Pick<
Api.${ModuleName}.${BusinessName},
#foreach($column in $columns)
#if($column.query && $column.queryType != 'BETWEEN')
| '${column.javaField}'
#end
#end
> &
Api.Common.CommonSearchParams
>;
/** ${businessname} operate params */
type ${BusinessName}OperateParams = CommonType.RecordNullable<
Pick<
Api.${ModuleName}.${BusinessName},
#foreach($column in $columns)
#if($column.insert || $column.edit)
| '${column.javaField}'
#end
#end
>
>;
/** ${businessname} operate params */
type ${BusinessName}OperateParams = CommonType.RecordNullable<
Pick<
Api.${ModuleName}.${BusinessName},
#foreach($column in $columns)
#if($column.insert || $column.edit)
| '${column.javaField}'
#end
#end
>
>;
/** ${businessname} list */
type ${BusinessName}List = Api.Common.PaginatingQueryRecord<${BusinessName}>;
/** ${businessname} list */
type ${BusinessName}List = Api.Common.PaginatingQueryRecord<${BusinessName}>;
}
}

View File

@ -1,7 +1,7 @@
{
"name": "ruoyi-vue-plus",
"type": "module",
"version": "1.1.1",
"version": "1.1.3",
"description": "结合了 RuoYi-Vue-Plus 的强大后端功能和 Soybean Admin 的现代化前端特性,为开发者提供了完整的企业管理解决方案。",
"author": {
"name": "xlsea",
@ -41,18 +41,21 @@
"scripts": {
"build": "vite build --mode prod",
"build:dev": "vite build --mode dev",
"build:tauri": "pnpm tauri build",
"build:test": "vite build --mode test",
"cleanup": "sa cleanup",
"commit": "sa git-commit",
"commit:zh": "sa git-commit -l=zh-cn",
"dev": "vite --mode dev",
"dev:prod": "vite --mode prod",
"dev:tauri": "pnpm tauri dev",
"dev:test": "vite --mode test",
"gen-route": "sa gen-route",
"lint": "eslint . --fix",
"prepare": "simple-git-hooks",
"preview": "vite preview",
"release": "sa release",
"tauri-icon": "pnpm tauri icon ./public/logo.png",
"typecheck": "vue-tsc --noEmit --skipLibCheck",
"update-pkg": "sa update-pkg"
},
@ -65,6 +68,7 @@
"@sa/materials": "workspace:*",
"@sa/tinymce": "workspace:*",
"@sa/utils": "workspace:*",
"@tauri-apps/api": "2.5.0",
"@types/streamsaver": "^2.0.5",
"@vueuse/core": "13.5.0",
"clipboard": "2.0.11",
@ -88,22 +92,23 @@
},
"devDependencies": {
"@elegant-router/vue": "0.3.8",
"@iconify/json": "2.2.354",
"@iconify/json": "2.2.357",
"@sa/scripts": "workspace:*",
"@sa/uno-preset": "workspace:*",
"@soybeanjs/eslint-config": "1.7.0",
"@types/node": "24.0.10",
"@soybeanjs/eslint-config": "1.7.1",
"@tauri-apps/cli": "2.5.0",
"@types/node": "24.0.13",
"@types/nprogress": "0.2.3",
"@unocss/eslint-config": "66.3.2",
"@unocss/preset-icons": "66.3.2",
"@unocss/preset-uno": "66.3.2",
"@unocss/transformer-directives": "66.3.2",
"@unocss/transformer-variant-group": "66.3.2",
"@unocss/vite": "66.3.2",
"@unocss/eslint-config": "66.3.3",
"@unocss/preset-icons": "66.3.3",
"@unocss/preset-uno": "66.3.3",
"@unocss/transformer-directives": "66.3.3",
"@unocss/transformer-variant-group": "66.3.3",
"@unocss/vite": "66.3.3",
"@vitejs/plugin-vue": "6.0.0",
"@vitejs/plugin-vue-jsx": "5.0.1",
"consola": "3.4.2",
"eslint": "9.30.1",
"eslint": "9.31.0",
"eslint-plugin-vue": "10.3.0",
"kolorist": "1.8.0",
"sass": "1.89.2",
@ -112,7 +117,7 @@
"typescript": "5.8.3",
"unplugin-icons": "22.1.0",
"unplugin-vue-components": "28.8.0",
"vite": "7.0.1",
"vite": "7.0.4",
"vite-plugin-monaco-editor": "^1.1.0",
"vite-plugin-progress": "0.0.7",
"vite-plugin-static-copy": "^3.1.0",

1030
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

BIN
public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

3
src-tauri/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# Generated by Cargo
# will have compiled files and executables
/target/

4580
src-tauri/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

26
src-tauri/Cargo.toml Normal file
View File

@ -0,0 +1,26 @@
[package]
name = "app"
version = "0.1.0"
description = "A Tauri App"
authors = ["you"]
license = ""
repository = ""
default-run = "app"
edition = "2021"
rust-version = "1.60"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
tauri-build = { version = "2", features = [] }
[dependencies]
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
tauri = { version = "2", features = [] }
[features]
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
# If you use cargo directly instead of tauri's cli you can use this feature flag to switch between tauri's `dev` and `build` modes.
# DO NOT REMOVE!!
custom-protocol = [ "tauri/custom-protocol" ]

3
src-tauri/build.rs Normal file
View File

@ -0,0 +1,3 @@
fn main() {
tauri_build::build()
}

View File

@ -0,0 +1,7 @@
{
"identifier": "migrated",
"description": "permissions that were migrated from v1",
"local": true,
"windows": ["main"],
"permissions": ["core:default"]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
{
"migrated": {
"identifier": "migrated",
"description": "permissions that were migrated from v1",
"local": true,
"windows": ["main"],
"permissions": ["core:default"]
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

BIN
src-tauri/icons/128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
src-tauri/icons/32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
src-tauri/icons/64x64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
src-tauri/icons/icon.icns Normal file

Binary file not shown.

BIN
src-tauri/icons/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
src-tauri/icons/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

8
src-tauri/src/main.rs Normal file
View File

@ -0,0 +1,8 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
tauri::Builder::default()
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

57
src-tauri/tauri.conf.json Normal file
View File

@ -0,0 +1,57 @@
{
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
"build": {
"beforeBuildCommand": "npm run build",
"beforeDevCommand": "npm run dev",
"frontendDist": "../dist",
"devUrl": "http://localhost:9527"
},
"bundle": {
"active": true,
"category": "DeveloperTool",
"copyright": "RuoYi-Plus-Soybean",
"targets": "all",
"externalBin": [],
"icon": ["icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"],
"windows": {
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": ""
},
"longDescription": "",
"macOS": {
"entitlements": null,
"exceptionDomain": "",
"frameworks": [],
"providerShortName": null,
"signingIdentity": null
},
"resources": [],
"shortDescription": "",
"linux": {
"deb": {
"depends": []
}
}
},
"productName": "RuoYi-Plus-Soybean",
"mainBinaryName": "RuoYi-Plus-Soybean",
"version": "1.0.0",
"identifier": "org.dromara.admin",
"plugins": {},
"app": {
"windows": [
{
"fullscreen": false,
"height": 768,
"resizable": true,
"title": "RuoYi-Plus-Soybean",
"width": 1366,
"useHttpsScheme": true
}
],
"security": {
"csp": null
}
}
}

View File

@ -21,27 +21,27 @@ const attrs: SelectProps = useAttrs();
const { loading: postLoading, startLoading: startPostLoading, endLoading: endPostLoading } = useLoading();
/** the enabled role options */
const roleOptions = ref<CommonType.Option<CommonType.IdType>[]>([]);
/** the enabled post options */
const postOptions = ref<CommonType.Option<CommonType.IdType>[]>([]);
watch(
() => props.deptId,
() => {
if (!props.deptId) {
roleOptions.value = [];
postOptions.value = [];
return;
}
getRoleOptions();
getPostOptions();
},
{ immediate: true }
);
async function getRoleOptions() {
async function getPostOptions() {
startPostLoading();
const { error, data } = await fetchGetPostSelect(props.deptId!);
if (!error) {
roleOptions.value = data.map(item => ({
postOptions.value = data.map(item => ({
label: item.postName,
value: item.postId
}));
@ -54,7 +54,7 @@ async function getRoleOptions() {
<NSelect
v-model:value="value"
:loading="postLoading"
:options="roleOptions"
:options="postOptions"
v-bind="attrs"
placeholder="请选择岗位"
/>

View File

@ -16,6 +16,12 @@ export function useDownload() {
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
const { baseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);
const isHttps = () => {
const protocol = document.location.protocol;
const hostname = document.location.hostname;
return protocol === 'https' || hostname === 'localhost' || hostname === '127.0.0.1';
};
/** 获取通用请求头 */
const getCommonHeaders = (contentType = 'application/octet-stream') => ({
Authorization: `Bearer ${localStg.get('token')}`,
@ -109,9 +115,10 @@ export function useDownload() {
await handleResponse(response);
const finalFilename = filename || response.headers.get('Download-Filename') || `download-${timestamp}`;
const rawHeader = response.headers.get('Download-Filename');
const finalFilename = filename || (rawHeader ? decodeURIComponent(rawHeader) : null) || `download-${timestamp}`;
if (response.body) {
if (response.body && isHttps()) {
const contentLength = Number(response.headers.get('Content-Length'));
await downloadByStream(response.body, finalFilename, contentLength);
return;

View File

@ -65,37 +65,47 @@ export const request = createFlatRequest<App.Service.Response, RequestInstanceSt
request.state.errMsgStack = request.state.errMsgStack.filter(msg => msg !== response.data.msg);
}
const isLogin = Boolean(localStg.get('token'));
// when the backend response code is in `logoutCodes`, it means the user will be logged out and redirected to login page
// const logoutCodes = import.meta.env.VITE_SERVICE_LOGOUT_CODES?.split(',') || [];
// if (logoutCodes.includes(responseCode)) {
// handleLogout();
// return null;
// }
const logoutCodes = import.meta.env.VITE_SERVICE_LOGOUT_CODES?.split(',') || [];
if (logoutCodes.includes(responseCode) && !isLogin) {
logoutAndCleanup();
return null;
}
// when the backend response code is in `modalLogoutCodes`, it means the user will be logged out by displaying a modal
const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || [];
if (modalLogoutCodes.includes(responseCode)) {
request.state.errMsgStack = [...(request.state.errMsgStack || []), response.data.msg];
// prevent the user from refreshing the page
window.addEventListener('beforeunload', handleLogout);
if (!window.location.pathname?.startsWith('/login')) {
window.$dialog?.warning({
title: '系统提示',
content: '登录状态已过期,您可以继续留在该页面,或者重新登录',
positiveText: '重新登录',
negativeText: '取消',
maskClosable: false,
closeOnEsc: false,
onPositiveClick() {
logoutAndCleanup();
}
});
request.cancelAllRequest();
if (modalLogoutCodes.includes(responseCode) && isLogin) {
const isExist = request.state.errMsgStack?.includes(response.data.msg);
if (isExist) {
return null;
}
if (window.location.pathname?.startsWith('/login')) {
logoutAndCleanup();
return null;
}
request.state.errMsgStack = [...(request.state.errMsgStack || []), response.data.msg];
window.$dialog?.warning({
title: '系统提示',
content: '登录状态已过期,请重新登录',
positiveText: '重新登录',
maskClosable: false,
closeOnEsc: false,
onAfterEnter() {
// prevent the user from refreshing the page
window.addEventListener('beforeunload', handleLogout);
},
onPositiveClick() {
logoutAndCleanup();
},
onClose() {
logoutAndCleanup();
}
});
request.cancelAllRequest();
return null;
}

View File

@ -65,11 +65,15 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
routes.forEach(route => {
if (authRouteMode.value === 'dynamic') {
if (route.path === '/') {
route.children?.forEach(child => {
parseRouter(child);
authRoutesMap.set(child.name, child);
});
if (route.path === '/' && route.children?.length) {
const child = route.children[0];
// @ts-expect-error no hidden field
child.hidden = route.hidden;
parseRouter(child);
child.name = Math.random().toString(36).slice(2, 12);
Object.assign(route, child);
delete route.children;
authRoutesMap.set(route.name, route);
return;
}
parseRouter(route);
@ -121,7 +125,6 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
} else if (!isNotNull(route.meta.icon)) {
route.meta.icon = defaultIcon;
}
// @ts-expect-error no hidden field
route.meta.hideInMenu = route.hidden;
if (route.meta.hideInMenu && parent) {

View File

@ -13,6 +13,13 @@
border-color: var(--un-default-border-color, #e5e7eb); /* 2 */
}
/*
* [Naive UI] Fix the icon size in the image preview toolbar
*/
.n-image-preview-toolbar .n-base-icon {
box-sizing: unset !important;
}
/*
1. Use a consistent sensible line-height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.

View File

@ -163,6 +163,8 @@ declare namespace Api {
postIds: string[];
/** user role ids */
roleIds: string[];
/** roles */
roles: Role[];
};
/** user list */

View File

@ -53,12 +53,14 @@ async function handleFetchTenantList() {
const { data, error } = await fetchTenantList();
if (error) return;
tenantEnabled.value = data.tenantEnabled;
tenantOption.value = data.voList.map(tenant => {
return {
label: tenant.companyName,
value: tenant.tenantId
};
});
if (data.tenantEnabled) {
tenantOption.value = data.voList.map(tenant => {
return {
label: tenant.companyName,
value: tenant.tenantId
};
});
}
endTenantLoading();
}

View File

@ -34,13 +34,13 @@ async function search() {
<NCollapseItem :title="$t('common.search')" name="user-search">
<NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
<NGrid responsive="screen" item-responsive>
<NFormItemGi span="24 s:12 m:6" label="IP地址" path="ipaddr" class="pr-24px">
<NFormItemGi span="24 s:12 m:8" label="IP地址" path="ipaddr" class="pr-24px">
<NInput v-model:value="model.ipaddr" placeholder="请输入IP地址" />
</NFormItemGi>
<NFormItemGi span="24 s:12 m:6" label="用户账号" path="userName" class="pr-24px">
<NFormItemGi span="24 s:12 m:8" label="用户账号" path="userName" class="pr-24px">
<NInput v-model:value="model.userName" placeholder="请输入用户账号" />
</NFormItemGi>
<NFormItemGi span="24" class="pr-24px">
<NFormItemGi span="24 s:24 m:8" class="pr-24px">
<NSpace class="w-full" justify="end">
<NButton @click="reset">
<template #icon>

View File

@ -61,7 +61,7 @@ async function search() {
clearable
/>
</NFormItemGi>
<NFormItemGi span="24" class="pr-24px">
<NFormItemGi span="24 s:12 m:6" class="pr-24px">
<NSpace class="w-full" justify="end">
<NButton @click="reset">
<template #icon>

View File

@ -21,9 +21,12 @@ const dateRangeCreateTime = ref<[string, string] | null>(null);
const model = defineModel<Api.System.ConfigSearchParams>('model', { required: true });
function onDateRangeCreateTimeUpdate(value: [string, string] | null) {
if (value?.length) {
model.value.params!.beginTime = value[0];
model.value.params!.endTime = value[1];
const params = model.value.params!;
if (value && value.length === 2) {
[params.beginTime, params.endTime] = value;
} else {
params.beginTime = undefined;
params.endTime = undefined;
}
}
@ -77,7 +80,7 @@ async function search() {
clearable
/>
</NFormItemGi>
<NFormItemGi span="24 s:12 m:12" label="创建时间" path="createTime" class="pr-24px">
<NFormItemGi span="24 s:12 m:6" label="创建时间" path="createTime" class="pr-24px">
<NDatePicker
v-model:formatted-value="dateRangeCreateTime"
type="datetimerange"
@ -86,7 +89,7 @@ async function search() {
@update:formatted-value="onDateRangeCreateTimeUpdate"
/>
</NFormItemGi>
<NFormItemGi span="24 s:12 m:12" class="pr-24px">
<NFormItemGi span="24" class="pr-24px">
<NSpace class="w-full" justify="end">
<NButton @click="reset">
<template #icon>

View File

@ -36,10 +36,10 @@ async function search() {
<NCollapseItem :title="$t('common.search')" name="user-search">
<NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
<NGrid responsive="screen" item-responsive>
<NFormItemGi span="8" :label="$t('page.system.dept.deptName')" path="deptName" class="pr-24px">
<NFormItemGi span="24 s:12 m:8" :label="$t('page.system.dept.deptName')" path="deptName" class="pr-24px">
<NInput v-model:value="model.deptName" :placeholder="$t('page.system.dept.form.deptName.required')" />
</NFormItemGi>
<NFormItemGi span="8 " :label="$t('page.system.dept.status')" path="status" class="pr-24px">
<NFormItemGi span="24 s:12 m:8 " :label="$t('page.system.dept.status')" path="status" class="pr-24px">
<NSelect
v-model:value="model.status"
:placeholder="$t('page.system.dept.form.status.required')"
@ -47,7 +47,7 @@ async function search() {
clearable
/>
</NFormItemGi>
<NFormItemGi span="8" class="pr-24px">
<NFormItemGi span="24 s:12 m:8" class="pr-24px">
<NSpace class="w-full" justify="end">
<NButton @click="reset">
<template #icon>

View File

@ -33,17 +33,16 @@ async function search() {
<NCollapse>
<NCollapseItem :title="$t('common.search')" name="user-search">
<NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
<NGrid responsive="self" item-responsive>
<NGrid responsive="screen" item-responsive>
<NFormItemGi
:show-feedback="false"
span="12"
span="24 s:12 m:12"
:label="$t('page.system.dict.data.label')"
path="dictLabel"
class="pr-24px"
>
<NInput v-model:value="model.dictLabel" :placeholder="$t('page.system.dict.form.dictLabel.required')" />
</NFormItemGi>
<NFormItemGi :show-feedback="false" span="12" class="pr-24px">
<NFormItemGi span="24 s:12 m:12" class="pr-24px">
<NSpace class="w-full" justify="end">
<NButton @click="reset">
<template #icon>

View File

@ -113,6 +113,24 @@ function renderLabel({ option }: { option: TreeOption }) {
if (label?.startsWith('route.') || label?.startsWith('menu.')) {
label = $t(label as App.I18n.I18nKey);
}
// 禁用的菜单显示红色
if (option.status === '1') {
return (
<div class="flex items-center gap-4px text-error-200">
{label}
<SvgIcon icon="ri:prohibited-line" class="text-16px" />
</div>
);
}
// 隐藏的菜单显示灰色
if (option.visible === '1') {
return (
<div class="flex items-center gap-4px text-gray-400">
{label}
<SvgIcon icon="codex:hidden" class="text-21px" />
</div>
);
}
return <div>{label}</div>;
}

View File

@ -33,13 +33,13 @@ async function search() {
<NCollapseItem :title="$t('common.search')" name="user-search">
<NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
<NGrid responsive="screen" item-responsive>
<NFormItemGi span="8" label="公告标题" path="noticeTitle" class="pr-24px">
<NFormItemGi span="24 s:12 m:8" label="公告标题" path="noticeTitle" class="pr-24px">
<NInput v-model:value="model.noticeTitle" placeholder="请输入公告标题" />
</NFormItemGi>
<NFormItemGi span="8" label="公告类型" path="noticeType" class="pr-24px">
<NFormItemGi span="24 s:12 m:8" label="公告类型" path="noticeType" class="pr-24px">
<DictSelect v-model:value="model.noticeType" dict-code="sys_notice_type" placeholder="请选择公告类型" />
</NFormItemGi>
<NFormItemGi span="8" class="pr-24px">
<NFormItemGi span="24 s:12 m:8" class="pr-24px">
<NSpace class="w-full" justify="end">
<NButton @click="reset">
<template #icon>

View File

@ -21,9 +21,12 @@ const dateRangeCreateTime = ref<[string, string] | null>(null);
const model = defineModel<Api.System.OssSearchParams>('model', { required: true });
function onDateRangeCreateTimeUpdate(value: [string, string] | null) {
if (value?.length) {
model.value.params!.beginCreateTime = value[0];
model.value.params!.endCreateTime = value[1];
const params = model.value.params!;
if (value && value.length === 2) {
[params.beginTime, params.endTime] = value;
} else {
params.beginTime = undefined;
params.endTime = undefined;
}
}

View File

@ -36,13 +36,13 @@ async function search() {
<NCollapseItem :title="$t('common.search')" name="user-search">
<NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
<NGrid responsive="screen" item-responsive>
<NFormItemGi span="6 s:12 m:6" label="岗位编码" path="postCode" class="pr-24px">
<NFormItemGi span="24 s:12 m:6" label="岗位编码" path="postCode" class="pr-24px">
<NInput v-model:value="model.postCode" placeholder="请输入岗位编码" />
</NFormItemGi>
<NFormItemGi span="6 s:12 m:6" label="岗位名称" path="postName" class="pr-24px">
<NFormItemGi span="24 s:12 m:6" label="岗位名称" path="postName" class="pr-24px">
<NInput v-model:value="model.postName" placeholder="请输入岗位名称" />
</NFormItemGi>
<NFormItemGi span="6 s:12 m:6" label="状态" path="status" class="pr-24px">
<NFormItemGi span="24 s:12 m:6" label="状态" path="status" class="pr-24px">
<NSelect
v-model:value="model.status"
placeholder="请选择状态"
@ -50,7 +50,7 @@ async function search() {
clearable
/>
</NFormItemGi>
<NFormItemGi span="6" class="pr-24px">
<NFormItemGi span="24 s:12 m:6" class="pr-24px">
<NSpace class="w-full" justify="end">
<NButton @click="reset">
<template #icon>

View File

@ -168,9 +168,12 @@ const dateRangeCreateTime = ref<[string, string] | null>(null);
const datePickerRef = ref<InstanceType<typeof NDatePicker>>();
function onDateRangeCreateTimeUpdate(value: [string, string] | null) {
if (value?.length) {
searchParams.params!.beginTime = value[0];
searchParams.params!.endTime = value[1];
const params = searchParams.params!;
if (value && value.length === 2) {
[params.beginTime, params.endTime] = value;
} else {
params.beginTime = undefined;
params.endTime = undefined;
}
}

View File

@ -24,9 +24,12 @@ const model = defineModel<Api.System.RoleSearchParams>('model', { required: true
const { options: sysNormalDisableOptions } = useDict('sys_normal_disable', false);
function onDateRangeCreateTimeUpdate(value: [string, string] | null) {
if (value?.length) {
model.value.params!.beginTime = `${value[0]} 00:00:00`;
model.value.params!.endTime = `${value[1]} 23:59:59`;
const params = model.value.params!;
if (value && value.length === 2) {
[params.beginTime, params.endTime] = value;
} else {
params.beginTime = undefined;
params.endTime = undefined;
}
}

View File

@ -38,7 +38,7 @@ async function search() {
<NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
<NGrid responsive="screen" item-responsive>
<NFormItemGi
span="8"
span="24 s:12 m:8"
:label="$t('page.system.tenantPackage.packageName')"
path="packageName"
class="pr-24px"
@ -48,7 +48,12 @@ async function search() {
:placeholder="$t('page.system.tenantPackage.form.packageName.required')"
/>
</NFormItemGi>
<NFormItemGi span="8" :label="$t('page.system.tenantPackage.status')" path="status" class="pr-24px">
<NFormItemGi
span="24 s:12 m:8"
:label="$t('page.system.tenantPackage.status')"
path="status"
class="pr-24px"
>
<NSelect
v-model:value="model.status"
:placeholder="$t('page.system.tenantPackage.form.status.required')"
@ -56,7 +61,7 @@ async function search() {
clearable
/>
</NFormItemGi>
<NFormItemGi span="8" class="pr-24px">
<NFormItemGi span="24 s:24 m:8" class="pr-24px">
<NSpace class="w-full" justify="end">
<NButton @click="reset">
<template #icon>

View File

@ -91,6 +91,7 @@ function handleDownloadTemplate() {
watch(visible, () => {
if (visible.value) {
data.value.updateSupport = false;
fileList.value = [];
success.value = false;
message.value = '';
@ -140,7 +141,7 @@ watch(visible, () => {
</NUploadDragger>
</NUpload>
<div class="flex-center">
<NCheckbox v-model="data.updateSupport">{{ $t('common.updateExisting') }}</NCheckbox>
<NCheckbox v-model:checked="data.updateSupport">{{ $t('common.updateExisting') }}</NCheckbox>
</div>
<NAlert v-if="message" :title="$t('common.importResult')" :type="success ? 'success' : 'error'" :bordered="false">

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, reactive, watch } from 'vue';
import { computed, reactive, ref, watch } from 'vue';
import { useLoading } from '@sa/hooks';
import { fetchCreateUser, fetchGetUserInfo, fetchUpdateUser } from '@/service/api/system';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
@ -49,6 +49,8 @@ type Model = Api.System.UserOperateParams;
const model: Model = reactive(createDefaultModel());
const roleOptions = ref<CommonType.Option<CommonType.IdType>[]>([]);
function createDefaultModel(): Model {
return {
deptId: null,
@ -76,18 +78,23 @@ const rules: Record<RuleKey, App.Global.FormRule[]> = {
roleIds: [{ ...createRequiredRule('请选择角色'), type: 'array' }]
};
async function getUserInfo() {
async function getUserInfo(id: CommonType.IdType = '') {
startLoading();
const { error, data } = await fetchGetUserInfo(props.rowData?.userId);
const { error, data } = await fetchGetUserInfo(id);
if (!error) {
model.roleIds = data.roleIds;
model.postIds = data.postIds;
roleOptions.value = data.roles.map(role => ({
label: role.roleName,
value: role.roleId
}));
}
endLoading();
}
function handleUpdateModelWhenEdit() {
if (props.operateType === 'add') {
getUserInfo();
Object.assign(model, createDefaultModel());
model.deptId = props.deptId;
return;
@ -97,7 +104,7 @@ function handleUpdateModelWhenEdit() {
startDeptLoading();
Object.assign(model, props.rowData);
model.password = '';
getUserInfo();
getUserInfo(props.rowData.userId);
endDeptLoading();
}
}
@ -209,7 +216,14 @@ watch(visible, () => {
<PostSelect v-model:value="model.postIds" :dept-id="model.deptId" multiple clearable />
</NFormItem>
<NFormItem :label="$t('page.system.user.roleIds')" path="roleIds">
<RoleSelect v-model:value="model.roleIds" multiple clearable />
<NSelect
v-model:value="model.roleIds"
:loading="loading"
:options="roleOptions"
multiple
clearable
placeholder="请选择角色"
/>
</NFormItem>
<NFormItem :label="$t('page.system.user.status')" path="status">
<DictRadio v-model:value="model.status" dict-code="sys_normal_disable" />

View File

@ -24,9 +24,12 @@ const datePickerRef = ref<InstanceType<typeof NDatePicker>>();
const model = defineModel<Api.System.UserSearchParams>('model', { required: true });
function onDateRangeCreateTimeUpdate(value: [string, string] | null) {
if (value?.length) {
model.value.params!.beginTime = value[0];
model.value.params!.endTime = value[1];
const params = model.value.params!;
if (value && value.length === 2) {
[params.beginTime, params.endTime] = value;
} else {
params.beginTime = undefined;
params.endTime = undefined;
}
}