315 Commits

Author SHA1 Message Date
dap
a3f8cd8f96 style(login): 优化登录按钮的样式类名处理
使用 cn 工具函数替代手动拼接样式类名,使代码更简洁易读
2026-03-10 19:32:56 +08:00
dap
486ce6a567 fix(router): 修正根路由匹配逻辑和仪表板路由路径
修正根路由匹配逻辑,从基于路径匹配改为同时检查名称和路径,以避免潜在的路由冲突。同时将仪表板模块的基础路径从'/'改为'/dashboard',以改善路由结构。
2026-03-10 19:25:05 +08:00
dap
1b63469c40 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into antdv-next 2026-03-04 11:01:03 +08:00
dap
a9241aef84 chore: 更新web-antd版本并调整按钮水波纹样式为默认
将版本号从2.0.0-alpha.2升级至2.0.0-alpha.3
将按钮水波纹样式从'Happy'改为'Default',以准备正式版发布
2026-03-03 19:53:28 +08:00
dap
6c6fb316f0 docs: 为配置更新提示添加多语言注释
在配置文件顶部添加多语言注释,提醒用户在更改配置后需清空 localStorage 缓存,以提高国际团队开发者的理解度。
2026-03-03 16:10:49 +08:00
zouawen
2a86404ba5 fix: 修复混合双列布局侧边栏拖拽线条位置显示bug,同步修复普通布局和混合双列布局切换时width计算导致侧边栏宽度显示异常问题,新增普通布局和混合双列布局侧边栏菜单折叠状态同步 (#7596) 2026-03-02 15:31:29 +08:00
han
b8a0199cde feat(preferences): add toggle for copy preferences button (#7594)
Co-authored-by: hl <hl@nmcsoft.com>
2026-03-02 15:30:38 +08:00
Bryan Qiu
a46ed55a86 fix: bump version to 5.6.0 (#7592) 2026-03-02 04:22:21 +08:00
Jin Mao
1a9fbddef4 Merge branch 'main' into main 2026-02-28 12:04:48 +08:00
zouawen
1209aaafb4 fix: 修复lint报错 2026-02-28 11:25:08 +08:00
zouawen
8e71261d49 fix: 侧边栏菜单拖拽功能在设置内增加开关 2026-02-28 11:19:24 +08:00
dap
55b9d5cdb7 refactor(代码生成模板): 将API模板中的requestClient替换为alovaInstance
统一HTTP客户端调用方式,提升代码一致性,便于后续维护和依赖管理
2026-02-28 11:11:29 +08:00
dap
4f9caec9d5 feat(generator): 添加antdv-next专用代码生成模板
添加针对antdv-next框架的代码生成模板,支持useVbenForm和原生antd表单两种表单生成方式
包含API层、视图层、数据模型等完整模板文件,新增更新指南文档说明迁移步骤
2026-02-28 11:06:42 +08:00
dependabot[bot]
49e45eab54 chore(deps): bump vue-router from 4.6.4 to 5.0.3 (#7583)
Bumps [vue-router](https://github.com/vuejs/router) from 4.6.4 to 5.0.3.
- [Release notes](https://github.com/vuejs/router/releases)
- [Commits](https://github.com/vuejs/router/compare/v4.6.4...v5.0.3)

---
updated-dependencies:
- dependency-name: vue-router
  dependency-version: 5.0.3
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-27 17:06:18 +08:00
Jin Mao
bd22793ceb feat: add the attribute routeCached to route to control cache the DOM corresponding to the route 2026-02-27 16:04:01 +08:00
zouawen
b2013436c5 fix: 优化最大值限制 2026-02-27 11:12:51 +08:00
zouawen
cc808cb8c5 fix: 优化最小值限制 2026-02-27 11:07:28 +08:00
zouawen
afffc4b3f0 fix: 优化侧边栏拖拽逻辑,支持展开和折叠 2026-02-27 10:54:15 +08:00
dap
a272c54561 refactor(表单): 移除查询表单中时间组件的冗余默认值
清理多个模块查询表单中 RangePicker 组件的 defaultValue 设置,因为框架后续版本已修复重置问题,不再需要显式设置为 [null, null] 来确保表单重置正常工作。同时更新相关文档说明。
2026-02-26 19:24:06 +08:00
dap
7f5758b89c chore: 更新依赖包版本至最新稳定版
更新 @antdv-next/auto-import-resolver、@antdv-next/icons 和 antdv-next 到最新版本,以获取错误修复和功能改进。
2026-02-26 19:19:42 +08:00
dap
ba6c450298 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into antdv-next 2026-02-26 19:16:40 +08:00
zouawen
99710ef9dc feat: 优化侧边栏拖拽逻辑 2026-02-26 18:11:53 +08:00
zouawen
3d4ae04d9b Merge branch 'main' into main 2026-02-26 10:20:32 +08:00
zouawen
707b391449 feat: 侧边栏宽度拖拽改为composable实现,同时修复tabbar.ts文件lint报错 2026-02-26 10:09:57 +08:00
ming4762
45b843f344 fix: fix bug where renderEcharts gets stuck in a dead loop (#7561)
* 触发条件:echart所在页面开启keepalive 在其他页面切换颜色模式
2026-02-26 06:21:08 +08:00
Wu Clan
191fd90f06 chore: 更新表单描述显示样式 (#6938) 2026-02-26 06:17:04 +08:00
moil-xm
05920cd66d feat(vite-config): vite export typing (#7569)
* feat(vite-config): vite export typing

* feat(vite-config): add type

---------

Co-authored-by: Jin Mao <50581550+jinmao88@users.noreply.github.com>
2026-02-26 06:14:12 +08:00
Jin Mao
01508d5e42 fix: fix lint 2026-02-26 05:45:36 +08:00
zouawen
57cf6cbc9e feature: 简易版菜单宽度拖拽功能 2026-02-25 17:50:22 +08:00
AxiosLeo
03ebbea46a fix(menu): update hover color variable to use the correct reference (#7544)
* fix(menu): update hover color variable to use the correct reference

Medium Severity

In the horizontal .is-light menu section, --menu-item-hover-color is set to hsl(var(--menu-item-color)), but --menu-item-color is already defined as hsl(var(--accent-foreground)). This results in hsl(hsl(...)) at computed-value time, which is invalid CSS. The non-horizontal .is-light block correctly uses var(--menu-item-color) without the extra hsl() wrapper.

* fix(menu): simplify hover styles by removing redundant nested hover rules

Low Severity

The SCSS &:not(.is-active):hover { &:hover { ... } } compiles to a :hover:hover pseudo-class chain, which is functionally identical to a single :hover. The inner &:hover nesting is redundant and adds unnecessary complexity compared to placing styles directly inside the &:not(.is-active):hover block.
2026-02-12 22:22:53 +08:00
zouawen
8e7a5d1ec3 fix: Fix layout change, ensure div[ref="asideRef"] is contained within <aside> (#7551) 2026-02-12 22:22:34 +08:00
AxiosLeo
aa74a2535b fix(tabbar): visitHistory field (#7543)
High Severity

The visitHistory field is a Stack<string> class instance persisted to sessionStorage via pinia-plugin-persistedstate. There's no custom serializer or hydration hook. When the page reloads, JSON.parse(JSON.stringify(stack)) produces a plain object {dedup, items, maxSize} that lacks all Stack methods (push, pop, remove, retain, etc.) and the size getter. Pinia's $patch replaces the Stack instance with this plain object, so subsequent calls like this.visitHistory.push(...) will throw a TypeError.
2026-02-11 16:09:37 +08:00
zouawen
32379ba4b7 fix: 双列菜单模式下新增深色侧边栏和深色侧边栏子栏 (#7542)
* fix: 双列菜单模式下新增深色侧边栏和深色侧边栏子栏

* fix: 修复报错 config.test.ts.snap

* fix: 修复lint报错

* fix: 修复侧边栏菜单文本内容溢出问题

* fix: 修复lint报错
2026-02-11 16:08:32 +08:00
dap
5177f5c98d style(web-antd): 统一输入框圆角样式
为客户端配置表单中的超时输入框添加一致的圆角样式,确保与设计系统变量保持一致
2026-02-11 11:28:57 +08:00
dap
e9d3200c38 fix(系统管理): 将表单排序字段默认值从0改为1
避免因默认值为0导致排序异常,确保新增记录时排序字段有合理的初始值
2026-02-10 21:20:26 +08:00
dap
27c78cb888 fix(表单): 修复表单验证错误样式并统一规则
修复表单验证错误状态下的样式问题,包括输入框、选择器、时间选择器等组件的边框和阴影颜色。使用 CSS 变量统一错误阴影样式,提高可维护性。同时为演示表单的所有字段统一添加必填规则,并移除数字字段的冗余后缀配置。
2026-02-10 21:09:59 +08:00
moil-xm
7fe8d7b4be fix: ts 错误: 类型实例化过深,且可能无限 2026-02-10 16:13:36 +08:00
Bin
aace726a91 feat(playground): add antdv-next router link (#7532)
Co-authored-by: fuwb <fuwb@sunsharing.com.cn>
2026-02-10 13:09:34 +08:00
Jin Mao
e6f6e5464a Merge branch 'main' into main 2026-02-10 12:08:16 +08:00
Aliner
7d04b600fb fix: correct updateDate to updateData in the echarts hook (#7538)
* fix(@vben/plugins): Fixed the misspelling of the data update method name in the echarts hook

Correct updateDate to updateData, ensuring that the API method name is correct and consistent

* Revert "fix(@vben/plugins): Fixed the misspelling of the data update method name in the echarts hook"

This reverts commit 86d679cf25631bd1abd56d4f971e6db3a9b9d6d5.

* fix(@vben/plugins): fixed the misspelling of the data update method name in the echarts hook

Correct updateDate to updateData, ensuring that the API method name is correct and consistent
2026-02-10 11:19:45 +08:00
dap
05b32dd249 docs: 更新分析仪表板配置变更说明
更新 change.md 文档,记录路由模式从 backend 改为 mix 的配置变更。混合路由模式下,路由文件应放置在 apps/web-antd/src/router/routes/modules 目录中,并移除原有的 local.ts 文件。
2026-02-10 11:03:29 +08:00
dap
ed42d9de65 refactor(router): 重构路由菜单生成逻辑并新增模块化路由
移除本地菜单列表的依赖,改为完全从后端API获取菜单数据
新增 profile 和 dashboard 模块化路由文件
简化菜单生成逻辑,避免不必要的深拷贝操作
2026-02-10 11:01:46 +08:00
zouawen
463bfde2ac fix: config.test.ts.snap新增showRefresh参数 2026-02-10 08:50:06 +08:00
dap
b788a7d860 feat: 将路由访问模式更改为混合模式并更新版本号
- 将 `accessMode` 从 'backend' 改为 'mixed',以支持后端路由与前端路由的合并
- 更新应用版本号至 2.0.0-alpha.2
- 为按钮波纹效果添加默认主题配置
2026-02-09 17:02:42 +08:00
dap
f3942edece refactor(router): 移除未使用的路由模块
清理不再使用的 dashboard 和 vben 路由模块文件,保持路由结构整洁
2026-02-09 16:47:51 +08:00
dap
4a6745a8ea perf(vite-config): 禁用 sourcemap 以减小构建输出体积 2026-02-09 16:45:42 +08:00
dap
88b311202d fix: 关闭弹窗前确认对话框禁用背景模糊
避免弹窗关闭时的背景闪烁问题,提升用户体验
2026-02-09 16:43:15 +08:00
dap
7d1a51bfe3 docs: 从文档中移除已知问题部分
移除关于 message duration 无效的已知问题记录,因为该问题已解决。
2026-02-09 16:40:57 +08:00
zouawen
893f74dc3e fix: 优化横向布局时菜单激活或聚焦时背景色,标签工具栏新增刷新按钮,其他样式优化 2026-02-09 16:32:02 +08:00
dap
7092cd59d3 chore: 移除 web-antdv-next 应用及相关文件 2026-02-09 16:28:41 +08:00
dap
2189f22bbd Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into antdv-next 2026-02-09 16:26:26 +08:00
Jin Mao
8a215fbcc7 chore: release 5.6.0 2026-02-09 05:09:57 +08:00
Jin Mao
ac5e4c4722 chore: update deps 2026-02-09 04:52:06 +08:00
Jin Mao
04d01b0bab chore: fix lint 2026-02-09 04:49:06 +08:00
Jin Mao
cb1d7565a3 Merge branch 'fork/ffgenius/antd-vue-next' 2026-02-09 03:09:01 +08:00
Jin Mao
1d9b6407a4 chore: 更新开发环境端口号配置
- 将 VITE_PORT 从 5555 修改为 5999
- 保持其他环境变量配置不变
2026-02-09 03:04:42 +08:00
MistyMoon
22ed522711 feat: support menuVisibleWithForbidden in generate-routes-backend (#7526)
当后端菜单项 `meta.menuVisibleWithForbidden` 为 true 时,将其路由组件替换为 403 页,菜单仍展示该项,访问时展示 403,便于用户知悉功能并申请权限。
2026-02-09 02:44:29 +08:00
Jin Mao
a3598ef859 chore: fix lint 2026-02-09 02:42:50 +08:00
Jin Mao
6fe09ec2dd perf: optimize the closing jump logic of tabs 2026-02-09 02:36:38 +08:00
Jin Mao
57911d9e09 Merge branch 'tab-2026020401' of https://github.com/ming4762/smart-boot-ui-vben into ming4762-tab-2026020401 2026-02-09 02:36:04 +08:00
Bin
3aee283495 Revert "feat(web): cancel pnpm-lock.yaml submission"
This reverts commit 54b24c2677.
2026-02-08 23:14:31 +08:00
Bin
54b24c2677 feat(web): cancel pnpm-lock.yaml submission 2026-02-08 23:12:40 +08:00
Bin
8cadad0a1e feat(web): add antdv-next model 2026-02-08 23:00:19 +08:00
zhongming4762
633c5f3cda perf: optimize the closing jump logic of tabs
* 依据tab访问历史回退上一个tab,原逻辑是返回一下个 或 上一个
 * 支持在配置中开启或关闭
2026-02-08 20:50:54 +08:00
zhongming4762
a8431e2040 perf: optimize the closing jump logic of tabs
* 依据tab访问历史回退上一个tab,原逻辑是返回一下个 或 上一个
 * 支持在配置中开启或关闭
2026-02-08 20:36:32 +08:00
zhongming4762
7a2b916387 perf: optimize the closing jump logic of tabs
* 依据tab访问历史回退上一个tab,原逻辑是返回一下个 或 上一个
 * 支持在配置中开启或关闭
2026-02-08 20:36:16 +08:00
Jin Mao
f4dfb68b7b Merge branch 'MrLeo-main' 2026-02-06 15:41:55 +08:00
Jin Mao
8f4f27d860 Merge branch 'main' of https://github.com/MrLeo/vue-vben-admin into MrLeo-main 2026-02-06 15:39:48 +08:00
tikitoki
e9eab29953 fix:fix password input icon visual bug in certain browser (#7521)
Co-authored-by: nick8799981325 <zc1078134211@163.com>
2026-02-06 15:28:48 +08:00
Leo Caan (陈栋)
4f1eeb7da5 fix: 修复设置default-expanded-level后无法check更低层级节点 logic and tree value updates (#7155)
假设缺省展开2级,当check 3级节点时,会触发effectWatch重新收缩到2级,并丢失check操作check操作andling.
2026-02-06 12:55:14 +08:00
dap
1b3eb65280 refactor: 简化按钮波浪模式选项数组的构建方式 2026-02-05 21:32:59 +08:00
dap
d1461f3fa4 feat(theme): 集成快乐工作主题的按钮波纹效果
从 @antdv-next/happy-work-theme 引入 DotEffect 组件,替换原有的自定义快乐波纹效果实现。这提升了波纹动画的视觉效果和一致性,并遵循了该主题库的推荐用法。

- 在 pnpm-workspace.yaml 和 package.json 中添加 @antdv-next/happy-work-theme 依赖
- 更新按钮波纹模式选择器的类型定义以匹配 ThemePreferences
- 重写 showHappyEffect 函数,使用 createApp 动态挂载 DotEffect 组件
2026-02-05 18:56:50 +08:00
Leo
6fd426d719 fix: 当 showToolbar 为 false 时禁用工具栏(vxe-table),减少无 Toolbar 的 Gird 留白 2026-02-04 22:20:17 +08:00
zhongming4762
331da3c8c7 perf: optimize the closing jump logic of tabs
* 依据tab访问历史回退上一个tab,原逻辑是返回一下个 或 上一个
2026-02-04 19:29:33 +08:00
dap
4c0dc60ce6 style(loading): 将熊猫加载动画替换为星球主题动画
更新加载页面的CSS和HTML结构,使用新的星球旋转动画替代原有熊猫动画,提升视觉新鲜感并保持加载功能不变。
2026-02-04 10:47:58 +08:00
dap
cba346b0fc refactor(布局): 将内容加载组件从 VbenSpinner 替换为 VbenLoading 2026-02-04 10:37:22 +08:00
dap
f53c7b48c0 perf(web-antd): 缩短加载页面的淡出过渡时间
将 loading.html 中全局隐藏过渡的持续时间从 1 秒减少到 0.6 秒,以加快页面切换时的视觉反馈速度,提升用户体验。
2026-02-03 21:31:03 +08:00
dap
543162986f feat: 添加自定义应用加载动画页面
添加一个带有熊猫动画的 loading.html 作为应用加载页面,替换默认的加载体验。同时更新 VS Code 设置,将 HTML 文件的默认格式化工具从 Prettier 改为 VS Code 内置的 HTML 语言功能,以更好地处理 HTML 文件。
2026-02-03 21:24:57 +08:00
dap
1276559728 fix(upload): 修复组件属性透传问题
在 file-upload 和 image-upload 组件中添加 v-bind="$attrs" 以确保所有未声明的属性能够正确传递给底层 Upload 组件,避免因属性丢失导致的功能异常。
2026-02-03 19:52:56 +08:00
dap
3c8d613623 fix(upload): 返回 Upload.LIST_IGNORE 防止超大文件被加入列表
修复 Safari 浏览器下文件类型校验问题,同时确保上传文件大小超过限制时,通过返回 Upload.LIST_IGNORE 来阻止文件被加入待上传列表,避免界面显示异常。
2026-02-03 19:18:05 +08:00
dap
2a126c9ca2 style(operlog): 优化操作日志预览的标签间距
统一使用 flex gap 替代空标签包裹,提升布局一致性
2026-02-03 15:53:07 +08:00
dap
70acbdd7c5 fix(notification): 限制全局消息最大显示数量为1
修复通知组件在多次触发时可能显示多条消息的问题,通过配置 message prop 的 maxCount 参数确保始终只显示最新的一条通知消息
2026-02-03 15:51:21 +08:00
dap
d7552b0faf build: 锁定 vxe-pc-ui 依赖版本为精确版本
修复依赖版本号前多余的特殊字符,确保构建一致性
2026-02-03 14:36:02 +08:00
dap
fb33137790 build: 将 antdv-next 依赖从 rc 版本升级至稳定版
升级 antdv-next 至 1.0.0 稳定版本,以在生产环境中使用经过完整测试的稳定组件库。
2026-02-03 10:33:23 +08:00
dap
f2bd1cc378 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into antdv-next 2026-02-03 10:30:21 +08:00
dap
6bf71681c4 fix(antd): 禁用模态框和抽屉背景模糊效果
由于当前 mask blur 配置不生效,显式设置 modal 和 drawer 的 mask blur 为 false
2026-02-02 13:55:56 +08:00
dap
a5f66bce57 chore: 删除演示用的访问统计视图及相关文件 2026-02-02 13:29:47 +08:00
dap
949b81e630 docs: 更新分析页面的变更说明文档
移除已恢复功能的过时说明,保持文档与当前实现同步
2026-02-02 13:29:08 +08:00
dap
17aefd5568 fix: 统一状态切换函数参数类型为 SwitchProps['checked']
修复多个系统管理页面及全局组件中状态切换函数参数类型不一致的问题,将原先的 `boolean` 类型统一为 `SwitchProps['checked']` 类型,确保与 antdv-next 组件库的类型定义保持一致,提高类型安全性和代码一致性。
2026-02-02 13:27:49 +08:00
dap
41f0e043e9 fix(租户套餐): 修复状态切换开关绑定值错误
使用 `:value` 替代 `v-model:value`,将绑定值修正为布尔类型,以匹配 `ApiSwitch` 组件的预期值。
2026-02-02 11:05:14 +08:00
dap
f276b0f062 perf(router): 并行获取用户信息和生成路由以提升性能
通过 Promise.all 并行执行用户信息获取和路由生成操作,减少页面加载等待时间
2026-02-02 10:45:34 +08:00
dap
6d42a6d1bd docs: 移除已修复问题的记录
移除“图片上传预览无效”这一已知问题记录,因为该问题已得到解决。
2026-02-02 09:35:50 +08:00
dap
3c2acf9ca1 fix(upload): 修复图片预览时隐藏样式不生效的问题
使用 :styles 属性替代 class 来隐藏预览图片,确保预览功能正常触发
2026-02-02 09:35:30 +08:00
dap
9b38389040 chore: 更新 antdv-next 依赖至 1.0.0-rc.8 2026-02-02 09:34:10 +08:00
ming4762
c48943bc67 fix: fix Nested Objects dependencies not effective (#7345) 2026-01-31 16:44:20 +08:00
dap
1f4592e6fb style(workflow): 调整审批时间线附件间距为 gap-4
使附件间距更符合设计规范,提升视觉一致性
2026-01-30 17:26:51 +08:00
dap
3dd1a07ae3 fix(workflow): 修复流程图底部操作栏被遮挡问题
为流程图底部操作栏添加 z-index,确保其始终显示在最上层
2026-01-30 17:12:00 +08:00
dap
1666a65ba0 fix(workflow): 修正附件参数格式,移除不必要的join转换
将三个工作流模态框组件中的附件参数从字符串拼接改为直接传递数组,以匹配后端接口期望的数据格式。
2026-01-30 17:10:44 +08:00
dap
4085b05dae fix(workflow): 移除表单附件默认值并优化时间线样式
移除apply-modal、approval-modal、approval-rejection-modal中附件上传字段的冗余defaultValue配置,避免潜在的表单数据冲突。同时调整approval-timeline组件样式,禁用非完成状态项的悬停颜色,并增加时间线项间距以改善视觉呈现。在approval-timeline-item中使用DictTag组件替代renderDict函数以提升字典渲染的一致性和可维护性。
2026-01-30 17:03:43 +08:00
dap
8e2901775e feat(workflow): 为流程预览添加淡入动画效果
使用 motion-v 库为 iframe 容器添加淡入动画,提升用户体验
2026-01-30 16:40:41 +08:00
dap
0049c76f78 refactor(workflow): 重构审批面板的标签页实现以提升性能
使用组合式 API 的 `h` 函数和 `computed` 动态生成标签项,替代模板中的静态 `TabPane` 组件。
将 `body-style` 属性更新为 `styles` 以适配 antdv-next 的 API 变更。
启用 `destroy-on-hidden` 属性以在标签页隐藏时销毁非活动内容,优化内存使用。
2026-01-30 16:36:32 +08:00
dap
48f979497e refactor(workflow): 重构流程操作按钮组件以使用 Dropdown 的 menu 属性
将手动构建的 Menu 和 MenuItem 组件替换为 Dropdown 的 items 属性和 menu-click 事件,简化模板结构并提升可维护性。同时统一按钮的 variant 和 color 属性以符合新的 Ant Design Vue 规范。
2026-01-30 16:26:39 +08:00
dap
cd908a967c build: 添加 antdv-next auto-import-resolver 依赖
更新 pnpm 工作区配置和 web-antd 应用依赖,以支持新的按需导入解析器。
同时更新 Vite 配置中的注释,将解析器从 `AntDesignVueResolver` 替换为 `AntdvNextResolver`。
2026-01-30 16:05:16 +08:00
dap
487dd67d76 feat(web-antd): 新增表单组件演示页面
添加表单组件基础示例页面,展示 useVbenForm 钩子的各种用法
包含 Input、Select、ApiSelect、DatePicker 等常见表单组件的配置示例
演示远程搜索、API 数据获取、表单值设置等高级功能
2026-01-30 16:02:52 +08:00
dap
2a8e712e6d build: 将 antdv-next 依赖从 beta.3 升级到 rc.5 2026-01-30 13:20:15 +08:00
dap
16544228b7 fix(monitor/operlog): 调整IP信息列宽度以避免内容溢出
设置 operLocation 列的固定宽度为 200,防止因IP地理位置信息过长导致表格布局错乱。
2026-01-29 20:50:45 +08:00
dap
330f2d81ed fix(租户管理): 修复租户编辑时过期时间处理错误
修复租户编辑时,从接口获取的 expireTime 字符串未转换为 dayjs 对象导致表单显示异常的问题。
同时移除未使用的 dayjs 导入和过期时间默认值注释,避免潜在的类型错误。
2026-01-29 20:42:09 +08:00
dap
585a543c8f style(leave-description): 调整请假详情布局样式与间距
移除外部容器的边框和内边距,为描述列表添加边框并调整标签宽度
将描述列表尺寸改为 small 以优化视觉层次
2026-01-29 19:00:55 +08:00
dap
25994bd3bb feat(主题): 添加默认主题模式配置
在主题配置中添加默认的 mode 字段,明确设置初始主题为亮色模式,避免主题状态未定义时的显示问题
2026-01-28 20:13:47 +08:00
dap
72a62fa77f perf(vite-config): 添加手动分包以优化antdv-next的加载性能
将antdv-next库配置为独立分包,避免其代码与其他业务代码混合,提升缓存利用率和首屏加载速度。同时更新web-antd项目的环境配置,统一生产环境构建参数。
2026-01-28 20:02:28 +08:00
dap
dab5f8ed72 fix(用户管理): 修复编辑用户时角色字段验证逻辑
编辑用户时角色字段为必填,新增用户时允许为空。通过添加动态验证规则实现此逻辑。
2026-01-28 19:48:13 +08:00
dap
9129026bcb refactor: 移除已弃用的 commonDownloadExcel 方法
使用 useBlobExport 替代 commonDownloadExcel 方法,并更新相关文档。
2026-01-28 19:42:55 +08:00
dap
7b4d68a164 refactor: 重构导出功能,使用新的 useBlobExport 钩子
移除旧的 commonDownloadExcel 函数,统一使用 useBlobExport 钩子处理文件导出
- 在用户导入模板、请假申请和字典类型页面中替换导出逻辑
- 移除 demo 页面未使用的导出按钮和相关导入
- 为导出按钮添加加载状态,提升用户体验
2026-01-28 19:41:50 +08:00
dap
35d67ad71c refactor(views): 替换导出功能为组合式函数以提升复用性
将租户套餐和租户管理页面的导出功能从 commonDownloadExcel 工具函数迁移至 useBlobExport 组合式函数。此重构统一了导出逻辑,自动处理加载状态和文件名构建,并移除了手动控制台日志语句,提高了代码的可维护性和一致性。
2026-01-28 19:36:41 +08:00
dap
1ff118c2e0 refactor(客户端管理): 替换导出功能为可复用钩子
- 使用 useBlobExport 钩子替代 commonDownloadExcel 工具函数,统一导出逻辑
- 增加导出按钮的加载状态和禁用状态,提升用户体验
- 通过钩子自动构建导出文件名,简化调用代码
2026-01-28 19:34:15 +08:00
dap
abb386f49d refactor(monitor): 重构操作日志与登录日志导出功能
使用 useBlobExport 组合式函数替换 commonDownloadExcel,统一导出逻辑
移除手动构建请求参数和文件名的代码,提高代码复用性
为导出按钮添加加载状态,改善用户体验
2026-01-28 19:33:25 +08:00
dap
d28d80295c refactor(系统配置): 重构导出功能以使用新的blob导出工具
替换commonDownloadExcel为useBlobExport钩子,统一导出逻辑
2026-01-28 19:31:55 +08:00
dap
e2f063907e refactor(views): 替换导出功能为 useBlobExport 钩子
重构字典类型和字典数据页面的导出功能,使用新的 useBlobExport 组合式 API 替代原有的 commonDownloadExcel 方法,以提供更好的加载状态管理和文件名构建功能。同时在字典数据页面中修复事件监听器内存泄漏问题,在组件卸载时移除事件监听。
2026-01-28 19:30:02 +08:00
dap
9454121963 refactor(views): 替换导出功能为 useBlobExport 钩子
使用新的 useBlobExport 组合式函数替换原有的 commonDownloadExcel 工具函数,以统一导出逻辑并支持加载状态。同时调整按钮状态绑定 exportLoading 并重构参数获取方式。
2026-01-28 19:27:17 +08:00
dap
189b86f5b7 refactor: 替换角色导出功能为 useBlobExport 钩子
将 commonDownloadExcel 替换为 useBlobExport 钩子以统一导出逻辑,
并添加导出时的加载状态控制,提升用户体验。
2026-01-28 19:25:12 +08:00
dap
bfb2287b2e fix(用户管理): 修复部门树搜索后子节点丢失的问题
搜索部门树时,由于直接修改了原始树数据导致子节点被清空。通过深拷贝部门树数据并显式清空搜索结果的子节点,确保原始树结构不受影响。
2026-01-28 18:47:30 +08:00
dap
048ee5833e fix: 修复通知组件引用从直接导入改为window对象
避免在未正确初始化antdv-next时使用notification导致运行时错误
2026-01-28 18:44:06 +08:00
xingyu
7680b33b99 fix: #7140 (#7153)
* chore: add yaml eslint validate

* chore: update deps

* fix: unused ts lint

* fix: 弹窗只能点击一次 #7140

* chore: update actions/checkout v6

* chore: update node version v22.22.0
2026-01-28 18:05:20 +08:00
dap
3cb93fd67c feat(theme): 新增按钮水波纹样式配置选项
添加按钮水波纹效果的自定义配置功能,支持默认、禁用、内嵌、抖动和欢乐五种样式。用户可在主题设置中选择不同效果,增强交互视觉体验。

- 在主题配置类型中添加 buttonWaveMode 字段
- 新增按钮水波纹配置组件和样式实现
- 更新中英文国际化文本
- 在应用配置中集成水波纹效果
2026-01-28 16:33:27 +08:00
dap
cb2a58425f chore: 锁定 antdv-next 依赖版本至 1.0.0-beta.3
避免使用 latest 标签带来的潜在不兼容风险,确保构建的稳定性与可复现性。
2026-01-28 15:34:25 +08:00
dap
1f6de0ec29 feat(用户管理): 优化部门树搜索与样式
- 将搜索输入与刷新按钮组合为紧凑布局,提升操作便捷性
- 实现部门树实时搜索过滤,高亮显示匹配的节点文本
- 调整选中节点的背景色为更柔和的悬停色
- 修复树节点标题渲染插槽名称错误
2026-01-28 15:11:33 +08:00
dap
703cdf4125 feat(导出): 重构导出功能并添加国际化支持
- 新增通用的 `useBlobExport` 组合式函数,封装导出逻辑,支持加载状态和取消操作
- 在用户管理页面使用新的导出函数替换原有的 `commonDownloadExcel` 调用
- 添加中英文国际化文案,包括导出标题、加载提示和取消提示
- 为通用页面文案补充“取消”按钮的翻译
2026-01-28 14:47:59 +08:00
dap
157fb22820 docs(locales): 为登录页面添加第三方登录的中文翻译 2026-01-28 14:32:39 +08:00
dap
2d1545106e refactor(modal): 重构确认删除弹窗以兼容 antdv-next 更新
- 调整导入路径以匹配 antdv-next 的新模块结构
- 使用 defineComponent 和 h 函数重构弹窗内容为组件
- 通过 ref 暴露表单实例以替代 useForm 方法
- 移除已弃用的 trigger 属性并更新表单验证方式
2026-01-28 14:22:35 +08:00
dap
dfbab164ec debug: 调试使用 sourcemap 2026-01-28 13:56:33 +08:00
dap
32344ed038 refactor(vxe-table): 将 gridOptions 类型从 DeepPartial 改为 Partial
简化类型定义,移除不必要的深层可选类型,因为 VxeTableGridOptions 本身可能已包含可选属性或嵌套对象的适当处理。
2026-01-28 10:57:08 +08:00
dap
f01093af6d feat(租户管理): 将同步操作合并至下拉菜单以优化界面
将同步租户字典和同步租户参数配置两个按钮合并为一个“操作”下拉菜单,通过权限控制菜单项显示。这减少了工具栏的视觉复杂度,使界面更简洁,同时保持了原有的功能与权限校验逻辑。
2026-01-28 10:48:34 +08:00
dap
3abf3333ec fix(通知管理): 仅在包含ossId时转换通知内容
避免对不包含ossId的通知内容进行不必要的转换查询
2026-01-28 10:04:33 +08:00
dap
0934d7b785 chore: 迁移图标依赖从 @ant-design/icons-vue 到 @antdv-next/icons
移除对 @ant-design/icons-vue 的依赖,统一使用 @antdv-next/icons。
更新了 pnpm-workspace.yaml 中的包版本管理,并在多个 Vue 组件中修改了图标导入语句。
2026-01-28 09:59:05 +08:00
dap
6baecb5199 build: 添加 @antdv-next/icons 依赖包
为 web-antd 应用添加 @antdv-next/icons 依赖,以支持 Ant Design Vue Next 版本的图标组件。
2026-01-28 09:56:53 +08:00
dap
6b613aacb9 chore: 更新生产环境客户端ID配置
将 VITE_GLOB_APP_CLIENT_ID 的值从 e5cd7e4891bf95d1d19206ce24a7b32e 更改为 3fd880a0e6476add885c95bd5afd630f。此变更为环境配置更新,用于切换或更新客户端身份标识。
2026-01-27 21:44:55 +08:00
dap
ecd2bdb5fc feat(workflow): 为请假详情添加淡入动画效果
使用 motion-v 库为请假详情描述组件添加淡入动画,提升用户界面交互体验。同时调整容器最小高度以确保加载状态布局稳定。
2026-01-27 21:37:15 +08:00
dap
59fc7b66ad chore: 将 web-antd 应用的依赖版本统一到 workspace catalog
将 web-antd 应用 package.json 中的依赖版本从固定版本号替换为 workspace catalog 引用,以统一管理依赖版本并添加 motion-v 依赖。
2026-01-27 21:31:02 +08:00
dap
2746c7bdf0 fix(workflow): 修复审批面板加载状态闪烁问题
引入防抖延迟设置 loading 状态,避免快速切换任务时出现闪烁
2026-01-27 21:26:58 +08:00
dap
ba577dda14 fix(workflow): 添加骨架屏延迟显示以避免快速请求导致的闪烁
使用 useTimeout 延迟 300ms 显示骨架屏,防止接口响应过快时骨架屏短暂闪烁,提升用户体验
2026-01-27 21:22:04 +08:00
dap
afb7222955 refactor(workflow): 使用 useRequest 替换手动数据获取和清理
移除手动 onMounted 数据获取和 shallowRef,改用 alova 的 useRequest hook 以简化代码并自动管理请求生命周期。同时添加 onBeforeUnmount 以在组件卸载时取消请求,避免潜在的内存泄漏。
2026-01-27 21:00:35 +08:00
dap
be5af9e991 style: 调整 Vue 组件中 CSS 类的顺序以遵循 Tailwind 约定
将 bg-background 类移至其他背景相关类之后,以符合 Tailwind CSS 的推荐类排序规则,提高代码可读性和维护性。
2026-01-27 20:55:22 +08:00
dap
a8576d2c05 fix(workflow): 修复切换任务时接口请求未取消的问题
在审批面板中切换任务时,之前的异步请求可能仍在进行,导致数据错乱。现在通过维护请求取消函数列表,在发起新请求前取消所有未完成的请求。
2026-01-27 20:55:17 +08:00
dap
188ef3a66e refactor(workflow): 替换 Switch 为 ApiSwitch 并优化状态常量
将流程定义列表中的 Switch 组件替换为 ApiSwitch 以统一异步操作处理,并添加 `as const` 修饰常量以提高类型安全性。同时修复激活状态逻辑,确保与系统其他定义一致。
2026-01-27 20:42:15 +08:00
dap
0636c5f4a6 chore: 移除开发环境的上传提示功能
该提示用于提醒从低版本升级到后端5.4.0+的用户执行升级SQL,现已不再需要。删除相关钩子函数及导入,简化应用初始化逻辑。
2026-01-27 20:15:58 +08:00
dap
154c8b664b fix(deploy): 修复 Docker 构建路径和优化 Nginx 配置
修复 Dockerfile 中构建产物复制路径错误,将 `/app/playground/dist` 更正为 `/app/apps/web-antd/dist`。
优化 Nginx 配置,增加安全设置、性能调优和代理规则,并移除冗余的 MIME 类型配置。
调整公告列表列对齐方式以改善界面一致性。
2026-01-27 20:14:17 +08:00
dap
8fea830f9d refactor: 更新菜单类型图标类名并移除冗余的h函数调用
更新菜单类型图标使用的CSS类名,将`icons-`前缀统一改为`icon-`前缀,并交换目录与菜单的图标
同时移除不再需要的Vue h函数导入与调用,简化图标渲染逻辑
2026-01-27 18:51:05 +08:00
dap
3907f206d9 style(views): 替换内联样式为 Tailwind CSS 类并移除多余对齐
将 operation-preview-drawer 中的内联样式替换为对应的 Tailwind CSS 工具类,以提升可维护性。
同时移除 login-info-modal 中两个 flex 容器多余的 `justify-center` 类,保持布局简洁。
2026-01-27 18:46:49 +08:00
dap
dc2de11f57 fix: 为时间范围选择器设置默认值为null以修复表单重置问题
修复多个查询表单中时间范围选择器在表单重置时无法正常清空的问题。
为所有使用RangePicker的查询表单字段添加defaultValue: [null, null],
确保调用formReset时能正确重置时间选择器状态。
2026-01-27 18:40:14 +08:00
dap
c2b1d880c1 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into antdv-next 2026-01-27 16:56:53 +08:00
Jin Mao
bb5d75bc7e fix: 修复表单展开无效 (#7148)
- 修正模板中 ref 属性的引用名称
2026-01-27 11:35:50 +08:00
dap
cf1ed14c00 chore: 移除Nitro Mock服务配置并升级版本号至2.0.0-alpha.1
移除开发环境变量中已废弃的VITE_NITRO_MOCK配置项,并将应用版本号升级至2.0.0-alpha.1,为后续版本更新做准备。
2026-01-26 19:21:30 +08:00
dap
e4d882b4bc chore: 移除 backend-mock 应用及相关配置
移除不再使用的 backend-mock 应用,包括其源代码、配置文件、依赖项以及相关的构建任务。
同时从工作区配置和 TurboRepo 构建管道中删除对该应用的引用。
2026-01-26 19:02:23 +08:00
dap
0b3ab4de63 chore: 移除文档站点及其相关资源
- 删除 docs 目录及其所有内容,包括文档源码、图片、组件示例和配置
- 从 pnpm-workspace.yaml 中移除 docs 工作空间
- 从 vben-admin.code-workspace 中移除 docs 项目
- 从 package.json 中移除与文档相关的构建和开发脚本
- 清理不再需要的文档依赖和构建配置
2026-01-26 18:55:36 +08:00
dap
1082ea90cf chore: 移除 Changesets 配置文件及相关文档
不再使用 Changesets 进行版本管理,因此删除其配置文件 config.json 和说明文档 README.md。
2026-01-26 18:54:27 +08:00
dap
edb887a7ed chore: 移除所有GitHub工作流和配置文件
移除不再需要的GitHub Actions工作流、依赖管理、语义化提交等配置文件,
以简化项目结构和维护工作
2026-01-26 18:54:04 +08:00
dap
1ec73473cf chore: 移除 playground 目录及相关配置
清理不再需要的 playground 项目,包括:
- 删除 playground 源码目录及所有相关文件
- 从 pnpm-workspace.yaml 移除 playground 工作区
- 从 .vscode 配置中移除 playground 相关路径
- 从 package.json 脚本中移除 build:play 和 dev:play 命令
- 从 vben-admin.code-workspace 移除 playground 项目引用
- 从 .vscode/launch.json 移除 playground 调试配置
2026-01-26 18:51:57 +08:00
dap
29028d7237 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into antdv-next 2026-01-26 18:50:23 +08:00
dap
09b147195a feat(popup-ui): 为抽屉和模态框添加确认按钮禁用状态
在 DrawerProps 接口中新增 confirmDisabled 属性,并在 drawer.vue 模板中绑定到确认按钮。
同时修改 modal-api.ts 和 drawer-api.ts 中的 modalLoading/drawerLoading 方法,
使其在 loading 时自动禁用确认按钮,防止用户在异步操作期间重复提交。
2026-01-26 18:45:06 +08:00
ming4762
528395e2c3 perf: optimizing hidden fields cannot trigger dependencies (#7142) 2026-01-26 16:12:26 +08:00
programmer
6a9012e5e4 chore: 给个人中心的2个按钮加上 i18n (#7138)
* fix: 个人中心按钮i18n

* fix: eslint format

* fix: 调整label宽度让英文显示在一行

* chore: 调整label小点

* fix: import

---------

Co-authored-by: Jin Mao <50581550+jinmao88@users.noreply.github.com>
2026-01-26 16:12:09 +08:00
橙子
6e8315ab40 fix: arguments order update (#7132)
Co-authored-by: Jin Mao <50581550+jinmao88@users.noreply.github.com>
2026-01-26 16:11:37 +08:00
Jin Mao
7cb2699f19 chore: 更新pnpm工作区配置
- 移除 neverBuiltDependencies 配置
- 移除 peerDependencyRules.allowedVersions 配置
- 重新整理 overrides 和 catalog 部分
- 保持 @ast-grep/napi 等依赖的目录引用配置
- 维持 eslint 版本约束在目录顶层配置中
2026-01-25 19:55:53 +08:00
Jin Mao
4b5da81ba6 chore(deps): 更新项目依赖包版本
- 更新 @playwright/test 从 1.57.0 到 1.58.0
- 更新 @tanstack/vue-query 从 5.92.8 到 5.92.9
- 更新 cheerio 从 1.1.2 到 1.2.0
- 更新 eslint-config-turbo 从 2.7.5 到 2.7.6
- 更新 playwright 从 1.57.0 到 1.58.0
- 更新 turbo 从 2.7.5 到 2.7.6
- 更新 vxe-pc-ui 从 4.12.10 到 4.12.12
- 更新 @babel/helper-define-polyfill-provider 从 0.6.5 到 0.6.6
- 更新 @cspell/dict-fullstack 从 3.2.7 到 3.2.8
- 更新 @cspell/dict-git 从 3.0.7 到 3.1.0
- 更新 @cspell/dict-node 从 5.0.8 到 5.0.9
- 更新 @cspell/dict-npm 从 5.2.29 到 5.2.30
- 更新 @parcel/watcher 相关包从 2.5.4 到 2.5.6
- 更新 @tanstack/query-core 从 5.90.19 到 5.90.20
- 更新 babel-plugin-polyfill 相关包到最新版本
- 更新 baseline-browser-mapping 从 2.9.17 到 2.9.18
- 更新 caniuse-lite 从 1.0.30001765 到 1.0.30001766
- 更新 electron-to-chromium 从 1.5.277 到 1.5.278
- 更新 eslint-plugin-turbo 从 2.7.5 到 2.7.6
- 更新 playwright-core 从 1.57.0 到 1.58.0
- 更新 turbo 平台特定版本到 2.7.6
- 更新 undici 从 7.19.0 到 7.19.1
2026-01-25 15:05:14 +08:00
Jin Mao
6aca9a9c99 test(dom): 更新元素可见区域计算的测试用例
- 修正了getElementVisibleRect函数的期望值断言
- 将bottom值从800更正为0以匹配实际计算结果
- 将left值从1100更正为0以匹配实际计算结果
- 将right值从1000更正为0以匹配实际计算结果
- 将top值从900更正为0以匹配实际计算结果
2026-01-25 14:22:22 +08:00
xingyu4j
fa195fde8e fix: lint 2026-01-23 14:48:21 +08:00
xingyu4j
1057f2932b chore: update deps 2026-01-23 14:48:06 +08:00
dap
682dc9a5d6 fix(monitor): 缩短过长操作系统名称显示
在在线用户和登录日志的表格列以及登录详情弹窗中,当操作系统字段包含“ or ”(如“Windows 10 or Windows Server 2016”)时,仅显示第一部分以优化表格显示宽度。完整的原始信息在详情中仍可查看。
2026-01-23 14:23:28 +08:00
Jin Mao
b9224fc379 Merge branch 'main' into fix 2026-01-23 13:48:54 +08:00
Jin Mao
57dd818170 Merge branch 'fork/kuchaguangjie/fix' 2026-01-23 13:47:54 +08:00
Jin Mao
49256ec1b7 Merge branch 'main' into fix 2026-01-23 13:46:59 +08:00
Jin Mao
f6f92e5403 Merge branch 'fork/kuchaguangjie/fix' 2026-01-23 13:45:38 +08:00
Jin Mao
613c311076 Merge branch 'fork/abcd0f/dev/sun-local' 2026-01-23 13:25:03 +08:00
Jin Mao
9ee7a7d9ff Merge branch 'fork/Child-qjj/patch-1' 2026-01-23 13:21:49 +08:00
橙子
44f8aed06d fix: timer not need reactivity (#7128) 2026-01-23 13:16:09 +08:00
dap
1539932556 fix(tenant-toggle): 修复租户选择器下拉菜单被遮挡问题
移除不再支持的 variant 属性,并为下拉菜单添加固定定位样式,避免在滚动时被遮挡
2026-01-23 11:50:21 +08:00
dap
d2e80b3ae0 refactor(web-antd): 替换图标组件为unocss内联图标
将 IconifyIcon 组件替换为 UnoCSS 的内联图标类,以简化依赖并提升性能
2026-01-23 11:45:35 +08:00
dap
657842336d docs(dashboard): 更新分析视图的变更日志
添加离线图标方案重构的说明,指导开发者在指定脚本中添加图标名称后执行生成命令
2026-01-23 11:41:46 +08:00
dap
f9c85bca3f chore(icons): 移除未使用的iconify图标包依赖
移除开发依赖中未实际使用的多个@iconify/icons-*包,仅保留ri和simple-icons。
这简化了依赖管理并减少了安装体积。
2026-01-23 11:39:44 +08:00
dap
fa4d16c542 feat(icons): 添加离线图标生成脚本并更新依赖
- 新增脚本 generate-offline-icons.js 用于自动生成离线图标集合
- 将手动维护的 menu-icons.ts 替换为脚本生成的 offline-icons.ts
- 更新 @iconify/json 依赖版本至 2.2.431
- 在 icons 包中添加 @iconify/json 作为工作区依赖
- 在根 package.json 中添加生成离线图标的 npm 脚本
2026-01-23 11:37:31 +08:00
dap
87706ad425 refactor(icons): 移除离线图标依赖并改用CSS类
移除 `@iconify/icons-flat-color-icons/folder`、`@iconify/icons-material-symbols/menu` 和 `@iconify/icons-mdi/button-pointer` 的显式导入与离线图标包装导出。将树组件和菜单视图中的图标使用方式从组件实例更改为CSS类(例如 `icons-[flat-color-icons--folder]`)。这消除了对特定离线图标包的依赖,使图标管理更统一并可能减少打包体积。
2026-01-23 11:21:01 +08:00
dap
d475b29e9f feat: 统一系统图标渲染方式并优化代码生成预览
- 将操作系统和浏览器图标从自定义组件改为使用 Iconify 类名,简化渲染逻辑
- 在登录信息和在线用户表格中,将操作系统图标与文本并排显示,提升可读性
- 重构代码生成预览功能,将图标配置移至独立文件,提高可维护性
- 更新 GitHub 图标引用,使用 Ant Design Vue 的 GithubOutlined 组件
2026-01-23 11:12:26 +08:00
Sun
d5d4a5c591 feat(effects-plugins): 添加 echarts 图表更新功能
新增 updateDate 方法用于更新 echarts 图表选项,支持合并配置、
完全替换和延迟更新等模式。该方法会在组件未初始化时自动执
行首次渲染,并能够合并全局配置如 backgroundColor 等选项。
2026-01-23 11:06:45 +08:00
dap
052d7d5cdd feat(monitor): 在浏览器列中同时显示图标和文本
重构浏览器图标渲染逻辑,使用 Iconify 图标集替代自定义 SVG 组件
- 修改 login-info-modal.vue 和 data.tsx 中的浏览器列显示,同时展示图标和浏览器名称
- 新增 online 监控页面的数据配置,包含浏览器和系统列
- 重写 render.tsx 中的 renderBrowserIcon 函数,支持 Iconify 在线/离线图标
- 清理 icons 包中已不再使用的浏览器相关离线图标定义
2026-01-23 10:49:39 +08:00
dap
948dc9b520 refactor(icons): 迁移部分图标到 @ant-design/icons-vue 并移除未使用的离线图标
移除 @vben/icons 中的 UserOutlined、InBoxIcon、ExcelIcon 等图标,改用 @ant-design/icons-vue 提供的对应组件。
删除 packages/icons 中未使用的离线图标定义,包括 TaobaoIcon、AlipayIcon、GithubOAuthIcon 等。
在 apps/web-antd/src/views/_core/ 新增 oauth-common.tsx 文件,集中管理 OAuth 绑定相关逻辑与数据。
2026-01-23 10:42:52 +08:00
dap
46fa96f556 refactor(icons): 将缓存监控页面的图标替换为内联iconify离线图标
移除从@vben/icons导入的RedisIcon、CommandLineIcon和MemoryIcon组件,
改为使用内联的iconify离线图标类名。同时清理packages/icons中不再使用的图标导出,
以保持图标库的简洁性。
2026-01-23 10:30:12 +08:00
dap
82c6674e7c refactor(monitor/cache): 使用 CSS Grid 替换 Ant Design Row/Col 布局
将 Redis 监控页面的布局从 Ant Design 的 Row/Col 组件迁移到 Tailwind CSS 的 Grid 系统,以简化代码结构并提高布局灵活性。

- 移除未使用的 Row、Col 组件导入和 baseSpan 变量
- 使用 grid-cols-1 和 lg:grid-cols-2 实现响应式网格布局
- 通过 lg:col-span-2 让 Redis 信息卡片跨两列显示
- 使用 gap-4 统一设置卡片间距
2026-01-23 10:26:03 +08:00
dap
49736f49a4 docs(dashboard/analytics): 更新已知问题文档
- 移除已解决的夜间模式切换和primary颜色问题
- 添加图片预览无效问题
2026-01-22 20:52:44 +08:00
yuhengshen
74381aa8c1 fix: 嵌套弹窗,错误 merge options (#7126) 2026-01-22 20:07:13 +08:00
橙子
203ee9b623 fix(@vben-core/shared): element outside viewport, the element visible rect each prop expect 0 (#7120)
* fix(@vben-core/shared): element outside viewport

* fix(@vben-core/shared): element outside viewport
2026-01-22 11:37:01 +08:00
JyQAQ
6c8c49966a Perf: 优化antd upload组件参数获取 (#7114)
* perf(antd upload params): 优化组件参数取值 确保不同调用场景配置参数可用

* perf(antd upload params): 优化组件参数取值 确保不同调用场景配置参数可用

* perf(antd upload params): 优化组件参数取值 确保不同调用场景配置参数可用

* perf(antd upload params): 优化组件参数取值 确保不同调用场景配置参数可用
2026-01-21 17:20:53 +08:00
Qiu
3862942e9f fix: chart instance disposal condition
dom has been disposed in vue3 v-if,but chartInstance exist
2026-01-21 11:47:01 +08:00
dap
919f166c16 docs(dashboard): 更新分析页面框架变更文档
- 补充表格操作列样式名称变更说明
- 添加静态方法调用注意事项
2026-01-20 12:02:00 +08:00
dap
f0253f6971 refactor(components): 重命名 GhostButton 为 ActionButton 以更准确描述用途 2026-01-20 12:00:59 +08:00
dap
c1b886e77f refactor(web-antd): 移除ConfigProvider的variant属性并设置默认弹窗配置
移除ConfigProvider组件中不再需要的variant属性
设置默认弹窗配置,禁用全屏按钮并添加缩放动画效果
2026-01-20 11:54:35 +08:00
dap
31b332a87f refactor(upload): 优化图片预览逻辑,移除未使用的标题状态
重构图片预览功能,移除未使用的previewTitle状态,拆分handleCancel为handleOpenChange和handleAfterOpenChange以更精确控制预览状态
2026-01-20 11:48:38 +08:00
dap
b6afd5fbb8 fix(oss): 修正文件上传和图片上传模态框中的文件列表类型
将fileList从字符串数组类型改为字符串类型,并在清空时赋值为空字符串而非空数组
2026-01-20 11:39:09 +08:00
dap
7b74975819 feat(oss): 添加测试上传功能
新增上传测试模态框组件,支持图片和文件上传测试
在OSS管理页面添加测试上传按钮
为上传API添加Content-Type头部配置
修复全屏引导hook的类型断言问题
2026-01-20 11:29:56 +08:00
dap
1246f8f77b refactor(upload): 修改文件上传组件绑定值为字符串类型
将文件上传组件的双向绑定值从字符串或字符串数组统一修改为字符串类型,使用逗号分隔多个文件ID
简化值处理逻辑,避免数组类型判断和操作
2026-01-20 11:19:32 +08:00
dap
7bb7e8b636 docs(dashboard): 更新分析页面中框架级别变化的文档
添加v1版本requestClient替换说明及context获取注意事项
记录version-polling和字典常量enum的变更
2026-01-20 11:09:47 +08:00
dap
efbd8e9bd1 fix(upload): 修复组件卸载时未正确中止所有上传请求的问题
将单个AbortController改为存储多个中止函数,确保所有上传请求都能在组件卸载时被正确中止
2026-01-20 11:08:35 +08:00
dap
3582807910 refactor: 迁移requestClient到alovaInstance并移除旧版上传组件
重构项目中所有使用requestClient的API调用,替换为alovaInstance
移除已废弃的旧版上传组件及相关代码
调整上传组件类型定义以适配antdv-next更新
优化上传逻辑,移除不必要的进度事件和取消信号
更新类型定义文件,迁移axios配置到alova类型
2026-01-19 21:58:07 +08:00
dap
fcc3daf904 refactor(http): 统一HTTP方法命名并添加消息提示功能
将大写的HTTP方法改为小写命名以提高一致性
添加带消息提示的HTTP方法变体
2026-01-19 19:15:43 +08:00
dap
736fa21410 refactor(http): 统一错误和成功消息的元数据字段命名
将 showErrorMessage 和 showSuccessMessage 重命名为 errorMessageMode 和 successMessageMode
2026-01-19 19:07:55 +08:00
dap
8b0cf671b5 feat(http): 实现基于alova的HTTP请求模块
添加HTTP请求核心模块,包括异常处理、状态码检查、消息提示等功能
- 新增alova实例配置,支持请求加密、token添加等特性
- 实现401状态码自动处理及登出逻辑
- 添加多种消息提示方式(message/modal/notification)
- 支持请求成功/失败的统一处理
- 添加WithMessage方法简化成功提示
- 更新相关依赖配置
2026-01-19 19:05:37 +08:00
dap
c713828037 fix(登录页面): 将密码输入框组件从Input.Password替换为InputPassword 2026-01-19 17:53:03 +08:00
xingyu
8571fc43b0 Merge branch 'main' into fix 2026-01-19 15:28:12 +08:00
JyQAQ
59aabd956d Perf: Optimization of cropping component result acquisition & optimization of cropping frame prompts (#7111)
* perf(cropper): enhance image cropping functionality and add output type support

* perf(cropper): enhance image cropping functionality and add output type support
2026-01-19 14:18:36 +08:00
xingyu
9b09ba4483 Merge branch 'main' into fix 2026-01-19 10:54:43 +08:00
dap
946b148cfa refactor(tenant-toggle): 重命名事件处理函数以提高可读性
将 onSelected 和 onDeselect 分别重命名为 handleSelect 和 handleClear,使其更符合事件处理函数的命名约定
2026-01-16 17:05:36 +08:00
dap
62abaedbdb refactor(tenant-toggle): 更新SelectProps为SelectEmits类型
修改导入类型以匹配antdv-next的更新,保持类型一致性
2026-01-16 17:03:36 +08:00
dap
1f859c45fa refactor(tenant-toggle): 移除未使用的getPopupContainer属性 2026-01-16 16:57:33 +08:00
dap
2a5c45e15c refactor(tenant): 替换 TableSwitch 为 ApiSwitch 并统一状态切换逻辑
将租户和租户套餐列表中的 TableSwitch 组件替换为 ApiSwitch,并统一处理状态切换逻辑。使用 EnableStatus 常量来管理状态值,提高代码可维护性。
2026-01-16 14:22:09 +08:00
dap
1f643874a9 refactor: 移除 Modal 组件直接导入,统一使用 window.modal 调用
将项目中直接导入的 antdv-next Modal 组件替换为通过 window.modal 调用,提升代码一致性
删除不再使用的 table-switch.vue 组件
2026-01-16 11:21:23 +08:00
dap
20f9a8a497 fix(tenant): 修复租户管理中日期类型转换问题
将DatePicker绑定值从string改为Dayjs类型,并在提交时转换为string格式
使用window.modal代替Modal直接调用,移除冗余的iconType配置
2026-01-16 10:45:38 +08:00
dap
e5bbaf5f9a feat(客户端管理): 优化客户端管理界面功能
- 添加默认客户端ID常量
- 重构密钥输入组件使用SpaceCompact布局
- 替换TableSwitch为ApiSwitch并优化状态切换逻辑
2026-01-16 09:36:49 +08:00
dap
29e0d0437e refactor(views): 移除未使用的getVxePopupContainer导入和属性
清理工作流分类、系统字典类型和数据视图中的冗余代码,移除不再需要的getVxePopupContainer工具函数导入及其相关属性配置
2026-01-16 09:30:00 +08:00
dap
fbd5b64345 feat(oss-config): 添加YesNo常量并优化OSS配置表单
在constants/core.ts中添加YesNo常量
移除oss-config表单中多余的formItemClass属性
将TableSwitch替换为ApiSwitch并实现状态切换功能
2026-01-15 10:14:16 +08:00
dap
884c4f39fd refactor(antd): 移除Popconfirm中已废弃的getVxePopupContainer属性
antd已支持滚动跟随,不再需要手动指定getVxePopupContainer属性。删除相关代码及工具函数,简化实现。
2026-01-15 10:07:06 +08:00
dap
448856e547 feat(role): 添加角色管理相关常量并优化角色状态切换
refactor(role): 使用常量替换硬编码的角色ID和key
fix(role): 修正角色排序默认值为1
feat(component): 导出ApiSwitch全局组件
2026-01-15 10:03:39 +08:00
dap
07fa5626fd refactor(component): 移除默认的variant属性设置 2026-01-15 09:57:49 +08:00
dap
3c8aac0203 docs(dashboard): 更新分析页面文档,添加Switch组件限制说明 2026-01-15 09:56:44 +08:00
dap
b84eabf1c9 feat(常量): 添加超级管理员ID和启用状态常量
在核心常量文件中添加 SUPERADMIN_USER_ID 和 EnableStatus 常量
在用户管理页面中使用新常量替代硬编码值
2026-01-15 09:54:42 +08:00
dap
35c96b3a9e refactor(constants): 将字典枚举从core/shared移动到@vben/constants
将字典枚举相关常量从packages/@core/base/shared/src/constants移动到packages/constants模块
更新相关导出和导入路径,保持功能不变但改善代码组织结构
2026-01-15 09:41:41 +08:00
dap
ee1b37c787 refactor(antdv-next): 将message组件调用统一改为window.message
将项目中直接导入的antdv-next的message组件调用改为通过window.message调用,提升代码一致性
移除不再需要的message组件导入
新增api-switch组件用于统一处理状态切换逻辑
2026-01-15 09:35:54 +08:00
dap
2312f438ac docs: 更新dashboard分析页面的已知问题列表 2026-01-14 21:57:35 +08:00
dap
63349395cf style(authentication): 调整验证码图片宽度从115px到150px 2026-01-14 21:48:23 +08:00
dap
64ecf47310 refactor(authentication): 使用 SpaceCompact 重构验证码输入组件布局
移除自定义的输入框圆角样式,改用 SpaceCompact 组件实现更一致的布局
2026-01-14 21:41:40 +08:00
橙子
686c3f9208 docs(@vben-core/preferences): update comments (#7107) 2026-01-14 19:36:45 +08:00
dap
32d395fbab docs(dashboard): 更新分析页面文档,添加框架级别变化说明
添加关于使用`version-polling`替代自带版本检测更新的说明,优化样式并在worker执行以避免阻塞主线程
2026-01-14 17:21:21 +08:00
dap
0ef6eb2502 feat(version): 添加版本更新检测功能
添加 version-polling 依赖并实现版本更新检测功能
移除旧的 CheckUpdates 组件,改用新的版本检测方案
2026-01-14 17:20:01 +08:00
dap
56c8c3db9a style(analytics): 为 MarkdownPreviewer 添加底部间距类名 2026-01-14 16:45:22 +08:00
dap
f47ff98160 fix(analytics): 修复分析页面加载状态并更新变更文档
添加Spin组件处理Markdown预览加载状态
更新change.md文档,移除已废弃组件并添加已知问题
2026-01-14 16:44:16 +08:00
dap
910dc5f3fb docs(dashboard): 更新analytics变更文档中的描述和框架变化
- 修正RadioGroup效果的描述从"水波纹"改为"波纹"
- 补充框架级别变化说明,关于message/modal/notification的context获取问题
2026-01-14 16:39:37 +08:00
dap
7c8e962a01 fix(form-field): 移除overflow-hidden以修复radio波纹效果显示问题 2026-01-14 16:37:14 +08:00
dap
76d698f670 style(web-antd): 更新颜色配置与移除未使用的Modal导入
更新主题颜色配置以保持与antd默认颜色一致
移除upload-tip中未使用的Modal导入,改为使用window.modal
2026-01-14 15:54:11 +08:00
dap
ba65f750d4 feat(全局): 添加全局弹窗上下文组件并声明类型
添加 PopupContext 组件用于全局提供 message、modal 和 notification 方法
在 global.d.ts 中声明对应的 window 类型
将 analytics 页面的 notification 调用改为使用全局方法
2026-01-14 15:45:39 +08:00
dap
5776672901 style(antd): 移除导致页面无法滚动的样式并清理注释代码
移除 overscroll-behavior 属性以修复页面滚动问题
清理不再使用的按钮和标签样式代码
2026-01-14 15:45:28 +08:00
MRSWC
8a7e2bd8e4 fix:修复默认默认首页如果携带参数时刷新页面参数丢失问题 (#7102)
Co-authored-by: chenwei <chenw@jiuzhekan.com>
2026-01-14 15:38:55 +08:00
JyQAQ
174c4ae749 fix(antd Upload onChange Event): rewrite onChange event to handle upl… (#7098)
* fix(antd Upload onChange Event): rewrite onChange event to handle upload success or error messages

* fix(antd Upload onChange Event): rewrite onChange event to handle upload success or error messages

* fix(antd Upload onChange Event): rewrite onChange event to handle upload success or error messages
2026-01-14 15:38:21 +08:00
JyQAQ
67da9417a8 feat(upload prop:crop,aspectRatio): from Upload component accept prop… (#7095)
* feat(upload prop:crop,aspectRatio): from Upload component accept prop crop,aspectRatio

* feat(upload prop:crop,aspectRatio): from Upload component accept prop crop,aspectRatio

* feat(upload prop:crop,aspectRatio): from Upload component accept prop crop,aspectRatio

* feat(upload prop:crop,aspectRatio): from Upload component accept prop crop,aspectRatio
2026-01-14 15:38:05 +08:00
dap
35e8549dcc refactor(auth): 移除登录成功后的测试通知代码
feat(analytics): 添加antdv-next变更说明文档和演示功能
2026-01-14 15:18:58 +08:00
dap
bc8ee604fb fix(notification): 统一使用title属性替代message属性
refactor: 将notification的message属性替换为title属性以保持一致性
feat: 在登录成功时添加新的notification样式演示
docs: 添加antdv-next替换ant-design-vue的提示
2026-01-14 14:55:41 +08:00
dap
2f6fd30fa7 docs: 更新中文README文档,添加antdv-next说明并调整表格格式 2026-01-13 21:57:20 +08:00
dap
e73f90bb05 refactor(dict): 重构字典标签展示逻辑使用 TSX 语法
将字典标签的展示逻辑从模板语法重构为 TSX 语法,使用 Descriptions 组件的 items 属性统一管理
修复 class 属性顺序不一致的问题,提升代码可维护性
2026-01-13 21:56:15 +08:00
dap
9428b44e30 refactor(workflow): 重构审批时间线组件,将头像逻辑移至父组件
将审批时间线项中的头像显示逻辑移动到父组件中统一管理
简化子组件代码并提高一致性
2026-01-13 21:52:20 +08:00
dap
5c30bcdefa refactor(views): 优化组件代码结构,使用tsx和计算属性重构描述列表
重构多个组件中的描述列表,使用tsx语法和计算属性items来简化模板代码
统一调整样式类名顺序,提升代码可读性和维护性
2026-01-13 21:45:21 +08:00
dap
b427a77fc1 refactor(workflow): 优化审批组件代码结构
重构审批卡片组件,使用 items 属性替代 DescriptionsItem 子组件
修复 Textarea 组件名称大小写问题
调整样式类顺序保持一致性
2026-01-13 21:35:05 +08:00
dap
58071810d9 refactor(redis-description): 重构 Redis 描述组件使用 computed 属性
使用 computed 属性动态生成 Descriptions 的 items 配置,提升代码可维护性
移除模板中的硬编码,使数据结构更清晰
2026-01-13 21:32:55 +08:00
dap
2ca75d7bf0 refactor: 简化默认过期时间的计算逻辑 2026-01-13 21:29:09 +08:00
dap
1cee71e18f refactor(login-info-modal): 使用 computed 重构描述列表项以提高可维护性 2026-01-13 21:26:47 +08:00
dap
935e86cdeb refactor(monitor): 重构操作日志预览组件使用 TSX 语法
使用 TSX 语法重写操作日志预览组件,简化模板代码并提高可维护性
移除 DescriptionsItem 组件,改用 items 属性配置描述项
2026-01-13 21:24:57 +08:00
dap
5fc59de0e9 refactor(notice-modal): 重构表单验证逻辑,使用FormInstance替代useForm
使用antdv-next的FormInstance替代原有的useForm方法,简化表单验证逻辑
表单验证规则类型从RuleObject更新为Rule以匹配新API
2026-01-13 21:14:29 +08:00
dap
2d68ff0d61 refactor(web-antd): 移除vue3-colorpicker依赖并使用antdv-next的ColorPicker
替换vue3-colorpicker为antdv-next内置的ColorPicker组件,简化依赖并统一组件库
2026-01-13 20:59:21 +08:00
dap
0ab5c46812 refactor(按钮样式): 替换btn-success类为variant和color属性
使用variant="link"和color="green"替代原有的btn-success类,统一按钮样式实现方式
2026-01-13 20:25:02 +08:00
dap
ff39e65d81 refactor(tenant-toggle): 使用getPopupContainer替代固定样式
移除Select组件的固定定位样式,改用getPopupContainer方法统一管理弹出层容器
2026-01-13 20:23:15 +08:00
dap
cc2f96b691 refactor(tenant-toggle): 更新antdv-next类型导入和下拉样式配置
更新Select组件类型导入为antdv-next的SelectProps,并调整下拉菜单样式配置格式以匹配最新API
2026-01-13 20:21:57 +08:00
dap
e4ab0bc359 refactor(菜单管理): 移除无用id属性并简化样式定义 2026-01-13 20:16:17 +08:00
dap
cb94bc5eca fix(menu): 修复子菜单按钮样式并更新组件类型声明
更新GhostButton的样式属性,将class改为variant和color
同时优化全局组件类型声明,直接引用Button类型
2026-01-13 20:16:02 +08:00
dap
efe744cfdd refactor(用户管理): 优化用户信息展示和操作菜单逻辑
重构用户信息模态框中的登录时间显示,移除重复代码并优化标签渲染
将用户列表中的操作菜单改为计算属性方式,简化模板代码
2026-01-13 19:58:30 +08:00
dap
0626b65c74 refactor(components): 移除废弃的Description组件并改用原生antd组件
移除已废弃的Description组件及其相关类型定义和hook,替换为直接使用antd原生Descriptions组件
更新user-reset-pwd-modal和user-info-modal使用新的实现方式
2026-01-13 19:40:17 +08:00
ppxb
f4a4ced88d fix: header auto mode issue (#7096) 2026-01-12 21:40:26 +08:00
dap
296bcbd857 fix(button): 将幽灵按钮类型从primary改为link并移除ghost属性 2026-01-12 11:28:37 +08:00
ppxb
19b2d7af41 fix: tdesign theme toggle and demos (#7087) 2026-01-10 14:11:08 +08:00
yuhengshen
343d8a1c1e fix: 切换时区后,页面不刷新 (#7085)
* fix: 切换时区后,页面不刷新

* fix: keep-alive 的页面,i18n 和 timezone 不更新
2026-01-10 14:10:27 +08:00
JyQAQ
9480f8272a feat(common-ui cropper): Implement the image cropping component VCropper (#7082)
* feat(common-ui cropper): Implement the image cropping component VCropper

* feat(common-ui cropper): Implement the image cropping component VCropper

* feat(common-ui cropper): Implement the image cropping component VCropper

* feat(common-ui cropper): Implement the image cropping component VCropper

* feat(common-ui cropper): Implement the image cropping component VCropper
2026-01-10 14:08:15 +08:00
ppxb
0d9e260a6a fix: vite.config.mts type error (#7081) 2026-01-10 14:07:28 +08:00
ppxb
51bca25345 fix(lint): pnpm format lint warning (#7080) 2026-01-10 14:06:03 +08:00
eric
694396dcfb refactor: move cleanup to finally block 2026-01-09 23:22:49 +08:00
eric
1cb53e943e refactor: 将跳转放到最后 2026-01-09 23:13:06 +08:00
eric
13c8318adc refactor: 1. 用 ref 包装 flag; 2. 在最后 清理 flag; 2026-01-09 23:05:05 +08:00
eric
48ed797055 fix: 防止 /logout 死循环 2026-01-09 22:38:11 +08:00
dap
a208034539 init: antdv-next 2026-01-08 20:56:07 +08:00
dap
1383f63361 refactor: 使用antd组件替换密码登录表单
- 废弃原有的shadcn-ui验证码组件,改用antd实现
- 更新登录表单中的验证码输入组件为新的antd实现
- 调整表单布局和样式
2026-01-08 11:47:37 +08:00
dap
dbe8beb7f9 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2026-01-08 11:18:02 +08:00
xingyu4j
3c2285141c chore: update deps 2026-01-06 13:58:42 +08:00
xingyu
49b884c0b1 Merge branch 'main' into fix 2026-01-06 13:50:26 +08:00
ppxb
24d20ca9ee refactor: preference manager and export (#7068)
* fix: preferences drawer outline z-index

* refactor: preferencesManager and exports
2026-01-06 12:42:32 +08:00
wyc001122
6f02181024 fix(layout): 修复双列模式下重复显示logo的问题(#7071) (#7072) 2026-01-05 21:13:06 +08:00
dap
3566191cd1 merge 2026-01-05 20:42:25 +08:00
ppxb
ed3353a271 fix: preferences drawer outline z-index (#7067) 2026-01-04 14:44:33 +08:00
xingyu4j
965f5f96b7 chore: update deps 2026-01-04 11:03:19 +08:00
xingyu4j
61d9df7f58 feat: add cascader cspell:words 2026-01-04 11:00:07 +08:00
xingyu4j
231a5169ec fix: lint 2026-01-04 10:56:55 +08:00
xingyu4j
ce7b7b910a Merge branch 'main' of https://github.com/xingyu4j/vue-vben-admin into fix 2026-01-04 10:56:14 +08:00
JyQAQ
81a61558cb feat(upload prop:maxSize): from Upload component accept prop maxSize (AI prompt fixed) (#7059)
* feat(upload prop:maxSize): from component accept prop maxSize

* feat(upload prop:maxSize): from component accept prop maxSize

* feat(upload prop:maxSize): from component accept prop maxSize

* feat(upload prop:maxSize): from component accept prop maxSize
2026-01-03 13:19:40 +08:00
ppxb
7d2bc2e885 fix: dropdown raido menu type error (#7062)
* fix: dropdown raido menu type

* chore: format code
2026-01-02 14:25:19 +08:00
luoqiz
89b237f6b4 feat: 添加上下文菜单演示,添加菜单项隐藏性 (#7057)
Co-authored-by: luoqiz <851092732@qq.com>
2026-01-02 14:22:19 +08:00
JyQAQ
a1bb132233 feat(api-cascader): 添加联级组件ApiCascader (#7031) 2025-12-22 20:00:31 +08:00
zhenghaoyang24
022d538940 Fix formatting in thin.md for clarity (#7008)
修改一些语句错误
2025-12-22 19:58:05 +08:00
xueyitt
ccf70a1b76 feat: 修正菜单排序在二级菜单不生效问题 (#7007)
* treeUtil增加对树形结构数据进行递归排序

* 菜单sort排序各级菜单均生效
2025-12-22 19:57:21 +08:00
xingyu4j
af3fe53ec8 fix: type error 2025-12-22 17:50:06 +08:00
xingyu4j
e981fb159f chore: update deps 2025-12-22 17:49:51 +08:00
xingyu
79b9d55854 Merge branch 'main' into fix 2025-12-22 16:42:15 +08:00
xingyu4j
b2055a4457 chore: update deps 2025-12-17 13:47:37 +08:00
JyQAQ
1479f159aa feat(CellImage): CellImage组件支持图片属性写入 (#6992) 2025-12-06 10:12:58 +08:00
xingyu4j
7bf7e09002 fix: lint 2025-12-05 15:09:43 +08:00
xingyu4j
de8d39ffed chore: workspace file is deprecated 2025-12-05 15:07:39 +08:00
xingyu4j
543a7e3962 chore: update deps 2025-12-05 14:55:44 +08:00
xingyu4j
9dfe3f5af8 fix: type not find 2025-12-04 18:03:55 +08:00
xingyu4j
f11b08d8cb chore: update deps 2025-12-04 17:59:12 +08:00
xingyu4j
45b6f08984 chore: neverBuiltDependencies 2025-12-03 16:34:14 +08:00
xingyu4j
92a4676f8d chore: update version 2025-12-03 16:27:14 +08:00
xingyu4j
7bf7c0bb06 chore: remove unused deps 2025-12-03 16:26:58 +08:00
xingyu4j
8f8cf5b704 chore: update deps 2025-12-03 16:22:14 +08:00
xingyu4j
6be238430d chore: add cspell 2025-12-03 16:12:08 +08:00
xingyu4j
f77216d8f4 feat: lint add pnpm config 2025-12-03 16:11:51 +08:00
xingyu4j
d42a9b2409 feat: lint add yaml config 2025-12-03 16:01:27 +08:00
xingyu4j
6753834054 fix: lint 2025-12-03 15:37:33 +08:00
xingyu4j
77a4a64eb4 fix: stylelint 2025-12-03 15:37:20 +08:00
xingyu4j
49db40d557 feat: cspell sort 2025-12-03 15:37:04 +08:00
xingyu4j
0032c608f1 chore: update deps 2025-12-03 15:36:43 +08:00
xingyu4j
fa603b32b1 fix: locales 2025-12-03 13:51:30 +08:00
JyQAQ
9105d4d14a feat(api-component): api-component组件的options支持指定disabled值 (#6991) 2025-12-03 10:03:23 +08:00
luoqiz
c76db7d8d1 fix: 修复icon丢失根属性导致的样式错误 (#6986) 2025-12-01 09:51:27 +08:00
843 changed files with 9621 additions and 143670 deletions

View File

@@ -1,5 +0,0 @@
# Changesets
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works with multi-package repos, or single-package repos to help you version and publish your code. You can find the full documentation for it [in our repository](https://github.com/changesets/changesets)
We have a quick list of common questions to get you started engaging with this project in [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)

View File

@@ -1,18 +0,0 @@
{
"$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
"changelog": [
"@changesets/changelog-github",
{ "repo": "vbenjs/vue-vben-admin" }
],
"commit": false,
"fixed": [["@vben-core/*", "@vben/*"]],
"snapshot": {
"prereleaseTemplate": "{tag}-{datetime}"
},
"privatePackages": { "version": true, "tag": true },
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}

14
.github/CODEOWNERS vendored
View File

@@ -1,14 +0,0 @@
# default onwer
* anncwb@126.com vince292007@gmail.com netfan@foxmail.com jinmao88@qq.com
# vben core onwer
/.github/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com jinmao88@qq.com
/.vscode/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com jinmao88@qq.com
/packages/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com jinmao88@qq.com
/packages/@core/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com jinmao88@qq.com
/internal/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com jinmao88@qq.com
/scripts/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com jinmao88@qq.com
# vben team onwer
apps/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com @vbenjs/team-v5 jinmao88@qq.com
docs/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com @vbenjs/team-v5 jinmao88@qq.com

View File

@@ -1,74 +0,0 @@
name: 🐞 Bug Report
description: Report an issue with Vben Admin to help us make it better.
title: 'Bug: '
labels: ['bug: pending triage']
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: dropdown
id: version
attributes:
label: Version
description: What version of our software are you running?
options:
- Vben Admin V5
- Vben Admin V2
default: 0
validations:
required: true
- type: textarea
id: bug-desc
attributes:
label: Describe the bug?
description: A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us in the description. Thanks!
placeholder: Bug Description
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Reproduction
description: Please provide a link to [StackBlitz](https://stackblitz.com/fork/github/vitest-dev/vitest/tree/main/examples/basic?initialPath=__vitest__/) (you can also use [examples](https://github.com/vitest-dev/vitest/tree/main/examples)) or a github repo that can reproduce the problem you ran into. A [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) is required unless you are absolutely sure that the issue is obvious and the provided information is enough to understand the problem. If a report is vague (e.g. just a generic error message) and has no reproduction, it will receive a "needs reproduction" label. If no reproduction is provided after 3 days, it will be auto-closed.
placeholder: Reproduction
validations:
required: true
- type: textarea
id: system-info
attributes:
label: System Info
description: Output of `npx envinfo --system --npmPackages '{vue}' --binaries --browsers`
render: shell
placeholder: System, Binaries, Browsers
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell
- type: checkboxes
id: terms
attributes:
label: Validations
description: Before submitting the issue, please make sure you do the following
# description: By submitting this issue, you agree to follow our [Code of Conduct](https://example.com).
options:
- label: Read the [docs](https://doc.vben.pro/)
required: true
- label: Ensure the code is up to date. (Some issues have been fixed in the latest version)
required: true
- label: I have searched the [existing issues](https://github.com/vbenjs/vue-vben-admin/issues) and checked that my issue does not duplicate any existing issues.
required: true
- label: Check that this is a concrete bug. For Q&A open a [GitHub Discussion](https://github.com/vbenjs/vue-vben-admin/discussions) or join our [Discord Chat Server](https://discord.gg/8GuAdwDhj6).
required: true
- label: The provided reproduction is a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) of the bug.
required: true

View File

@@ -1,38 +0,0 @@
name: 📚 Documentation
description: Report an issue with Vben Admin Website to help us make it better.
title: 'Docs: '
labels: [documentation]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this issue!
- type: checkboxes
id: documentation_is
attributes:
label: Documentation is
options:
- label: Missing
- label: Outdated
- label: Confusing
- label: Not sure?
- type: textarea
id: description
attributes:
label: Explain in Detail
description: A clear and concise description of your suggestion. If you intend to submit a PR for this issue, tell us in the description. Thanks!
placeholder: The description of ... page is not clear. I thought it meant ... but it wasn't.
validations:
required: true
- type: textarea
id: suggestion
attributes:
label: Your Suggestion for Changes
validations:
required: true
- type: textarea
id: reproduction-steps
attributes:
label: Steps to reproduce
description: Please provide any reproduction steps that may need to be described. E.g. if it happens only when running the dev or build script make sure it's clear which one to use.
placeholder: Run `pnpm install` followed by `pnpm run docs:dev`

View File

@@ -1,70 +0,0 @@
name: ✨ New Feature Proposal
description: Propose a new feature to be added to Vben Admin
title: 'FEATURE: '
labels: ['enhancement: pending triage']
body:
- type: markdown
attributes:
value: |
Thank you for suggesting a feature for our project! Please fill out the information below to help us understand and implement your request!
- type: dropdown
id: version
attributes:
label: Version
description: What version of our software are you running?
options:
- Vben Admin V5
- Vben Admin V2
default: 0
validations:
required: true
- type: textarea
id: description
attributes:
label: Description
description: A detailed description of the feature request.
placeholder: Please describe the feature you would like to see, and why it would be useful.
validations:
required: true
- type: textarea
id: proposed-solution
attributes:
label: Proposed Solution
description: A clear and concise description of what you want to happen.
placeholder: Describe the solution you'd like to see
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives Considered
description: |
A clear and concise description of any alternative solutions or features you've considered.
placeholder: Describe any alternative solutions or features you've considered
validations:
required: false
- type: input
id: additional-context
attributes:
label: Additional Context
description: Add any other context or screenshots about the feature request here.
placeholder: Any additional information
validations:
required: false
- type: checkboxes
id: checkboxes
attributes:
label: Validations
description: Before submitting the issue, please make sure you do the following
options:
- label: Read the [docs](https://doc.vben.pro/)
required: true
- label: Ensure the code is up to date. (Some issues have been fixed in the latest version)
required: true
- label: I have searched the [existing issues](https://github.com/vbenjs/vue-vben-admin/issues) and checked that my issue does not duplicate any existing issues.
required: true

View File

@@ -1,40 +0,0 @@
name: 'Setup Node'
description: 'Setup node and pnpm'
runs:
using: 'composite'
steps:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version-file: .node-version
cache: 'pnpm'
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
if: ${{ github.ref_name == 'main' }}
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- uses: actions/cache/restore@v4
if: ${{ github.ref_name != 'main' }}
with:
path: ${{ env.STORE_PATH }}
key: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
shell: bash
run: pnpm install --frozen-lockfile

View File

@@ -1,89 +0,0 @@
## Git Commit Message Convention
> This is adapted from [Angular's commit convention](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular).
#### TL;DR:
Messages must be matched by the following regex:
```js
/^(revert: )?(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|types|wip): .{1,50}/;
```
#### Examples
Appears under "Features" header, `dev` subheader:
```
feat(dev): add 'comments' option
```
Appears under "Bug Fixes" header, `dev` subheader, with a link to issue #28:
```
fix(dev): fix dev error
close #28
```
Appears under "Performance Improvements" header, and under "Breaking Changes" with the breaking change explanation:
```
perf(build): remove 'foo' option
BREAKING CHANGE: The 'foo' option has been removed.
```
The following commit and commit `667ecc1` do not appear in the changelog if they are under the same release. If not, the revert commit appears under the "Reverts" header.
```
revert: feat(compiler): add 'comments' option
This reverts commit 667ecc1654a317a13331b17617d973392f415f02.
```
### Full Message Format
A commit message consists of a **header**, **body** and **footer**. The header has a **type**, **scope** and **subject**:
```
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
The **header** is mandatory and the **scope** of the header is optional.
### Revert
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body, it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
### Type
If the prefix is `feat`, `fix` or `perf`, it will appear in the changelog. However, if there is any [BREAKING CHANGE](#footer), the commit will always appear in the changelog.
Other prefixes are up to your discretion. Suggested prefixes are `docs`, `chore`, `style`, `refactor`, and `test` for non-changelog related tasks.
### Scope
The scope could be anything specifying the place of the commit change. For example `dev`, `build`, `workflow`, `cli` etc...
### Subject
The subject contains a succinct description of the change:
- use the imperative, present tense: "change" not "changed" nor "changes"
- don't capitalize the first letter
- no dot (.) at the end
### Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes". The body should include the motivation for the change and contrast this with previous behavior.
### Footer
The footer should contain any information about **Breaking Changes** and is also the place to reference GitHub issues that this commit **Closes**.
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.

39
.github/config.yml vendored
View File

@@ -1,39 +0,0 @@
# Prevent issues being created without using the template
blank_issues_enabled: false
checkIssueTemplate: true
checkPullRequestTemplate: true
contact_links:
- name: 💬 Discord Chat
url: https://discord.gg/8GuAdwDhj6
about: Ask questions and discuss with other Vben users in real time.
- name: ❓ Questions & Discussions
url: https://github.com/@vbenjs/vue-vben-admin/discussions
about: Use GitHub discussions for message-board style questions and discussions.
# Comment to be posted to on PRs from first time contributors in your repository
newPRWelcomeComment: |
💖 Thanks for opening this pull request! 💖
Please be patient and we will get back to you as soon as we can.
# Comment to be posted to on pull requests merged by a first time user
firstPRMergeComment: >
Thanks for your contribution! 🎉🎉🎉
# Comment to be posted to on first time issues
newIssueWelcomeComment: >
Thanks for opening your first issue! Be sure to follow the issue template and provide every bit of information to help the developers!
# *OPTIONAL* default titles to check against for lack of descriptiveness
# MUST BE ALL LOWERCASE
requestInfoDefaultTitles:
- update readme.md
- updates
# *Required* Comment to reply with
requestInfoReplyComment: >
Thanks for filing this issue/PR! It would be much appreciated if you could provide us with more information so we can effectively analyze the situation in context.

View File

@@ -1,40 +0,0 @@
# Vben Admin Contributing Guide
Hi! We're really excited that you are interested in contributing to Vben Admin. Before submitting your contribution, please make sure to take a moment and read through the following guidelines:
- [Pull Request Guidelines](#pull-request-guidelines)
## Contributor Code of Conduct
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free experience for everyone, regardless of the level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
## Pull Request Guidelines
- Checkout a topic branch from the relevant branch, e.g. main, and merge back against that branch.
- If adding a new feature:
- Provide a convincing reason to add this feature. Ideally, you should open a suggestion issue first and have it approved before working on it.
- If fixing bug:
- Provide a detailed description of the bug in the PR. Live demo preferred.
- It's OK to have multiple small commits as you work on the PR - GitHub can automatically squash them before merging.
## Development Setup
You will need [pnpm](https://pnpm.io/)
After cloning the repo, run:
```bash
# install the dependencies of the project
$ pnpm install
# start the project
$ pnpm run dev
```

View File

@@ -1,17 +0,0 @@
version: 2
updates:
- package-ecosystem: npm
directory: '/'
schedule:
interval: daily
groups:
non-breaking-changes:
update-types: [minor, patch]
- package-ecosystem: github-actions
directory: '/'
schedule:
interval: weekly
groups:
non-breaking-changes:
update-types: [minor, patch]

View File

@@ -1,33 +0,0 @@
## Description
<!-- Please describe the change as necessary. If it's a feature or enhancement please be as detailed as possible. If it's a bug fix, please link the issue that it fixes or describe the bug in as much detail.
-->
<!-- You can also add additional context here -->
## Type of change
Please delete options that are not relevant.
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change requires a documentation update
- [ ] Please, don't make changes to `pnpm-lock.yaml` unless you introduce a new test example.
## Checklist
> Check all checkboxes - this will indicate that you have done everything in accordance with the rules in [CONTRIBUTING](contributing.md).
- [ ] If you introduce new functionality, document it. You can run documentation with `pnpm run docs:dev` command.
- [ ] Run the tests with `pnpm test`.
- [ ] Changes in changelog are generated from PR name. Please, make sure that it explains your changes in an understandable manner. Please, prefix changeset messages with `feat:`, `fix:`, `perf:`, `docs:`, or `chore:`.
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream modules

View File

@@ -1,61 +0,0 @@
name-template: 'v$RESOLVED_VERSION'
tag-template: 'v$RESOLVED_VERSION'
version-template: $MAJOR.$MINOR.$PATCH
change-template: '* $TITLE (#$NUMBER) @$AUTHOR'
template: |
# What's Changed
$CHANGES
**Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION
categories:
- title: '🚀 Features'
labels:
- 'feature'
- title: '🐞 Bug Fixes'
labels:
- 'bug'
- title: '📈 Performance & Enhancement'
labels:
- 'perf'
- 'enhancement'
- title: 📝 Documentation
labels:
- 'documentation'
- title: 👻 Maintenance
labels:
- 'chore'
- 'dependencies'
# collapse-after: 12
- title: 🚦 Tests
labels:
- 'tests'
- title: 'Breaking'
label: 'breaking'
version-resolver:
major:
labels:
- 'major'
- 'breaking'
minor:
labels:
- 'minor'
patch:
labels:
- 'feature'
- 'patch'
- 'bug'
- 'maintenance'
- 'docs'
- 'dependencies'
- 'security'
exclude-labels:
- 'skip-changelog'
- 'no-changelog'
- 'changelog'
- 'bump versions'
- 'reverted'
- 'invalid'

13
.github/semantic.yml vendored
View File

@@ -1,13 +0,0 @@
titleAndCommits: true
types:
- feat
- fix
- docs
- chore
- style
- refactor
- perf
- test
- build
- ci
- revert

View File

@@ -1,48 +0,0 @@
# name: Dependabot post-update
name: Build detection
on:
pull_request_target:
types: [opened, synchronize, reopened]
branches:
- main
env:
HUSKY: '0'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: write
jobs:
post-update:
if: github.repository == 'vbenjs/vue-vben-admin'
# if: ${{ github.actor == 'dependabot[bot]' }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- ubuntu-latest
# - macos-latest
- windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Checkout out pull request
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr checkout ${{ github.event.pull_request.number }}
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Build
run: |
pnpm run build

View File

@@ -1,42 +0,0 @@
# https://github.com/changesets/action
name: Changeset version
on:
workflow_dispatch:
pull_request:
types:
- closed
branches:
- main
permissions:
pull-requests: write
contents: write
env:
CI: true
jobs:
version:
if: (github.event.pull_request.merged || github.event_name == 'workflow_dispatch') && github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]') && github.repository == 'vbenjs/vue-vben-admin'
# if: github.repository == 'vbenjs/vue-vben-admin'
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Create Release Pull Request
uses: changesets/action@v1
with:
version: pnpm run version
commit: 'chore: bump versions'
title: 'chore: bump versions'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,125 +0,0 @@
name: CI
on:
pull_request:
push:
branches:
- main
- 'releases/*'
permissions:
contents: read
env:
CI: true
TZ: Asia/Shanghai
jobs:
test:
name: Test
if: github.repository == 'vbenjs/vue-vben-admin'
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- ubuntu-latest
# - macos-latest
- windows-latest
timeout-minutes: 20
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node
uses: ./.github/actions/setup-node
# - name: Check Git version
# run: git --version
# - name: Setup mock Git user
# run: git config --global user.email "you@example.com" && git config --global user.name "Your Name"
- name: Vitest tests
run: pnpm run test:unit
# - name: Upload coverage
# uses: codecov/codecov-action@v4
# with:
# token: ${{ secrets.CODECOV_TOKEN }}
lint:
name: Lint
if: github.repository == 'vbenjs/vue-vben-admin'
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- ubuntu-latest
# - macos-latest
- windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Lint
run: pnpm run lint
check:
name: Check
if: github.repository == 'vbenjs/vue-vben-admin'
runs-on: ${{ matrix.os }}
timeout-minutes: 20
strategy:
matrix:
os:
- ubuntu-latest
# - macos-latest
- windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Typecheck
run: pnpm check:type
# From https://github.com/rhysd/actionlint/blob/main/docs/usage.md#use-actionlint-on-github-actions
- name: Check workflow files
if: runner.os == 'Linux'
run: |
bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
./actionlint -color -shellcheck=""
ci-ok:
name: CI OK
if: github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest
needs: [test, check, lint]
env:
FAILURE: ${{ contains(join(needs.*.result, ','), 'failure') }}
steps:
- name: Check for failure
run: |
echo $FAILURE
if [ "$FAILURE" = "false" ]; then
exit 0
else
exit 1
fi

View File

@@ -1,94 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: 'CodeQL'
on:
push:
branches: ['main']
pull_request:
branches: ['main']
schedule:
- cron: '35 0 * * 0'
jobs:
analyze:
name: Analyze (${{ matrix.language }})
if: github.repository == 'vbenjs/vue-vben-admin'
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
strategy:
fail-fast: false
matrix:
include:
- language: javascript-typescript
build-mode: none
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
shell: bash
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: '/language:${{matrix.language}}'

View File

@@ -1,172 +0,0 @@
name: Deploy Website on push
on:
push:
branches:
- main
jobs:
deploy-playground-ftp:
name: Deploy Push Playground Ftp
if: github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]') && github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Sed Config Base
shell: bash
run: |
sed -i "s#VITE_COMPRESS\s*=.*#VITE_COMPRESS = gzip#g" ./playground/.env.production
sed -i "s#VITE_PWA\s*=.*#VITE_PWA = true#g" ./playground/.env.production
cat ./playground/.env.production
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Build
run: pnpm build:play
- name: Sync Playground files
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
with:
server: ${{ secrets.PRO_FTP_HOST }}
username: ${{ secrets.WEB_PLAYGROUND_FTP_ACCOUNT }}
password: ${{ secrets.WEB_PLAYGROUND_FTP_PWSSWORD }}
local-dir: ./playground/dist/
deploy-docs-ftp:
name: Deploy Push Docs Ftp
if: github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]') && github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Build
run: pnpm build:docs
- name: Sync Docs files
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
with:
server: ${{ secrets.PRO_FTP_HOST }}
username: ${{ secrets.WEBSITE_FTP_ACCOUNT }}
password: ${{ secrets.WEBSITE_FTP_PASSWORD }}
local-dir: ./docs/.vitepress/dist/
deploy-antd-ftp:
name: Deploy Push Antd Ftp
if: github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]') && github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Sed Config Base
shell: bash
run: |
sed -i "s#VITE_COMPRESS\s*=.*#VITE_COMPRESS = gzip#g" ./apps/web-antd/.env.production
sed -i "s#VITE_PWA\s*=.*#VITE_PWA = true#g" ./apps/web-antd/.env.production
cat ./apps/web-antd/.env.production
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Build
run: pnpm run build:antd
- name: Sync files
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
with:
server: ${{ secrets.PRO_FTP_HOST }}
username: ${{ secrets.WEB_ANTD_FTP_ACCOUNT }}
password: ${{ secrets.WEB_ANTD_FTP_PASSWORD }}
local-dir: ./apps/web-antd/dist/
deploy-ele-ftp:
name: Deploy Push Element Ftp
if: github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]') && github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Sed Config Base
shell: bash
run: |
sed -i "s#VITE_COMPRESS\s*=.*#VITE_COMPRESS = gzip#g" ./apps/web-ele/.env.production
sed -i "s#VITE_PWA\s*=.*#VITE_PWA = true#g" ./apps/web-ele/.env.production
cat ./apps/web-ele/.env.production
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Build
run: pnpm run build:ele
- name: Sync files
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
with:
server: ${{ secrets.PRO_FTP_HOST }}
username: ${{ secrets.WEB_ELE_FTP_ACCOUNT }}
password: ${{ secrets.WEB_ELE_FTP_PASSWORD }}
local-dir: ./apps/web-ele/dist/
deploy-naive-ftp:
name: Deploy Push Naive Ftp
if: github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]') && github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Sed Config Base
shell: bash
run: |
sed -i "s#VITE_COMPRESS\s*=.*#VITE_COMPRESS = gzip#g" ./apps/web-naive/.env.production
sed -i "s#VITE_PWA\s*=.*#VITE_PWA = true#g" ./apps/web-naive/.env.production
cat ./apps/web-naive/.env.production
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Build
run: pnpm run build:naive
- name: Sync files
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
with:
server: ${{ secrets.PRO_FTP_HOST }}
username: ${{ secrets.WEB_NAIVE_FTP_ACCOUNT }}
password: ${{ secrets.WEB_NAIVE_FTP_PASSWORD }}
local-dir: ./apps/web-naive/dist/
rerun-on-failure:
name: Rerun on failure
needs:
- deploy-playground-ftp
- deploy-docs-ftp
- deploy-antd-ftp
- deploy-ele-ftp
- deploy-naive-ftp
if: failure() && fromJSON(github.run_attempt) < 10
runs-on: ubuntu-latest
steps:
- name: Retry ${{ fromJSON(github.run_attempt) }} of 10
env:
GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ github.token }}
run: gh workflow run rerun.yml -F run_id=${{ github.run_id }}

View File

@@ -1,25 +0,0 @@
name: Release Drafter
on:
push:
branches:
- main
permissions:
contents: read
pull-requests: write
jobs:
update_release_draft:
permissions:
# write permission is required to create a github release
contents: write
# write permission is required for autolabeler
# otherwise, read permission is required at least
pull-requests: write
if: github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest
steps:
- uses: release-drafter/release-drafter@v6
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,31 +0,0 @@
# 每天零点运行一次,它会检查所有带有 "need reproduction" 标签的 Issues。如果这些 Issues 在过去的 3 天内没有任何活动,它们将会被自动关闭。这有助于保持 Issue 列表的整洁,并且提醒用户在必要时提供更多的信息。
name: Issue Close Require
# 触发条件:每天零点
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * *'
permissions:
pull-requests: write
contents: write
issues: write
jobs:
close-issues:
if: github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest
steps:
# 关闭未活动的 Issues
- name: Close Inactive Issues
uses: actions/stale@v9
with:
days-before-stale: -1 # Issues and PR will never be flagged stale automatically.
stale-issue-label: needs-reproduction # Label that flags an issue as stale.
only-labels: needs-reproduction # Only process these issues
days-before-issue-close: 3
ignore-updates: true
remove-stale-when-updated: false
close-issue-message: This issue was closed because it was open for 3 days without a valid reproduction.
close-issue-label: closed-by-action

View File

@@ -1,46 +0,0 @@
name: Label Based Actions
on:
issues:
types: [labeled]
# pull_request:
# types: [labeled]
permissions:
issues: write
pull-requests: write
contents: write
jobs:
reply-labeled:
if: github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest
steps:
- name: remove enhancement pending
if: github.event.label.name == 'enhancement'
uses: actions-cool/issues-helper@v3
with:
actions: 'remove-labels'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
labels: 'enhancement: pending triage'
- name: remove bug pending
if: github.event.label.name == 'bug'
uses: actions-cool/issues-helper@v3
with:
actions: 'remove-labels'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
labels: 'bug: pending triage'
- name: needs reproduction
if: github.event.label.name == 'needs reproduction'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment, remove-labels'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
Hello @${{ github.event.issue.user.login }}. Please provide the complete reproduction steps and code. Issues labeled by `needs reproduction` will be closed if no activities in 3 days.
labels: 'bug: pending triage'

View File

@@ -1,24 +0,0 @@
name: Lock Threads
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
permissions:
issues: write
pull-requests: write
jobs:
action:
if: github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v5
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
issue-inactive-days: '14'
issue-lock-reason: ''
pr-inactive-days: '30'
pr-lock-reason: ''
process-only: 'issues, prs'

View File

@@ -1,80 +0,0 @@
name: Create Release Tag
on:
push:
tags:
- 'v*.*.*' # Push events to matching v*, i.e. v1.0, v20.15.10
env:
HUSKY: '0'
permissions:
pull-requests: write
contents: write
jobs:
build:
name: Create Release
if: github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20]
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
# - name: Checkout code
# uses: actions/checkout@v4
# with:
# fetch-depth: 0
# - name: Install pnpm
# uses: pnpm/action-setup@v4
# - name: Use Node.js ${{ matrix.node-version }}
# uses: actions/setup-node@v4
# with:
# node-version: ${{ matrix.node-version }}
# cache: "pnpm"
# - name: Install dependencies
# run: pnpm install --frozen-lockfile
# - name: Test and Build
# run: |
# pnpm run test
# pnpm run build
- name: version
id: version
run: |
tag=${GITHUB_REF/refs\/tags\//}
version=${tag#v}
major=${version%%.*}
echo "tag=${tag}" >> $GITHUB_OUTPUT
echo "version=${version}" >> $GITHUB_OUTPUT
echo "major=${major}" >> $GITHUB_OUTPUT
- uses: release-drafter/release-drafter@v6
with:
version: ${{ steps.version.outputs.version }}
publish: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# - name: force update major tag
# run: |
# git tag v${{ steps.version.outputs.major }} ${{ steps.version.outputs.tag }} -f
# git push origin refs/tags/v${{ steps.version.outputs.major }} -f
# - name: Create Release for Tag
# id: release_tag
# uses: ncipollo/release-action@v1
# with:
# token: ${{ secrets.GITHUB_TOKEN }}
# generateReleaseNotes: "true"
# body: |
# > Please refer to [CHANGELOG.md](https://github.com/vbenjs/vue-vben-admin/blob/main/CHANGELOG.md) for details.

View File

@@ -1,19 +0,0 @@
name: Rerun workflow
on:
workflow_dispatch:
inputs:
run_id:
description: The workflow id to relanch
required: true
jobs:
rerun:
runs-on: ubuntu-latest
steps:
- name: rerun ${{ inputs.run_id }}
env:
GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ github.token }}
run: |
gh run watch ${{ inputs.run_id }} > /dev/null 2>&1
gh run rerun ${{ inputs.run_id }} --failed

View File

@@ -1,41 +0,0 @@
name: Semantic Pull Request
on:
pull_request_target:
types:
- opened
- edited
- synchronize
jobs:
main:
name: Semantic Pull Request
if: github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest
steps:
- name: Validate PR title
uses: amannn/action-semantic-pull-request@v5
with:
wip: true
subjectPattern: ^(?![A-Z]).+$
subjectPatternError: |
The subject "{subject}" found in the pull request title "{title}"
didn't match the configured pattern. Please ensure that the subject
doesn't start with an uppercase character.
requireScope: false
types: |
fix
feat
docs
style
refactor
perf
test
build
ci
chore
revert
types
release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,19 +0,0 @@
name: 'Close stale issues'
on:
schedule:
- cron: '0 1 * * *'
jobs:
stale:
if: github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days'
stale-pr-message: 'This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days'
exempt-issue-labels: 'bug,enhancement'
days-before-stale: 60
days-before-close: 7

View File

@@ -1 +1 @@
22.1.0
22.22.0

9
.vscode/launch.json vendored
View File

@@ -2,15 +2,6 @@
"$schema": "https://json.schemastore.org/launchsettings.json",
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"name": "vben admin playground dev",
"request": "launch",
"url": "http://localhost:5555",
"env": { "NODE_ENV": "development" },
"sourceMaps": true,
"webRoot": "${workspaceFolder}/playground"
},
{
"type": "chrome",
"name": "vben admin antd dev",

View File

@@ -38,7 +38,7 @@
},
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
"editor.defaultFormatter": "vscode.html-language-features"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
@@ -181,7 +181,8 @@
"markdown",
"json",
"jsonc",
"json5"
"json5",
"yaml"
],
"tailwindCSS.experimental.classRegex": [
@@ -199,7 +200,6 @@
"i18n-ally.localesPaths": [
"packages/locales/src/langs",
"playground/src/locales/langs",
"apps/*/src/locales/langs"
],
"i18n-ally.pathMatcher": "{locale}/{namespace}.{ext}",

View File

@@ -2,6 +2,10 @@
dev中 未发布
**REFACTOR**
- 使用antd组件替换密码登录表单
**FEATURES**
- 合并官方更新 将Radix(v1)替换为Reka UI(v2)

View File

@@ -2,6 +2,8 @@
## 提示
该分支使用[antdv-next](https://github.com/antdv-next/antdv-next)替代已经不维护的antd-design-vue
该仓库使用vben最新版本v5开发
v5版本采用分仓(包)目录结构, 具体开发路径为: `根目录/apps/web-antd`
@@ -14,13 +16,13 @@ V1.2.0版本对接warmflow工作流
## 简介
基于 [vben5 & ant-design-vue](https://github.com/vbenjs/vue-vben-admin) 的 RuoYi-Vue-Plus 前端项目
基于 [vben5 & antdv-next](https://github.com/vbenjs/vue-vben-admin) 的 RuoYi-Vue-Plus 前端项目
| 组件/框架 | 版本 |
| :------------- | :----- |
| vben | 5.5.9 |
| ant-design-vue | 4.2.6 |
| vue | 3.5.13 |
| 组件/框架 | 版本 |
| :--------- | :----- |
| vben | 5.5.9 |
| antdv-next | 4.2.6 |
| vue | 3.5.13 |
对应后端项目: **(分布式 5.X 分支 微服务 2.分支)**

View File

@@ -1,3 +0,0 @@
PORT=5320
ACCESS_TOKEN_SECRET=access_token_secret
REFRESH_TOKEN_SECRET=refresh_token_secret

View File

@@ -1,15 +0,0 @@
# @vben/backend-mock
## Description
Vben Admin 数据 mock 服务,没有对接任何的数据库,所有数据都是模拟的,用于前端开发时提供数据支持。线上环境不再提供 mock 集成,可自行部署服务或者对接真实数据,由于 `mock.js` 等工具有一些限制,比如上传文件不行、无法模拟复杂的逻辑等,所以这里使用了真实的后端服务来实现。唯一麻烦的是本地需要同时启动后端服务和前端服务,但是这样可以更好的模拟真实环境。该服务不需要手动启动,已经集成在 vite 插件内,随应用一起启用。
## Running the app
```bash
# development
$ pnpm run start
# production mode
$ pnpm run build
```

View File

@@ -1,16 +0,0 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { MOCK_CODES } from '~/utils/mock-data';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
export default eventHandler((event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const codes =
MOCK_CODES.find((item) => item.username === userinfo.username)?.codes ?? [];
return useResponseSuccess(codes);
});

View File

@@ -1,42 +0,0 @@
import { defineEventHandler, readBody, setResponseStatus } from 'h3';
import {
clearRefreshTokenCookie,
setRefreshTokenCookie,
} from '~/utils/cookie-utils';
import { generateAccessToken, generateRefreshToken } from '~/utils/jwt-utils';
import { MOCK_USERS } from '~/utils/mock-data';
import {
forbiddenResponse,
useResponseError,
useResponseSuccess,
} from '~/utils/response';
export default defineEventHandler(async (event) => {
const { password, username } = await readBody(event);
if (!password || !username) {
setResponseStatus(event, 400);
return useResponseError(
'BadRequestException',
'Username and password are required',
);
}
const findUser = MOCK_USERS.find(
(item) => item.username === username && item.password === password,
);
if (!findUser) {
clearRefreshTokenCookie(event);
return forbiddenResponse(event, 'Username or password is incorrect.');
}
const accessToken = generateAccessToken(findUser);
const refreshToken = generateRefreshToken(findUser);
setRefreshTokenCookie(event, refreshToken);
return useResponseSuccess({
...findUser,
accessToken,
});
});

View File

@@ -1,17 +0,0 @@
import { defineEventHandler } from 'h3';
import {
clearRefreshTokenCookie,
getRefreshTokenFromCookie,
} from '~/utils/cookie-utils';
import { useResponseSuccess } from '~/utils/response';
export default defineEventHandler(async (event) => {
const refreshToken = getRefreshTokenFromCookie(event);
if (!refreshToken) {
return useResponseSuccess('');
}
clearRefreshTokenCookie(event);
return useResponseSuccess('');
});

View File

@@ -1,35 +0,0 @@
import { defineEventHandler } from 'h3';
import {
clearRefreshTokenCookie,
getRefreshTokenFromCookie,
setRefreshTokenCookie,
} from '~/utils/cookie-utils';
import { generateAccessToken, verifyRefreshToken } from '~/utils/jwt-utils';
import { MOCK_USERS } from '~/utils/mock-data';
import { forbiddenResponse } from '~/utils/response';
export default defineEventHandler(async (event) => {
const refreshToken = getRefreshTokenFromCookie(event);
if (!refreshToken) {
return forbiddenResponse(event);
}
clearRefreshTokenCookie(event);
const userinfo = verifyRefreshToken(refreshToken);
if (!userinfo) {
return forbiddenResponse(event);
}
const findUser = MOCK_USERS.find(
(item) => item.username === userinfo.username,
);
if (!findUser) {
return forbiddenResponse(event);
}
const accessToken = generateAccessToken(findUser);
setRefreshTokenCookie(event, refreshToken);
return accessToken;
});

View File

@@ -1,32 +0,0 @@
import { eventHandler, setHeader } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse } from '~/utils/response';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const data = `
{
"code": 0,
"message": "success",
"data": [
{
"id": 123456789012345678901234567890123456789012345678901234567890,
"name": "John Doe",
"age": 30,
"email": "john-doe@demo.com"
},
{
"id": 987654321098765432109876543210987654321098765432109876543210,
"name": "Jane Smith",
"age": 25,
"email": "jane@demo.com"
}
]
}
`;
setHeader(event, 'Content-Type', 'application/json');
return data;
});

View File

@@ -1,15 +0,0 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { MOCK_MENUS } from '~/utils/mock-data';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const menus =
MOCK_MENUS.find((item) => item.username === userinfo.username)?.menus ?? [];
return useResponseSuccess(menus);
});

View File

@@ -1,8 +0,0 @@
import { eventHandler, getQuery, setResponseStatus } from 'h3';
import { useResponseError } from '~/utils/response';
export default eventHandler((event) => {
const { status } = getQuery(event);
setResponseStatus(event, Number(status));
return useResponseError(`${status}`);
});

View File

@@ -1,16 +0,0 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import {
sleep,
unAuthorizedResponse,
useResponseSuccess,
} from '~/utils/response';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
await sleep(600);
return useResponseSuccess(null);
});

View File

@@ -1,16 +0,0 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import {
sleep,
unAuthorizedResponse,
useResponseSuccess,
} from '~/utils/response';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
await sleep(1000);
return useResponseSuccess(null);
});

View File

@@ -1,16 +0,0 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import {
sleep,
unAuthorizedResponse,
useResponseSuccess,
} from '~/utils/response';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
await sleep(2000);
return useResponseSuccess(null);
});

View File

@@ -1,62 +0,0 @@
import { faker } from '@faker-js/faker';
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
const formatterCN = new Intl.DateTimeFormat('zh-CN', {
timeZone: 'Asia/Shanghai',
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
});
function generateMockDataList(count: number) {
const dataList = [];
for (let i = 0; i < count; i++) {
const dataItem: Record<string, any> = {
id: faker.string.uuid(),
pid: 0,
name: faker.commerce.department(),
status: faker.helpers.arrayElement([0, 1]),
createTime: formatterCN.format(
faker.date.between({ from: '2021-01-01', to: '2022-12-31' }),
),
remark: faker.lorem.sentence(),
};
if (faker.datatype.boolean()) {
dataItem.children = Array.from(
{ length: faker.number.int({ min: 1, max: 5 }) },
() => ({
id: faker.string.uuid(),
pid: dataItem.id,
name: faker.commerce.department(),
status: faker.helpers.arrayElement([0, 1]),
createTime: formatterCN.format(
faker.date.between({ from: '2023-01-01', to: '2023-12-31' }),
),
remark: faker.lorem.sentence(),
}),
);
}
dataList.push(dataItem);
}
return dataList;
}
const mockData = generateMockDataList(10);
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const listData = structuredClone(mockData);
return useResponseSuccess(listData);
});

View File

@@ -1,13 +0,0 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { MOCK_MENU_LIST } from '~/utils/mock-data';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
return useResponseSuccess(MOCK_MENU_LIST);
});

View File

@@ -1,29 +0,0 @@
import { eventHandler, getQuery } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { MOCK_MENU_LIST } from '~/utils/mock-data';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
const namesMap: Record<string, any> = {};
function getNames(menus: any[]) {
menus.forEach((menu) => {
namesMap[menu.name] = String(menu.id);
if (menu.children) {
getNames(menu.children);
}
});
}
getNames(MOCK_MENU_LIST);
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const { id, name } = getQuery(event);
return (name as string) in namesMap &&
(!id || namesMap[name as string] !== String(id))
? useResponseSuccess(true)
: useResponseSuccess(false);
});

View File

@@ -1,29 +0,0 @@
import { eventHandler, getQuery } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { MOCK_MENU_LIST } from '~/utils/mock-data';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
const pathMap: Record<string, any> = { '/': 0 };
function getPaths(menus: any[]) {
menus.forEach((menu) => {
pathMap[menu.path] = String(menu.id);
if (menu.children) {
getPaths(menu.children);
}
});
}
getPaths(MOCK_MENU_LIST);
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const { id, path } = getQuery(event);
return (path as string) in pathMap &&
(!id || pathMap[path as string] !== String(id))
? useResponseSuccess(true)
: useResponseSuccess(false);
});

View File

@@ -1,84 +0,0 @@
import { faker } from '@faker-js/faker';
import { eventHandler, getQuery } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { getMenuIds, MOCK_MENU_LIST } from '~/utils/mock-data';
import { unAuthorizedResponse, usePageResponseSuccess } from '~/utils/response';
const formatterCN = new Intl.DateTimeFormat('zh-CN', {
timeZone: 'Asia/Shanghai',
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
});
const menuIds = getMenuIds(MOCK_MENU_LIST);
function generateMockDataList(count: number) {
const dataList = [];
for (let i = 0; i < count; i++) {
const dataItem: Record<string, any> = {
id: faker.string.uuid(),
name: faker.commerce.product(),
status: faker.helpers.arrayElement([0, 1]),
createTime: formatterCN.format(
faker.date.between({ from: '2022-01-01', to: '2025-01-01' }),
),
permissions: faker.helpers.arrayElements(menuIds),
remark: faker.lorem.sentence(),
};
dataList.push(dataItem);
}
return dataList;
}
const mockData = generateMockDataList(100);
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const {
page = 1,
pageSize = 20,
name,
id,
remark,
startTime,
endTime,
status,
} = getQuery(event);
let listData = structuredClone(mockData);
if (name) {
listData = listData.filter((item) =>
item.name.toLowerCase().includes(String(name).toLowerCase()),
);
}
if (id) {
listData = listData.filter((item) =>
item.id.toLowerCase().includes(String(id).toLowerCase()),
);
}
if (remark) {
listData = listData.filter((item) =>
item.remark?.toLowerCase()?.includes(String(remark).toLowerCase()),
);
}
if (startTime) {
listData = listData.filter((item) => item.createTime >= startTime);
}
if (endTime) {
listData = listData.filter((item) => item.createTime <= endTime);
}
if (['0', '1'].includes(status as string)) {
listData = listData.filter((item) => item.status === Number(status));
}
return usePageResponseSuccess(page as string, pageSize as string, listData);
});

View File

@@ -1,117 +0,0 @@
import { faker } from '@faker-js/faker';
import { eventHandler, getQuery } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import {
sleep,
unAuthorizedResponse,
usePageResponseSuccess,
} from '~/utils/response';
function generateMockDataList(count: number) {
const dataList = [];
for (let i = 0; i < count; i++) {
const dataItem = {
id: faker.string.uuid(),
imageUrl: faker.image.avatar(),
imageUrl2: faker.image.avatar(),
open: faker.datatype.boolean(),
status: faker.helpers.arrayElement(['success', 'error', 'warning']),
productName: faker.commerce.productName(),
price: faker.commerce.price(),
currency: faker.finance.currencyCode(),
quantity: faker.number.int({ min: 1, max: 100 }),
available: faker.datatype.boolean(),
category: faker.commerce.department(),
releaseDate: faker.date.past(),
rating: faker.number.float({ min: 1, max: 5 }),
description: faker.commerce.productDescription(),
weight: faker.number.float({ min: 0.1, max: 10 }),
color: faker.color.human(),
inProduction: faker.datatype.boolean(),
tags: Array.from({ length: 3 }, () => faker.commerce.productAdjective()),
};
dataList.push(dataItem);
}
return dataList;
}
const mockData = generateMockDataList(100);
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
await sleep(600);
const { page, pageSize, sortBy, sortOrder } = getQuery(event);
// 规范化分页参数,处理 string[]
const pageRaw = Array.isArray(page) ? page[0] : page;
const pageSizeRaw = Array.isArray(pageSize) ? pageSize[0] : pageSize;
const pageNumber = Math.max(
1,
Number.parseInt(String(pageRaw ?? '1'), 10) || 1,
);
const pageSizeNumber = Math.min(
100,
Math.max(1, Number.parseInt(String(pageSizeRaw ?? '10'), 10) || 10),
);
const listData = structuredClone(mockData);
// 规范化 query 入参,兼容 string[]
const sortKeyRaw = Array.isArray(sortBy) ? sortBy[0] : sortBy;
const sortOrderRaw = Array.isArray(sortOrder) ? sortOrder[0] : sortOrder;
// 检查 sortBy 是否是 listData 元素的合法属性键
if (
typeof sortKeyRaw === 'string' &&
listData[0] &&
Object.prototype.hasOwnProperty.call(listData[0], sortKeyRaw)
) {
// 定义数组元素的类型
type ItemType = (typeof listData)[0];
const sortKey = sortKeyRaw as keyof ItemType; // 将 sortBy 断言为合法键
const isDesc = sortOrderRaw === 'desc';
listData.sort((a, b) => {
const aValue = a[sortKey] as unknown;
const bValue = b[sortKey] as unknown;
let result = 0;
if (typeof aValue === 'number' && typeof bValue === 'number') {
result = aValue - bValue;
} else if (aValue instanceof Date && bValue instanceof Date) {
result = aValue.getTime() - bValue.getTime();
} else if (typeof aValue === 'boolean' && typeof bValue === 'boolean') {
if (aValue === bValue) {
result = 0;
} else {
result = aValue ? 1 : -1;
}
} else {
const aStr = String(aValue);
const bStr = String(bValue);
const aNum = Number(aStr);
const bNum = Number(bStr);
result =
Number.isFinite(aNum) && Number.isFinite(bNum)
? aNum - bNum
: aStr.localeCompare(bStr, undefined, {
numeric: true,
sensitivity: 'base',
});
}
return isDesc ? -result : result;
});
}
return usePageResponseSuccess(
String(pageNumber),
String(pageSizeNumber),
listData,
);
});

View File

@@ -1,3 +0,0 @@
import { defineEventHandler } from 'h3';
export default defineEventHandler(() => 'Test get handler');

View File

@@ -1,3 +0,0 @@
import { defineEventHandler } from 'h3';
export default defineEventHandler(() => 'Test post handler');

View File

@@ -1,12 +0,0 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
import { getTimezone } from '~/utils/timezone-utils';
export default eventHandler((event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
return useResponseSuccess(getTimezone());
});

View File

@@ -1,11 +0,0 @@
import { eventHandler } from 'h3';
import { TIME_ZONE_OPTIONS } from '~/utils/mock-data';
import { useResponseSuccess } from '~/utils/response';
export default eventHandler(() => {
const data = TIME_ZONE_OPTIONS.map((o) => ({
label: `${o.timezone} (GMT${o.offset >= 0 ? `+${o.offset}` : o.offset})`,
value: o.timezone,
}));
return useResponseSuccess(data);
});

View File

@@ -1,22 +0,0 @@
import { eventHandler, readBody } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { TIME_ZONE_OPTIONS } from '~/utils/mock-data';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
import { setTimezone } from '~/utils/timezone-utils';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const body = await readBody<{ timezone?: unknown }>(event);
const timezone =
typeof body?.timezone === 'string' ? body.timezone : undefined;
const allowed = TIME_ZONE_OPTIONS.some((o) => o.timezone === timezone);
if (!timezone || !allowed) {
setResponseStatus(event, 400);
return useResponseError('Bad Request', 'Invalid timezone');
}
setTimezone(timezone);
return useResponseSuccess({});
});

View File

@@ -1,14 +0,0 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
export default eventHandler((event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
return useResponseSuccess({
url: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
});
// return useResponseError("test")
});

View File

@@ -1,11 +0,0 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
export default eventHandler((event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
return useResponseSuccess(userinfo);
});

View File

@@ -1,7 +0,0 @@
import type { NitroErrorHandler } from 'nitropack';
const errorHandler: NitroErrorHandler = function (error, event) {
event.node.res.end(`[Error Handler] ${error.stack}`);
};
export default errorHandler;

View File

@@ -1,20 +0,0 @@
import { defineEventHandler } from 'h3';
import { forbiddenResponse, sleep } from '~/utils/response';
export default defineEventHandler(async (event) => {
event.node.res.setHeader(
'Access-Control-Allow-Origin',
event.headers.get('Origin') ?? '*',
);
if (event.method === 'OPTIONS') {
event.node.res.statusCode = 204;
event.node.res.statusMessage = 'No Content.';
return 'OK';
} else if (
['DELETE', 'PATCH', 'POST', 'PUT'].includes(event.method) &&
event.path.startsWith('/api/system/')
) {
await sleep(Math.floor(Math.random() * 2000));
return forbiddenResponse(event, '演示环境,禁止修改');
}
});

View File

@@ -1,20 +0,0 @@
import errorHandler from './error';
process.env.COMPATIBILITY_DATE = new Date().toISOString();
export default defineNitroConfig({
devErrorHandler: errorHandler,
errorHandler: '~/error',
routeRules: {
'/api/**': {
cors: true,
headers: {
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Headers':
'Accept, Authorization, Content-Length, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With',
'Access-Control-Allow-Methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
'Access-Control-Allow-Origin': '*',
'Access-Control-Expose-Headers': '*',
},
},
},
});

View File

@@ -1,21 +0,0 @@
{
"name": "@vben/backend-mock",
"version": "0.0.1",
"description": "",
"private": true,
"license": "MIT",
"author": "",
"scripts": {
"build": "nitro build",
"start": "nitro dev"
},
"dependencies": {
"@faker-js/faker": "catalog:",
"jsonwebtoken": "catalog:",
"nitropack": "catalog:"
},
"devDependencies": {
"@types/jsonwebtoken": "catalog:",
"h3": "catalog:"
}
}

View File

@@ -1,15 +0,0 @@
import { defineEventHandler } from 'h3';
export default defineEventHandler(() => {
return `
<h1>Hello Vben Admin</h1>
<h2>Mock service is starting</h2>
<ul>
<li><a href="/api/user">/api/user/info</a></li>
<li><a href="/api/menu">/api/menu/all</a></li>
<li><a href="/api/auth/codes">/api/auth/codes</a></li>
<li><a href="/api/auth/login">/api/auth/login</a></li>
<li><a href="/api/upload">/api/upload</a></li>
</ul>
`;
});

View File

@@ -1,4 +0,0 @@
{
"extends": "./tsconfig.json",
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
}

View File

@@ -1,3 +0,0 @@
{
"extends": "./.nitro/types/tsconfig.json"
}

View File

@@ -1,28 +0,0 @@
import type { EventHandlerRequest, H3Event } from 'h3';
import { deleteCookie, getCookie, setCookie } from 'h3';
export function clearRefreshTokenCookie(event: H3Event<EventHandlerRequest>) {
deleteCookie(event, 'jwt', {
httpOnly: true,
sameSite: 'none',
secure: true,
});
}
export function setRefreshTokenCookie(
event: H3Event<EventHandlerRequest>,
refreshToken: string,
) {
setCookie(event, 'jwt', refreshToken, {
httpOnly: true,
maxAge: 24 * 60 * 60, // unit: seconds
sameSite: 'none',
secure: true,
});
}
export function getRefreshTokenFromCookie(event: H3Event<EventHandlerRequest>) {
const refreshToken = getCookie(event, 'jwt');
return refreshToken;
}

View File

@@ -1,77 +0,0 @@
import type { EventHandlerRequest, H3Event } from 'h3';
import type { UserInfo } from './mock-data';
import { getHeader } from 'h3';
import jwt from 'jsonwebtoken';
import { MOCK_USERS } from './mock-data';
// TODO: Replace with your own secret key
const ACCESS_TOKEN_SECRET = 'access_token_secret';
const REFRESH_TOKEN_SECRET = 'refresh_token_secret';
export interface UserPayload extends UserInfo {
iat: number;
exp: number;
}
export function generateAccessToken(user: UserInfo) {
return jwt.sign(user, ACCESS_TOKEN_SECRET, { expiresIn: '7d' });
}
export function generateRefreshToken(user: UserInfo) {
return jwt.sign(user, REFRESH_TOKEN_SECRET, {
expiresIn: '30d',
});
}
export function verifyAccessToken(
event: H3Event<EventHandlerRequest>,
): null | Omit<UserInfo, 'password'> {
const authHeader = getHeader(event, 'Authorization');
if (!authHeader?.startsWith('Bearer')) {
return null;
}
const tokenParts = authHeader.split(' ');
if (tokenParts.length !== 2) {
return null;
}
const token = tokenParts[1] as string;
try {
const decoded = jwt.verify(
token,
ACCESS_TOKEN_SECRET,
) as unknown as UserPayload;
const username = decoded.username;
const user = MOCK_USERS.find((item) => item.username === username);
if (!user) {
return null;
}
const { password: _pwd, ...userinfo } = user;
return userinfo;
} catch {
return null;
}
}
export function verifyRefreshToken(
token: string,
): null | Omit<UserInfo, 'password'> {
try {
const decoded = jwt.verify(token, REFRESH_TOKEN_SECRET) as UserPayload;
const username = decoded.username;
const user = MOCK_USERS.find(
(item) => item.username === username,
) as UserInfo;
if (!user) {
return null;
}
const { password: _pwd, ...userinfo } = user;
return userinfo;
} catch {
return null;
}
}

View File

@@ -1,421 +0,0 @@
export interface UserInfo {
id: number;
password: string;
realName: string;
roles: string[];
username: string;
homePath?: string;
}
export interface TimezoneOption {
offset: number;
timezone: string;
}
export const MOCK_USERS: UserInfo[] = [
{
id: 0,
password: '123456',
realName: 'Vben',
roles: ['super'],
username: 'vben',
},
{
id: 1,
password: '123456',
realName: 'Admin',
roles: ['admin'],
username: 'admin',
homePath: '/workspace',
},
{
id: 2,
password: '123456',
realName: 'Jack',
roles: ['user'],
username: 'jack',
homePath: '/analytics',
},
];
export const MOCK_CODES = [
// super
{
codes: ['AC_100100', 'AC_100110', 'AC_100120', 'AC_100010'],
username: 'vben',
},
{
// admin
codes: ['AC_100010', 'AC_100020', 'AC_100030'],
username: 'admin',
},
{
// user
codes: ['AC_1000001', 'AC_1000002'],
username: 'jack',
},
];
const dashboardMenus = [
{
meta: {
order: -1,
title: 'page.dashboard.title',
},
name: 'Dashboard',
path: '/dashboard',
redirect: '/analytics',
children: [
{
name: 'Analytics',
path: '/analytics',
component: '/dashboard/analytics/index',
meta: {
affixTab: true,
title: 'page.dashboard.analytics',
},
},
{
name: 'Workspace',
path: '/workspace',
component: '/dashboard/workspace/index',
meta: {
title: 'page.dashboard.workspace',
},
},
],
},
];
const createDemosMenus = (role: 'admin' | 'super' | 'user') => {
const roleWithMenus = {
admin: {
component: '/demos/access/admin-visible',
meta: {
icon: 'mdi:button-cursor',
title: 'demos.access.adminVisible',
},
name: 'AccessAdminVisibleDemo',
path: '/demos/access/admin-visible',
},
super: {
component: '/demos/access/super-visible',
meta: {
icon: 'mdi:button-cursor',
title: 'demos.access.superVisible',
},
name: 'AccessSuperVisibleDemo',
path: '/demos/access/super-visible',
},
user: {
component: '/demos/access/user-visible',
meta: {
icon: 'mdi:button-cursor',
title: 'demos.access.userVisible',
},
name: 'AccessUserVisibleDemo',
path: '/demos/access/user-visible',
},
};
return [
{
meta: {
icon: 'ic:baseline-view-in-ar',
keepAlive: true,
order: 1000,
title: 'demos.title',
},
name: 'Demos',
path: '/demos',
redirect: '/demos/access',
children: [
{
name: 'AccessDemos',
path: '/demosaccess',
meta: {
icon: 'mdi:cloud-key-outline',
title: 'demos.access.backendPermissions',
},
redirect: '/demos/access/page-control',
children: [
{
name: 'AccessPageControlDemo',
path: '/demos/access/page-control',
component: '/demos/access/index',
meta: {
icon: 'mdi:page-previous-outline',
title: 'demos.access.pageAccess',
},
},
{
name: 'AccessButtonControlDemo',
path: '/demos/access/button-control',
component: '/demos/access/button-control',
meta: {
icon: 'mdi:button-cursor',
title: 'demos.access.buttonControl',
},
},
{
name: 'AccessMenuVisible403Demo',
path: '/demos/access/menu-visible-403',
component: '/demos/access/menu-visible-403',
meta: {
authority: ['no-body'],
icon: 'mdi:button-cursor',
menuVisibleWithForbidden: true,
title: 'demos.access.menuVisible403',
},
},
roleWithMenus[role],
],
},
],
},
];
};
export const MOCK_MENUS = [
{
menus: [...dashboardMenus, ...createDemosMenus('super')],
username: 'vben',
},
{
menus: [...dashboardMenus, ...createDemosMenus('admin')],
username: 'admin',
},
{
menus: [...dashboardMenus, ...createDemosMenus('user')],
username: 'jack',
},
];
export const MOCK_MENU_LIST = [
{
id: 1,
name: 'Workspace',
status: 1,
type: 'menu',
icon: 'mdi:dashboard',
path: '/workspace',
component: '/dashboard/workspace/index',
meta: {
icon: 'carbon:workspace',
title: 'page.dashboard.workspace',
affixTab: true,
order: 0,
},
},
{
id: 2,
meta: {
icon: 'carbon:settings',
order: 9997,
title: 'system.title',
badge: 'new',
badgeType: 'normal',
badgeVariants: 'primary',
},
status: 1,
type: 'catalog',
name: 'System',
path: '/system',
children: [
{
id: 201,
pid: 2,
path: '/system/menu',
name: 'SystemMenu',
authCode: 'System:Menu:List',
status: 1,
type: 'menu',
meta: {
icon: 'carbon:menu',
title: 'system.menu.title',
},
component: '/system/menu/list',
children: [
{
id: 20_101,
pid: 201,
name: 'SystemMenuCreate',
status: 1,
type: 'button',
authCode: 'System:Menu:Create',
meta: { title: 'common.create' },
},
{
id: 20_102,
pid: 201,
name: 'SystemMenuEdit',
status: 1,
type: 'button',
authCode: 'System:Menu:Edit',
meta: { title: 'common.edit' },
},
{
id: 20_103,
pid: 201,
name: 'SystemMenuDelete',
status: 1,
type: 'button',
authCode: 'System:Menu:Delete',
meta: { title: 'common.delete' },
},
],
},
{
id: 202,
pid: 2,
path: '/system/dept',
name: 'SystemDept',
status: 1,
type: 'menu',
authCode: 'System:Dept:List',
meta: {
icon: 'carbon:container-services',
title: 'system.dept.title',
},
component: '/system/dept/list',
children: [
{
id: 20_401,
pid: 202,
name: 'SystemDeptCreate',
status: 1,
type: 'button',
authCode: 'System:Dept:Create',
meta: { title: 'common.create' },
},
{
id: 20_402,
pid: 202,
name: 'SystemDeptEdit',
status: 1,
type: 'button',
authCode: 'System:Dept:Edit',
meta: { title: 'common.edit' },
},
{
id: 20_403,
pid: 202,
name: 'SystemDeptDelete',
status: 1,
type: 'button',
authCode: 'System:Dept:Delete',
meta: { title: 'common.delete' },
},
],
},
],
},
{
id: 9,
meta: {
badgeType: 'dot',
order: 9998,
title: 'demos.vben.title',
icon: 'carbon:data-center',
},
name: 'Project',
path: '/vben-admin',
type: 'catalog',
status: 1,
children: [
{
id: 901,
pid: 9,
name: 'VbenDocument',
path: '/vben-admin/document',
component: 'IFrameView',
type: 'embedded',
status: 1,
meta: {
icon: 'carbon:book',
iframeSrc: 'https://doc.vben.pro',
title: 'demos.vben.document',
},
},
{
id: 902,
pid: 9,
name: 'VbenGithub',
path: '/vben-admin/github',
component: 'IFrameView',
type: 'link',
status: 1,
meta: {
icon: 'carbon:logo-github',
link: 'https://github.com/vbenjs/vue-vben-admin',
title: 'Github',
},
},
{
id: 903,
pid: 9,
name: 'VbenAntdv',
path: '/vben-admin/antdv',
component: 'IFrameView',
type: 'link',
status: 0,
meta: {
icon: 'carbon:hexagon-vertical-solid',
badgeType: 'dot',
link: 'https://ant.vben.pro',
title: 'demos.vben.antdv',
},
},
],
},
{
id: 10,
component: '_core/about/index',
type: 'menu',
status: 1,
meta: {
icon: 'lucide:copyright',
order: 9999,
title: 'demos.vben.about',
},
name: 'About',
path: '/about',
},
];
export function getMenuIds(menus: any[]) {
const ids: number[] = [];
menus.forEach((item) => {
ids.push(item.id);
if (item.children && item.children.length > 0) {
ids.push(...getMenuIds(item.children));
}
});
return ids;
}
/**
* 时区选项
*/
export const TIME_ZONE_OPTIONS: TimezoneOption[] = [
{
offset: -5,
timezone: 'America/New_York',
},
{
offset: 0,
timezone: 'Europe/London',
},
{
offset: 8,
timezone: 'Asia/Shanghai',
},
{
offset: 9,
timezone: 'Asia/Tokyo',
},
{
offset: 9,
timezone: 'Asia/Seoul',
},
];

View File

@@ -1,70 +0,0 @@
import type { EventHandlerRequest, H3Event } from 'h3';
import { setResponseStatus } from 'h3';
export function useResponseSuccess<T = any>(data: T) {
return {
code: 0,
data,
error: null,
message: 'ok',
};
}
export function usePageResponseSuccess<T = any>(
page: number | string,
pageSize: number | string,
list: T[],
{ message = 'ok' } = {},
) {
const pageData = pagination(
Number.parseInt(`${page}`),
Number.parseInt(`${pageSize}`),
list,
);
return {
...useResponseSuccess({
items: pageData,
total: list.length,
}),
message,
};
}
export function useResponseError(message: string, error: any = null) {
return {
code: -1,
data: null,
error,
message,
};
}
export function forbiddenResponse(
event: H3Event<EventHandlerRequest>,
message = 'Forbidden Exception',
) {
setResponseStatus(event, 403);
return useResponseError(message, message);
}
export function unAuthorizedResponse(event: H3Event<EventHandlerRequest>) {
setResponseStatus(event, 401);
return useResponseError('Unauthorized Exception', 'Unauthorized Exception');
}
export function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
export function pagination<T = any>(
pageNo: number,
pageSize: number,
array: T[],
): T[] {
const offset = (pageNo - 1) * Number(pageSize);
return offset + Number(pageSize) >= array.length
? array.slice(offset)
: array.slice(offset, offset + Number(pageSize));
}

View File

@@ -1,9 +0,0 @@
let mockTimeZone: null | string = null;
export const setTimezone = (timeZone: string) => {
mockTimeZone = timeZone;
};
export const getTimezone = () => {
return mockTimeZone;
};

View File

@@ -1,7 +1,35 @@
# public path
VITE_BASE=/
# Basic interface address SPA
VITE_GLOB_API_URL=/api
# 是否开启压缩,可以设置为 none, brotli, gzip
VITE_COMPRESS=gzip
# 是否开启 PWA
VITE_PWA=false
# vue-router 的模式
VITE_ROUTER_HISTORY=history
# 是否注入全局loading
VITE_INJECT_APP_LOADING=true
# 打包后是否生成dist.zip
VITE_ARCHIVER=true
# 后端接口地址
VITE_GLOB_API_URL=/prod-api
# 全局加密开关(即开启了加解密功能才会生效 不是全部接口加密 需要和后端对应)
VITE_GLOB_ENABLE_ENCRYPT=true
# RSA公钥 请求加密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
VITE_GLOB_RSA_PUBLIC_KEY=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
# RSA私钥 响应解密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
VITE_GLOB_RSA_PRIVATE_KEY=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
# 客户端id
# VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
VITE_GLOB_APP_CLIENT_ID=3fd880a0e6476add885c95bd5afd630f
# 开启SSE 具体消息逻辑: apps/web-antd/src/store/notify.ts
VITE_GLOB_SSE_ENABLE=true
# 开启websocket 具体消息逻辑: apps/web-antd/src/store/notify.ts
VITE_GLOB_WEBSOCKET_ENABLE=false
VITE_VISUALIZER=true

View File

@@ -2,8 +2,6 @@
VITE_PORT=5666
VITE_BASE=/
# 是否开启 Nitro Mock服务true 为开启false 为关闭
VITE_NITRO_MOCK=false
# 是否打开 devtoolstrue 为打开false 为关闭
VITE_DEVTOOLS=false
# 是否注入全局loading

View File

@@ -25,7 +25,8 @@ VITE_GLOB_RSA_PUBLIC_KEY=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj6
# RSA私钥 响应解密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
VITE_GLOB_RSA_PRIVATE_KEY=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
# 客户端id
VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
# VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
VITE_GLOB_APP_CLIENT_ID=3fd880a0e6476add885c95bd5afd630f
# 开启SSE 具体消息逻辑: apps/web-antd/src/store/notify.ts
VITE_GLOB_SSE_ENABLE=true

290
apps/web-antd/loading.html Normal file
View File

@@ -0,0 +1,290 @@
<style data-app-loading="inject-css">
html {
/* same as antdv-next/dist/reset.css setting, avoid the title line-height changed */
line-height: 1.15;
}
.dark .loading {
background-color: #0d0d10;
}
.dark .loading .title {
color: rgb(255 255 255 / 85%);
}
.loading {
position: fixed;
top: 0;
left: 0;
z-index: 9999;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
overflow: hidden;
pointer-events: none;
background-color: #f4f7f9;
}
/* .loading.hidden {
visibility: hidden;
opacity: 0;
transition: all 0.6s ease-out;
} */
.loading .title {
margin-top: 36px;
font-size: 30px;
font-weight: 600;
color: rgb(0 0 0 / 85%);
}
#__app-loading__.hidden {
pointer-events: none;
visibility: hidden;
opacity: 0;
transition: all 0.6s ease-out;
}
/** 下面是自定义 **/
/* From Uiverse.io by Admin12121 */
.content {
width: 300px;
height: 300px;
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.content .planet {
width: 65%;
height: 65%;
background-color: #546c8c;
border-radius: 100%;
position: absolute;
display: flex;
align-items: center;
transform-origin: center center;
box-shadow: inset 2px -10px 0px rgba(0, 0, 0, 0.1);
animation: planet 5s ease infinite alternate;
/* planet ring */
/* to cover the back of the ring */
/* planet spots */
}
@keyframes planet {
0% {
transform: rotate(10deg);
}
100% {
transform: rotate(-10deg);
}
}
.content .planet .ring {
position: absolute;
width: 300px;
height: 300px;
border-radius: 100%;
background-color: #bacbd9;
display: flex;
align-items: center;
justify-content: center;
transform-origin: 33% center;
box-shadow: 2px -10px 0px rgba(0, 0, 0, 0.1), inset -5px -10px 0px rgba(0, 0, 0, 0.1);
animation: ring 3s ease infinite;
/* small ball */
/* inner ring */
}
@keyframes ring {
0% {
transform: rotateX(110deg) rotateZ(0deg) translate(-50px, 5px);
}
100% {
transform: rotateX(110deg) rotateZ(360deg) translate(-50px, 5px);
}
}
.content .planet .ring:before {
content: "";
position: absolute;
width: 10px;
height: 30px;
border-radius: 100%;
background-color: #7ea1bf;
z-index: 2;
left: calc(0px - 5px);
box-shadow: inset -3px 3px 0px rgba(0, 0, 0, 0.2);
}
.content .planet .ring:after {
content: "";
position: absolute;
width: 240px;
height: 240px;
border-radius: 100%;
background-color: #7ea1bf;
box-shadow: inset 2px -10px 0px rgba(0, 0, 0, 0.1);
}
.content .planet .cover-ring {
position: absolute;
width: 100%;
height: 50%;
border-bottom-left-radius: 80%;
border-bottom-right-radius: 80%;
border-top-left-radius: 100px;
border-top-right-radius: 100px;
transform: translate(0px, -17px);
background-color: #546c8c;
z-index: 2;
box-shadow: inset 0px -2px 0px rgba(0, 0, 0, 0.1);
}
.content .planet .spots {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
z-index: 2;
}
.content .planet .spots span {
width: 30px;
height: 30px;
background-color: #3c4359;
position: absolute;
border-radius: 100%;
box-shadow: inset -2px 3px 0px rgba(0, 0, 0, 0.3);
animation: dots 5s ease infinite alternate;
}
@keyframes dots {
0% {
box-shadow: inset -3px 3px 0px rgba(0, 0, 0, 0.3);
}
100% {
box-shadow: inset 3px 3px 0px rgba(0, 0, 0, 0.3);
}
}
.content .planet .spots span:nth-child(1) {
top: 20px;
right: 50px;
}
.content .planet .spots span:nth-child(2) {
top: 40px;
left: 50px;
width: 15px;
height: 15px;
}
.content .planet .spots span:nth-child(3) {
top: 80px;
left: 20px;
width: 25px;
height: 25px;
}
.content .planet .spots span:nth-child(4) {
top: 80px;
left: 90px;
width: 40px;
height: 40px;
}
.content .planet .spots span:nth-child(5) {
top: 160px;
left: 70px;
width: 15px;
height: 15px;
}
.content .planet .spots span:nth-child(6) {
top: 165px;
left: 125px;
width: 10px;
height: 10px;
}
.content .planet .spots span:nth-child(7) {
top: 90px;
left: 150px;
width: 15px;
height: 15px;
}
.content p {
color: #bacbd9;
font-size: 14px;
z-index: 2;
position: absolute;
bottom: -20px;
font-family: "Roboto Mono", monospace;
animation: text 4s ease infinite;
width: 100px;
text-align: center;
}
@keyframes text {
0% {
transform: translateX(-30px);
letter-spacing: 0px;
color: #bacbd9;
}
25% {
letter-spacing: 3px;
color: #7ea1bf;
}
50% {
transform: translateX(30px);
letter-spacing: 0px;
color: #bacbd9;
}
75% {
letter-spacing: 3px;
color: #7ea1bf;
}
100% {
transform: translateX(-30px);
letter-spacing: 0px;
color: #bacbd9;
}
}
</style>
<div class="loading" id="__app-loading__">
<div class="content">
<div class="planet">
<div class="ring"></div>
<div class="cover-ring"></div>
<div class="spots">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
</div>
</div>
<div class="title">
<%= VITE_APP_TITLE %>
</div>
</div>

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/web-antd",
"version": "1.5.2",
"version": "2.0.0-alpha.3",
"homepage": "https://vben.pro",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {
@@ -27,8 +27,11 @@
"#/*": "./src/*"
},
"dependencies": {
"@ant-design/icons-vue": "^7.0.1",
"@tinymce/tinymce-vue": "^6.0.1",
"@alova/adapter-axios": "catalog:",
"@antdv-next/auto-import-resolver": "catalog:",
"@antdv-next/happy-work-theme": "catalog:",
"@antdv-next/icons": "catalog:",
"@tinymce/tinymce-vue": "catalog:",
"@vben/access": "workspace:*",
"@vben/common-ui": "workspace:*",
"@vben/constants": "workspace:*",
@@ -44,19 +47,22 @@
"@vben/types": "workspace:*",
"@vben/utils": "workspace:*",
"@vueuse/core": "catalog:",
"ant-design-vue": "catalog:",
"cropperjs": "^1.6.2",
"alova": "catalog:",
"antdv-next": "catalog:",
"axios": "catalog:",
"cropperjs": "catalog:",
"dayjs": "catalog:",
"echarts": "^5.5.1",
"lodash-es": "^4.17.21",
"echarts": "catalog:conflicts_echarts_h5_5_1",
"lodash-es": "catalog:",
"motion-v": "catalog:",
"pinia": "catalog:",
"tinymce": "7.9.1",
"unplugin-vue-components": "^0.27.3",
"tinymce": "catalog:",
"unplugin-vue-components": "catalog:",
"version-polling": "catalog:",
"vue": "catalog:",
"vue-router": "catalog:",
"vue3-colorpicker": "^2.3.0"
"vue-router": "catalog:"
},
"devDependencies": {
"@types/lodash-es": "^4.17.12"
"@types/lodash-es": "catalog:"
}
}

View File

@@ -13,10 +13,6 @@ import { computed, defineAsyncComponent, defineComponent, h, ref } from 'vue';
import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { notification } from 'ant-design-vue';
import { FileUploadOld, ImageUploadOld } from '#/components/upload-old';
const RichTextarea = defineAsyncComponent(() =>
import('#/components/tinymce/index').then((res) => res.Tinymce),
);
@@ -29,57 +25,68 @@ const ImageUpload = defineAsyncComponent(() =>
import('#/components/upload').then((res) => res.ImageUpload),
);
const AutoComplete = defineAsyncComponent(
() => import('ant-design-vue/es/auto-complete'),
const Button = defineAsyncComponent(
() => import('antdv-next/dist/button/index'),
);
const Button = defineAsyncComponent(() => import('ant-design-vue/es/button'));
const Cascader = defineAsyncComponent(
() => import('ant-design-vue/es/cascader'),
() => import('antdv-next/dist/cascader/index'),
);
const Checkbox = defineAsyncComponent(
() => import('ant-design-vue/es/checkbox'),
() => import('antdv-next/dist/checkbox/index'),
);
const CheckboxGroup = defineAsyncComponent(() =>
import('ant-design-vue/es/checkbox').then((res) => res.CheckboxGroup),
const CheckboxGroup = defineAsyncComponent(
() => import('antdv-next/dist/checkbox/Group'),
);
const DatePicker = defineAsyncComponent(
() => import('ant-design-vue/es/date-picker'),
() => import('antdv-next/dist/date-picker/index'),
);
const Divider = defineAsyncComponent(() => import('ant-design-vue/es/divider'));
const Input = defineAsyncComponent(() => import('ant-design-vue/es/input'));
const Divider = defineAsyncComponent(
() => import('antdv-next/dist/divider/index'),
);
const Input = defineAsyncComponent(() => import('antdv-next/dist/input/index'));
const InputNumber = defineAsyncComponent(
() => import('ant-design-vue/es/input-number'),
() => import('antdv-next/dist/input-number/index'),
);
const InputPassword = defineAsyncComponent(() =>
import('ant-design-vue/es/input').then((res) => res.InputPassword),
const InputPassword = defineAsyncComponent(
() => import('antdv-next/dist/input/Password'),
);
const Mentions = defineAsyncComponent(
() => import('ant-design-vue/es/mentions'),
() => import('antdv-next/dist/mentions/index'),
);
const Radio = defineAsyncComponent(() => import('ant-design-vue/es/radio'));
const Radio = defineAsyncComponent(() => import('antdv-next/dist/radio/index'));
const RadioGroup = defineAsyncComponent(() =>
import('ant-design-vue/es/radio').then((res) => res.RadioGroup),
import('antdv-next/dist/radio/index').then((res) => res.RadioGroup),
);
const RangePicker = defineAsyncComponent(() =>
import('ant-design-vue/es/date-picker').then((res) => res.RangePicker),
import('antdv-next/dist/date-picker/index').then(
(res) => res.DateRangePicker,
),
);
const Rate = defineAsyncComponent(() => import('ant-design-vue/es/rate'));
const Select = defineAsyncComponent(() => import('ant-design-vue/es/select'));
const Space = defineAsyncComponent(() => import('ant-design-vue/es/space'));
const Switch = defineAsyncComponent(() => import('ant-design-vue/es/switch'));
const Textarea = defineAsyncComponent(() =>
import('ant-design-vue/es/input').then((res) => res.Textarea),
const Rate = defineAsyncComponent(() => import('antdv-next/dist/rate/index'));
const Select = defineAsyncComponent(
() => import('antdv-next/dist/select/index'),
);
const Space = defineAsyncComponent(() => import('antdv-next/dist/space/index'));
const Switch = defineAsyncComponent(
() => import('antdv-next/dist/switch/index'),
);
const Textarea = defineAsyncComponent(
() => import('antdv-next/dist/input/TextArea'),
);
const TimePicker = defineAsyncComponent(
() => import('ant-design-vue/es/time-picker'),
() => import('antdv-next/dist/time-picker/index'),
);
const TimeRangePicker = defineAsyncComponent(() =>
import('ant-design-vue/es/time-picker').then((res) => res.TimeRangePicker),
import('antdv-next/dist/time-picker/index').then(
(res) => res.TimeRangePicker,
),
);
const TreeSelect = defineAsyncComponent(
() => import('ant-design-vue/es/tree-select'),
() => import('antdv-next/dist/tree-select/index'),
);
const Upload = defineAsyncComponent(
() => import('antdv-next/dist/upload/Upload'),
);
const Upload = defineAsyncComponent(() => import('ant-design-vue/es/upload'));
const withDefaultPlaceholder = <T extends Component>(
component: T,
@@ -127,6 +134,7 @@ const withDefaultPlaceholder = <T extends Component>(
// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
export type ComponentType =
| 'ApiCascader'
| 'ApiSelect'
| 'ApiTreeSelect'
| 'AutoComplete'
@@ -137,10 +145,8 @@ export type ComponentType =
| 'DefaultButton'
| 'Divider'
| 'FileUpload'
| 'FileUploadOld'
| 'IconPicker'
| 'ImageUpload'
| 'ImageUploadOld'
| 'Input'
| 'InputNumber'
| 'InputPassword'
@@ -166,6 +172,14 @@ async function initComponentAdapter() {
// 如果你的组件体积比较大,可以使用异步加载
// Button: () =>
// import('xxx').then((res) => res.Button),
ApiCascader: withDefaultPlaceholder(ApiComponent, 'select', {
component: Cascader,
fieldNames: { label: 'label', value: 'value', children: 'children' },
loadingSlot: 'suffixIcon',
modelPropName: 'value',
visibleEvent: 'onVisibleChange',
}),
ApiSelect: withDefaultPlaceholder(
{
...ApiComponent,
@@ -194,7 +208,6 @@ async function initComponentAdapter() {
visibleEvent: 'onVisibleChange',
},
),
AutoComplete,
Cascader: withDefaultPlaceholder(Cascader, 'select'),
Checkbox,
CheckboxGroup,
@@ -232,8 +245,6 @@ async function initComponentAdapter() {
ImageUpload,
FileUpload,
RichTextarea,
ImageUploadOld,
FileUploadOld,
};
// 将组件注册到全局共享状态中
@@ -243,9 +254,9 @@ async function initComponentAdapter() {
globalShareState.defineMessage({
// 复制成功消息提示
copyPreferencesSuccess: (title, content) => {
notification.success({
window.notification.success({
description: content,
message: title,
title,
placement: 'bottomRight',
});
},

View File

@@ -4,7 +4,7 @@ import { h } from 'vue';
import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table';
import { Button, Image } from 'ant-design-vue';
import { Button, Image } from 'antdv-next';
import { useVbenForm } from './form';
@@ -78,9 +78,10 @@ setupVbenVxeTable({
// 表格配置项可以用 cellRender: { name: 'CellImage' },
vxeUI.renderer.add('CellImage', {
renderTableDefault(_renderOpts, params) {
renderTableDefault(renderOpts, params) {
const { props } = renderOpts;
const { column, row } = params;
return h(Image, { src: row[column.field] });
return h(Image, { src: row[column.field], ...props });
},
});

View File

@@ -3,7 +3,7 @@ import type { HttpResponse } from '@vben/request';
import { useAppConfig } from '@vben/hooks';
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
const { clientId, sseEnable } = useAppConfig(
import.meta.env,
@@ -78,7 +78,7 @@ export namespace AuthApi {
* 登录
*/
export async function loginApi(data: AuthApi.LoginParams) {
return requestClient.post<AuthApi.LoginResult>(
return alovaInstance.post<AuthApi.LoginResult>(
'/auth/login',
{ ...data, clientId },
{
@@ -92,7 +92,7 @@ export async function loginApi(data: AuthApi.LoginParams) {
* @returns void
*/
export function doLogout() {
return requestClient.post<HttpResponse<void>>('/auth/logout');
return alovaInstance.post<HttpResponse<void>>('/auth/logout');
}
/**
@@ -106,7 +106,7 @@ export function seeConnectionClose() {
if (!sseEnable) {
return;
}
return requestClient.get<void>('/resource/sse/close');
return alovaInstance.get<void>('/resource/sse/close');
}
/**
@@ -133,7 +133,7 @@ export interface TenantResp {
* 获取租户列表 下拉框使用
*/
export function tenantList() {
return requestClient.get<TenantResp>('/auth/tenant/list');
return alovaInstance.get<TenantResp>('/auth/tenant/list');
}
/**
@@ -141,7 +141,7 @@ export function tenantList() {
* @returns string[]
*/
export async function getAccessCodesApi() {
return requestClient.get<string[]>('/auth/codes');
return alovaInstance.get<string[]>('/auth/codes');
}
/**
@@ -150,7 +150,7 @@ export async function getAccessCodesApi() {
* @returns 跳转url
*/
export function authBinding(source: string, tenantId: string) {
return requestClient.get<string>(`/auth/binding/${source}`, {
return alovaInstance.get<string>(`/auth/binding/${source}`, {
params: {
domain: window.location.host,
tenantId,
@@ -163,7 +163,7 @@ export function authBinding(source: string, tenantId: string) {
* @param id id
*/
export function authUnbinding(id: string) {
return requestClient.deleteWithMsg<void>(`/auth/unlock/${id}`);
return alovaInstance.deleteWithMsg<void>(`/auth/unlock/${id}`);
}
/**
@@ -172,5 +172,5 @@ export function authUnbinding(id: string) {
* @returns void
*/
export function authCallback(data: AuthApi.OAuthLoginParams) {
return requestClient.post<void>('/auth/social/callback', data);
return alovaInstance.post<void>('/auth/social/callback', data);
}

View File

@@ -1,4 +1,4 @@
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
/**
* 发送短信验证码
@@ -6,7 +6,7 @@ import { requestClient } from '#/api/request';
* @returns void
*/
export function sendSmsCode(phonenumber: string) {
return requestClient.get<void>('/resource/sms/code', {
return alovaInstance.get<void>('/resource/sms/code', {
params: { phonenumber },
});
}
@@ -17,7 +17,7 @@ export function sendSmsCode(phonenumber: string) {
* @returns void
*/
export function sendEmailCode(email: string) {
return requestClient.get<void>('/resource/email/code', {
return alovaInstance.get<void>('/resource/email/code', {
params: { email },
});
}
@@ -38,5 +38,5 @@ export interface CaptchaResponse {
* @returns resp
*/
export function captchaImage() {
return requestClient.get<CaptchaResponse>('/auth/code');
return alovaInstance.get<CaptchaResponse>('/auth/code');
}

View File

@@ -1,4 +1,4 @@
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
/**
* @description: 菜单meta
@@ -41,5 +41,5 @@ export interface Menu {
* 获取用户所有菜单
*/
export async function getAllMenusApi() {
return requestClient.get<Menu[]>('/system/menu/getRouters');
return alovaInstance.get<Menu[]>('/system/menu/getRouters');
}

View File

@@ -1,6 +1,7 @@
import type { AxiosRequestConfig } from '@vben/request';
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
import { ContentTypeEnum } from '#/utils/http/helper';
/**
* Axios上传进度事件
@@ -20,24 +21,25 @@ export interface UploadResult {
* 通过单文件上传接口
* @param file 上传的文件
* @param options 一些配置项
* @param options.onUploadProgress 上传进度事件
* @param options.signal 上传取消信号
* @param options.otherData 其他请求参数 后端拓展可能会用到
* @returns 上传结果
*/
export function uploadApi(
file: Blob | File,
options?: {
onUploadProgress?: AxiosProgressEvent;
otherData?: Record<string, any>;
signal?: AbortSignal;
},
) {
const { onUploadProgress, signal, otherData = {} } = options ?? {};
return requestClient.upload<UploadResult>(
const { otherData = {} } = options ?? {};
return alovaInstance.post<UploadResult>(
'/resource/oss/upload',
{ file, ...otherData },
{ onUploadProgress, signal, timeout: 60_000 },
{
timeout: 60_000,
headers: {
'Content-Type': ContentTypeEnum.FORM_DATA,
},
},
);
}

View File

@@ -1,4 +1,4 @@
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
export interface Role {
dataScope: string;
@@ -42,5 +42,5 @@ export interface UserInfoResp {
* 存在返回null的情况(401) 不会抛出异常 需要手动抛异常
*/
export async function getUserInfoApi() {
return requestClient.get<null | UserInfoResp>('/system/user/getInfo');
return alovaInstance.get<null | UserInfoResp>('/system/user/getInfo');
}

View File

@@ -1,10 +1,7 @@
import { $t } from '@vben/locales';
import { message, Modal } from 'ant-design-vue';
import { useAuthStore } from '#/store';
import { requestClient } from './request';
import { alovaInstance } from '#/utils/http';
/**
* @description: contentType
@@ -25,8 +22,7 @@ export const ContentTypeEnum = {
* @returns blob二进制
*/
export function commonExport(url: string, data: Record<string, any>) {
return requestClient.post<Blob>(url, data, {
data,
return alovaInstance.post<Blob>(url, data, {
headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED },
isTransformResponse: false,
responseType: 'blob',
@@ -83,7 +79,7 @@ export function handleUnauthorizedLogout() {
if (error instanceof ImpossibleReturn401Exception) {
lockLogoutRequest = true;
if (import.meta.env.DEV) {
Modal.error({
window.modal.error({
title: '提示',
centered: true,
content:
@@ -93,7 +89,7 @@ export function handleUnauthorizedLogout() {
}
})
.finally(() => {
message.error(timeoutMsg);
window.message.error(timeoutMsg);
isLogoutProcessing = false;
});
// 不再执行下面逻辑

View File

@@ -1,4 +1,4 @@
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
export interface CommandStats {
name: string;
@@ -20,5 +20,5 @@ export interface CacheInfo {
* @returns redis信息
*/
export function redisCacheInfo() {
return requestClient.get<CacheInfo>('/monitor/cache');
return alovaInstance.get<CacheInfo>('/monitor/cache');
}

View File

@@ -3,7 +3,7 @@ import type { LoginLog } from './model';
import type { IDS, PageQuery, PageResult } from '#/api/common';
import { commonExport } from '#/api/helper';
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
enum Api {
loginInfoClean = '/monitor/logininfor/clean',
@@ -19,7 +19,7 @@ enum Api {
* @returns list[]
*/
export function loginInfoList(params?: PageQuery) {
return requestClient.get<PageResult<LoginLog>>(Api.loginInfoList, { params });
return alovaInstance.get<PageResult<LoginLog>>(Api.loginInfoList, { params });
}
/**
@@ -37,7 +37,7 @@ export function loginInfoExport(data: any) {
* @returns void
*/
export function loginInfoRemove(infoIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${infoIds}`);
return alovaInstance.deleteWithMsg<void>(`${Api.root}/${infoIds}`);
}
/**
@@ -46,7 +46,7 @@ export function loginInfoRemove(infoIds: IDS) {
* @returns void
*/
export function userUnlock(username: string) {
return requestClient.get<void>(`${Api.userUnlock}/${username}`, {
return alovaInstance.get<void>(`${Api.userUnlock}/${username}`, {
successMessageMode: 'message',
});
}
@@ -56,5 +56,5 @@ export function userUnlock(username: string) {
* @returns void
*/
export function loginInfoClean() {
return requestClient.deleteWithMsg<void>(Api.loginInfoClean);
return alovaInstance.deleteWithMsg<void>(Api.loginInfoClean);
}

View File

@@ -2,7 +2,7 @@ import type { OnlineUser } from './model';
import type { PageQuery, PageResult } from '#/api/common';
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
enum Api {
onlineList = '/monitor/online/list',
@@ -14,7 +14,7 @@ enum Api {
* @returns OnlineUser[]
*/
export function onlineDeviceList() {
return requestClient.get<PageResult<OnlineUser>>(Api.root);
return alovaInstance.get<PageResult<OnlineUser>>(Api.root);
}
/**
@@ -23,7 +23,7 @@ export function onlineDeviceList() {
* @returns 结果
*/
export function onlineList(params?: PageQuery) {
return requestClient.get<PageResult<OnlineUser>>(Api.onlineList, { params });
return alovaInstance.get<PageResult<OnlineUser>>(Api.onlineList, { params });
}
/**
@@ -32,7 +32,7 @@ export function onlineList(params?: PageQuery) {
* @returns void
*/
export function forceLogout(tokenId: string) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${tokenId}`);
return alovaInstance.deleteWithMsg<void>(`${Api.root}/${tokenId}`);
}
/**
@@ -41,5 +41,5 @@ export function forceLogout(tokenId: string) {
* @returns void
*/
export function forceLogout2(tokenId: string) {
return requestClient.deleteWithMsg<void>(`${Api.root}/myself/${tokenId}`);
return alovaInstance.deleteWithMsg<void>(`${Api.root}/myself/${tokenId}`);
}

View File

@@ -3,7 +3,7 @@ import type { OperationLog } from './model';
import type { IDS, PageQuery, PageResult } from '#/api/common';
import { commonExport } from '#/api/helper';
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
enum Api {
operLogClean = '/monitor/operlog/clean',
@@ -18,7 +18,7 @@ enum Api {
* @returns 分页结果
*/
export function operLogList(params?: PageQuery) {
return requestClient.get<PageResult<OperationLog>>(Api.operLogList, {
return alovaInstance.get<PageResult<OperationLog>>(Api.operLogList, {
params,
});
}
@@ -28,14 +28,14 @@ export function operLogList(params?: PageQuery) {
* @param operIds id/ids
*/
export function operLogDelete(operIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${operIds}`);
return alovaInstance.deleteWithMsg<void>(`${Api.root}/${operIds}`);
}
/**
* 清空全部分页日志
*/
export function operLogClean() {
return requestClient.deleteWithMsg<void>(Api.operLogClean);
return alovaInstance.deleteWithMsg<void>(Api.operLogClean);
}
/**

View File

@@ -1,319 +0,0 @@
/**
* 该文件可自行根据业务逻辑进行调整
*/
import type { HttpResponse } from '@vben/request';
import type {
BaseAsymmetricEncryption,
BaseSymmetricEncryption,
} from '@vben/utils';
import { BUSINESS_SUCCESS_CODE, UNAUTHORIZED_CODE } from '@vben/constants';
import { useAppConfig } from '@vben/hooks';
import { $t } from '@vben/locales';
import { preferences } from '@vben/preferences';
import {
authenticateResponseInterceptor,
errorMessageResponseInterceptor,
RequestClient,
stringify,
} from '@vben/request';
import { useAccessStore } from '@vben/stores';
import {
AesEncryption,
decodeBase64,
encodeBase64,
randomStr,
RsaEncryption,
} from '@vben/utils';
import { message, Modal } from 'ant-design-vue';
import { isEmpty, isNull } from 'lodash-es';
import { useAuthStore } from '#/store';
import { handleUnauthorizedLogout } from './helper';
const { apiURL, clientId, enableEncrypt, rsaPublicKey, rsaPrivateKey } =
useAppConfig(import.meta.env, import.meta.env.PROD);
/**
* 使用非对称加密的实现 前端已经实现RSA/SM2
*
* 你可以使用Sm2Encryption来替换 后端也需要同步替换公私钥对
*
* 后端文件位置: ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/DecryptRequestBodyWrapper.java
*
* 注意前端sm-crypto库只能支持04开头的公钥! 否则加密会有问题 你可以使用前端的import { logSm2KeyPair } from '@vben/utils';方法来生成
* 如果你生成的公钥开头不是04 那么不能正常加密
* 或者使用这个网站来生成: https://tool.hiofd.com/sm2-key-gen/
*/
const asymmetricEncryption: BaseAsymmetricEncryption = new RsaEncryption({
publicKey: rsaPublicKey,
privateKey: rsaPrivateKey,
});
/**
* 对称加密的实现 AES/SM4
*/
const symmetricEncryption: BaseSymmetricEncryption = new AesEncryption();
function createRequestClient(baseURL: string) {
const client = new RequestClient({
// 后端地址
baseURL,
// 消息提示类型
errorMessageMode: 'message',
// 是否返回原生响应 比如:需要获取响应头时使用该属性
isReturnNativeResponse: false,
// 需要对返回数据进行处理
isTransformResponse: true,
});
/**
* 重新认证逻辑
*/
async function doReAuthenticate() {
console.warn('Access token or refresh token is invalid or expired. ');
const accessStore = useAccessStore();
const authStore = useAuthStore();
accessStore.setAccessToken(null);
if (
preferences.app.loginExpiredMode === 'modal' &&
accessStore.isAccessChecked
) {
accessStore.setLoginExpired(true);
} else {
await authStore.logout();
}
}
/**
* 刷新token逻辑
*/
async function doRefreshToken() {
// 不需要
// 保留此方法只是为了合并方便
return '';
}
function formatToken(token: null | string) {
return token ? `Bearer ${token}` : null;
}
client.addRequestInterceptor({
fulfilled: (config) => {
const accessStore = useAccessStore();
// 添加token
config.headers.Authorization = formatToken(accessStore.accessToken);
/**
* locale跟后台不一致 需要转换
*/
const language = preferences.app.locale.replace('-', '_');
config.headers['Accept-Language'] = language;
config.headers['Content-Language'] = language;
/**
* 添加全局clientId
* 关于header的clientId被错误绑定到实体类
* https://gitee.com/dapppp/ruoyi-plus-vben5/issues/IC0BDS
*/
config.headers.ClientID = clientId;
/**
* 格式化get/delete参数
* 如果包含自定义的paramsSerializer则不走此逻辑
*/
if (
['DELETE', 'GET'].includes(config.method?.toUpperCase() || '') &&
config.params &&
!config.paramsSerializer
) {
/**
* 1. 格式化参数 微服务在传递区间时间选择(后端的params Map类型参数)需要格式化key 否则接收不到
* 2. 数组参数需要格式化 后端才能正常接收 会变成arr=1&arr=2&arr=3的格式来接收
*/
config.paramsSerializer = (params) =>
stringify(params, { arrayFormat: 'repeat' });
}
const { encrypt } = config;
// 全局开启请求加密功能 && 该请求开启 && 是post/put请求
if (
enableEncrypt &&
encrypt &&
['POST', 'PUT'].includes(config.method?.toUpperCase() || '')
) {
// sm4这里改为randomStr(16)
const key = randomStr(32);
const keyWithBase64 = encodeBase64(key);
config.headers['encrypt-key'] =
asymmetricEncryption.encrypt(keyWithBase64);
/**
* axios会默认给字符串前后加上引号 RSA可以正常解密(加不加都能解密) 但是SM2不行(大坑!!!)
* 这里通过transformRequest强制返回原始内容
*/
config.transformRequest = (data) => data;
config.data =
typeof config.data === 'object'
? symmetricEncryption.encrypt(JSON.stringify(config.data), key)
: symmetricEncryption.encrypt(config.data, key);
}
return config;
},
});
// 通用的错误处理, 如果没有进入上面的错误处理逻辑,就会进入这里
// 主要处理http状态码不为200(如网络异常/离线)的情况 必须放在在下面的响应拦截器之前
client.addResponseInterceptor(
errorMessageResponseInterceptor((msg: string) => message.error(msg)),
);
client.addResponseInterceptor<HttpResponse>({
fulfilled: async (response) => {
const encryptKey = (response.headers ?? {})['encrypt-key'];
if (encryptKey) {
/** RSA私钥解密 拿到解密秘钥的base64 */
const base64Str = asymmetricEncryption.decrypt(encryptKey);
/** base64 解码 得到请求头的 AES 秘钥 */
const secret = decodeBase64(base64Str);
/** 使用aesKey解密 responseData */
const decryptData = symmetricEncryption.decrypt(
response.data as unknown as string,
secret,
);
/** 赋值 需要转为对象 */
response.data = JSON.parse(decryptData);
}
const { isReturnNativeResponse, isTransformResponse } = response.config;
// 是否返回原生响应 比如:需要获取响应时使用该属性
if (isReturnNativeResponse) {
return response;
}
// 不进行任何处理,直接返回
// 用于页面代码可能需要直接获取codedatamessage这些信息时开启
if (!isTransformResponse) {
/**
* @warning 注意 微服务版本在401(网关)会返回text/plain的头 所以这里代码会无效
* 我建议你改后端而不是前端来做兼容
*/
// json数据的判断
if (response.headers['content-type']?.includes?.('application/json')) {
/**
* 需要判断是否登录超时/401
* 执行登出操作
*/
const resp = response.data as unknown as HttpResponse;
// 抛出异常 不再执行
if (
typeof resp === 'object' &&
Reflect.has(resp, 'code') &&
resp.code === UNAUTHORIZED_CODE
) {
handleUnauthorizedLogout();
}
/**
* 需要判断下载二进制的情况 正常是返回二进制 报错会返回json
* 当type为blob且content-type为application/json时 则判断已经下载出错
*/
if (response.config.responseType === 'blob') {
// 这时候的data为blob类型
const blob = response.data as unknown as Blob;
// 拿到字符串转json对象
response.data = JSON.parse(await blob.text());
// 然后按正常逻辑执行下面的代码(判断业务状态码)
} else {
// 其他类型数据 直接返回
return response.data;
}
} else {
// 非json数据 直接返回 不做校验
return response.data;
}
}
const axiosResponseData = response.data;
if (!axiosResponseData) {
throw new Error($t('http.apiRequestFailed'));
}
// 后端并没有采用严格的{code, msg, data}模式
const { code, data, msg, ...other } = axiosResponseData;
// 业务状态码为200 则请求成功
const hasSuccess =
Reflect.has(axiosResponseData, 'code') &&
code === BUSINESS_SUCCESS_CODE;
if (hasSuccess) {
let successMsg = msg;
if (isNull(successMsg) || isEmpty(successMsg)) {
successMsg = $t(`http.operationSuccess`);
}
if (response.config.successMessageMode === 'modal') {
Modal.success({
content: successMsg,
title: $t('http.successTip'),
});
} else if (response.config.successMessageMode === 'message') {
message.success(successMsg);
}
// 分页情况下为code msg rows total 并没有data字段
// 如果有data 直接返回data 没有data将剩余参数(...other)封装为data返回
// 需要考虑data为null的情况(比如查询为空) 所以这里直接判断undefined
if (data !== undefined) {
return data;
}
// 没有data 将其他参数包装为data
return other;
}
// 在此处根据自己项目的实际情况对不同的code执行不同的操作
// 如果不希望中断当前请求请return数据否则直接抛出异常即可
let timeoutMsg = '';
switch (code) {
// 登录超时
case UNAUTHORIZED_CODE: {
handleUnauthorizedLogout();
break;
}
default: {
if (msg) {
timeoutMsg = msg;
}
}
}
// errorMessageMode='modal'的时候会显示modal错误弹窗而不是消息提示用于一些比较重要的错误
// errorMessageMode='none' 一般是调用时明确表示不希望自动弹出错误提示
if (response.config.errorMessageMode === 'modal') {
Modal.error({
content: timeoutMsg,
title: $t('http.errorTip'),
});
} else if (response.config.errorMessageMode === 'message') {
message.error(timeoutMsg);
}
throw new Error(timeoutMsg || $t('http.apiRequestFailed'));
},
});
// token过期的处理
client.addResponseInterceptor(
authenticateResponseInterceptor({
client,
doReAuthenticate,
doRefreshToken,
enableRefreshToken: preferences.app.enableRefreshToken,
formatToken,
}),
);
return client;
}
export const requestClient = createRequestClient(apiURL);
export const baseRequestClient = new RequestClient({ baseURL: apiURL });

View File

@@ -3,7 +3,7 @@ import type { Client } from './model';
import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
import { commonExport } from '#/api/helper';
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
enum Api {
clientChangeStatus = '/system/client/changeStatus',
@@ -18,7 +18,7 @@ enum Api {
* @returns 列表
*/
export function clientList(params?: PageQuery) {
return requestClient.get<PageResult<Client>>(Api.clientList, { params });
return alovaInstance.get<PageResult<Client>>(Api.clientList, { params });
}
/**
@@ -35,7 +35,7 @@ export function clientExport(data: Partial<Client>) {
* @returns 详情
*/
export function clientInfo(id: ID) {
return requestClient.get<Client>(`${Api.root}/${id}`);
return alovaInstance.get<Client>(`${Api.root}/${id}`);
}
/**
@@ -43,7 +43,7 @@ export function clientInfo(id: ID) {
* @param data 参数
*/
export function clientAdd(data: Partial<Client>) {
return requestClient.postWithMsg<void>(Api.root, data);
return alovaInstance.postWithMsg<void>(Api.root, data);
}
/**
@@ -51,7 +51,7 @@ export function clientAdd(data: Partial<Client>) {
* @param data 参数
*/
export function clientUpdate(data: Partial<Client>) {
return requestClient.putWithMsg<void>(Api.root, data);
return alovaInstance.putWithMsg<void>(Api.root, data);
}
/**
@@ -63,7 +63,7 @@ export function clientChangeStatus(data: any) {
clientId: data.clientId,
status: data.status,
};
return requestClient.putWithMsg<void>(Api.clientChangeStatus, requestData);
return alovaInstance.putWithMsg<void>(Api.clientChangeStatus, requestData);
}
/**
@@ -71,5 +71,5 @@ export function clientChangeStatus(data: any) {
* @param ids id集合
*/
export function clientRemove(ids: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${ids}`);
return alovaInstance.deleteWithMsg<void>(`${Api.root}/${ids}`);
}

View File

@@ -3,7 +3,7 @@ import type { SysConfig } from './model';
import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
import { commonExport } from '#/api/helper';
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
enum Api {
configExport = '/system/config/export',
@@ -19,11 +19,11 @@ enum Api {
* @returns 列表
*/
export function configList(params?: PageQuery) {
return requestClient.get<PageResult<SysConfig>>(Api.configList, { params });
return alovaInstance.get<PageResult<SysConfig>>(Api.configList, { params });
}
export function configInfo(configId: ID) {
return requestClient.get<SysConfig>(`${Api.root}/${configId}`);
return alovaInstance.get<SysConfig>(`${Api.root}/${configId}`);
}
/**
@@ -39,7 +39,7 @@ export function configExport(data: Partial<SysConfig>) {
* @returns void
*/
export function configRefreshCache() {
return requestClient.deleteWithMsg<void>(Api.configRefreshCache);
return alovaInstance.deleteWithMsg<void>(Api.configRefreshCache);
}
/**
@@ -47,7 +47,7 @@ export function configRefreshCache() {
* @param data 参数
*/
export function configUpdate(data: Partial<SysConfig>) {
return requestClient.putWithMsg<void>(Api.root, data);
return alovaInstance.putWithMsg<void>(Api.root, data);
}
/**
@@ -55,7 +55,7 @@ export function configUpdate(data: Partial<SysConfig>) {
* @param data 参数
*/
export function configAdd(data: Partial<SysConfig>) {
return requestClient.postWithMsg<void>(Api.root, data);
return alovaInstance.postWithMsg<void>(Api.root, data);
}
/**
@@ -63,7 +63,7 @@ export function configAdd(data: Partial<SysConfig>) {
* @param configIds ids
*/
export function configRemove(configIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${configIds}`);
return alovaInstance.deleteWithMsg<void>(`${Api.root}/${configIds}`);
}
/**
@@ -72,5 +72,5 @@ export function configRemove(configIds: IDS) {
* @returns value
*/
export function configInfoByKey(configKey: string) {
return requestClient.get<string>(`${Api.configInfoByKey}/${configKey}`);
return alovaInstance.get<string>(`${Api.configInfoByKey}/${configKey}`);
}

View File

@@ -2,7 +2,7 @@ import type { Dept } from './model';
import type { ID } from '#/api/common';
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
enum Api {
deptList = '/system/dept/list',
@@ -15,7 +15,7 @@ enum Api {
* @returns list
*/
export function deptList(params?: { deptName?: string; status?: string }) {
return requestClient.get<Dept[]>(Api.deptList, { params });
return alovaInstance.get<Dept[]>(Api.deptList, { params });
}
/**
@@ -24,7 +24,7 @@ export function deptList(params?: { deptName?: string; status?: string }) {
* @returns void
*/
export function deptNodeList(deptId: ID) {
return requestClient.get<Dept[]>(`${Api.deptNodeInfo}/${deptId}`);
return alovaInstance.get<Dept[]>(`${Api.deptNodeInfo}/${deptId}`);
}
/**
@@ -33,7 +33,7 @@ export function deptNodeList(deptId: ID) {
* @returns 部门信息
*/
export function deptInfo(deptId: ID) {
return requestClient.get<Dept>(`${Api.root}/${deptId}`);
return alovaInstance.get<Dept>(`${Api.root}/${deptId}`);
}
/**
@@ -41,7 +41,7 @@ export function deptInfo(deptId: ID) {
* @param data 参数
*/
export function deptAdd(data: Partial<Dept>) {
return requestClient.postWithMsg<void>(Api.root, data);
return alovaInstance.postWithMsg<void>(Api.root, data);
}
/**
@@ -49,7 +49,7 @@ export function deptAdd(data: Partial<Dept>) {
* @param data 参数
*/
export function deptUpdate(data: Partial<Dept>) {
return requestClient.putWithMsg<void>(Api.root, data);
return alovaInstance.putWithMsg<void>(Api.root, data);
}
/**
@@ -58,5 +58,5 @@ export function deptUpdate(data: Partial<Dept>) {
* @returns void
*/
export function deptRemove(deptId: ID) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${deptId}`);
return alovaInstance.deleteWithMsg<void>(`${Api.root}/${deptId}`);
}

View File

@@ -3,7 +3,7 @@ import type { DictData } from './dict-data-model';
import type { ID, IDS, PageQuery } from '#/api/common';
import { commonExport } from '#/api/helper';
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
enum Api {
dictDataExport = '/system/dict/data/export',
@@ -17,7 +17,7 @@ enum Api {
* @returns 字典数据
*/
export function dictDataInfo(dictType: string) {
return requestClient.get<DictData[]>(`${Api.root}/type/${dictType}`);
return alovaInstance.get<DictData[]>(`${Api.root}/type/${dictType}`);
}
/**
@@ -26,7 +26,7 @@ export function dictDataInfo(dictType: string) {
* @returns 字典数据列表
*/
export function dictDataList(params?: PageQuery) {
return requestClient.get<DictData[]>(Api.dictDataList, { params });
return alovaInstance.get<DictData[]>(Api.dictDataList, { params });
}
/**
@@ -44,7 +44,7 @@ export function dictDataExport(data: Partial<DictData>) {
* @returns void
*/
export function dictDataRemove(dictIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${dictIds}`);
return alovaInstance.deleteWithMsg<void>(`${Api.root}/${dictIds}`);
}
/**
@@ -53,7 +53,7 @@ export function dictDataRemove(dictIds: IDS) {
* @returns void
*/
export function dictDataAdd(data: Partial<DictData>) {
return requestClient.postWithMsg<void>(Api.root, data);
return alovaInstance.postWithMsg<void>(Api.root, data);
}
/**
@@ -62,7 +62,7 @@ export function dictDataAdd(data: Partial<DictData>) {
* @returns void
*/
export function dictDataUpdate(data: Partial<DictData>) {
return requestClient.putWithMsg<void>(Api.root, data);
return alovaInstance.putWithMsg<void>(Api.root, data);
}
/**
@@ -71,5 +71,5 @@ export function dictDataUpdate(data: Partial<DictData>) {
* @returns 字典数据
*/
export function dictDetailInfo(dictCode: ID) {
return requestClient.get<DictData>(`${Api.root}/${dictCode}`);
return alovaInstance.get<DictData>(`${Api.root}/${dictCode}`);
}

View File

@@ -3,7 +3,7 @@ import type { DictType } from './dict-type-model';
import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
import { commonExport } from '#/api/helper';
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
enum Api {
dictOptionSelectList = '/system/dict/type/optionselect',
@@ -19,7 +19,7 @@ enum Api {
* @returns list
*/
export function dictTypeList(params?: PageQuery) {
return requestClient.get<PageResult<DictType>>(Api.dictTypeList, { params });
return alovaInstance.get<PageResult<DictType>>(Api.dictTypeList, { params });
}
/**
@@ -37,7 +37,7 @@ export function dictTypeExport(data: Partial<DictType>) {
* @returns void
*/
export function dictTypeRemove(dictIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${dictIds}`);
return alovaInstance.deleteWithMsg<void>(`${Api.root}/${dictIds}`);
}
/**
@@ -45,7 +45,7 @@ export function dictTypeRemove(dictIds: IDS) {
* @returns void
*/
export function refreshDictTypeCache() {
return requestClient.deleteWithMsg<void>(Api.dictTypeRefreshCache);
return alovaInstance.deleteWithMsg<void>(Api.dictTypeRefreshCache);
}
/**
@@ -54,7 +54,7 @@ export function refreshDictTypeCache() {
* @returns void
*/
export function dictTypeAdd(data: Partial<DictType>) {
return requestClient.postWithMsg<void>(Api.root, data);
return alovaInstance.postWithMsg<void>(Api.root, data);
}
/**
@@ -63,7 +63,7 @@ export function dictTypeAdd(data: Partial<DictType>) {
* @returns void
*/
export function dictTypeUpdate(data: Partial<DictType>) {
return requestClient.putWithMsg<void>(Api.root, data);
return alovaInstance.putWithMsg<void>(Api.root, data);
}
/**
@@ -72,7 +72,7 @@ export function dictTypeUpdate(data: Partial<DictType>) {
* @returns 信息
*/
export function dictTypeInfo(dictId: ID) {
return requestClient.get<DictType>(`${Api.root}/${dictId}`);
return alovaInstance.get<DictType>(`${Api.root}/${dictId}`);
}
/**
@@ -81,5 +81,5 @@ export function dictTypeInfo(dictId: ID) {
* @returns options
*/
export function dictOptionSelectList() {
return requestClient.get<DictType[]>(Api.dictOptionSelectList);
return alovaInstance.get<DictType[]>(Api.dictOptionSelectList);
}

View File

@@ -2,7 +2,7 @@ import type { Menu, MenuOption, MenuQuery, MenuResp } from './model';
import type { ID, IDS } from '#/api/common';
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
enum Api {
menuList = '/system/menu/list',
@@ -18,7 +18,7 @@ enum Api {
* @returns 列表
*/
export function menuList(params?: MenuQuery) {
return requestClient.get<Menu[]>(Api.menuList, { params });
return alovaInstance.get<Menu[]>(Api.menuList, { params });
}
/**
@@ -27,7 +27,7 @@ export function menuList(params?: MenuQuery) {
* @returns 菜单详情
*/
export function menuInfo(menuId: ID) {
return requestClient.get<Menu>(`${Api.root}/${menuId}`);
return alovaInstance.get<Menu>(`${Api.root}/${menuId}`);
}
/**
@@ -35,7 +35,7 @@ export function menuInfo(menuId: ID) {
* @param data 参数
*/
export function menuAdd(data: Partial<Menu>) {
return requestClient.postWithMsg<void>(Api.root, data);
return alovaInstance.postWithMsg<void>(Api.root, data);
}
/**
@@ -43,7 +43,7 @@ export function menuAdd(data: Partial<Menu>) {
* @param data 参数
*/
export function menuUpdate(data: Partial<Menu>) {
return requestClient.putWithMsg<void>(Api.root, data);
return alovaInstance.putWithMsg<void>(Api.root, data);
}
/**
@@ -51,7 +51,7 @@ export function menuUpdate(data: Partial<Menu>) {
* @param menuIds ids
*/
export function menuRemove(menuIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${menuIds}`);
return alovaInstance.deleteWithMsg<void>(`${Api.root}/${menuIds}`);
}
/**
@@ -60,7 +60,7 @@ export function menuRemove(menuIds: IDS) {
* @returns resp
*/
export function roleMenuTreeSelect(roleId: ID) {
return requestClient.get<MenuResp>(`${Api.roleMenuTree}/${roleId}`);
return alovaInstance.get<MenuResp>(`${Api.roleMenuTree}/${roleId}`);
}
/**
@@ -68,7 +68,7 @@ export function roleMenuTreeSelect(roleId: ID) {
* @returns []
*/
export function menuTreeSelect() {
return requestClient.get<MenuOption[]>(Api.menuTreeSelect);
return alovaInstance.get<MenuOption[]>(Api.menuTreeSelect);
}
/**
@@ -77,7 +77,7 @@ export function menuTreeSelect() {
* @returns resp
*/
export function tenantPackageMenuTreeSelect(packageId: ID) {
return requestClient.get<MenuResp>(
return alovaInstance.get<MenuResp>(
`${Api.tenantPackageMenuTreeselect}/${packageId}`,
);
}
@@ -88,5 +88,5 @@ export function tenantPackageMenuTreeSelect(packageId: ID) {
* @returns void
*/
export function menuCascadeRemove(menuIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/cascade/${menuIds}`);
return alovaInstance.deleteWithMsg<void>(`${Api.root}/cascade/${menuIds}`);
}

View File

@@ -2,7 +2,7 @@ import type { Notice } from './model';
import type { ID, IDS, PageQuery } from '#/api/common';
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
enum Api {
noticeList = '/system/notice/list',
@@ -15,7 +15,7 @@ enum Api {
* @returns 分页结果
*/
export function noticeList(params?: PageQuery) {
return requestClient.get<Notice[]>(Api.noticeList, { params });
return alovaInstance.get<Notice[]>(Api.noticeList, { params });
}
/**
@@ -24,7 +24,7 @@ export function noticeList(params?: PageQuery) {
* @returns 详情
*/
export function noticeInfo(noticeId: ID) {
return requestClient.get<Notice>(`${Api.root}/${noticeId}`);
return alovaInstance.get<Notice>(`${Api.root}/${noticeId}`);
}
/**
@@ -32,7 +32,7 @@ export function noticeInfo(noticeId: ID) {
* @param data 参数
*/
export function noticeAdd(data: Partial<Notice>) {
return requestClient.postWithMsg<void>(Api.root, data);
return alovaInstance.postWithMsg<void>(Api.root, data);
}
/**
@@ -40,7 +40,7 @@ export function noticeAdd(data: Partial<Notice>) {
* @param data 参数
*/
export function noticeUpdate(data: any) {
return requestClient.putWithMsg<void>(Api.root, data);
return alovaInstance.putWithMsg<void>(Api.root, data);
}
/**
@@ -48,5 +48,5 @@ export function noticeUpdate(data: any) {
* @param noticeIds ids
*/
export function noticeRemove(noticeIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${noticeIds}`);
return alovaInstance.deleteWithMsg<void>(`${Api.root}/${noticeIds}`);
}

View File

@@ -2,7 +2,7 @@ import type { OssConfig } from './model';
import type { ID, IDS, PageQuery } from '#/api/common';
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
enum Api {
ossConfigChangeStatus = '/resource/oss/config/changeStatus',
@@ -12,27 +12,27 @@ enum Api {
// 获取OSS配置列表
export function ossConfigList(params?: PageQuery) {
return requestClient.get<OssConfig[]>(Api.ossConfigList, { params });
return alovaInstance.get<OssConfig[]>(Api.ossConfigList, { params });
}
// 获取OSS配置的信息
export function ossConfigInfo(ossConfigId: ID) {
return requestClient.get<OssConfig>(`${Api.root}/${ossConfigId}`);
return alovaInstance.get<OssConfig>(`${Api.root}/${ossConfigId}`);
}
// 添加新的OSS配置
export function ossConfigAdd(data: Partial<OssConfig>) {
return requestClient.postWithMsg<void>(Api.root, data);
return alovaInstance.postWithMsg<void>(Api.root, data);
}
// 更新现有的OSS配置
export function ossConfigUpdate(data: Partial<OssConfig>) {
return requestClient.putWithMsg<void>(Api.root, data);
return alovaInstance.putWithMsg<void>(Api.root, data);
}
// 删除OSS配置
export function ossConfigRemove(ossConfigIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${ossConfigIds}`);
return alovaInstance.deleteWithMsg<void>(`${Api.root}/${ossConfigIds}`);
}
// 更改OSS配置的状态
@@ -42,5 +42,5 @@ export function ossConfigChangeStatus(data: any) {
status: data.status,
configKey: data.configKey,
};
return requestClient.putWithMsg(Api.ossConfigChangeStatus, requestData);
return alovaInstance.putWithMsg(Api.ossConfigChangeStatus, requestData);
}

View File

@@ -1,11 +1,9 @@
import type { AxiosRequestConfig } from '@vben/request';
import type { OssFile } from './model';
import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
import { ContentTypeEnum } from '#/api/helper';
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
enum Api {
ossDownload = '/resource/oss/download',
@@ -21,7 +19,7 @@ enum Api {
* @returns 分页
*/
export function ossList(params?: PageQuery) {
return requestClient.get<PageResult<OssFile>>(Api.ossList, { params });
return alovaInstance.get<PageResult<OssFile>>(Api.ossList, { params });
}
/**
@@ -30,7 +28,7 @@ export function ossList(params?: PageQuery) {
* @returns 信息数组
*/
export function ossInfo(ossIds: ID | IDS) {
return requestClient.get<OssFile[]>(`${Api.ossInfo}/${ossIds}`);
return alovaInstance.get<OssFile[]>(`${Api.ossInfo}/${ossIds}`);
}
/**
@@ -41,7 +39,7 @@ export function ossInfo(ossIds: ID | IDS) {
export function ossUpload(file: Blob | File) {
const formData = new FormData();
formData.append('file', file);
return requestClient.postWithMsg(Api.ossUpload, formData, {
return alovaInstance.postWithMsg(Api.ossUpload, formData, {
headers: { 'Content-Type': ContentTypeEnum.FORM_DATA },
timeout: 30 * 1000,
});
@@ -50,18 +48,13 @@ export function ossUpload(file: Blob | File) {
/**
* 下载文件 返回为二进制
* @param ossId ossId
* @param onDownloadProgress 下载进度(可选)
* @returns blob
*/
export function ossDownload(
ossId: ID,
onDownloadProgress?: AxiosRequestConfig['onDownloadProgress'],
) {
return requestClient.get<Blob>(`${Api.ossDownload}/${ossId}`, {
export function ossDownload(ossId: ID) {
return alovaInstance.get<Blob>(`${Api.ossDownload}/${ossId}`, {
responseType: 'blob',
timeout: 30 * 1000,
isTransformResponse: false,
onDownloadProgress,
});
}
@@ -74,7 +67,7 @@ export function ossDownload(
* @returns void
*/
export function checkLoginBeforeDownload() {
return requestClient.get<OssFile[]>(`${Api.ossInfo}/1`, {
return alovaInstance.get<OssFile[]>(`${Api.ossInfo}/1`, {
errorMessageMode: 'none',
});
}
@@ -85,5 +78,5 @@ export function checkLoginBeforeDownload() {
* @returns void
*/
export function ossRemove(ossIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${ossIds}`);
return alovaInstance.deleteWithMsg<void>(`${Api.root}/${ossIds}`);
}

View File

@@ -4,7 +4,7 @@ import type { Post } from './model';
import type { ID, IDS, PageQuery } from '#/api/common';
import { commonExport } from '#/api/helper';
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
enum Api {
postExport = '/system/post/export',
@@ -19,7 +19,7 @@ enum Api {
* @returns Post[]
*/
export function postList(params?: PageQuery) {
return requestClient.get<Post[]>(Api.postList, { params });
return alovaInstance.get<Post[]>(Api.postList, { params });
}
/**
@@ -37,7 +37,7 @@ export function postExport(data: Partial<Post>) {
* @returns 岗位信息
*/
export function postInfo(postId: ID) {
return requestClient.get<Post>(`${Api.root}/${postId}`);
return alovaInstance.get<Post>(`${Api.root}/${postId}`);
}
/**
@@ -46,7 +46,7 @@ export function postInfo(postId: ID) {
* @returns void
*/
export function postAdd(data: Partial<Post>) {
return requestClient.postWithMsg<void>(Api.root, data);
return alovaInstance.postWithMsg<void>(Api.root, data);
}
/**
@@ -55,7 +55,7 @@ export function postAdd(data: Partial<Post>) {
* @returns void
*/
export function postUpdate(data: Partial<Post>) {
return requestClient.putWithMsg<void>(Api.root, data);
return alovaInstance.putWithMsg<void>(Api.root, data);
}
/**
@@ -64,7 +64,7 @@ export function postUpdate(data: Partial<Post>) {
* @returns void
*/
export function postRemove(postIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${postIds}`);
return alovaInstance.deleteWithMsg<void>(`${Api.root}/${postIds}`);
}
/**
@@ -73,7 +73,7 @@ export function postRemove(postIds: IDS) {
* @returns 岗位
*/
export function postOptionSelect(deptId: ID) {
return requestClient.get<Post[]>(Api.postSelect, { params: { deptId } });
return alovaInstance.get<Post[]>(Api.postSelect, { params: { deptId } });
}
/**
@@ -81,5 +81,5 @@ export function postOptionSelect(deptId: ID) {
* @returns 部门树
*/
export function postDeptTreeSelect() {
return requestClient.get<DeptTree[]>('/system/post/deptTree');
return alovaInstance.get<DeptTree[]>('/system/post/deptTree');
}

View File

@@ -2,7 +2,7 @@ import type { FileCallBack, UpdatePasswordParam, UserProfile } from './model';
import { buildUUID } from '@vben/utils';
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
enum Api {
root = '/system/user/profile',
@@ -15,7 +15,7 @@ enum Api {
* @returns userInformation
*/
export function userProfile() {
return requestClient.get<UserProfile>(Api.root);
return alovaInstance.get<UserProfile>(Api.root);
}
/**
@@ -24,7 +24,7 @@ export function userProfile() {
* @returns void
*/
export function userProfileUpdate(data: any) {
return requestClient.putWithMsg<void>(Api.root, data);
return alovaInstance.putWithMsg<void>(Api.root, data);
}
/**
@@ -33,7 +33,7 @@ export function userProfileUpdate(data: any) {
* @returns void
*/
export function userUpdatePassword(data: UpdatePasswordParam) {
return requestClient.putWithMsg<void>(Api.updatePassword, data, {
return alovaInstance.putWithMsg<void>(Api.updatePassword, data, {
encrypt: true,
});
}
@@ -55,7 +55,7 @@ export function userUpdateAvatar(fileCallback: FileCallBack) {
file = filename
? new File([file], filename)
: new File([file], `${buildUUID()}.png`);
return requestClient.post(
return alovaInstance.post(
Api.updateAvatar,
{
avatarfile: file,

View File

@@ -4,7 +4,7 @@ import type { DeptResp, Role } from './model';
import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
import { commonExport } from '#/api/helper';
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
enum Api {
roleAllocatedList = '/system/role/authUser/allocatedList',
@@ -27,7 +27,7 @@ enum Api {
* @returns 分页列表
*/
export function roleList(params?: PageQuery) {
return requestClient.get<PageResult<Role>>(Api.roleList, { params });
return alovaInstance.get<PageResult<Role>>(Api.roleList, { params });
}
/**
@@ -45,7 +45,7 @@ export function roleExport(data: Partial<Role>) {
* @returns 角色信息
*/
export function roleInfo(roleId: ID) {
return requestClient.get<Role>(`${Api.root}/${roleId}`);
return alovaInstance.get<Role>(`${Api.root}/${roleId}`);
}
/**
@@ -54,7 +54,7 @@ export function roleInfo(roleId: ID) {
* @returns void
*/
export function roleAdd(data: Partial<Role>) {
return requestClient.postWithMsg<void>(Api.root, data);
return alovaInstance.postWithMsg<void>(Api.root, data);
}
/**
@@ -63,7 +63,7 @@ export function roleAdd(data: Partial<Role>) {
* @returns void
*/
export function roleUpdate(data: Partial<Role>) {
return requestClient.putWithMsg<void>(Api.root, data);
return alovaInstance.putWithMsg<void>(Api.root, data);
}
/**
@@ -76,7 +76,7 @@ export function roleChangeStatus(data: Partial<Role>) {
roleId: data.roleId,
status: data.status,
};
return requestClient.putWithMsg<void>(Api.roleChangeStatus, requestData);
return alovaInstance.putWithMsg<void>(Api.roleChangeStatus, requestData);
}
/**
@@ -85,7 +85,7 @@ export function roleChangeStatus(data: Partial<Role>) {
* @returns void
*/
export function roleRemove(roleIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${roleIds}`);
return alovaInstance.deleteWithMsg<void>(`${Api.root}/${roleIds}`);
}
/**
@@ -94,14 +94,14 @@ export function roleRemove(roleIds: IDS) {
* @returns void
*/
export function roleDataScope(data: any) {
return requestClient.putWithMsg<void>(Api.roleDataScope, data);
return alovaInstance.putWithMsg<void>(Api.roleDataScope, data);
}
/**
* @deprecated 全局并没有用到这个方法
*/
export function roleOptionSelect(params?: any) {
return requestClient.get(Api.roleOptionSelect, { params });
return alovaInstance.get(Api.roleOptionSelect, { params });
}
/**
@@ -110,7 +110,7 @@ export function roleOptionSelect(params?: any) {
* @returns 分页
*/
export function roleAllocatedList(params?: PageQuery) {
return requestClient.get<PageResult<User>>(Api.roleAllocatedList, { params });
return alovaInstance.get<PageResult<User>>(Api.roleAllocatedList, { params });
}
/**
@@ -119,7 +119,7 @@ export function roleAllocatedList(params?: PageQuery) {
* @returns void
*/
export function roleUnallocatedList(params: any) {
return requestClient.get<PageResult<User>>(Api.roleUnallocatedList, {
return alovaInstance.get<PageResult<User>>(Api.roleUnallocatedList, {
params,
});
}
@@ -129,7 +129,7 @@ export function roleUnallocatedList(params: any) {
* @returns void
*/
export function roleAuthCancel(data: { roleId: ID; userId: ID }) {
return requestClient.putWithMsg<void>(Api.roleAuthCancel, data);
return alovaInstance.putWithMsg<void>(Api.roleAuthCancel, data);
}
/**
@@ -139,7 +139,7 @@ export function roleAuthCancel(data: { roleId: ID; userId: ID }) {
* @returns void
*/
export function roleAuthCancelAll(roleId: ID, userIds: IDS) {
return requestClient.putWithMsg<void>(
return alovaInstance.putWithMsg<void>(
`${Api.roleAuthCancelAll}?roleId=${roleId}&userIds=${userIds.join(',')}`,
);
}
@@ -151,7 +151,7 @@ export function roleAuthCancelAll(roleId: ID, userIds: IDS) {
* @returns void
*/
export function roleSelectAll(roleId: ID, userIds: IDS) {
return requestClient.putWithMsg<void>(
return alovaInstance.putWithMsg<void>(
`${Api.roleAuthSelectAll}?roleId=${roleId}&userIds=${userIds.join(',')}`,
);
}
@@ -162,5 +162,5 @@ export function roleSelectAll(roleId: ID, userIds: IDS) {
* @returns DeptResp
*/
export function roleDeptTree(roleId: ID) {
return requestClient.get<DeptResp>(`${Api.roleDeptTree}/${roleId}`);
return alovaInstance.get<DeptResp>(`${Api.roleDeptTree}/${roleId}`);
}

View File

@@ -2,7 +2,7 @@ import type { SocialInfo } from './model';
import type { ID } from '#/api/common';
import { requestClient } from '#/api/request';
import { alovaInstance } from '#/utils/http';
enum Api {
root = '/system/social',
@@ -14,12 +14,12 @@ enum Api {
* @returns info
*/
export function socialList() {
return requestClient.get<SocialInfo[]>(Api.socialList);
return alovaInstance.get<SocialInfo[]>(Api.socialList);
}
/**
* @deprecated 并没有用到这个方法
*/
export function socialInfo(id: ID) {
return requestClient.get(`${Api.root}/${id}`);
return alovaInstance.get(`${Api.root}/${id}`);
}

Some files were not shown because too many files have changed in this diff Show More