657 Commits

Author SHA1 Message Date
dap
f415664acf docs: changelog 2025-03-13 14:13:17 +08:00
dap
786b617179 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-03-11 13:38:22 +08:00
dap
e6ee1f57b4 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-03-11 13:38:13 +08:00
Netfan
feab6b3b30 fix: form item style adjustment (#5694) 2025-03-11 02:47:06 +08:00
dap
7f1548b343 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-03-10 19:17:57 +08:00
Netfan
2d4ac33046 fix: miss default value in vbenLayout 2025-03-10 18:59:56 +08:00
Netfan
17e2a02281 feat: auto set component name for keep-alive (#5690)
* fix: auto set component name for keep-alive

* fix: type define
2025-03-10 16:25:30 +08:00
Netfan
096545c5a1 docs: update table slots docs 2025-03-10 10:53:17 +08:00
Netfan
04dff33ac5 feat: improved formApi for component instance support
* 改进表单API以支持组件实例的获取,以及焦点字段的获取
2025-03-10 02:56:44 +08:00
Netfan
cfa18c2b8e fix: improve component repackaging 2025-03-10 02:56:44 +08:00
Netfan
13354955db chore: update depts 2025-03-10 02:56:44 +08:00
dap
056dee009f Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-03-09 15:29:45 +08:00
dap
1309c8425e docs: 关于表单 2025-03-09 14:24:55 +08:00
dap
f0ded13df1 refactor: 重构 2025-03-09 14:07:25 +08:00
dap
e78d367cea feat: 请假申请-排他并行网关 2025-03-09 13:50:58 +08:00
ijackwu
bb683804f4 fix: live-server set port use [--port=PORT] (#5687) 2025-03-09 08:49:06 +08:00
dap
209214f6a3 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-03-08 20:25:01 +08:00
dap
ab003826a3 Merge branch 'native_form' of https://gitee.com/dapppp/ruoyi-plus-vben5 into dev 2025-03-08 20:05:47 +08:00
dap
817c4a265d Merge branch 'generator' of https://gitee.com/dapppp/ruoyi-plus-vben5 into native_form 2025-03-08 20:01:26 +08:00
dap
8ed893fb21 chore: 注释说明 2025-03-08 19:57:56 +08:00
dap
55f5e6bd0c feat: 代码生成 支持选择表单生成类型(需要模板支持) 2025-03-08 16:00:32 +08:00
dap
62d03605a3 feat: 流程发起时的按钮权限 2025-03-08 12:18:16 +08:00
dap
6170da0870 feat: 选择下一步审批人权限 2025-03-08 12:08:01 +08:00
Netfan
e2a577de24 feat: add size prop to avatar component and update logo component for size handling (#5684) 2025-03-08 11:37:02 +08:00
Netfan
89d963c81a fix: vxeTable search button not working with slot (#5678) 2025-03-07 22:35:09 +08:00
dap
a9b7bf6442 refactor: 更新注释 2025-03-07 20:48:12 +08:00
dap
a66e13eca6 refactor: 通知公告 原生表单(非最终确定版) 2025-03-07 20:29:27 +08:00
Netfan
b37ed48b9d feat: role management page with component tree (#5675)
* feat: add shadcn tree

* fix: update vbenTree component

* feat: role management demo page

* feat: add cellSwitch renderer for vxeTable

* chore: remove tree examples
2025-03-07 16:03:08 +08:00
dap
e78f4e984d Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-03-07 15:57:38 +08:00
dap
9f70a61c24 feat: 按钮权限 2025-03-07 15:50:39 +08:00
Netfan
4b9cfcb867 fix: demo nested menu path (#5667)
* 修复演示的嵌套菜单path配置导致的面包屑跳转问题
2025-03-06 22:48:54 +08:00
Netfan
f86c9f90ad fix: keepAlive not working for popup appendToMain (#5666)
* 修复弹窗和抽屉 `appendToMain` 时且启用`keepAlive` 时未能正确缓存的问题
2025-03-06 22:22:45 +08:00
dap
3229899c40 fix: 错误的国际化文案 2025-03-06 17:54:00 +08:00
Netfan
31a6ab59fb feat: vben checkbox support indeterminate state and transition animation (#5662) 2025-03-06 16:11:02 +08:00
dap
11083d5b7e refactor: remove 'less' (迁移v2代码漏掉了) 2025-03-05 19:29:34 +08:00
dap
7b5fb4f164 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-03-05 10:10:09 +08:00
Netfan
34789645f7 fix: nitro server cookie maxAge fixed 2025-03-04 22:29:27 +08:00
Netfan
f380452ef0 feat: modal and drawer locking improve (#5648)
* feat: add `unlock` for modalApi

* fix: modal's close button style in locking

* fix: fix modal's close button disabled on locking

* feat: add `lock` and `unlock` for drawerApi
2025-03-04 22:00:32 +08:00
jasonz18
decd9c55e5 docs: typo 2025-03-04 21:40:34 +08:00
dap
d8cac9bb00 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-03-03 13:16:50 +08:00
dap
1dacd96e3c fix: 重复的tooltip help 2025-03-03 11:48:17 +08:00
Netfan
e815f0ff89 docs: vbenVxeTable slots docs update 2025-03-01 22:16:36 +08:00
dap
43534b6142 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-03-01 15:22:35 +08:00
Netfan
5ea6b4a8d8 fix: logo style in login page is affected by the globally-imported antd styles
* 修复登录页左上角LOGO部分的文字在全局导入antd样式的时候位置不正确的问题
2025-02-28 22:39:42 +08:00
Netfan
a53ca3faf1 chore: update depts 2025-02-28 20:30:59 +08:00
Netfan
86fdd6c93b fix: drawer close icon placement default value 2025-02-28 14:54:11 +08:00
Netfan
0e0661fe02 fix: breadcrumb style is affected by the globally-imported antd styles (#5627)
* 修复全局引入Antd时,面包屑的样式会受到影响的问题
2025-02-27 22:28:59 +08:00
Netfan
86ce65e0ea fix: hideChildrenInMenu demo code (#5626) 2025-02-27 20:21:48 +08:00
Netfan
c3eb4fab13 docs: fix zod rules docs 2025-02-27 17:27:00 +08:00
jinmao88
7a476372e1 fix: useDrawer中closeIconPlacement设置无效 (#5624) 2025-02-27 14:34:42 +08:00
Netfan
5e421ce607 chore: demo page menu management (#5619)
* 添加菜单管理演示页面
2025-02-27 01:22:25 +08:00
dap
279fc98d76 refactor: items-baseline -> items-start 2025-02-26 13:16:07 +08:00
dap
36a78dda90 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-02-26 09:17:03 +08:00
Netfan
1d8676f456 chore: remove sleep in department list api 2025-02-25 22:15:27 +08:00
Netfan
0c3dd92592 fix: getPopupContainer will return closet form first (#5612) 2025-02-25 22:07:56 +08:00
Netfan
d33261d0c2 chore: demo page for system/department (#5611)
* feat: department management demo

* perf: department page improve

* feat: demo api middleware

* fix: add losing import
2025-02-25 19:47:45 +08:00
dap
4da1bb9896 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-02-25 09:22:24 +08:00
Netfan
7041c6a106 chore: output console error for invalid route component (#5593) 2025-02-24 16:03:52 +08:00
littlesparklet
12ffb310bf fix: Fix inconsistent spacing around search form (issue #5429) (#5495) 2025-02-24 15:57:50 +08:00
Netfan
d9799fec70 fix: search take no effect in icon-picker with antd (#5592) 2025-02-24 14:13:53 +08:00
Netfan
4570d5b54b feat: add VbenButtonGroup and VbenCheckButtonGroup with demo (#5591)
* 添加按钮组、选择按钮组以及相应的Demo
2025-02-24 13:50:50 +08:00
Netfan
d49e3e81a4 fix: loading and spinner style fixed and improved (#5588) 2025-02-23 15:30:17 +08:00
Netfan
579b1b486c feat: loading and spinner component with directive (#5587)
* 添加loading和spinner组件,以及对应的vue指令
2025-02-23 12:41:54 +08:00
Netfan
eba372062e feat: improve form demo (#5582) 2025-02-21 12:07:32 +08:00
Netfan
c9ccd2bbab fix: form label and control style (#5580)
* fix: form label and control style

* fix: empty label mark with required rules
2025-02-21 11:14:59 +08:00
handsomeFu
5aff8bac10 fix: CountTo component resolve separator prop not taking effect (#5578) 2025-02-21 11:06:18 +08:00
Netfan
1a12687027 fix: vben count to animator event name fixed (#5573) 2025-02-20 23:53:47 +08:00
Netfan
a221d2b491 fix: form item overflow fixed and layout improved (#5572)
* fix: form item overflow fixed and layout improved

* fix: basic form demo update

* feat: form label support render

* fix: form docs update
2025-02-20 23:05:08 +08:00
dap
98d5d607b6 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-02-20 18:26:39 +08:00
dap
9ee5369f35 fix: replace ?? to || for fix avatar 2025-02-20 18:25:08 +08:00
anyup
ccd99eb24d fix: solve the problem of inconsistent returns of formSchema custom field names when code login (#5563) 2025-02-20 09:09:32 +08:00
Netfan
c5c6760b5d chore: eslint rules update 2025-02-18 15:41:16 +08:00
dap
fbb0d641db Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-02-18 14:08:05 +08:00
Netfan
c07281bf41 fix: form item slot context fixed (#5552)
* 修复表单插槽
2025-02-17 21:37:05 +08:00
Netfan
24bad09c74 refactor: new CountTo component with demo (#5551) 2025-02-17 21:16:10 +08:00
Netfan
cddf71e600 fix: playground route missing 2025-02-17 17:57:15 +08:00
Netfan
9f82052c71 feat: demo of motion plugin (#5550)
添加Motion的用法例子
2025-02-17 15:25:45 +08:00
Netfan
e0eb57d38d fix: nitro server cors support with cookie (#5549)
* 修复nitro server在使用cookie时的跨域配置
2025-02-17 15:17:31 +08:00
Netfan
b6b97accb1 feat: add more event for jsonViewer (#5546)
* 为JsonViewer添加事件支持
2025-02-17 10:41:09 +08:00
Netfan
799934171a style: code style fixed 2025-02-16 23:32:06 +08:00
Netfan
10ebf03698 fix: auth api definition 2025-02-16 23:06:20 +08:00
Netfan
cd258fbb52 chore: update deps 2025-02-16 23:03:41 +08:00
Netfan
6cba181fad feat: new component jsonViewer (#5544)
* 添加新组件JsonViewer用于展示JSON结构数据
2025-02-16 22:57:00 +08:00
jinmao88
f9504cece3 chore: add qq group 5 (#5530) 2025-02-13 14:45:51 +08:00
Netfan
182f1c9da8 fix: userDropdown triggered unnecessary while overlay shown (#5520)
* 修复顶部的用户资料下拉在弹窗被打开时,仍然可以被触发的问题
2025-02-12 17:59:59 +08:00
dap
6e0c79411b docs: readme 2025-02-12 17:59:55 +08:00
dap
de27e8691d Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-02-12 17:51:25 +08:00
Netfan
e7b009786b fix: width for ellipsisText tooltip in popover content (#5517)
* 修复省略文本用在气泡中时,提示弹出层的宽度计算有误的问题
2025-02-12 14:25:12 +08:00
dap
5e7aeaf12e feat: 代码生成支持路径方式生成 2025-02-08 19:53:12 +08:00
dap
bc6818f531 docs: version update 2025-02-07 14:43:46 +08:00
dap
f78bc4e4f7 chore: 修改路径 2025-02-07 14:42:47 +08:00
dap
cd77063f68 fix: 加密后修改请求头会造成报错HttpMediaTypeNotSupportedException 2025-02-07 11:45:57 +08:00
dap
0be1a0825d perf: 去除顶部进度条样式 2025-02-06 22:44:05 +08:00
dap
551841bdd7 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-02-06 22:38:05 +08:00
Netfan
5262233312 feat: tabbar support max count limit (#5490)
* 标签栏支持限制打开的最大数量
2025-02-06 19:33:10 +08:00
dap
52dc3e1788 perf: 加密后修改content-type 2025-02-06 15:35:33 +08:00
Netfan
a9f9031f49 docs: update form docs (#5485) 2025-02-06 09:45:28 +08:00
dap
f7c00cd8f7 refactor: 去除不需要的css样式 2025-02-05 19:48:56 +08:00
dap
bdc1cb6d3b Merge branch 'dev' of https://gitee.com/dapppp/ruoyi-plus-vben5 into dev 2025-02-05 19:42:59 +08:00
dap
b8ed931eb6 chore: 1 2025-02-05 19:41:33 +08:00
dap
8edc7c8ea4 chore: 存在即合理 2025-02-05 19:27:47 +08:00
dap
ba3fc0fe10 refactor: 点击遮罩不关闭 2025-02-05 15:06:01 +08:00
dap
a37dccdec0 fix: modal/drawer升级后zIndex(2000)会遮挡Tinymce的下拉框zIndex(1300) 2025-02-05 15:03:28 +08:00
dap
1df9236a53 fix: 客户端管理 错误的status disabled 2025-02-05 13:20:30 +08:00
dap
049ccca3e0 chore: 锁定cspell版本 2025-02-04 22:41:33 +08:00
dap
00c4501d13 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-02-04 18:40:47 +08:00
Netfan
061fcf926d chore: update deps 2025-02-04 17:14:14 +08:00
Netfan
7e7a5f3fd4 chore: remove testing code 2025-02-04 15:07:10 +08:00
Netfan
f8bb396dc4 fix: ant tag icon default style (#5473) 2025-02-04 10:19:39 +08:00
jsxz
a832edce0d docs: update request and access docs (#5468)
* fix: Update server.md

* docs: update request and access docs
2025-02-03 16:29:34 +08:00
dap
af3fdeb1da fix: remove getPopupContainer 2025-01-26 22:58:46 +08:00
Netfan
67d1f299b3 fix: renderComponentContent lose slot props data (#5466)
* 修复FormItem传递插槽时丢失插槽props的问题
2025-01-26 22:33:16 +08:00
Netfan
cb7c0ecaa2 fix: menu data for backend mode fixed (#5465) 2025-01-26 20:37:37 +08:00
dap
64d3a21153 refactor: update url 2025-01-26 17:35:09 +08:00
dap
a8019ed88a refactor: 移除后缀图标插槽 2025-01-26 13:40:28 +08:00
dap
4959574f21 feat: getPopupContainer 2025-01-26 13:37:25 +08:00
dap
e89d1a0520 perf: 优化timeline丢失的样式 2025-01-24 20:42:56 +08:00
dap
7f0b40b565 docs: version update 2025-01-24 13:26:49 +08:00
dap
bc2040bbdc docs: readme & preview 2025-01-24 13:25:58 +08:00
dap
a3d105c04c chore: gitee bug issue template 2025-01-23 15:58:31 +08:00
dap
40a75a9904 chore: gitee template 2025-01-23 15:57:25 +08:00
dap
463d50328f fix: missing type 2025-01-23 15:15:20 +08:00
dap
3e3d56b82e fix: 错误的插槽更改 2025-01-22 15:16:42 +08:00
dap
379778412b Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-01-22 14:48:53 +08:00
dap
93199b4dc6 feat: 对windows微信图标的支持 2025-01-22 14:33:12 +08:00
dap
1e3990f41d feat: 审批驳回(带附件) 2025-01-22 14:28:18 +08:00
Netfan
e225159cce fix: request download and upload not support responseReturn (#5456)
* fix: request download and upload not support `responseReturn`

* docs: update

* fix: type of request client upload result
2025-01-22 00:59:10 +08:00
vben
195ceec9b4 chore: release 5.5.3 2025-01-21 22:07:55 +08:00
dap
8c75d13ab4 refactor: 使用更简洁的写法 2025-01-21 18:13:06 +08:00
dap
fd4ecfeb4c refactor: replace deprecated field 2025-01-21 18:11:40 +08:00
Netfan
5bd73867b6 feat: auto fetch icon list in iconPicker (#5446)
* feat: auto fetch icon list in iconPicker

* fix: add timeout controller for fetching

* feat: add pending controller

* fix: icon demo prefix
2025-01-21 13:09:42 +08:00
dap
0497383ec5 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-01-21 12:03:08 +08:00
Netfan
22e6f28464 perf: easy to define fieldName of response data (#5442) 2025-01-20 18:38:49 +08:00
dap
4c80ba2c3a fix: 字典label需要置空的情况 2025-01-20 16:49:05 +08:00
dap
48e7146b05 feat: 验证码autocomplete off 2025-01-20 11:55:35 +08:00
玲娜贝er
fa2f8c15d0 !12 merge
Merge pull request !12 from 玲娜贝er/dev
2025-01-20 03:47:28 +00:00
dap
300d6f5609 chore: 去除锁定的eslint版本 2025-01-20 11:46:04 +08:00
玲娜贝er
29f9f3de31 !11 follow后端发布
* docs: readme
* fix: missing formPath
* chore: 去除锁定的esbuild版本
* perf: 去除debug组件
* perf: 参数键值 自动高度
* refactor: 代码生成配置页面重构 去除步骤条
* perf: 移除文件
* docs: 文件夹说明
* chore: 移除一些配置项
* chore: 注释优化
* refactor: 移除ele和naive目录
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
* perf: request support to set how to return response (#5436)
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
* refactor: 登录超时的i18n
* fix: requestClient缺失i18n内容
* refactor: 优化oss下载进度提示
* feat: 下载进度loading
* fix: antd button icon style (#5421)
* feat: oss下载进度(已下载的KB 无法作为进度显示 total返回为null)
* fix: 下载文件时(responseType === 'blob')需要判断下载失败(返回json而非二进制)的情况
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
* refactor: 新增后跳转到未发布流程
* fix: same name route
* chore: 调整为部署json类型
* fix: mouse events ignored on modal loading (#5409)
* docs: update docs (#5408)
* refactor: 移除已经弃用的方法
* refactor: follow官方handleRangeTimeValue更新
* chore: 删除文件夹(前端路由需要的)
* chore: 修改本地路由写法(新版)/新增本地菜单图标
* fix: form update state error before form mounted (#5406)
* fix: demos route fixed (#5405)
* chore: 不使用基础布局(仅在顶级生效)
* feat: modal state locked on submitting (#5401)
* chore: 修改zIndex
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
* refactor: fix popup component zIndex (#5397)
* style: element plus loading style fixed (#5393)
* perf: improve fieldMappingTime to support format function (#5392)
* fix: hide root route in breadcrumb
* feat: support set default props for drawer and modal (#5390)
* fix: root router config fixed (#5389)
* fix: 修改Vxe默认zIndex为995 解决右上角全屏后modal/drawer(zIndex: 1000)被遮挡
* feat: add `noBasicLayout` in route meta (#5386)
* chore: wechat image
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
* chore: 改为全局参数配置 去除局部参数
* fix: spinner may stop playing animation after dismiss (#5365)
* style: popover bgColor is too close to common (#5364)
* docs: version update
* docs: changelog
* chore: 文件上传 描述
* ci: retry deploy while faild
* feat: 文件上传 进度条+提示文字
* feat: 文件上传 进度条
* feat: 上传文件格式说明
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into warmflow
* fix: useEcharts return invalid instance (#5360)
* feat: popup component support overlay blur effect (#5359)
* feat: improve `tippy` demo (#5357)
* feat: integrate new component `Tippy` with demo (#5355)
* chore: 优化表格图片显示
* perf: add nested modal demo (#5353)
* chore: 默认显示右边的滚动条 防止出现滚动条被挤压
* perf: modal and drawer api support chain calls (#5351)
* feat: allow close tab when mouse middle button click (#5347)
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into warmflow
* refactor: 重构显示total的逻辑
* chore: 调整高度自适应代码
* chore: vxe升级4.10.0版本(锁定)
* fix: 添加失效的option
* fix: 需要为数组
* fix: locale switching logic correction (#5344)
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into warmflow
* chore: 导入类型优化 解决eslint报红
* refactor: type/注释优化 去除大量any
* fix: vxeGrid init without search form (#5342)
* chore: 锁屏默认false  关闭该功能
* chore: 调整接口
* chore: update deps
* fix: primaryColor calculation (#5337)
* fix: form valid-error style in naive (#5336)
* fix: form `fieldMappingTime` improve and `modelPropName` support (#5335)
* fix: code lint
* fix: form `fieldMappingTime` is not working (#5333)
* chore: 选人组件样式
* fix: download from url triggered twice sometimes (#5319)
* chore: 优化代码
* chore: 动态类名(无效)改为style
* refactor: 字典相关功能重构 采用一个Map储存字典(之前为两个Map)
* feat: 字典支持number类型存储
* chore: 调整样式
* chore: 修改选中border为1px
* chore: 字段
* chore: 改为新窗口打开(适用于pdf/图片)而非直接下载
* chore: 更新样式
* chore: 更新字段
* chore: 改为computed
* chore: 跳转到未发布流程tab
* chore: 优化样式
* docs: readme
* fix: name重复导致的404
* Merge branch 'dev' of https://gitee.com/dapppp/ruoyi-plus-vben5 into warmflow
* chore: 使用legacy来保证copy的兼容性
* chore: 去除log 添加说明
* chore: 优化代码
* feat: 节点关联/节点独立的切换逻辑
* chore: remove logic
* chore: vxe可编辑表格demo
* chore: 不允许在按钮下添加数据
* docs: changelog
* fix: wrong code
* chore: 移除测试菜单
* chore: 优化代码
* refactor: 租户套餐菜单替换为新版
* refactor: 使用新版菜单勾选
* chore: 点行会勾选/取消全部权限  点权限不会勾选行
* chore: 全屏引导+样式优化
* chore: 调整间距
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
* feat: useEcharts exports echarts instance#5294 (#5299)
* chore: update quick-start.md (#5303)
* chore: updateCheckedNumber
* refactor: 优化代码
* chore: 优化代码
* chore: 优化样式
* chore: keys依赖于menu 需要先加载menu
* chore: 菜单加载完毕再显示
* feat: 新的菜单选择组件(beta)
* chore: $t
* chore: 测试菜单页面
* chore: 优化代码
* feat: 对ossId回显的支持
* chore: 只获取一次默认密码而非每次打开modal都获取
* fix: vben select placeholder color (#5286)
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
* perf: format code with better style (#5283)
* chore: 工作流演示站
* fix: sidebar preferences fixed (#5276)
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
* fix: breadcrumb setting not valid for `header-sidebar-nav` layout (#5275)
* fix: header logo may not be collapsed in `header-sidebar-nav` layout (#5274)
* feat: new layout `sidebar nav with full header` (#5270)
* feat: drawer close icon placement (#5269)
* docs: update dialog and drawer docs
* feat: drawer support destroy on close
* feat: drawer support `onOpened` & `onClosed`
* feat: modal support destroy on close
* fix: wrong boolean
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
* chore: 调整tab位置
* chore: 删除历史流程 改为tab切换
* fix: header-mixed layout side-menu active (#5265)
* feat: header mixed layout (#5263)
* chore: release 5.5.2
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
* chore: downgrade vue-tsc version
* feat: header menu align support (#5256)
* chore: update deps
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
* chore: add apiSelect remote search demo (#5246)
* chore: 审批改为description而非disabled的表单
* chore: 改为ts
* chore: 错误的conetnt
* refactor: 终止/转办/委托支持填写意见
* chore: 第一次拿到的是readonly的数据 如果需要修改 需要cloneDeep
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
* fix: grid form submit button locale switch (#5205)
* chore: 调整驳回
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
* fix: build error (#5199)
* fix: esbuild自动升级导致运行/打包报错
* fix: esbuild自动升级导致运行/打包报错
* chore: 流程定义 激活改为switch
* chore: 流程申请支持上传文件
* chore: title 审批通过
* fix: vxeGrid top padding (#5193)
* fix: 表格排序翻页会丢失排序参数
* chore: 去除log打印
* chore: 流程监控 待办任务
* chore: 我发起的
* chore: 去除已经移除的菜单页面
* chore: 我的已办
* chore: 页面优化
* chore: 重置tooltip
* feat: 我的抄送搜索/优化重复触发的接口
* feat: 流程定义 历史
* chore: 修改分类
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
* fix: grid tools in toolbar config not working as expected (#5190)
* feat: add `resizable` and `ColPage` component (#5188)
* chore: 条件
* chore: break-all
* feat: 流程分类 搜索
* chore: 弹窗关闭后仍然显示表单浮层
* chore: 选人组件的样式
* chore: 搜索的样式
* chore: 漏掉的导入
* chore: 最大显示的头像数量 超过显示为省略号头像
* fix: 选人的一些问题
* Merge branch 'warmflow' of https://gitee.com/dapppp/ruoyi-plus-vben5 i…
* chore: 没有更多数据了
* fix: sidebar header height (#5183)
* chore: 搜索表单布局+申请人
* fix: remove the overlap caused by border-b (#5160)
* docs: fix typos (#5169)
* fix: resolve eslint errors as well as TS type errors (#5172)
* chore: enter提交表单
* chore: 修改文案
* chore: 默认全部展开
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
* feat: page content class override (#5179)
* fix: sidebar style on focus (#5178)
* fix: 抄送选人 最右侧已选中删除item无效
* feat: 复制
* chore: 昵称过长的显示
* chore: 默认选中第一个
* chore: 修改relative位置
* chore: 搜索
* feat: 我的待办 - 搜索条件
* chore: 流程监控 - 待办任务页面的id不唯一 改为前端处理
* feat: 修改办理人
* chore: 流程干预 - 加签/减签
* chore: avatar大小
* chore: 抄送需要手动添加createByName
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
* chore: 审批通过 抄送
* feat: 流程实例-流程预览
* chore: spell
* chore: clientid
* chore: 分类条件
* chore: 修改办理人
* chore: 更改postMessage参数
* chore: 内嵌iframe高度根据表单高度调整
* chore: 流程详情
* feat: 抄送选择
* chore: 调整分类树
* fix: user homePath no effect sometimes (#5166)
* feat: form compact mode support (#5165)
* fix: form auto submit no effect when showDefaultActions is false (#5163)
* chore: 修改width
* feat: 待办任务
* feat: 我的抄送
* chore: 流程定义 样式
* chore: 退回后重新申请
* chore: 请假申请布局
* chore: 请假申请-并行会签网关
* chore: 分类去除根目录
* chore: 详情modal(未完成)
* chore: 请假申请根据不同状态显示按钮
* chore: 流程删除/撤销
* chore: 审批完成后刷新当前页
* feat: 选人组件(未完成) 加签减签
* docs: fix docs-link and add `EllipsisText` docs (#5158)
* chore: 新窗口打开文件
* chore: 审批通过
* chore: 使用useEventListener替换原生
* chore: 字段错误
* chore: iframe通信 加载完毕后才显示表单 解决卡顿问题
* chore: 审批终止/驳回
* chore: 附件图标
* chore: process_running显示按钮
* chore: label错误
* chore: 保存的事件
* chore: 需要加上clientId
* Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
* feat: form `colon` support (#5156)
* chore: 完善请假申请
* feat: improve code login demo (#5154)
* chore: 客户端管理 行高自适应
* chore: 内嵌表单的路径
* chore: 修改avatar背景色
* chore: 注释
* chore: activePath
* chore: leave表单
* chore: 修改请假demo路径
* chore: categoryId
* chore: 我的已办
* chore: 我发起的
* chore: loading
* chore: 历史版本
* chore: 完善task api
* chore: 隐藏'菜单加载中'
* chore: missing import
* feat: add demo for modify menu badge data
* chore: 流程实例
* chore: 审批附件
* chore: 我的待办 提取公共组件
* chore: 流程部署
* chore: 新增/编辑/导出xml
* chore: 流程定义(除历史版本)
* feat: `autoActivateChild` support more layout mode (#5148)
* feat: auto activate subMenu on select root menu (#5147)
* fix: `disabledOnChangeListener` not work in form (#5146)
* fix: login expired modal z-index (#5145)
* feat: user-dropdown support `hover` trigger (#5143)
* fix: pinInput value synchronous update (#5142)
* fix: vxeGrid default sort data no effect in first query (#5141)
* fix: vscode debug profile (#5140)
* fix: form component events bind (#5137)
* chore: 在线用户样式 开启虚拟滚动
* chore: 去掉个人中心 在线设备的分页
* chore: 去掉在线用户的分页
* chore: changelog
* refactor: 获取字典的方法 提取公共函数 减少冗余代码
* fix: element plus validate failed style (#5130)
* chore: 使用私有桶的提示
* feat: tabbar support mouse wheel vertical (#5129)
* fix: form support `disabledOnInputListener` (#5127)
* fix: form submission not appropriate (#5126)
* Merge branch 'main' of https://gitee.com/dapppp/ruoyi-plus-vben5 into dev
* chore: release 5.5.1
* feat: table search form visible control (#5121)
* chore: 需要隐藏菜单
* chore: 我的待办 & 请假
* chore: 流程定义(未完成)
* chore: 流程定义(开发中)
* Merge branch 'main' of https://gitee.com/dapppp/ruoyi-plus-vben5 into dev
* Merge branch 'main' of https://gitee.com/dapppp/ruoyi-plus-vben5 into dev
* Merge branch 'main' of https://gitee.com/dapppp/ruoyi-plus-vben5 into dev
* chore: version
* chore: 锁定vxe-table版本 4.9.8版本存在样式问题
* chore: 暂时锁定cspell版本
* refactor: 由于不能输入 需要使用watch监听
* chore: https://gitee.com/dapppp/ruoyi-plus-vben5/issues/IB7ANL
* chore: 移除冗余代码
* chore: 组件卸载时移除emitter
* fix: the route path did not synchronize with the page (#4947)
* style: typo (#4948)
* chore: 替换为commonDownloadExcel
* fix: 左边部门树错误emit导致会调用两次列表api
* chore: label样式
* chore: 改为Textarea
* chore: 滚动条宽度
* chore: 审批样式
* chore: 部门及以下或本人数据权限
* Merge branch 'main' of https://gitee.com/dapppp/ruoyi-plus-vben5 into dev
* chore: 个人中心强退设备接口路径
2025-01-20 03:43:19 +00:00
dap
a84569c0e1 docs: readme 2025-01-20 11:40:38 +08:00
dap
15a7793dce fix: missing formPath 2025-01-20 11:26:29 +08:00
dap
a3bad43c16 chore: 去除锁定的esbuild版本 2025-01-19 21:27:48 +08:00
dap
0f2e107e5c perf: 去除debug组件 2025-01-19 21:18:39 +08:00
dap
2006754889 perf: 参数键值 自动高度 2025-01-19 21:15:46 +08:00
dap
ac9e76ae93 refactor: 代码生成配置页面重构 去除步骤条 2025-01-19 21:11:26 +08:00
dap
233817c2ed perf: 移除文件 2025-01-19 20:12:13 +08:00
dap
4d4e909652 docs: 文件夹说明 2025-01-19 20:09:34 +08:00
dap
0e090bc80a chore: 移除一些配置项 2025-01-19 19:44:51 +08:00
dap
114126dfc4 chore: 注释优化 2025-01-19 19:42:44 +08:00
dap
1a47c88d84 refactor: 移除ele和naive目录 2025-01-19 19:32:37 +08:00
dap
429002ade2 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-01-19 19:20:24 +08:00
Netfan
5611f6c7f5 perf: request support to set how to return response (#5436)
* feat: request support to set how to return response

* docs: typo

* fix: test unit

* test: add request responseReturn test
2025-01-19 17:41:26 +08:00
dap
1a166a797c Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-01-18 08:42:53 +08:00
dap
261be4a3a6 refactor: 登录超时的i18n 2025-01-17 21:18:44 +08:00
dap
087b9126b2 fix: requestClient缺失i18n内容 2025-01-17 21:13:56 +08:00
dap
c08f9efb1a refactor: 优化oss下载进度提示 2025-01-17 20:35:13 +08:00
dap
0eaa63b2c2 feat: 下载进度loading 2025-01-17 19:05:49 +08:00
Netfan
3f0f4d50a1 fix: antd button icon style (#5421) 2025-01-17 14:30:49 +08:00
dap
14b7296200 feat: oss下载进度(已下载的KB 无法作为进度显示 total返回为null) 2025-01-17 11:13:03 +08:00
dap
77cd005f15 fix: 下载文件时(responseType === 'blob')需要判断下载失败(返回json而非二进制)的情况 2025-01-17 10:48:52 +08:00
dap
6716e0c979 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-01-16 17:07:16 +08:00
dap
cd6d413f08 refactor: 新增后跳转到未发布流程 2025-01-16 16:57:17 +08:00
dap
1877888846 fix: same name route 2025-01-16 14:38:45 +08:00
dap
b1bc6f632d chore: 调整为部署json类型 2025-01-16 14:12:27 +08:00
Netfan
2d0859a727 fix: mouse events ignored on modal loading (#5409) 2025-01-16 12:17:08 +08:00
Netfan
509b268fba docs: update docs (#5408) 2025-01-16 11:30:03 +08:00
dap
8816086b37 refactor: 移除已经弃用的方法 2025-01-15 23:34:50 +08:00
dap
11dba43d83 refactor: follow官方handleRangeTimeValue更新 2025-01-15 23:24:06 +08:00
dap
9b68aacc27 chore: 删除文件夹(前端路由需要的) 2025-01-15 23:16:12 +08:00
dap
dcd633bb39 chore: 修改本地路由写法(新版)/新增本地菜单图标 2025-01-15 23:02:48 +08:00
Netfan
c3129663eb fix: form update state error before form mounted (#5406) 2025-01-15 20:11:32 +08:00
Netfan
816d1f5a69 fix: demos route fixed (#5405) 2025-01-15 19:24:02 +08:00
dap
bef98489b1 chore: 不使用基础布局(仅在顶级生效) 2025-01-15 17:13:46 +08:00
Netfan
8cc903c0e1 feat: modal state locked on submitting (#5401)
* feat: modal state locked on submitting

* docs: 更新modal文档
2025-01-15 17:00:46 +08:00
dap
02fba565e0 chore: 修改zIndex 2025-01-15 15:28:17 +08:00
dap
256a29dae1 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-01-15 15:22:21 +08:00
Netfan
13087a10b7 refactor: fix popup component zIndex (#5397) 2025-01-15 12:32:03 +08:00
Netfan
27a3888e35 style: element plus loading style fixed (#5393)
* Element Plus的loading组件默认zIndex太高
2025-01-15 00:49:11 +08:00
Netfan
fb0ec05ff8 perf: improve fieldMappingTime to support format function (#5392) 2025-01-14 18:15:00 +08:00
Netfan
76c4aa2c55 fix: hide root route in breadcrumb 2025-01-14 17:51:39 +08:00
Netfan
e1c503e51e feat: support set default props for drawer and modal (#5390)
* feat: support set default props for drawer and modal

* docs: fix typo
2025-01-14 17:11:18 +08:00
Netfan
5965755caa fix: root router config fixed (#5389) 2025-01-14 15:15:02 +08:00
dap
2bef75e044 fix: 修改Vxe默认zIndex为995 解决右上角全屏后modal/drawer(zIndex: 1000)被遮挡 2025-01-14 14:10:40 +08:00
Netfan
1ad54561b0 feat: add noBasicLayout in route meta (#5386)
所有菜单数据无需配置component为BasicLayout,它们将会默认使用基础布局,也可以通过meta.noBasicLayout来阻止这一行为
2025-01-14 12:12:08 +08:00
dap
ee9c271854 chore: wechat image 2025-01-13 21:33:34 +08:00
dap
c372a564d8 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-01-13 17:10:00 +08:00
dap
a9cae15d98 chore: 改为全局参数配置 去除局部参数 2025-01-13 17:08:00 +08:00
Netfan
42e322012c fix: spinner may stop playing animation after dismiss (#5365)
* fix: spinner may stop playing animation after dismiss

* fix: animation paused more safely
2025-01-12 15:43:44 +08:00
Netfan
8cf6e8ec75 style: popover bgColor is too close to common (#5364)
修复Dark主题下,弹出层的背景色与主体背景色太过接近的问题
2025-01-12 14:48:05 +08:00
dap
21dd7bd6c0 docs: version update 2025-01-12 12:03:47 +08:00
dap
a49f7f8816 docs: changelog 2025-01-12 12:03:19 +08:00
dap
996f498bfc chore: 文件上传 描述 2025-01-12 12:00:19 +08:00
Netfan
79d4d2fb22 ci: retry deploy while faild 2025-01-12 11:58:07 +08:00
dap
684cc83256 feat: 文件上传 进度条+提示文字 2025-01-12 11:57:09 +08:00
dap
2378728d7f feat: 文件上传 进度条 2025-01-12 11:43:23 +08:00
dap
93673fd095 feat: 上传文件格式说明 2025-01-12 10:56:32 +08:00
dap
f81dffd072 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into warmflow 2025-01-12 10:07:39 +08:00
Netfan
b785bc5704 fix: useEcharts return invalid instance (#5360) 2025-01-12 09:54:37 +08:00
Netfan
6719e2679f feat: popup component support overlay blur effect (#5359) 2025-01-11 23:37:17 +08:00
Netfan
cb9c8db5ba feat: improve tippy demo (#5357) 2025-01-11 20:42:38 +08:00
Netfan
a2637313f8 feat: integrate new component Tippy with demo (#5355)
* 添加新的工具提示组件Tippy
2025-01-11 17:35:59 +08:00
dap
7277b3f98b chore: 优化表格图片显示 2025-01-11 12:45:40 +08:00
Netfan
467689525f perf: add nested modal demo (#5353) 2025-01-11 12:12:50 +08:00
dap
c1d0a8fe3e chore: 默认显示右边的滚动条 防止出现滚动条被挤压 2025-01-11 11:49:49 +08:00
Netfan
1a04a05b79 perf: modal and drawer api support chain calls (#5351)
* perf: modal and drawer api support chain calls

* fix: typo
2025-01-11 10:56:54 +08:00
Netfan
b8bffd884c feat: allow close tab when mouse middle button click (#5347)
* 偏好设置增加鼠标中键关闭标签页的设置
2025-01-10 20:52:31 +08:00
dap
e57df4e522 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into warmflow 2025-01-10 16:39:14 +08:00
dap
ca7373cd63 refactor: 重构显示total的逻辑 2025-01-10 15:41:55 +08:00
dap
d00e37a619 chore: 调整高度自适应代码 2025-01-10 15:26:36 +08:00
dap
ed631b6358 chore: vxe升级4.10.0版本(锁定) 2025-01-10 15:26:05 +08:00
dap
7a3c211db7 fix: 添加失效的option 2025-01-10 15:10:41 +08:00
dap
8276026b01 fix: 需要为数组 2025-01-10 14:47:12 +08:00
Netfan
624beb6fa0 fix: locale switching logic correction (#5344)
* 修复语言切换后的数据更新逻辑

* 表单默认按钮的content属性可提供computed类型的值
2025-01-10 14:32:21 +08:00
dap
c3fdeda1ca Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into warmflow 2025-01-10 14:24:43 +08:00
dap
0440ac84fd chore: 导入类型优化 解决eslint报红 2025-01-10 14:12:42 +08:00
dap
9f6bee86f0 refactor: type/注释优化 去除大量any 2025-01-10 14:02:21 +08:00
Netfan
7606b86854 fix: vxeGrid init without search form (#5342)
* 修复vxeGrid在未使用表单的情况下,自动加载数据失效的问题。

* 暂时将vxeGrid版本锁定在4.10.0,新版本尺寸计算尚有问题
2025-01-10 11:53:06 +08:00
dap
6e3b468303 chore: 锁屏默认false 关闭该功能 2025-01-10 11:02:54 +08:00
dap
170b9baca6 chore: 调整接口 2025-01-10 10:59:02 +08:00
Netfan
e10cbe23b9 chore: update deps 2025-01-10 09:22:32 +08:00
Netfan
d34838bdd8 fix: primaryColor calculation (#5337) 2025-01-10 01:51:38 +08:00
Netfan
c979c23e6b fix: form valid-error style in naive (#5336) 2025-01-10 01:15:30 +08:00
Netfan
516d0b8dc8 fix: form fieldMappingTime improve and modelPropName support (#5335)
* 表单的fieldMappingTime支持将格式化掩码设为null以便原值映射,这样可以支持非日期时间类型的组件;
* 表单增加modelPropName设置组件的双向绑定属性名,用于支持未提前注册的双向绑定属性为非默认名称的组件。
* 增加一些经常会有人提到的组合字段演示,
2025-01-09 22:49:28 +08:00
Netfan
99c7fd72f8 fix: code lint 2025-01-09 13:04:14 +08:00
Netfan
2828e7a7b6 fix: form fieldMappingTime is not working (#5333)
* fix: form option `fieldMappingTime` is not working

* fix: form merge support `fieldMappingTime`
2025-01-09 12:28:33 +08:00
dap
eb7b7c33d2 chore: 选人组件样式 2025-01-08 18:28:02 +08:00
王文庭
16162c01ed fix: download from url triggered twice sometimes (#5319)
解决Chrome、Safari通过路径一次下载两个文件的BUG
2025-01-08 16:01:23 +08:00
dap
160d4a0a82 chore: 优化代码 2025-01-08 15:47:25 +08:00
dap
a60ff01c3a chore: 动态类名(无效)改为style 2025-01-08 15:42:14 +08:00
dap
51c29fcc9c refactor: 字典相关功能重构 采用一个Map储存字典(之前为两个Map) 2025-01-08 13:22:47 +08:00
dap
74198a0edc feat: 字典支持number类型存储 2025-01-08 12:51:04 +08:00
dap
8df6e3860f chore: 调整样式 2025-01-08 10:55:03 +08:00
dap
d5482decb8 chore: 修改选中border为1px 2025-01-08 10:34:00 +08:00
dap
9a15896125 chore: 字段 2025-01-08 00:34:25 +08:00
dap
721042ed5f chore: 改为新窗口打开(适用于pdf/图片)而非直接下载 2025-01-07 20:12:30 +08:00
dap
5d8206f291 chore: 更新样式 2025-01-07 20:03:14 +08:00
dap
451dca4793 chore: 更新字段 2025-01-07 19:46:37 +08:00
dap
9f5a5c5fc4 chore: 改为computed 2025-01-07 19:14:46 +08:00
dap
69556310e5 chore: 跳转到未发布流程tab 2025-01-07 19:03:16 +08:00
dap
79a14ab5d3 chore: 优化样式 2025-01-07 19:01:27 +08:00
dap
891a59a323 docs: readme 2025-01-07 16:47:17 +08:00
dap
d98bc819d8 fix: name重复导致的404 2025-01-07 16:32:31 +08:00
dap
c11cca2c2e Merge branch 'dev' of https://gitee.com/dapppp/ruoyi-plus-vben5 into warmflow 2025-01-07 16:24:53 +08:00
dap
02d42de133 chore: 使用legacy来保证copy的兼容性 2025-01-07 15:58:05 +08:00
dap
95650da33b chore: 去除log 添加说明 2025-01-07 15:21:48 +08:00
dap
5444098ab7 chore: 优化代码 2025-01-07 15:19:25 +08:00
dap
273d28be4c feat: 节点关联/节点独立的切换逻辑 2025-01-07 15:01:10 +08:00
dap
d8acb86427 chore: remove logic 2025-01-06 21:23:25 +08:00
dap
23588b02d9 chore: vxe可编辑表格demo 2025-01-06 21:13:48 +08:00
dap
ac913595a9 chore: 不允许在按钮下添加数据 2025-01-06 18:10:55 +08:00
dap
6569265fab docs: changelog 2025-01-06 14:55:52 +08:00
dap
0726067bff fix: wrong code 2025-01-06 14:54:30 +08:00
dap
a37a16c70e chore: 移除测试菜单 2025-01-06 14:47:20 +08:00
dap
e72f82d4ee chore: 优化代码 2025-01-06 14:46:29 +08:00
dap
2bf317c617 refactor: 租户套餐菜单替换为新版 2025-01-06 14:44:56 +08:00
dap
e554106eb9 refactor: 使用新版菜单勾选 2025-01-06 14:32:08 +08:00
dap
5033ea2e82 chore: 点行会勾选/取消全部权限 点权限不会勾选行 2025-01-06 14:27:00 +08:00
dap
d1ef1192b2 chore: 全屏引导+样式优化 2025-01-06 12:36:57 +08:00
dap
d50b4fa47c chore: 调整间距 2025-01-06 10:48:28 +08:00
dap
78806a0933 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-01-06 10:30:25 +08:00
clddup
bbbdbfa912 feat: useEcharts exports echarts instance#5294 (#5299) 2025-01-05 15:54:13 +08:00
John
06cccc53fa chore: update quick-start.md (#5303)
change COREPACK_REGISTRY to COREPACK_NPM_REGISTRY
2025-01-05 15:52:27 +08:00
dap
831a1abac7 chore: updateCheckedNumber 2025-01-04 19:25:45 +08:00
dap
a48a7a9444 refactor: 优化代码 2025-01-04 19:13:54 +08:00
dap
e838537356 chore: 优化代码 2025-01-04 18:30:20 +08:00
dap
543fb0cf91 chore: 优化样式 2025-01-04 17:10:36 +08:00
dap
2b850a5b89 chore: keys依赖于menu 需要先加载menu 2025-01-04 16:49:15 +08:00
dap
6cf8f57ed4 chore: 菜单加载完毕再显示 2025-01-04 16:37:13 +08:00
dap
ada7fdc78d feat: 新的菜单选择组件(beta) 2025-01-04 16:25:14 +08:00
dap
e53ac28331 chore: $t 2025-01-03 19:19:30 +08:00
dap
cc5adaf02f chore: 测试菜单页面 2025-01-03 19:14:40 +08:00
dap
1a535e5202 chore: 优化代码 2025-01-03 15:30:55 +08:00
dap
103b1a6f4a feat: 对ossId回显的支持 2025-01-03 15:27:03 +08:00
dap
62da4edae4 chore: 只获取一次默认密码而非每次打开modal都获取 2025-01-02 19:59:09 +08:00
Netfan
801c640724 fix: vben select placeholder color (#5286) 2025-01-02 10:19:20 +08:00
dap
844a9b5013 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2025-01-01 12:57:20 +08:00
Vben
081d2aed23 perf: format code with better style (#5283) 2025-01-01 11:39:49 +08:00
dap
26431faf6c chore: 工作流演示站 2024-12-31 12:39:35 +08:00
Netfan
4d81b9d18d fix: sidebar preferences fixed (#5276) 2024-12-31 12:36:45 +08:00
dap
cf9edbb1c4 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2024-12-31 12:31:49 +08:00
Netfan
e9dc613548 fix: breadcrumb setting not valid for header-sidebar-nav layout (#5275) 2024-12-31 12:00:50 +08:00
Netfan
3af22f7e91 fix: header logo may not be collapsed in header-sidebar-nav layout (#5274) 2024-12-31 11:35:58 +08:00
Netfan
2135cb8ece feat: new layout sidebar nav with full header (#5270) 2024-12-31 00:30:15 +08:00
Netfan
376aad5d26 feat: drawer close icon placement (#5269) 2024-12-30 23:30:53 +08:00
Netfan
27ba45aa75 docs: update dialog and drawer docs 2024-12-30 22:21:01 +08:00
Netfan
de17007788 feat: drawer support destroy on close 2024-12-30 22:21:01 +08:00
Netfan
e86a7906fe feat: drawer support onOpened & onClosed 2024-12-30 22:21:01 +08:00
Netfan
4a8e6abc06 feat: modal support destroy on close 2024-12-30 22:21:01 +08:00
dap
4ed02e1ebb fix: wrong boolean 2024-12-30 19:39:09 +08:00
dap
e3025176ff Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2024-12-30 19:38:01 +08:00
dap
6e4b7f4695 chore: 调整tab位置 2024-12-30 19:28:34 +08:00
dap
39dfa81f58 chore: 删除历史流程 改为tab切换 2024-12-30 18:55:47 +08:00
Netfan
2eb7fed9f4 fix: header-mixed layout side-menu active (#5265)
* fix: header-mixed layout side-menu active

* fix: config test
2024-12-30 15:24:01 +08:00
Netfan
ff8d5ca351 feat: header mixed layout (#5263)
* feat: new layout header-mixed

* fix: header-mixed layout update

* feat: layout preference update

* fix: extra menus follow layout setting
2024-12-30 14:01:17 +08:00
vben
07c4ad05f4 chore: release 5.5.2 2024-12-28 22:15:00 +08:00
dap
5234f2ef54 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2024-12-28 19:08:49 +08:00
Netfan
548c2e5500 chore: downgrade vue-tsc version 2024-12-28 17:53:39 +08:00
Netfan
ec2c6eff6f feat: header menu align support (#5256)
* feat: header menu align support

* fix: typo
2024-12-28 16:16:48 +08:00
Netfan
15fe82c62f chore: update deps 2024-12-28 16:15:39 +08:00
dap
70808e7d85 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2024-12-27 07:43:05 +08:00
Netfan
cb5ecf4a8a chore: add apiSelect remote search demo (#5246) 2024-12-26 19:23:59 +08:00
dap
f8c9d41776 chore: 审批改为description而非disabled的表单 2024-12-25 11:27:52 +08:00
dap
c7a7f94cc5 chore: 改为ts 2024-12-23 08:41:17 +08:00
dap
cf24596e4d chore: 错误的conetnt 2024-12-22 19:20:00 +08:00
dap
2e4ae78ee0 refactor: 终止/转办/委托支持填写意见 2024-12-21 21:01:16 +08:00
dap
24045455e8 chore: 第一次拿到的是readonly的数据 如果需要修改 需要cloneDeep 2024-12-21 19:21:30 +08:00
dap
5d877f049f Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2024-12-21 19:07:22 +08:00
Netfan
68a7e790d8 fix: grid form submit button locale switch (#5205) 2024-12-21 15:36:48 +08:00
dap
7ca161ed75 chore: 调整驳回 2024-12-21 15:07:27 +08:00
dap
677889f266 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2024-12-21 12:24:17 +08:00
Vben
24a4935e85 fix: build error (#5199) 2024-12-20 22:41:38 +08:00
dap
c7253f468f fix: esbuild自动升级导致运行/打包报错 2024-12-20 19:45:57 +08:00
dap
0281441318 fix: esbuild自动升级导致运行/打包报错 2024-12-20 19:42:12 +08:00
dap
8ab0bd2212 fix: esbuild自动升级导致运行/打包报错 2024-12-20 19:31:31 +08:00
dap
31b7551852 chore: 流程定义 激活改为switch 2024-12-20 16:37:56 +08:00
dap
4439533b09 chore: 流程申请支持上传文件 2024-12-20 15:46:02 +08:00
dap
a320bc3778 chore: title 审批通过 2024-12-20 15:25:10 +08:00
Netfan
9a660827a6 fix: vxeGrid top padding (#5193) 2024-12-20 14:47:33 +08:00
dap
aa95783fc9 fix: 表格排序翻页会丢失排序参数 2024-12-20 13:58:01 +08:00
dap
94721d7e66 chore: 去除log打印 2024-12-20 11:14:18 +08:00
dap
58c361c908 chore: 流程监控 待办任务 2024-12-20 11:12:38 +08:00
dap
58dac45dde chore: 我发起的 2024-12-20 10:35:03 +08:00
dap
af8052ce49 chore: 去除已经移除的菜单页面 2024-12-20 10:06:38 +08:00
dap
4db697e714 chore: 我的已办 2024-12-20 10:02:31 +08:00
dap
fc43527cf1 chore: 页面优化 2024-12-20 09:55:42 +08:00
dap
72d82ac94b chore: 重置tooltip 2024-12-20 09:51:50 +08:00
dap
7f239133b5 feat: 我的抄送搜索/优化重复触发的接口 2024-12-20 09:49:03 +08:00
dap
4e79182c7a feat: 流程定义 历史 2024-12-20 09:18:43 +08:00
dap
cf044cc679 chore: 修改分类 2024-12-20 08:50:53 +08:00
dap
5e82866370 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2024-12-20 07:58:43 +08:00
Netfan
a44ff73dd3 fix: grid tools in toolbar config not working as expected (#5190) 2024-12-19 21:34:47 +08:00
Netfan
acd87b2250 feat: add resizable and ColPage component (#5188)
* feat: add component resizable

* feat: component `ColPage` with demo
2024-12-19 20:37:42 +08:00
dap
8b01f8316d chore: 条件 2024-12-19 16:41:31 +08:00
dap
3c427086e7 chore: break-all 2024-12-19 16:31:06 +08:00
dap
994b49fb87 feat: 流程分类 搜索 2024-12-19 15:58:37 +08:00
dap
6ec8f4ced9 chore: 弹窗关闭后仍然显示表单浮层 2024-12-19 15:17:20 +08:00
dap
78fe591111 chore: 选人组件的样式 2024-12-19 15:09:38 +08:00
dap
a873c74a7c chore: 搜索的样式 2024-12-19 14:58:27 +08:00
dap
3bebdfda77 chore: 漏掉的导入 2024-12-19 14:54:39 +08:00
dap
1b5b0f4736 chore: 最大显示的头像数量 超过显示为省略号头像 2024-12-19 14:49:36 +08:00
dap
e7eb0577ec fix: 选人的一些问题 2024-12-19 14:31:46 +08:00
dap
5577f8d339 Merge branch 'warmflow' of https://gitee.com/dapppp/ruoyi-plus-vben5 into warmflow 2024-12-19 13:03:54 +08:00
dap
b1a6c0f880 chore: 没有更多数据了 2024-12-19 11:51:00 +08:00
Netfan
1853ba1d60 fix: sidebar header height (#5183) 2024-12-19 11:45:32 +08:00
dap
d304e8a2a3 chore: sse配置文件关闭 2024-12-19 11:27:23 +08:00
dap
2b19cea0d8 chore: 搜索表单布局+申请人 2024-12-19 11:16:07 +08:00
OldDriver
85cbb3b842 fix: remove the overlap caused by border-b (#5160) 2024-12-19 09:36:36 +08:00
booshaw
968c44572a docs: fix typos (#5169) 2024-12-19 09:35:25 +08:00
Journey
3201b843a8 fix: resolve eslint errors as well as TS type errors (#5172)
* fix: remove TypeScript error suppression for missing types in Vue ESLint config

* fix: enhance application configuration with CSS options type support
2024-12-19 09:34:42 +08:00
dap
6946471d96 chore: enter提交表单 2024-12-19 08:33:53 +08:00
dap
02e0927a9c chore: 修改文案 2024-12-19 08:22:14 +08:00
dap
911b52e938 chore: 默认全部展开 2024-12-19 08:19:34 +08:00
dap
0a9e85bb58 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2024-12-19 07:49:46 +08:00
Netfan
db5b727300 feat: page content class override (#5179) 2024-12-18 22:53:05 +08:00
Netfan
10b3a16f79 fix: sidebar style on focus (#5178) 2024-12-18 22:52:40 +08:00
dap
9f15cd47ea fix: 抄送选人 最右侧已选中删除item无效 2024-12-18 20:55:07 +08:00
dap
9a259642af feat: 复制 2024-12-18 17:15:53 +08:00
dap
8702d1ddfe chore: 昵称过长的显示 2024-12-18 17:01:02 +08:00
dap
80558b9cf1 chore: 默认选中第一个 2024-12-18 16:32:05 +08:00
dap
7a9ea1d4dc chore: 修改relative位置 2024-12-18 16:22:51 +08:00
dap
6307ff5759 chore: 搜索 2024-12-18 15:54:27 +08:00
dap
2805590755 feat: 我的待办 - 搜索条件 2024-12-18 15:36:12 +08:00
dap
75d059f15a chore: 流程监控 - 待办任务页面的id不唯一 改为前端处理 2024-12-18 14:10:50 +08:00
dap
86013b44a6 feat: 修改办理人 2024-12-18 13:57:50 +08:00
dap
877fa1b2d1 chore: 流程干预 - 加签/减签 2024-12-18 13:50:05 +08:00
dap
239c0f60fb chore: avatar大小 2024-12-18 13:38:42 +08:00
dap
9c65206ab0 chore: 抄送需要手动添加createByName 2024-12-18 13:36:26 +08:00
dap
59e039896e Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2024-12-18 13:32:33 +08:00
dap
4d7fe96c87 chore: 审批通过 抄送 2024-12-18 11:44:52 +08:00
dap
1b9583c2d0 feat: 流程实例-流程预览 2024-12-18 11:24:43 +08:00
dap
95aced6209 chore: spell 2024-12-18 11:21:48 +08:00
dap
2c3f247c08 chore: clientid 2024-12-18 11:20:39 +08:00
dap
728f4339e6 chore: 分类条件 2024-12-18 11:06:29 +08:00
dap
d28cf0d98f chore: 修改办理人 2024-12-18 10:53:25 +08:00
dap
f56ba6ba33 chore: 更改postMessage参数 2024-12-18 10:08:02 +08:00
dap
ada0a7edf6 chore: 内嵌iframe高度根据表单高度调整 2024-12-18 09:57:31 +08:00
dap
129059b7a5 chore: 流程详情 2024-12-18 09:38:57 +08:00
dap
3de8104e44 feat: 抄送选择 2024-12-18 09:32:53 +08:00
dap
b641b0eb15 chore: 调整分类树 2024-12-18 08:16:03 +08:00
Netfan
a97c998be5 fix: user homePath no effect sometimes (#5166) 2024-12-17 21:39:12 +08:00
Netfan
b22d900e27 feat: form compact mode support (#5165) 2024-12-17 20:51:17 +08:00
Netfan
181e38733c fix: form auto submit no effect when showDefaultActions is false (#5163) 2024-12-17 20:15:09 +08:00
dap
e09e95c3f5 chore: 修改width 2024-12-17 20:00:16 +08:00
dap
13d9b42ca7 feat: 待办任务 2024-12-17 19:58:02 +08:00
dap
2667bffd34 feat: 我的抄送 2024-12-17 19:33:25 +08:00
dap
ffdbd3435a chore: 流程定义 样式 2024-12-17 19:29:53 +08:00
dap
0f2909172d chore: 退回后重新申请 2024-12-17 19:27:42 +08:00
dap
540108ac8d chore: 请假申请布局 2024-12-17 19:16:55 +08:00
dap
3319310c11 chore: 请假申请-并行会签网关 2024-12-17 19:10:05 +08:00
dap
5ea280b611 chore: 分类去除根目录 2024-12-17 19:08:56 +08:00
dap
e3188acbc4 chore: 详情modal(未完成) 2024-12-17 17:10:08 +08:00
dap
15e6209aa3 chore: 请假申请根据不同状态显示按钮 2024-12-17 16:09:13 +08:00
dap
3c1df9c880 chore: 流程删除/撤销 2024-12-17 15:41:07 +08:00
dap
7d9ddd4698 chore: 审批完成后刷新当前页 2024-12-17 15:08:31 +08:00
dap
2e3d385747 feat: 选人组件(未完成) 加签减签 2024-12-17 14:47:51 +08:00
Netfan
4fe44611d3 docs: fix docs-link and add EllipsisText docs (#5158)
* docs: fix docs-link and add `EllipsisText` docs

* fix: ellipsisText docs link
2024-12-17 14:41:03 +08:00
dap
8b58440e00 chore: 新窗口打开文件 2024-12-17 09:53:32 +08:00
dap
28caf89748 chore: 审批通过 2024-12-17 09:50:19 +08:00
dap
3558bbf6a0 chore: 使用useEventListener替换原生 2024-12-17 09:27:48 +08:00
dap
dac65eb262 chore: 字段错误 2024-12-17 09:26:41 +08:00
dap
34d091adfa chore: iframe通信 加载完毕后才显示表单 解决卡顿问题 2024-12-17 09:23:54 +08:00
dap
06f76bea0a chore: 审批终止/驳回 2024-12-17 09:06:46 +08:00
dap
4b41f8d9dc chore: 附件图标 2024-12-17 08:23:01 +08:00
dap
7e0bb9d06e chore: process_running显示按钮 2024-12-17 08:21:00 +08:00
dap
3e565666c6 chore: label错误 2024-12-17 08:15:27 +08:00
dap
f735e8e536 chore: 保存的事件 2024-12-17 08:15:08 +08:00
dap
395b45fa48 chore: 需要加上clientId 2024-12-17 08:09:47 +08:00
dap
219cde1e0e Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev 2024-12-17 08:01:02 +08:00
Netfan
593916d6aa feat: form colon support (#5156) 2024-12-16 22:37:29 +08:00
dap
e52ec4f9b9 chore: 完善请假申请 2024-12-16 21:01:30 +08:00
Netfan
38805a0e1f feat: improve code login demo (#5154)
* feat: add some method in formApi

* fix: VbenPinInput style with small screen

* chore: improve code login demo
2024-12-16 20:48:51 +08:00
dap
3d7f3aef58 chore: 客户端管理 行高自适应 2024-12-16 19:14:12 +08:00
dap
a216db37fe chore: 内嵌表单的路径 2024-12-16 17:42:18 +08:00
dap
68cf6cd790 chore: 修改avatar背景色 2024-12-16 17:23:05 +08:00
dap
6ca385f1bc chore: 注释 2024-12-16 17:12:30 +08:00
dap
0a3b54e320 chore: activePath 2024-12-16 17:11:53 +08:00
dap
bdfb757219 chore: leave表单 2024-12-16 16:48:18 +08:00
dap
5e5f4fbb97 chore: 修改请假demo路径 2024-12-16 16:10:06 +08:00
dap
d7d3186ef0 chore: categoryId 2024-12-16 15:59:27 +08:00
dap
ac8e1b672f chore: 我的已办 2024-12-16 15:22:37 +08:00
dap
1c9ea51780 chore: 我发起的 2024-12-16 15:19:15 +08:00
dap
75b766eeba chore: loading 2024-12-16 14:52:05 +08:00
dap
c978d14ea2 chore: 历史版本 2024-12-16 14:27:31 +08:00
dap
e2864974db chore: 完善task api 2024-12-16 14:00:48 +08:00
dap
993ac11eb6 chore: 隐藏'菜单加载中' 2024-12-16 13:53:58 +08:00
dap
63429789ea chore: missing import 2024-12-16 13:43:19 +08:00
Netfan
0f756503ff feat: add demo for modify menu badge data 2024-12-16 12:45:07 +08:00
dap
e7c443a63a chore: 流程实例 2024-12-16 11:36:17 +08:00
dap
238809ecfd chore: 审批附件 2024-12-16 10:18:33 +08:00
dap
e56672864f chore: 我的待办 提取公共组件 2024-12-16 09:45:00 +08:00
dap
ed9448d1ba chore: 流程部署 2024-12-16 09:15:04 +08:00
dap
330aaf69b2 chore: 新增/编辑/导出xml 2024-12-16 08:48:53 +08:00
dap
cf5e6a1f1e chore: 流程定义(除历史版本) 2024-12-16 08:21:38 +08:00
Netfan
f6faeb034e feat: autoActivateChild support more layout mode (#5148) 2024-12-16 04:54:32 +08:00
Netfan
2efb5b71c3 feat: auto activate subMenu on select root menu (#5147)
* feat: auto activate subMenu on click root menu

* fix: prop name fixed

* chore: test and docs update
2024-12-16 02:57:50 +08:00
Netfan
22c1f86ca1 fix: disabledOnChangeListener not work in form (#5146) 2024-12-16 00:57:10 +08:00
Netfan
ce4af37fd8 fix: login expired modal z-index (#5145)
* fix: login expired modal z-index

* feat: support custom z-index
2024-12-15 23:25:40 +08:00
Netfan
f446cbf9e5 feat: user-dropdown support hover trigger (#5143)
* feat: user-dropdown support `hover` trigger

* fix: modified type declaration
2024-12-15 18:24:22 +08:00
Netfan
7581fb381f fix: pinInput value synchronous update (#5142) 2024-12-15 14:26:42 +08:00
Netfan
bedf19993d fix: vxeGrid default sort data no effect in first query (#5141)
* fix: vxeGrid default sort data no effect in first query

* fix: query params lost
2024-12-15 12:52:56 +08:00
Netfan
e558087bcf fix: vscode debug profile (#5140) 2024-12-15 12:44:33 +08:00
Netfan
698daf46c7 fix: form component events bind (#5137)
* fix: from component events bind

* chore: update docs

* chore: default value and docs sync
2024-12-14 17:42:13 +08:00
dap
831696e275 chore: 在线用户样式 开启虚拟滚动 2024-12-13 17:22:28 +08:00
dap
6f9a805f0c chore: 去掉个人中心 在线设备的分页 2024-12-13 16:41:10 +08:00
dap
982ccd57c6 chore: 去掉在线用户的分页 2024-12-13 16:37:53 +08:00
dap
c74369fd76 chore: changelog 2024-12-13 15:42:09 +08:00
dap
7ad45c897b refactor: 获取字典的方法 提取公共函数 减少冗余代码 2024-12-13 15:41:20 +08:00
Netfan
0410f1e1be fix: element plus validate failed style (#5130)
* fix: element plus validate failed style

* fix: element plus textarea style
2024-12-13 15:33:30 +08:00
dap
ccbc385bc8 chore: 使用私有桶的提示 2024-12-13 15:22:02 +08:00
Netfan
7fbf7b189a feat: tabbar support mouse wheel vertical (#5129)
* feat: tabbar support mouse wheel

* docs: add tabbar wheelable tips

* chore: resolve vitest test
2024-12-13 14:45:06 +08:00
Netfan
be208fe915 fix: form support disabledOnInputListener (#5127)
* fix: form support `disabledOnInputListener`

* chore: docs update
2024-12-13 11:18:45 +08:00
Netfan
1d3729aa24 fix: form submission not appropriate (#5126) 2024-12-13 10:56:24 +08:00
dap
b0d44b07b4 Merge branch 'main' of https://gitee.com/dapppp/ruoyi-plus-vben5 into dev 2024-12-13 08:36:45 +08:00
vben
cbca9ffd95 chore: release 5.5.1 2024-12-12 22:47:11 +08:00
Netfan
ed465d2b5b feat: table search form visible control (#5121)
* feat: table search form visible control

* chore: fix docs and demo

* chore: type error fixed
2024-12-12 22:28:03 +08:00
dap
fbcb3c6caf chore: 需要隐藏菜单 2024-12-12 16:19:25 +08:00
dap
e6e2c84f45 chore: 我的待办 & 请假 2024-12-12 16:07:42 +08:00
dap
8f9215ffad chore: 流程定义(未完成) 2024-12-12 09:08:07 +08:00
dap
6183d22b20 fix: 字典项为空时getDict方法无限调用接口((无奈兼容 不给字典item本来就是错误用法)) 2024-12-11 22:12:13 +08:00
dap
97b91aaf7c chore: 流程定义(开发中) 2024-12-11 21:33:59 +08:00
dap
7577f17dd9 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin 2024-12-11 16:00:25 +08:00
dap
4fab8251c7 feat: 通用的vxe-table排序事件(排序逻辑改为在排序事件中处理而非在api处理) 2024-12-11 15:46:45 +08:00
Netfan
d308da6ba1 fix: resolve table toolbar error (#5109) 2024-12-11 15:44:45 +08:00
Netfan
7c4dfdc1c2 feat: form support reverse action buttons (#5108)
* feat: form support reverse action buttons

* fix: submit button class
2024-12-11 15:29:25 +08:00
dap
b9a4b709db fix: 回滚错误修改 2024-12-11 15:17:00 +08:00
dap
2aa4756a3e chore: 改为Partial DeepPartial导致识别不出具体类型 2024-12-11 15:16:04 +08:00
Netfan
991ada31ba chore: update deps (#5107) 2024-12-11 15:09:38 +08:00
Netfan
43adc943b9 docs: fix typos (#5105) 2024-12-11 14:48:08 +08:00
Netfan
4a20156f3d fix: table auto height (#5101) 2024-12-11 13:46:52 +08:00
dap
137f753471 Merge branch 'main' of https://gitee.com/dapppp/ruoyi-plus-vben5 into dev 2024-12-11 11:37:35 +08:00
dap
b29b41fc73 chore: version 2024-12-11 11:35:16 +08:00
dap
a7d9697397 chore: 移除调试代码 2024-12-11 11:22:13 +08:00
dap
7ec3cfb3fd refactor: 判断vxe-table的复选框是否选中 2024-12-11 11:09:16 +08:00
Netfan
eec6f41f6a refactor: ApiComponent with docs (#5099)
* refactor:  `ApiComponent` with docs

* docs: remove invalid docs

* docs: remove duplicate prop docs

* docs: update `ApiComponent` docs
2024-12-11 10:45:04 +08:00
Arthur Darkstone
2cc918f79d feat: replace ElSelect with ElSelectV2 in component adapter for butter performance (#5085) 2024-12-11 09:57:45 +08:00
dap
3014b62086 chore: 标记为非代理对象 消除warning 2024-12-10 19:39:14 +08:00
Netfan
07b1ad121c chore: remove redundant test code (#5094) 2024-12-10 17:58:57 +08:00
Netfan
e419b03cab feat: modal&drawer support appendToMain and zIndex (#5092)
* feat: modal/drawer support append to main content

* feat: modal zIndex support

* fix: drawer prop define

* chore: type

* fix: modal/drawer position fixed while append to body

* docs: typo

* chore: add full-width drawer in content area

* chore: remove unnecessary class
2024-12-10 17:37:06 +08:00
dap
e0b4bf0956 fix: 上下文导致渲染不正常 2024-12-09 15:38:58 +08:00
dap
686e09a1f8 fix: h导致的页面报错(原因未知) 2024-12-09 15:24:12 +08:00
Netfan
018ddc75c6 feat: add default placeholder for ApiSelect (#5078) 2024-12-09 14:03:46 +08:00
Netfan
d085736bac feat: improve ApiSelect component (#5075)
* feat: improve `ApiSelect` component

* chore: `ApiSelect` props name changed
2024-12-09 12:47:33 +08:00
dap
4778ead7c2 chore: gitee地址 2024-12-09 09:57:27 +08:00
dap
7825333190 Merge branch 'main' of https://gitee.com/dapppp/ruoyi-plus-vben5 into dev 2024-12-09 08:10:10 +08:00
dap
131310efef Merge branch 'main' of https://gitee.com/dapppp/ruoyi-plus-vben5 2024-12-09 08:09:21 +08:00
dap
a13f808aa2 chore: 间距 2024-12-09 08:09:04 +08:00
Netfan
305549e7f2 feat: improve element plus form component (#5072) 2024-12-08 19:29:49 +08:00
Netfan
958c8b4f21 feat: imporve naive form component (#5071) 2024-12-08 19:23:46 +08:00
dap
41b415362c chore: markdown直接v-model改变值 保持与编辑器的同步 2024-12-08 19:18:09 +08:00
dap
1178f7a0bf chore: 多余的文件 2024-12-08 19:05:03 +08:00
dap
359d837dee Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin 2024-12-08 11:04:04 +08:00
Netfan
373766691f chore: remove useless fixedHeader prop for Page (#5069) 2024-12-07 23:26:47 +08:00
Netfan
bac0275624 chore: page prop type check (#5067) 2024-12-07 12:15:51 +08:00
Netfan
0fc0f13064 fix: layout overflow style (#5066) 2024-12-07 12:05:03 +08:00
Netfan
b75a8e6a2b fix: form setValues not support dayjs and Date value (#5064)
* fix: setFormValues not support  `dayjs object` value

* fix: setFormValues not support `Date` value

* chore: remove console log
2024-12-07 11:09:55 +08:00
Netfan
68ab73bdb5 fix: range picker props fixed for element-plus (#5042) 2024-12-07 11:09:33 +08:00
Netfan
4c1fc4a11e fix: validate message not display, fix #5034 (#5038) 2024-12-07 11:02:59 +08:00
Netfan
03f166f8a4 fix: form prop handleValuesChange no effect (#5060) 2024-12-07 11:02:14 +08:00
Netfan
d42daf9ce0 fix: modal radius not follow preferences (#5063) 2024-12-07 11:00:53 +08:00
Netfan
d1862fba27 fix: replace input component in IconPicker (#5047)
* fix: replace input component in `IconPicker`

* chore: fixed IconPicker demo
2024-12-06 13:46:52 +08:00
Netfan
f0db3d6b79 chore: codeowners update (#5048) 2024-12-06 13:46:32 +08:00
dap
0efbf57152 chore: 搜索忽略tinymce 2024-12-06 10:45:46 +08:00
dap
1d842b1b87 fix: break-normal更改位置 2024-12-06 09:32:27 +08:00
dap
48ca7aca8c fix: 微服务版本 区间查询和中文搜索条件一起使用 无法正确查询 2024-12-06 09:27:11 +08:00
dap
827ef2e403 fix: 默认word-break: break-word;会导致json预览样式异常 2024-12-05 16:08:56 +08:00
dap
4df62b563e fix: 在description组件中json预览样式异常 2024-12-05 16:03:35 +08:00
Netfan
21d37a1be0 fix: dialog and drawer footer gap in small screen (#5025) 2024-12-05 11:24:09 +08:00
huangxiaomin
fe236ea929 feat: add submitOnChange props to vben form (#5032) 2024-12-05 11:23:21 +08:00
huangxiaomin
05b4b61c6e fix: select Long option style problem (#5030) 2024-12-05 11:22:35 +08:00
dap
e2b91f88ab fix: 官方Commit17c7ce8造成的页面漂移 2024-12-05 08:29:46 +08:00
dap
e89c9c1c6a Merge branch 'main' of https://gitee.com/dapppp/ruoyi-plus-vben5 into dev 2024-12-05 08:06:55 +08:00
dap
eeba7b50f9 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin 2024-12-05 08:04:03 +08:00
vben
7ab00250bf chore: release 5.5.0 2024-12-04 22:57:27 +08:00
Vben
9896a67c21 feat: add api-select component (#5024) 2024-12-04 22:56:29 +08:00
Netfan
db38ef522f fix: Page header class in fixed mode (#5023) 2024-12-04 22:56:06 +08:00
Netfan
845f2a2abd fix: header left padding fixed (#5007) 2024-12-04 21:43:54 +08:00
Netfan
9b73792dc9 fix: extra menu title follow locale change (#5006) 2024-12-04 21:43:29 +08:00
Netfan
fccbe44cf7 feat: v-loading support for element plus (#5008) 2024-12-04 21:42:48 +08:00
Netfan
e23486dbc6 feat: form component IconPicker (#5005) 2024-12-04 21:42:21 +08:00
Netfan
935df713f3 fix: app config support .env.local (#5012) 2024-12-04 21:41:22 +08:00
Netfan
17c7ce8f21 feat: improve page component (#5013)
* feat: `page` component support fixed header

* docs: `page`  component documentation

* docs: Improve `props` types of `page`

* docs: improve `fixedHeader` description of `page`

* fix: `page` header border color with fixedHeader

* feat: add `headerClass` for `Page`
2024-12-04 21:40:41 +08:00
vben
24b9aa44d2 chore: Revert "fix: form 表单不支持field.xxx.xx格式的defaultValue配置 (#4965)"
This reverts commliit 12f216c0e7.
2024-12-02 00:47:06 +08:00
Vben
014e6d38a0 chore: update deps (#4993) 2024-12-01 21:53:52 +08:00
leizhiyou
12f216c0e7 fix: form 表单不支持field.xxx.xx格式的defaultValue配置 (#4965)
* fix: form 表单不支持field.xxx.xx格式的defaultValue配置

* chore: 修复代码规范问题
2024-12-01 21:48:54 +08:00
Netfan
ae3f7cb909 fix: mixed menu layout in full content mode (#4990) 2024-12-01 21:37:36 +08:00
Netfan
32117b73aa docs: add form slots docs (#4992) 2024-12-01 21:37:19 +08:00
dap
e1414b2b10 chore: i18n 2024-12-01 15:36:44 +08:00
dap
839e2e4321 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin 2024-11-30 20:03:53 +08:00
huangfe1
e8992a1d16 chore: update modal.vue (#4987)
loading时候 子组件禁用点击事件

Co-authored-by: Vben <ann.vben@gmail.com>
2024-11-30 11:18:22 +08:00
Svend
3c4af23edf fix: 修复 Form Api 根据字段名移除表单项,字段取反了的问题 (#4971) 2024-11-30 10:58:17 +08:00
LinaBell
e3a93970f4 fix: when VxeTable toolbarConfig.refresh is enabled, it will carry incorrect parameters (#4980) 2024-11-30 10:57:23 +08:00
richex-cn
7b9866158b chore: update deprecated document link in .github/ISSUE_TEMPLATE (#4986) 2024-11-30 10:56:42 +08:00
Netfan
3fb286b552 fix: element hover style in dark theme (#4983) 2024-11-30 10:55:29 +08:00
dap
7461693aa7 chore: 需要排除Button组件 全局已经默认导入了 2024-11-29 16:42:34 +08:00
dap
3afb8395a7 chore: 改为hideLabel 2024-11-29 16:03:16 +08:00
dap
0950022f09 chore: w-full改为在commonConfig配置 2024-11-29 15:55:16 +08:00
dap
227cf1e72b chore: 角色管理 优化Drawer布局 2024-11-29 15:45:42 +08:00
dap
a3e98aedf9 chore: 去除用于调试的menuList打印 2024-11-29 15:22:24 +08:00
dap
ac3ec4746f fix: 节点树在节点独立情况下的控制台warning 2024-11-29 15:21:03 +08:00
dap
36939f36ee fix: 节点树在编辑 & 空数组(不勾选)情况 勾选节点会造成watch延迟触发 导致会带上父节点id造成id重 2024-11-29 15:01:26 +08:00
dap
07325d4c5e chore: vxe-table的头部颜色和antd保持一致 2024-11-29 11:52:14 +08:00
dap
da512f166c chore: version 2024-11-29 08:45:46 +08:00
dap
f2692d4a85 chore: version 2024-11-29 08:43:09 +08:00
dap
9a9492bbee chore: 锁定vxe-table版本 4.9.8版本存在样式问题 2024-11-29 08:36:28 +08:00
dap
d2e3d44c14 chore: 暂时锁定cspell版本 2024-11-29 08:36:28 +08:00
dap
06c777ee81 refactor: 由于不能输入 需要使用watch监听 2024-11-29 08:36:28 +08:00
dap
68a45c25c8 chore: https://gitee.com/dapppp/ruoyi-plus-vben5/issues/IB7ANL 2024-11-29 08:36:27 +08:00
dap
3a9f670ec6 chore: 移除冗余代码 2024-11-29 08:36:27 +08:00
dap
4f96194084 chore: 组件卸载时移除emitter 2024-11-29 08:36:26 +08:00
huangxiaomin
a478721f07 fix: the route path did not synchronize with the page (#4947) 2024-11-29 08:36:26 +08:00
眼圈发黑
ff1c6a9de9 style: typo (#4948) 2024-11-29 08:36:25 +08:00
dap
edad22c23a chore: 替换为commonDownloadExcel 2024-11-29 08:36:25 +08:00
dap
5ffa2be89a fix: 左边部门树错误emit导致会调用两次列表api 2024-11-29 08:36:25 +08:00
dap
8dc00185ea chore: label样式 2024-11-29 08:36:24 +08:00
dap
79edae70d6 chore: 改为Textarea 2024-11-29 08:36:24 +08:00
dap
f9d964bdc3 chore: 滚动条宽度 2024-11-29 08:36:23 +08:00
dap
7c834308f0 chore: 审批样式 2024-11-29 08:36:23 +08:00
Netfan
253abc5ef1 chore: tailwind css icon example (#4969) 2024-11-28 15:10:14 +08:00
Jeff
5f55799572 fix: button-control page mistake (#4963)
* fix: button-control page mistake

按钮控制展示逻辑错误

* fix: button-control.vue button text
2024-11-28 10:01:26 +08:00
vince
54a9ff088f feat: upgrade vite version to 6.0.0 (#4961)
* chore: upgrade vite version to 6.0.0

* chore: update lock
2024-11-27 15:52:25 +08:00
dap
63db6ee4d7 chore: 锁定vxe-table版本 4.9.8版本存在样式问题 2024-11-27 14:07:34 +08:00
Netfan
73502677ff feat: add placement for Drawer (#4958) 2024-11-27 11:29:25 +08:00
Netfan
dedba18553 feat: add confirmDisabled for Dialog (#4959) 2024-11-27 11:28:49 +08:00
dap
95d8522b9f chore: 暂时锁定cspell版本 2024-11-27 10:32:35 +08:00
dap
56d77021c4 refactor: 由于不能输入 需要使用watch监听 2024-11-27 10:29:19 +08:00
dap
f4a1cc72d9 chore: https://gitee.com/dapppp/ruoyi-plus-vben5/issues/IB7ANL 2024-11-27 10:11:34 +08:00
dap
d8d884ecc1 chore: 移除冗余代码 2024-11-27 08:39:02 +08:00
dap
a70ae0f603 chore: 组件卸载时移除emitter 2024-11-27 08:35:38 +08:00
dap
41b69b5f93 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin 2024-11-26 20:30:16 +08:00
dap
c8e01a70b6 chore: 替换为commonDownloadExcel 2024-11-26 20:27:20 +08:00
dap
4b98a143c7 fix: 左边部门树错误emit导致会调用两次列表api 2024-11-26 20:25:48 +08:00
dap
593ed62585 chore: label样式 2024-11-26 20:08:39 +08:00
dap
afdf186fa4 chore: 改为Textarea 2024-11-26 13:51:39 +08:00
dap
40448b9365 chore: 滚动条宽度 2024-11-25 15:41:14 +08:00
huangxiaomin
f85badf482 fix: the route path did not synchronize with the page (#4947) 2024-11-25 15:07:52 +08:00
眼圈发黑
12f25cf3a2 style: typo (#4948) 2024-11-25 15:07:16 +08:00
dap
90c7bf625a chore: 审批样式 2024-11-25 15:02:01 +08:00
dap
198f65b467 chore: 部门及以下或本人数据权限 2024-11-25 11:31:58 +08:00
dap
3a4518db0e Merge branch 'main' of https://gitee.com/dapppp/ruoyi-plus-vben5 into dev 2024-11-25 11:29:58 +08:00
dap
af622d852f chore: 注释位置 2024-11-25 10:07:59 +08:00
dap
046476f8bd chore: eslint 2024-11-25 10:07:29 +08:00
dap
34a11ce64d chore: 主动登出不需要带跳转地址 2024-11-25 09:42:27 +08:00
dap
24e889adbe chore: 移除无用的工具function 2024-11-25 09:38:48 +08:00
dap
d214da3303 chore: 移除requestClient的一些冗余参数 2024-11-25 09:34:21 +08:00
dap
da0ddfc8c7 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin 2024-11-25 09:22:59 +08:00
dap
eb782a9080 feat: Options转Enum工具函数 2024-11-25 09:07:25 +08:00
vben
c8dd9bbf0b chore: release 5.4.8 2024-11-24 22:00:41 +08:00
Vben
3587ec54eb fix: supplement datepicker component (#4943)
* fix: supplement datepicker component

* chore: typo
2024-11-24 21:56:41 +08:00
dap
733f43bc47 docs: changelog 2024-11-23 18:03:29 +08:00
dap
0428b5447e fix: Content-Language header 2024-11-23 17:56:03 +08:00
dap
8a64165a2a chore: 个人中心强退设备接口路径 2024-11-22 16:09:24 +08:00
dap
28f8ee440d chore: 我的待办 样式 2024-11-21 19:53:16 +08:00
dap
53e1a6fdf7 chore: 我的待办 样式 2024-11-21 19:21:20 +08:00
dap
012808a1da chore: 滚动到底部的判断 2024-11-21 17:02:22 +08:00
dap
f32a949482 feat: 审批demo页 2024-11-21 16:29:40 +08:00
dap
883e6c5033 chore: wrong text 2024-11-20 19:44:02 +08:00
dap
41093a39b0 chore: 更换logo的说明 2024-11-20 13:55:19 +08:00
dap
ab988cf82e chore: oauth登录页开关 2024-11-19 08:29:12 +08:00
dap
40bb93afcd Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin 2024-11-18 07:47:46 +08:00
Vben
dbcb7138f2 fix: resolve issue with Upload component not working correctly inside Form (#4916) 2024-11-17 21:37:37 +08:00
ryomahan
fe58af2e78 fix: form-api.setValues can't resolve nested fields (#4915)
fix #4912
2024-11-17 21:04:35 +08:00
huangxiaomin
94c68c966e fix: fieldMappingTime data error when clear inputvalue (#4906) 2024-11-17 21:04:04 +08:00
Arthur Darkstone
77083abcc5 feat: add 3 resize examples (#4907) 2024-11-17 21:01:32 +08:00
Netfan
1302092798 fix: dialog opened/closed event triggered incorrectly,fixed #4902 (#4908) 2024-11-17 20:55:19 +08:00
Mintnoii
ec53bf8084 docs: optimize the introduction in both Chinese and English (#4913)
* 优化简介中文文档

1. 优化文案及病句
2. 统一格式

* Optimize the introduction English document

1. Optimize copywriting and sentences
2. Uniform format
2024-11-17 20:54:28 +08:00
dap
5fa31aa97e fix: some error in range picker 2024-11-16 09:30:29 +08:00
dap
924eeca280 fix: range-picker clear时值没有被正确清除 2024-11-15 16:10:05 +08:00
dap
d6c0ed6429 chore: tips 2024-11-15 14:51:10 +08:00
Netfan
b87d41bada fix: adjust useWatermark logic (#4896) 2024-11-15 14:06:13 +08:00
dap
2f37942961 chore: 虚拟滚动及自动list转tree(由vxe处理) 2024-11-15 13:46:36 +08:00
dap
acd305bd9d chore: 导入成功需要reload 2024-11-15 09:17:06 +08:00
vben
788a29a8cb chore: release v5.4.7 2024-11-14 22:15:46 +08:00
zyy
3bd5ef4523 fix(@vben/common-ui): pagination current page error (#4893) 2024-11-14 22:11:32 +08:00
dap
9e8e92a8e0 chore: v1.1.1 2024-11-14 15:10:28 +08:00
dap
979bf1b431 chore: 更改文件名 2024-11-14 15:09:09 +08:00
dap
1e74e7c0fb chore: 替换为commonDownloadExcel 2024-11-14 15:04:58 +08:00
dap
240573e354 chore: 替换为commonDownloadExcel 2024-11-14 14:58:42 +08:00
dap
36c6a65d22 fix: 表格的表单搜索无法在modal/drawer中使用 https://gitee.com/dapppp/ruoyi-plus-vben5/issues/IB0960 2024-11-14 14:51:29 +08:00
dap
a814bed79e Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin 2024-11-14 07:58:37 +08:00
Vben
86e52ce58a fix: resolve onChange issue in form component (#4890) 2024-11-13 22:53:09 +08:00
Vben
9ddaba5333 fix: correct grid styling issue (#4889) 2024-11-13 22:28:30 +08:00
Vben
5b079471b9 fix: resolve issue with grid reload parameter not working (#4888) 2024-11-13 22:27:50 +08:00
Arthur Darkstone
8cc73cf59c feat: add reize components & demo (#4862)
* feat: resize component

* chore: change positon of resize components

* feat: add resize demo

* chore: resize demo completed

* chore: fix display number

* chore: add infer comment

* fix: move reszie demo to examples

* fix: fix icon & removed scss
2024-11-13 15:43:17 +08:00
dap
fc28f4ec7e refactor: 重构下载excel及区间选择器字段逻辑处理 2024-11-13 10:45:58 +08:00
dap
995e9d6fdc Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin 2024-11-12 15:29:27 +08:00
vince
a89711610d chore: update eslint configuration (#4872) 2024-11-12 13:42:32 +08:00
vince
67c2b13713 fix: drawer console warning (#4871) 2024-11-12 13:34:47 +08:00
Netfan
1ff1e4a8d7 fix: form enter event handling, fixed #4865 (#4867) 2024-11-12 13:20:48 +08:00
Arthur Darkstone
ea8af98324 docs: add route config desc (#4857) 2024-11-11 19:22:39 +08:00
dap
43a0ce6d76 chore: 冗余代码优化 2024-11-11 17:45:17 +08:00
dap
3ba0e169b2 chore: 去除右上角操作列 2024-11-11 15:06:36 +08:00
Arthur Darkstone
dc15accd04 fix: clipboard demo not working with a-input (#4856) 2024-11-11 14:50:30 +08:00
dap
12d53db740 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin 2024-11-11 14:09:47 +08:00
dap
10b6fd26dc chore: 代码生成样式 2024-11-11 09:12:10 +08:00
dap
06e56338d8 chore: oauth table height 2024-11-11 08:51:48 +08:00
dap
16622e62de Merge branch 'main' of https://gitee.com/dapppp/ruoyi-plus-vben5 2024-11-10 12:54:32 +08:00
dap
75779da35c chore: 表格样式 2024-11-10 12:54:04 +08:00
vben
94efcec7da chore: release v5.4.6 2024-11-10 11:50:46 +08:00
Vben
a3d0d2ed34 feat: added file download examples (#4853) 2024-11-10 11:50:06 +08:00
dap
45024f5dcb chore: 表格样式 2024-11-10 10:58:31 +08:00
Vben
90dc00b168 fix: unable to preventDefault inside passive event listener invocation (#4852) 2024-11-10 10:26:35 +08:00
Vben
ba36ce8836 feat: pinInput supports disabled props (#4851)
* feat: pinInput supports disabled props
2024-11-10 10:09:06 +08:00
dap
db5c1487cb Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin 2024-11-09 21:51:34 +08:00
vben
57d5a919d2 chore: release v5.4.5 2024-11-09 21:06:10 +08:00
Vben
546c0928fb fix: form data that is not submitted by the form should not be carried when switching paging (#4847) 2024-11-09 21:04:58 +08:00
dap
4c487fe85f Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin 2024-11-09 20:10:36 +08:00
Vben
5e44aa9283 fix: drawer header is missing (#4846) 2024-11-09 20:00:09 +08:00
dap
c6b3ca9815 chore: 默认显示Drawer的title 2024-11-09 19:38:45 +08:00
dap
d69618e491 Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin 2024-11-09 16:45:50 +08:00
Vben
26bec4222f fix: pages cannot be quickly moved back by hand gestures (#4845) 2024-11-09 16:32:55 +08:00
Vben
4005023fd4 fix: drawer component header does not take effect (#4844) 2024-11-09 15:53:17 +08:00
Vben
8617d3dd1e perf: formApi added validateAndSubmitForm & filedMapToTime renamed fieldMappingTime (#4842)
* perf: formApi added validateAndSubmitForm & filedMapToTime renamed fieldMappingTime
2024-11-09 15:00:59 +08:00
huangxiaomin
632081e828 feat: add icon-picker component (#4832)
* feat: add icon-picker component

* fix: resolve conversations

* refactor: resort @vben/hooks
2024-11-09 14:10:17 +08:00
huangxiaomin
6b9acf09dc feat: add fieldMapToTime prop to FormRenderProps (#4838) 2024-11-09 14:08:46 +08:00
Vben
2c6edafeb2 fix: when opening the tool separately, there is no need to pass the toolbar-tools slot (#4841) 2024-11-09 14:07:41 +08:00
Vben
9cf0573921 perf: optimize local startup speed and add header Class configuration to drawer (#4840) 2024-11-09 11:12:30 +08:00
Xiaoyu
da7d61b160 feat: add click-to-click event support to the WorkenchProject and WorkenchQuickNav components (#4831)
* feat(@vben/common-ui): add click event emission to WorkbenchProject and WorkbenchQuickNav components

* feat: add navigation and project link functionality to dashboard workspace

* feat: add URL property to WorkbenchProjectItem and WorkbenchQuickNavItem for enhanced navigation

---------

Co-authored-by: XiaoyuDing <xiaoyuding@keymedbio.com>
2024-11-09 10:26:58 +08:00
dap
f11523953f refactor: 使用VxeTable重构OAuth账号绑定列表(替代antdv的Table) 2024-11-08 20:52:23 +08:00
908 changed files with 23714 additions and 9894 deletions

View File

@@ -20,6 +20,12 @@ body:
options:
- label: 未点赞(star)问题直接删除, 不予理会
required: true
- type: checkboxes
attributes:
label: 基础框架问题(如布局,modal,drawer等)请提交给vben官方
options:
- label: 我确认是业务问题而非基础框架问题
required: true
- type: textarea
attributes:
label: 如何复现

18
.github/CODEOWNERS vendored
View File

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

View File

@@ -62,7 +62,7 @@ body:
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://anncwb.github.io/vue-vben-admin-doc/)
- 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

View File

@@ -62,7 +62,7 @@ body:
label: Validations
description: Before submitting the issue, please make sure you do the following
options:
- label: Read the [docs](https://anncwb.github.io/vue-vben-admin-doc/)
- 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

View File

@@ -153,3 +153,20 @@ jobs:
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 }}

19
.github/workflows/rerun.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
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,4 +1,10 @@
export default {
'*.md': ['prettier --cache --ignore-unknown --write'],
'*.vue': [
'prettier --write',
'eslint --cache --fix',
'stylelint --fix --allow-empty-input',
],
'*.{js,jsx,ts,tsx}': [
'prettier --cache --ignore-unknown --write',
'eslint --cache --fix',
@@ -7,14 +13,8 @@ export default {
'prettier --cache --ignore-unknown --write',
'stylelint --fix --allow-empty-input',
],
'*.md': ['prettier --cache --ignore-unknown --write'],
'*.vue': [
'prettier --write',
'eslint --cache --fix',
'stylelint --fix --allow-empty-input',
],
'package.json': ['prettier --cache --write'],
'{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': [
'prettier --cache --write--parser json',
],
'package.json': ['prettier --cache --write'],
};

8
.vscode/launch.json vendored
View File

@@ -9,7 +9,7 @@
"url": "http://localhost:5555",
"env": { "NODE_ENV": "development" },
"sourceMaps": true,
"webRoot": "${workspaceFolder}"
"webRoot": "${workspaceFolder}/playground"
},
{
"type": "chrome",
@@ -18,7 +18,7 @@
"url": "http://localhost:5666",
"env": { "NODE_ENV": "development" },
"sourceMaps": true,
"webRoot": "${workspaceFolder}"
"webRoot": "${workspaceFolder}/apps/web-antd"
},
{
"type": "chrome",
@@ -27,7 +27,7 @@
"url": "http://localhost:5777",
"env": { "NODE_ENV": "development" },
"sourceMaps": true,
"webRoot": "${workspaceFolder}"
"webRoot": "${workspaceFolder}/apps/web-ele"
},
{
"type": "chrome",
@@ -36,7 +36,7 @@
"url": "http://localhost:5888",
"env": { "NODE_ENV": "development" },
"sourceMaps": true,
"webRoot": "${workspaceFolder}"
"webRoot": "${workspaceFolder}/apps/web-naive"
}
]
}

View File

@@ -99,7 +99,8 @@
"**/.stylelintcache": true,
"**/.DS_Store": true,
"**/vite.config.mts.*": true,
"**/tea.yaml": true
"**/tea.yaml": true,
"**/public/tinymce/**": true
},
"files.watcherExclude": {
"**/.git/objects/**": true,
@@ -227,5 +228,6 @@
"typescript.tsdk": "node_modules/typescript/lib",
"editor.linkedEditing": true, // 自动同步更改html标签,
"vscodeCustomCodeColor.highlightValue": "v-access", // v-access显示的颜色
"vscodeCustomCodeColor.highlightValueColor": "#CCFFFF"
"vscodeCustomCodeColor.highlightValueColor": "#CCFFFF",
"oxc.enable": false
}

View File

@@ -1,3 +1,105 @@
# 1.2.2
**FEATURES**
- 代码生成支持路径方式生成
- 代码生成 支持选择表单生成类型(需要模板支持)
- 工作流 支持按钮权限
# 1.2.1
# BUG FIXES
- 客户端管理 错误的status disabled
- modal/drawer升级后zIndex(2000)会遮挡Tinymce的下拉框zIndex(1300)
# 1.2.0
**REFACTOR**
- 菜单选择组件重构为Table形式
- 字典相关功能重构 采用一个Map储存字典(之前为两个Map)
- 代码生成配置页面重构 去除步骤条
**Features**
- 对接后端工作流
- ~~通用的vxe-table排序事件(排序逻辑改为在排序事件中处理而非在api处理)~~
- getDict/getDictOptions 提取公共逻辑 减少冗余代码
- 字典新增对Number类型的支持 -> `getDictOptions('', true);`即可获取number类型的value
- 文件上传 增加上传进度条 下方上传提示
- 图片上传 增加上传进度条 下方上传提示
- oss下载进度提示
**BUG FIXES**
- 字典项为空时getDict方法无限调用接口(无奈兼容 不给字典item本来就是错误用法)
- 表格排序翻页会丢失排序参数
- 下载文件时(responseType === 'blob')需要判断下载失败(返回json而非二进制)的情况
- requestClient缺失i18n内容
**OTHERS**
- 用户管理 新增只获取一次(mounted)默认密码而非每次打开modal都获取
- `apps/web-antd/src/utils/dict.ts` `getDict`方法将于下个版本删除 使用`getDictOptions`替代
- VxeTable升级V4.10.0
- 移除`@deprecated` `apps/web-antd/src/adapter/vxe-table.ts``tableCheckboxEvent`方法
- 移除`由于更新方案弃用的` `apps/web-antd/src/adapter/vxe-table.ts``vxeSortEvent`方法
- 移除apps下的ele和naive目录
# 1.1.3
**REFACTOR**
- 重构: 判断vxe-table的复选框是否选中
**Bug Fixes**
- 节点树在编辑 & 空数组(不勾选)情况 勾选节点会造成watch延迟触发 导致会带上父节点id造成id重复
- 节点树在节点独立情况下的控制台warning: Invalid prop: type check failed for prop "value". Expected Array, got Object
**Others**
- 角色管理 优化Drawer布局
- unplugin-vue-components插件(默认未开启) 需要排除Button组件 全局已经默认导入了
**BUG FIXES**
- 操作日志详情 在description组件中json预览样式异常
- 微服务版本 区间查询和中文搜索条件一起使用 无法正确查询
# 1.1.2
**Features**
- Options转Enum工具函数
**OTHERS**
- 菜单管理 改为虚拟滚动
- 移除requestClient的一些冗余参数
- 主动退出登录(右上角个人选项)不需要带跳转地址
**BUG FIXES**
- 语言 漏加Content-Language请求头
- 用户管理/岗位管理 左边部门树错误emit导致会调用两次列表api
# 1.1.1
**REFACTOR**
- 使用VxeTable重构OAuth账号绑定列表(替代antdv的Table)
- commonDownloadExcel方法 支持处理区间选择器字段导出excel
**BUG FIXES**
- 修复在Modal/Drawer中使用VxeTable时, 第二次打开表单参数依旧为第一次提交的参数
**OTHERS**
- 废弃downloadExcel方法 统一使用commonDownloadExcel方法
# 1.1.0
**FEATURES**

View File

@@ -2,21 +2,21 @@
## 提示
该仓库使用vben最新版本v5开发, ~~老版本v2地址(不维护)~~ [前往](https://gitee.com/dapppp/ruoyi-plus-vben)
该仓库使用vben最新版本v5开发
v5版本采用分仓(包)目录结构, 具体开发路径为: `根目录/apps/web-antd`
目前对应后端版本: **5.2.3/2.2.3**
目前对应后端版本: **分布式5.3.0/微服务2.2.2**
V1.1.0版本已支持离线图标
## 进度
V1.2.0版本对接warmflow工作流
**工作流相关模块等待后端重构后开发**
`微服务最新版暂不支持warmflow工作流`
基础功能已经开发完毕
`微服务最新版暂不支持warmflow工作流`
👉 [更新日志](https://gitee.com/dapppp/ruoyi-plus-vben5/blob/main/CHANGELOG.md)
`微服务最新版暂不支持warmflow工作流`
## 简介
@@ -24,9 +24,9 @@ V1.1.0版本已支持离线图标
| 组件/框架 | 版本 |
| :------------- | :----- |
| vben | 5.4.1 |
| ant-design-vue | 4.2.5 |
| vue | 3.5.11 |
| vben | 5.5.3 |
| ant-design-vue | 4.2.6 |
| vue | 3.5.13 |
对应后端项目: **(分布式 5.X 分支 微服务 2.分支)**
@@ -52,9 +52,17 @@ admin 账号: admin admin123
[RuoYi-Plus 文档地址](https://plus-doc.dromara.org/#/)
## 关于表单
如果你觉得`useVbenForm`难度很大, 完全可以**使用原生antd表单**进行开发, 不一定非得用`useVbenForm`进行开发
`apps/web-antd/src/views/system/notice/notice-modal.vue``通知公告modal`使用**原生antd form**进行(反向🤔)重构, 不想用`useVbenForm`可参考该页面进行表单开发
复杂表单(如各种联动, 需要自定义样式布局, 需要自定义组件)**优先使用原生表单**(反正说了也没人听听😅)
## 预览图
![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/1.png) ![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/2.png) ![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/3.png) ![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/4.png) ![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/5.png) ![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/6.png) ![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/7.png) ![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/8.png) ![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/9.png) ![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/10.png)
![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/1.png) ![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/2.png) ![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/3.png) ![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/4.png) ![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/5.png) ![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/6.png) ![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/7.png) ![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/8.png) ![图片](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/9.png)
## 安装使用
@@ -189,9 +197,3 @@ pnpm build:antd
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
| :-: | :-: | :-: | :-: | :-: |
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## 捐赠
如果项目帮助到您 可以考虑请作者喝杯咖啡 万分感谢您对开源的支持!
<img src=https://plus.dapdap.top/minio-server/plus/2024/03/16/98a9d704eb0c4c04b721bf7799217571.jpg height=360px />

View File

@@ -0,0 +1,15 @@
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

@@ -0,0 +1,15 @@
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

@@ -0,0 +1,15 @@
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

@@ -0,0 +1,61 @@
import { faker } from '@faker-js/faker';
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

@@ -0,0 +1,12 @@
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

@@ -0,0 +1,28 @@
import { verifyAccessToken } from '~/utils/jwt-utils';
import { MOCK_MENU_LIST } from '~/utils/mock-data';
import { unAuthorizedResponse } 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

@@ -0,0 +1,28 @@
import { verifyAccessToken } from '~/utils/jwt-utils';
import { MOCK_MENU_LIST } from '~/utils/mock-data';
import { unAuthorizedResponse } 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

@@ -0,0 +1,83 @@
import { faker } from '@faker-js/faker';
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,6 +1,6 @@
import { faker } from '@faker-js/faker';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse } from '~/utils/response';
import { unAuthorizedResponse, usePageResponseSuccess } from '~/utils/response';
function generateMockDataList(count: number) {
const dataList = [];
@@ -43,6 +43,31 @@ export default eventHandler(async (event) => {
await sleep(600);
const { page, pageSize } = getQuery(event);
return usePageResponseSuccess(page as string, pageSize as string, mockData);
const { page, pageSize, sortBy, sortOrder } = getQuery(event);
const listData = structuredClone(mockData);
if (sortBy && Reflect.has(listData[0], sortBy as string)) {
listData.sort((a, b) => {
if (sortOrder === 'asc') {
if (sortBy === 'price') {
return (
Number.parseFloat(a[sortBy as string]) -
Number.parseFloat(b[sortBy as string])
);
} else {
return a[sortBy as string] > b[sortBy as string] ? 1 : -1;
}
} else {
if (sortBy === 'price') {
return (
Number.parseFloat(b[sortBy as string]) -
Number.parseFloat(a[sortBy as string])
);
} else {
return a[sortBy as string] < b[sortBy as string] ? 1 : -1;
}
}
});
}
return usePageResponseSuccess(page as string, pageSize as string, listData);
});

View File

@@ -1,7 +1,19 @@
export default defineEventHandler((event) => {
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

@@ -9,7 +9,8 @@ export default defineNitroConfig({
cors: true,
headers: {
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Headers': '*',
'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

@@ -14,7 +14,7 @@ export function setRefreshTokenCookie(
) {
setCookie(event, 'jwt', refreshToken, {
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000,
maxAge: 24 * 60 * 60, // unit: seconds
sameSite: 'none',
secure: true,
});

View File

@@ -4,6 +4,7 @@ export interface UserInfo {
realName: string;
roles: string[];
username: string;
homePath?: string;
}
export const MOCK_USERS: UserInfo[] = [
@@ -20,6 +21,7 @@ export const MOCK_USERS: UserInfo[] = [
realName: 'Admin',
roles: ['admin'],
username: 'admin',
homePath: '/workspace',
},
{
id: 2,
@@ -27,6 +29,7 @@ export const MOCK_USERS: UserInfo[] = [
realName: 'Jack',
roles: ['user'],
username: 'jack',
homePath: '/analytics',
},
];
@@ -50,13 +53,12 @@ export const MOCK_CODES = [
const dashboardMenus = [
{
component: 'BasicLayout',
meta: {
order: -1,
title: 'page.dashboard.title',
},
name: 'Dashboard',
path: '/',
path: '/dashboard',
redirect: '/analytics',
children: [
{
@@ -113,7 +115,6 @@ const createDemosMenus = (role: 'admin' | 'super' | 'user') => {
return [
{
component: 'BasicLayout',
meta: {
icon: 'ic:baseline-view-in-ar',
keepAlive: true,
@@ -184,3 +185,206 @@ export const MOCK_MENUS = [
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: 201,
name: 'SystemDeptCreate',
status: 1,
type: 'button',
authCode: 'System:Dept:Create',
meta: { title: 'common.create' },
},
{
id: 20_402,
pid: 201,
name: 'SystemDeptEdit',
status: 1,
type: 'button',
authCode: 'System:Dept:Edit',
meta: { title: 'common.edit' },
},
{
id: 20_403,
pid: 201,
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;
}

View File

@@ -21,5 +21,5 @@ VITE_GLOB_RSA_PRIVATE_KEY=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuP
# 客户端id
VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
# 开启WEBSOCKET
VITE_GLOB_WEBSOCKET_ENABLE=false
# 开启SSE
VITE_GLOB_SSE_ENABLE=true

View File

@@ -27,6 +27,6 @@ VITE_GLOB_RSA_PRIVATE_KEY=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuP
# 客户端id
VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
# 开启WEBSOCKET
VITE_GLOB_WEBSOCKET_ENABLE=false
# 开启SSE
VITE_GLOB_SSE_ENABLE=true

View File

@@ -1,9 +0,0 @@
{
"editor.tabSize": 2,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.fixAll.stylelint": "explicit"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/web-antd",
"version": "1.1.0",
"version": "1.2.2",
"homepage": "https://vben.pro",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -3,12 +3,14 @@
* 可用于 vben-form、vben-modal、vben-drawer 等组件使用,
*/
import type { Component } from 'vue';
import type { BaseFormComponentType } from '@vben/common-ui';
import type { Recordable } from '@vben/types';
import type { Component, SetupContext } from 'vue';
import { h } from 'vue';
import { defineComponent, getCurrentInstance, h, ref } from 'vue';
import { globalShareState } from '@vben/common-ui';
import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';
import { $t } from '@vben/locales';
import {
@@ -43,14 +45,36 @@ const withDefaultPlaceholder = <T extends Component>(
component: T,
type: 'input' | 'select',
) => {
return (props: any, { attrs, slots }: Omit<SetupContext, 'expose'>) => {
const placeholder = props?.placeholder || $t(`ui.placeholder.${type}`);
return h(component, { ...props, ...attrs, placeholder }, slots);
};
return defineComponent({
inheritAttrs: false,
name: component.name,
setup: (props: any, { attrs, expose, slots }) => {
const placeholder =
props?.placeholder ||
attrs?.placeholder ||
$t(`ui.placeholder.${type}`);
// 透传组件暴露的方法
const innerRef = ref();
const publicApi: Recordable<any> = {};
expose(publicApi);
const instance = getCurrentInstance();
instance?.proxy?.$nextTick(() => {
for (const key in innerRef.value) {
if (typeof innerRef.value[key] === 'function') {
publicApi[key] = innerRef.value[key];
}
}
});
return () =>
h(component, { ...props, ...attrs, placeholder, ref: innerRef }, slots);
},
});
};
// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
export type ComponentType =
| 'ApiSelect'
| 'ApiTreeSelect'
| 'AutoComplete'
| 'Checkbox'
| 'CheckboxGroup'
@@ -58,6 +82,7 @@ export type ComponentType =
| 'DefaultButton'
| 'Divider'
| 'FileUpload'
| 'IconPicker'
| 'ImageUpload'
| 'Input'
| 'InputNumber'
@@ -83,7 +108,38 @@ async function initComponentAdapter() {
// 如果你的组件体积比较大,可以使用异步加载
// Button: () =>
// import('xxx').then((res) => res.Button),
ApiSelect: (props, { attrs, slots }) => {
return h(
ApiComponent,
{
placeholder: $t('ui.placeholder.select'),
...props,
...attrs,
component: Select,
loadingSlot: 'suffixIcon',
visibleEvent: 'onDropdownVisibleChange',
modelPropName: 'value',
},
slots,
);
},
ApiTreeSelect: (props, { attrs, slots }) => {
return h(
ApiComponent,
{
placeholder: $t('ui.placeholder.select'),
...props,
...attrs,
component: TreeSelect,
fieldNames: { label: 'label', value: 'value', children: 'children' },
loadingSlot: 'suffixIcon',
modelPropName: 'value',
optionsPropName: 'treeData',
visibleEvent: 'onVisibleChange',
},
slots,
);
},
AutoComplete,
Checkbox,
CheckboxGroup,
@@ -93,6 +149,19 @@ async function initComponentAdapter() {
return h(Button, { ...props, attrs, type: 'default' }, slots);
},
Divider,
IconPicker: (props, { attrs, slots }) => {
return h(
IconPicker,
{
iconSlot: 'addonAfter',
inputComponent: Input,
modelValueProp: 'value',
...props,
...attrs,
},
slots,
);
},
Input: withDefaultPlaceholder(Input, 'input'),
InputNumber: withDefaultPlaceholder(InputNumber, 'input'),
InputPassword: withDefaultPlaceholder(InputPassword, 'input'),

View File

@@ -1,10 +1,8 @@
import { h, type Ref } from 'vue';
import type { VxeGridPropTypes } from '@vben/plugins/vxe-table';
import {
setupVbenVxeTable,
useVbenVxeGrid,
type VxeGridDefines,
} from '@vben/plugins/vxe-table';
import { h } from 'vue';
import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table';
import { Button, Image } from 'ant-design-vue';
@@ -43,7 +41,7 @@ setupVbenVxeTable({
// 鼠标移入行显示 hover 样式
isHover: true,
// 点击行高亮
isCurrent: true,
isCurrent: false,
},
columnConfig: {
// 可拖拽列宽
@@ -106,15 +104,32 @@ export { useVbenVxeGrid };
export type * from '@vben/plugins/vxe-table';
/**
* 通用的表格复选框是否选中事件
* @param checked 是否选中
* @returns function
* 判断vxe-table的复选框是否选中
* @param tableApi api
* @returns boolean
*/
export function tableCheckboxEvent(checked: Ref<boolean>) {
const event: (params: VxeGridDefines.CheckboxChangeEventParams) => void = (
params,
) => {
checked.value = params.$table.getCheckboxRecords().length > 0;
};
return event;
export function vxeCheckboxChecked(
tableApi: ReturnType<typeof useVbenVxeGrid>[1],
) {
return tableApi?.grid?.getCheckboxRecords?.()?.length > 0;
}
/**
* 通用的 排序参数添加到请求参数中
* @param params 请求参数
* @param sortList vxe-table的排序参数
*/
export function addSortParams(
params: Record<string, any>,
sortList: VxeGridPropTypes.ProxyAjaxQuerySortCheckedParams[],
) {
// 这里是排序取消 length为0 就不添加参数了
if (sortList.length === 0) {
return;
}
// 支持单/多字段排序
const orderByColumn = sortList.map((item) => item.field).join(',');
const isAsc = sortList.map((item) => item.order).join(',');
params.orderByColumn = orderByColumn;
params.isAsc = isAsc;
}

View File

@@ -21,14 +21,22 @@ export interface PageResult<T = any> {
/**
* 分页查询参数
*
* 排序支持的用法如下:
* {isAsc:"asc",orderByColumn:"id"} order by id asc
* {isAsc:"asc",orderByColumn:"id,createTime"} order by id asc,create_time asc
* {isAsc:"desc",orderByColumn:"id,createTime"} order by id desc,create_time desc
* {isAsc:"asc,desc",orderByColumn:"id,createTime"} order by id asc,create_time desc
*
* @param pageNum 当前页
* @param pageSize 每页大小
* @param orderByColumn 排序字段
* @param isAsc 是否升序
*/
export interface PageQuery {
isAsc?: boolean;
isAsc?: string;
orderByColumn?: string;
pageNum?: number;
pageSize?: number;
[key: string]: any;
}

View File

@@ -4,7 +4,10 @@ import { useAppConfig } from '@vben/hooks';
import { requestClient } from '#/api/request';
const { clientId } = useAppConfig(import.meta.env, import.meta.env.PROD);
const { clientId, sseEnable } = useAppConfig(
import.meta.env,
import.meta.env.PROD,
);
export namespace AuthApi {
/**
@@ -96,6 +99,12 @@ export function doLogout() {
* @returns void
*/
export function seeConnectionClose() {
/**
* 未开启sse 不需要处理
*/
if (!sseEnable) {
return;
}
return requestClient.get<void>('/resource/sse/close');
}

View File

@@ -19,7 +19,7 @@ export interface MenuMeta {
* @param name 菜单名
* @param path 菜单路径
* @param hidden 是否隐藏
* @param component 组件名称 Laout
* @param component 组件名称 Layout
* @param alwaysShow 总是显示
* @param query 路由参数(json形式)
* @param meta 路由信息

View File

@@ -1,12 +1,27 @@
import type { AxiosRequestConfig } from '@vben/request';
import { requestClient } from '#/api/request';
/**
* Axios上传进度事件
*/
export type AxiosProgressEvent = AxiosRequestConfig['onUploadProgress'];
/**
* 通过单文件上传接口
* @param file 上传的文件
* @param onUploadProgress 上传进度事件 非必传
* @returns 上传结果
*/
export function uploadApi(file: Blob | File) {
return requestClient.upload('/resource/oss/upload', { file });
export function uploadApi(
file: Blob | File,
onUploadProgress?: AxiosProgressEvent,
) {
return requestClient.upload(
'/resource/oss/upload',
{ file },
{ onUploadProgress, timeout: 60_000 },
);
}
/**
* 默认上传结果

View File

@@ -1,75 +1,5 @@
import { isObject, isString } from '@vben/utils';
import { requestClient } from './request';
const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss';
export function joinTimestamp<T extends boolean>(
join: boolean,
restful: T,
): T extends true ? string : object;
export function joinTimestamp(join: boolean, restful = false): object | string {
if (!join) {
return restful ? '' : {};
}
const now = Date.now();
if (restful) {
return `?_t=${now}`;
}
return { _t: now };
}
/**
* @description: Format request parameter time
*/
export function formatRequestDate(params: Record<string, any>) {
if (Object.prototype.toString.call(params) !== '[object Object]') {
return;
}
for (const key in params) {
const format = params[key]?.format ?? null;
if (format && typeof format === 'function') {
params[key] = params[key].format(DATE_TIME_FORMAT);
}
if (isString(key)) {
const value = params[key];
if (value) {
try {
params[key] = isString(value) ? value.trim() : value;
} catch (error: any) {
throw new Error(error);
}
}
}
if (isObject(params[key])) {
formatRequestDate(params[key]);
}
}
}
/**
* Add the object as a parameter to the URL
* @param baseUrl url
* @param obj
* @returns {string}
* eg:
* let obj = {a: '3', b: '4'}
* setObjToUrlParams('www.baidu.com', obj)
* ==>www.baidu.com?a=3&b=4
*/
export function setObjToUrlParams(baseUrl: string, obj: any): string {
let parameters = '';
for (const key in obj) {
parameters += `${key}=${encodeURIComponent(obj[key])}&`;
}
parameters = parameters.replace(/&$/, '');
return /\?$/.test(baseUrl)
? baseUrl + parameters
: baseUrl.replace(/\/?$/, '?') + parameters;
}
/**
* @description: contentType
*/

View File

@@ -17,6 +17,11 @@ export function onlineDeviceList() {
return requestClient.get<PageResult<OnlineUser>>(Api.root);
}
/**
* 这里的分页参数无效 返回的是全部的分页
* @param params 请求参数
* @returns 结果
*/
export function onlineList(params?: PageQuery) {
return requestClient.get<PageResult<OnlineUser>>(Api.onlineList, { params });
}
@@ -36,5 +41,5 @@ export function forceLogout(tokenId: string) {
* @returns void
*/
export function forceLogout2(tokenId: string) {
return requestClient.postWithMsg<void>(`${Api.root}/${tokenId}`);
return requestClient.deleteWithMsg<void>(`${Api.root}/myself/${tokenId}`);
}

View File

@@ -12,20 +12,36 @@ enum Api {
root = '/monitor/operlog',
}
/**
* 操作日志分页
* @param params 查询参数
* @returns 分页结果
*/
export function operLogList(params?: PageQuery) {
return requestClient.get<PageResult<OperationLog>>(Api.operLogList, {
params,
});
}
/**
* 删除操作日志
* @param operIds id/ids
*/
export function operLogDelete(operIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${operIds}`);
}
/**
* 清空全部分页日志
*/
export function operLogClean() {
return requestClient.deleteWithMsg<void>(Api.operLogClean);
}
export function operLogExport(data: any) {
/**
* 导出操作日志
* @param data 查询参数
*/
export function operLogExport(data: Partial<OperationLog>) {
return commonExport(Api.operLogExport, data);
}

View File

@@ -1,6 +1,7 @@
/**
* 该文件可自行根据业务逻辑进行调整
*/
import type { HttpResponse } from '@vben/request';
import { useAppConfig } from '@vben/hooks';
@@ -10,9 +11,9 @@ import {
authenticateResponseInterceptor,
errorMessageResponseInterceptor,
RequestClient,
stringify,
} from '@vben/request';
import { useAccessStore } from '@vben/stores';
import { isString } from '@vben/utils';
import { message, Modal } from 'ant-design-vue';
import { isEmpty, isNull } from 'lodash-es';
@@ -27,8 +28,6 @@ import {
} from '#/utils/encryption/crypto';
import * as encryptUtil from '#/utils/encryption/jsencrypt';
import { formatRequestDate, joinTimestamp, setObjToUrlParams } from './helper';
const { apiURL, clientId, enableEncrypt } = useAppConfig(
import.meta.env,
import.meta.env.PROD,
@@ -46,16 +45,10 @@ function createRequestClient(baseURL: string) {
baseURL,
// 消息提示类型
errorMessageMode: 'message',
// 格式化提交参数时间
formatDate: true,
// 是否返回原生响应 比如:需要获取响应头时使用该属性
isReturnNativeResponse: false,
// 需要对返回数据进行处理
isTransformResponse: true,
// post请求的时候添加参数到url
joinParamsToUrl: false,
// 是否加入时间戳
joinTime: false,
});
/**
@@ -99,54 +92,28 @@ function createRequestClient(baseURL: string) {
*/
const language = preferences.app.locale.replace('-', '_');
config.headers['Accept-Language'] = language;
config.headers['Content-Language'] = language;
// 添加全局clientId
config.headers.clientId = clientId;
const { encrypt, formatDate, joinParamsToUrl, joinTime = true } = config;
const params = config.params || {};
const data = config.data || false;
// TODO: 这块要重构 复杂度太高了
formatDate && data && !isString(data) && formatRequestDate(data);
if (config.method?.toUpperCase() === 'GET') {
if (isString(params)) {
// 兼容restful风格
config.url = `${config.url + params}${joinTimestamp(joinTime, true)}`;
config.params = undefined;
} else {
// 给 get 请求加上时间戳参数,避免从缓存中拿数据。
config.params = Object.assign(
params || {},
joinTimestamp(joinTime, false),
);
}
} else {
if (isString(params)) {
// 兼容restful风格
config.url = config.url + params;
config.params = undefined;
} else {
formatDate && formatRequestDate(params);
if (
Reflect.has(config, 'data') &&
config.data &&
(Object.keys(config.data).length > 0 ||
config.data instanceof FormData)
) {
config.data = data;
config.params = params;
} else {
// 非GET请求如果没有提供data则将params视为data
config.data = params;
config.params = undefined;
}
if (joinParamsToUrl) {
config.url = setObjToUrlParams(
config.url as string,
Object.assign({}, config.params, config.data),
);
}
}
/**
* 格式化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 &&
@@ -168,14 +135,14 @@ function createRequestClient(baseURL: string) {
});
// 通用的错误处理, 如果没有进入上面的错误处理逻辑,就会进入这里
// 主要处理http状态码不为200的情况 必须放在在下面的响应拦截器之前
// 主要处理http状态码不为200(如网络异常/离线)的情况 必须放在在下面的响应拦截器之前
client.addResponseInterceptor(
errorMessageResponseInterceptor((msg: string) => message.error(msg)),
);
client.addResponseInterceptor<HttpResponse>({
fulfilled: (response) => {
const encryptKey = (response.headers || {})['encrypt-key'];
fulfilled: async (response) => {
const encryptKey = (response.headers ?? {})['encrypt-key'];
if (encryptKey) {
/** RSA私钥解密 拿到解密秘钥的base64 */
const base64Str = encryptUtil.decrypt(encryptKey);
@@ -198,39 +165,57 @@ function createRequestClient(baseURL: string) {
// 不进行任何处理,直接返回
// 用于页面代码可能需要直接获取codedatamessage这些信息时开启
if (!isTransformResponse) {
return response.data;
/**
* 需要判断下载二进制的情况 正常是返回二进制 报错会返回json
* 当type为blob且content-type为application/json时 则判断已经下载出错
*/
if (
response.config.responseType === 'blob' &&
response.headers['content-type']?.includes?.('application/json')
) {
// 这时候的data为blob类型
const blob = response.data as unknown as Blob;
// 拿到字符串转json对象
response.data = JSON.parse(await blob.text());
// 然后按正常逻辑执行下面的代码(判断业务状态码)
} else {
// 其他情况 直接返回
return response.data;
}
}
const axiosResponseData = response.data;
if (!axiosResponseData) {
throw new Error($t('fallback.http.apiRequestFailed'));
throw new Error($t('http.apiRequestFailed'));
}
// ruoyi-plus没有采用严格的{code, msg, data}模式
// 后端并没有采用严格的{code, msg, data}模式
const { code, data, msg, ...other } = axiosResponseData;
// 这里逻辑可以根据项目进行修改
// 业务状态码为200则请求成功
const hasSuccess = Reflect.has(axiosResponseData, 'code') && code === 200;
if (hasSuccess) {
let successMsg = msg;
if (isNull(successMsg) || isEmpty(successMsg)) {
successMsg = $t(`fallback.http.operationSuccess`);
successMsg = $t(`http.operationSuccess`);
}
if (response.config.successMessageMode === 'modal') {
Modal.success({
content: successMsg,
title: $t('fallback.http.successTip'),
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的情况(比如查询为空)
// 需要考虑data为null的情况(比如查询为空) 所以这里直接判断undefined
if (data !== undefined) {
return data;
}
// 没有data 将其他参数包装为data
return other;
}
// 在此处根据自己项目的实际情况对不同的code执行不同的操作
@@ -243,7 +228,7 @@ function createRequestClient(baseURL: string) {
return;
}
isLogoutProcessing = true;
const _msg = '登录超时, 请重新登录';
const _msg = $t('http.loginTimeout');
const userStore = useAuthStore();
userStore.logout().finally(() => {
message.error(_msg);
@@ -264,13 +249,13 @@ function createRequestClient(baseURL: string) {
if (response.config.errorMessageMode === 'modal') {
Modal.error({
content: timeoutMsg,
title: $t('fallback.http.errorTip'),
title: $t('http.errorTip'),
});
} else if (response.config.errorMessageMode === 'message') {
message.error(timeoutMsg);
}
throw new Error(timeoutMsg || $t('fallback.http.apiRequestFailed'));
throw new Error(timeoutMsg || $t('http.apiRequestFailed'));
},
});

View File

@@ -12,30 +12,60 @@ enum Api {
root = '/system/client',
}
/**
* 查询客户端分页列表
* @param params 请求参数
* @returns 列表
*/
export function clientList(params?: PageQuery) {
return requestClient.get<PageResult<Client>>(Api.clientList, { params });
}
export function clientExport(data: any) {
/**
* 导出客户端excel
* @param data 请求参数
*/
export function clientExport(data: Partial<Client>) {
return commonExport(Api.clientExport, data);
}
/**
* 客户端详情
* @param id id
* @returns 详情
*/
export function clientInfo(id: ID) {
return requestClient.get<Client>(`${Api.root}/${id}`);
}
export function clientAdd(data: any) {
/**
* 客户端新增
* @param data 参数
*/
export function clientAdd(data: Partial<Client>) {
return requestClient.postWithMsg<void>(Api.root, data);
}
export function clientUpdate(data: any) {
/**
* 客户端修改
* @param data 参数
*/
export function clientUpdate(data: Partial<Client>) {
return requestClient.putWithMsg<void>(Api.root, data);
}
/**
* 客户端状态修改
* @param data 状态
*/
export function clientChangeStatus(data: any) {
return requestClient.putWithMsg<void>(Api.root, data);
return requestClient.putWithMsg<void>(Api.clientChangeStatus, data);
}
/**
* 客户端删除
* @param ids id集合
*/
export function clientRemove(ids: IDS) {
return requestClient.deleteWithMsg(`${Api.root}/${ids}`);
return requestClient.deleteWithMsg<void>(`${Api.root}/${ids}`);
}

View File

@@ -1,4 +1,4 @@
import type { Config } from './model';
import type { SysConfig } from './model';
import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
@@ -13,15 +13,24 @@ enum Api {
root = '/system/config',
}
/**
* 系统参数分页列表
* @param params 请求参数
* @returns 列表
*/
export function configList(params?: PageQuery) {
return requestClient.get<PageResult<Config>>(Api.configList, { params });
return requestClient.get<PageResult<SysConfig>>(Api.configList, { params });
}
export function configInfo(configId: ID) {
return requestClient.get<Config>(`${Api.root}/${configId}`);
return requestClient.get<SysConfig>(`${Api.root}/${configId}`);
}
export function configExport(data: any) {
/**
* 导出
* @param data 参数
*/
export function configExport(data: Partial<SysConfig>) {
return commonExport(Api.configExport, data);
}
@@ -33,14 +42,26 @@ export function configRefreshCache() {
return requestClient.deleteWithMsg<void>(Api.configRefreshCache);
}
export function configUpdate(data: any) {
/**
* 更新系统配置
* @param data 参数
*/
export function configUpdate(data: Partial<SysConfig>) {
return requestClient.putWithMsg<void>(Api.root, data);
}
export function configAdd(data: any) {
/**
* 新增系统配置
* @param data 参数
*/
export function configAdd(data: Partial<SysConfig>) {
return requestClient.postWithMsg<void>(Api.root, data);
}
/**
* 删除配置
* @param configIds ids
*/
export function configRemove(configIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${configIds}`);
}

View File

@@ -1,4 +1,4 @@
export interface Config {
export interface SysConfig {
configId: number;
configName: string;
configKey: string;

View File

@@ -10,7 +10,11 @@ enum Api {
root = '/system/dept',
}
export function deptList(params?: any) {
/**
* 部门列表
* @returns list
*/
export function deptList(params?: { deptName?: string; status?: string }) {
return requestClient.get<Dept[]>(Api.deptList, { params });
}
@@ -23,15 +27,28 @@ export function deptNodeList(deptId: ID) {
return requestClient.get<Dept[]>(`${Api.deptNodeInfo}/${deptId}`);
}
/**
* 部门详情
* @param deptId 部门id
* @returns 部门信息
*/
export function deptInfo(deptId: ID) {
return requestClient.get<Dept>(`${Api.root}/${deptId}`);
}
export function deptAdd(data: any) {
/**
* 部门新增
* @param data 参数
*/
export function deptAdd(data: Partial<Dept>) {
return requestClient.postWithMsg<void>(Api.root, data);
}
export function deptUpdate(data: any) {
/**
* 部门更新
* @param data 参数
*/
export function deptUpdate(data: Partial<Dept>) {
return requestClient.putWithMsg<void>(Api.root, data);
}

View File

@@ -34,7 +34,7 @@ export function dictDataList(params?: PageQuery) {
* @param data 表单参数
* @returns blob
*/
export function dictDataExport(data: any) {
export function dictDataExport(data: Partial<DictData>) {
return commonExport(Api.dictDataExport, data);
}
@@ -52,7 +52,7 @@ export function dictDataRemove(dictIds: IDS) {
* @param data 表单参数
* @returns void
*/
export function dictDataAdd(data: any) {
export function dictDataAdd(data: Partial<DictData>) {
return requestClient.postWithMsg<void>(Api.root, data);
}
@@ -61,7 +61,7 @@ export function dictDataAdd(data: any) {
* @param data 表单参数
* @returns void
*/
export function dictDataUpdate(data: any) {
export function dictDataUpdate(data: Partial<DictData>) {
return requestClient.putWithMsg<void>(Api.root, data);
}

View File

@@ -27,7 +27,7 @@ export function dictTypeList(params?: PageQuery) {
* @param data 表单参数
* @returns blob
*/
export function dictTypeExport(data: any) {
export function dictTypeExport(data: Partial<DictType>) {
return commonExport(Api.dictTypeExport, data);
}
@@ -53,7 +53,7 @@ export function refreshDictTypeCache() {
* @param data 表单参数
* @returns void
*/
export function dictTypeAdd(data: any) {
export function dictTypeAdd(data: Partial<DictType>) {
return requestClient.postWithMsg<void>(Api.root, data);
}
@@ -62,7 +62,7 @@ export function dictTypeAdd(data: any) {
* @param data 表单参数
* @returns void
*/
export function dictTypeUpdate(data: any) {
export function dictTypeUpdate(data: Partial<DictType>) {
return requestClient.putWithMsg<void>(Api.root, data);
}
@@ -76,6 +76,7 @@ export function dictTypeInfo(dictId: ID) {
}
/**
* 这个在ele用到 v5用不上
* 下拉框 返回值和list一样
* @returns options
*/

View File

@@ -1,4 +1,4 @@
import type { Menu, MenuOption, MenuResp } from './model';
import type { Menu, MenuOption, MenuQuery, MenuResp } from './model';
import type { ID, IDS } from '#/api/common';
@@ -12,22 +12,44 @@ enum Api {
tenantPackageMenuTreeselect = '/system/menu/tenantPackageMenuTreeselect',
}
export function menuList(params?: any) {
/**
* 菜单列表
* @param params 参数
* @returns 列表
*/
export function menuList(params?: MenuQuery) {
return requestClient.get<Menu[]>(Api.menuList, { params });
}
/**
* 菜单详情
* @param menuId 菜单id
* @returns 菜单详情
*/
export function menuInfo(menuId: ID) {
return requestClient.get<Menu>(`${Api.root}/${menuId}`);
}
export function menuAdd(data: any) {
/**
* 菜单新增
* @param data 参数
*/
export function menuAdd(data: Partial<Menu>) {
return requestClient.postWithMsg<void>(Api.root, data);
}
export function menuUpdate(data: any) {
/**
* 菜单更新
* @param data 参数
*/
export function menuUpdate(data: Partial<Menu>) {
return requestClient.putWithMsg<void>(Api.root, data);
}
/**
* 菜单删除
* @param menuIds ids
*/
export function menuRemove(menuIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${menuIds}`);
}

View File

@@ -33,6 +33,8 @@ export interface MenuOption {
weight: number;
children: MenuOption[];
key: string; // 实际上不存在 ide报错
menuType: string;
icon: string;
}
/**
@@ -44,3 +46,12 @@ export interface MenuResp {
checkedKeys: number[];
menus: MenuOption[];
}
/**
* 菜单表单查询
*/
export interface MenuQuery {
menuName?: string;
visible?: string;
status?: string;
}

View File

@@ -9,22 +9,44 @@ enum Api {
root = '/system/notice',
}
/**
* 通知公告分页
* @param params 分页参数
* @returns 分页结果
*/
export function noticeList(params?: PageQuery) {
return requestClient.get<Notice[]>(Api.noticeList, { params });
}
/**
* 通知公告详情
* @param noticeId id
* @returns 详情
*/
export function noticeInfo(noticeId: ID) {
return requestClient.get<Notice>(`${Api.root}/${noticeId}`);
}
export function noticeAdd(data: any) {
/**
* 通知公告新增
* @param data 参数
*/
export function noticeAdd(data: Partial<Notice>) {
return requestClient.postWithMsg<void>(Api.root, data);
}
/**
* 通知公告更新
* @param data 参数
*/
export function noticeUpdate(data: any) {
return requestClient.putWithMsg<void>(Api.root, data);
}
/**
* 通知公告删除
* @param noticeIds ids
*/
export function noticeRemove(noticeIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${noticeIds}`);
}

View File

@@ -21,12 +21,12 @@ export function ossConfigInfo(ossConfigId: ID) {
}
// 添加新的OSS配置
export function ossConfigAdd(data: any) {
export function ossConfigAdd(data: Partial<OssConfig>) {
return requestClient.postWithMsg<void>(Api.root, data);
}
// 更新现有的OSS配置
export function ossConfigUpdate(data: any) {
export function ossConfigUpdate(data: Partial<OssConfig>) {
return requestClient.putWithMsg<void>(Api.root, data);
}

View File

@@ -1,3 +1,5 @@
import type { AxiosRequestConfig } from '@vben/request';
import type { OssFile } from './model';
import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
@@ -13,20 +15,30 @@ enum Api {
root = '/resource/oss',
}
/**
* 文件list
* @param params 参数
* @returns 分页
*/
export function ossList(params?: PageQuery) {
return requestClient.get<PageResult<OssFile>>(Api.ossList, { params });
}
/**
* 查询文件信息 返回为数组
* @param ossIds id数组
* @returns 信息数组
*/
export function ossInfo(ossIds: IDS) {
return requestClient.get<OssFile>(`${Api.ossInfo}/${ossIds}`);
return requestClient.get<OssFile[]>(`${Api.ossInfo}/${ossIds}`);
}
/**
* @deprecated
* @deprecated 使用apps/web-antd/src/api/core/upload.ts uploadApi方法
* @param file 文件
* @returns void
*/
export function ossUpload(file: any) {
export function ossUpload(file: Blob | File) {
const formData = new FormData();
formData.append('file', file);
return requestClient.postWithMsg(Api.ossUpload, formData, {
@@ -38,16 +50,26 @@ export function ossUpload(file: any) {
/**
* 下载文件 返回为二进制
* @param ossId ossId
* @param onDownloadProgress 下载进度(可选)
* @returns blob
*/
export function ossDownload(ossId: ID) {
export function ossDownload(
ossId: ID,
onDownloadProgress?: AxiosRequestConfig['onDownloadProgress'],
) {
return requestClient.get<Blob>(`${Api.ossDownload}/${ossId}`, {
responseType: 'blob',
timeout: 30 * 1000,
isTransformResponse: false,
onDownloadProgress,
});
}
/**
* 删除文件
* @param ossIds id数组
* @returns void
*/
export function ossRemove(ossIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${ossIds}`);
}

View File

@@ -21,26 +21,56 @@ export function postList(params?: PageQuery) {
return requestClient.get<Post[]>(Api.postList, { params });
}
export function postExport(data: any) {
/**
* 导出岗位信息
* @param data 请求参数
* @returns blob
*/
export function postExport(data: Partial<Post>) {
return commonExport(Api.postExport, data);
}
/**
* 查询岗位信息
* @param postId id
* @returns 岗位信息
*/
export function postInfo(postId: ID) {
return requestClient.get<Post>(`${Api.root}/${postId}`);
}
export function postAdd(data: any) {
/**
* 岗位新增
* @param data 参数
* @returns void
*/
export function postAdd(data: Partial<Post>) {
return requestClient.postWithMsg<void>(Api.root, data);
}
export function postUpdate(data: any) {
/**
* 岗位更新
* @param data 参数
* @returns void
*/
export function postUpdate(data: Partial<Post>) {
return requestClient.putWithMsg<void>(Api.root, data);
}
/**
* 岗位删除
* @param postIds ids
* @returns void
*/
export function postRemove(postIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${postIds}`);
}
/**
* 根据部门id获取岗位下拉列表
* @param deptId 部门id
* @returns 岗位
*/
export function postOptionSelect(deptId: ID) {
return requestClient.get<Post[]>(Api.postSelect, { params: { deptId } });
}

View File

@@ -1,3 +1,4 @@
import type { User } from '../user/model';
import type { DeptResp, Role } from './model';
import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
@@ -20,30 +21,65 @@ enum Api {
root = '/system/role',
}
/**
* 查询角色分页列表
* @param params 搜索条件
* @returns 分页列表
*/
export function roleList(params?: PageQuery) {
return requestClient.get<PageResult<Role>>(Api.roleList, { params });
}
export function roleExport(data: any) {
/**
* 导出角色信息
* @param data 查询参数
* @returns blob
*/
export function roleExport(data: Partial<Role>) {
return commonExport(Api.roleExport, data);
}
/**
* 查询角色信息
* @param roleId 角色id
* @returns 角色信息
*/
export function roleInfo(roleId: ID) {
return requestClient.get<Role>(`${Api.root}/${roleId}`);
}
export function roleAdd(data: any) {
/**
* 角色新增
* @param data 参数
* @returns void
*/
export function roleAdd(data: Partial<Role>) {
return requestClient.postWithMsg<void>(Api.root, data);
}
export function roleUpdate(data: any) {
/**
* 角色更新
* @param data 参数
* @returns void
*/
export function roleUpdate(data: Partial<Role>) {
return requestClient.putWithMsg<void>(Api.root, data);
}
export function roleChangeStatus(data: any) {
/**
* 修改角色状态
* @param data 参数
* @returns void
*/
export function roleChangeStatus(data: Partial<Role>) {
return requestClient.putWithMsg<void>(Api.roleChangeStatus, data);
}
/**
* 角色删除
* @param roleIds ids
* @returns void
*/
export function roleRemove(roleIds: IDS) {
return requestClient.deleteWithMsg<void>(`${Api.root}/${roleIds}`);
}
@@ -57,12 +93,20 @@ export function roleDataScope(data: any) {
return requestClient.putWithMsg<void>(Api.roleDataScope, data);
}
/**
* @deprecated 全局并没有用到这个方法
*/
export function roleOptionSelect(params?: any) {
return requestClient.get(Api.roleOptionSelect, { params });
}
export function roleAllocatedList(params: any) {
return requestClient.get(Api.roleAllocatedList, { params });
/**
* 已分配角色的用户分页
* @param params 请求参数
* @returns 分页
*/
export function roleAllocatedList(params?: PageQuery) {
return requestClient.get<PageResult<User>>(Api.roleAllocatedList, { params });
}
/**
@@ -71,28 +115,26 @@ export function roleAllocatedList(params: any) {
* @returns void
*/
export function roleUnallocatedList(params: any) {
return requestClient.get(Api.roleUnallocatedList, { params });
return requestClient.get<PageResult<User>>(Api.roleUnallocatedList, {
params,
});
}
/**
* 取消授权
* @param data {userId: 2, roleId: "2"}
* 取消用户角色授权
* @returns void
*/
export function roleAuthCancel(data: any) {
export function roleAuthCancel(data: { roleId: ID; userId: ID }) {
return requestClient.putWithMsg<void>(Api.roleAuthCancel, data);
}
/**
* 批量取消授权
* @param roleId
* @param userIds
* @param roleId 角色ID
* @param userIds 用户ID集合
* @returns void
*/
export function roleAuthCancelAll(
roleId: number | string,
userIds: number[] | string[],
) {
export function roleAuthCancelAll(roleId: ID, userIds: IDS) {
return requestClient.putWithMsg<void>(
`${Api.roleAuthCancelAll}?roleId=${roleId}&userIds=${userIds.join(',')}`,
);
@@ -100,21 +142,18 @@ export function roleAuthCancelAll(
/**
* 批量授权用户
* @param roleId
* @param userIds
* @param roleId 角色ID
* @param userIds 用户ID集合
* @returns void
*/
export function roleSelectAll(
roleId: number | string,
userIds: number[] | string[],
) {
export function roleSelectAll(roleId: ID, userIds: IDS) {
return requestClient.putWithMsg<void>(
`${Api.roleAuthSelectAll}?roleId=${roleId}&userIds=${userIds.join(',')}`,
);
}
/**
* 部门树
* 根据角色id获取部门树
* @param roleId 角色id
* @returns DeptResp
*/

View File

@@ -1,5 +1,7 @@
import type { SocialInfo } from './model';
import type { ID } from '#/api/common';
import { requestClient } from '#/api/request';
enum Api {
@@ -15,6 +17,9 @@ export function socialList() {
return requestClient.get<SocialInfo[]>(Api.socialList);
}
export function socialInfo(id: number | string) {
/**
* @deprecated 并没有用到这个方法
*/
export function socialInfo(id: ID) {
return requestClient.get(`${Api.root}/${id}`);
}

View File

@@ -13,37 +13,75 @@ enum Api {
root = '/system/tenant/package',
}
/**
* 租户套餐分页列表
* @param params 请求参数
* @returns 分页列表
*/
export function packageList(params?: PageQuery) {
return requestClient.get<PageResult<TenantPackage>>(Api.packageList, {
params,
});
}
// 下拉框
/**
* 租户套餐下拉框
* @returns 下拉框
*/
export function packageSelectList() {
return requestClient.get<TenantPackage[]>(Api.packageSelectList);
}
export function packageExport(data: any) {
/**
* 租户套餐导出
* @param data 参数
* @returns blob
*/
export function packageExport(data: Partial<TenantPackage>) {
return commonExport(Api.packageExport, data);
}
/**
* 租户套餐信息
* @param id id
* @returns 信息
*/
export function packageInfo(id: ID) {
return requestClient.get<TenantPackage>(`${Api.root}/${id}`);
}
export function packageAdd(data: any) {
/**
* 租户套餐新增
* @param data data
* @returns void
*/
export function packageAdd(data: Partial<TenantPackage>) {
return requestClient.postWithMsg<void>(Api.root, data);
}
export function packageUpdate(data: any) {
/**
* 租户套餐更新
* @param data data
* @returns void
*/
export function packageUpdate(data: Partial<TenantPackage>) {
return requestClient.putWithMsg<void>(Api.root, data);
}
export function packageChangeStatus(data: any) {
return requestClient.putWithMsg(Api.packageChangeStatus, data);
/**
* 租户套餐状态变更
* @param data data
* @returns void
*/
export function packageChangeStatus(data: Partial<TenantPackage>) {
return requestClient.putWithMsg<void>(Api.packageChangeStatus, data);
}
/**
* 租户套餐移除
* @param ids ids
* @returns void
*/
export function packageRemove(ids: IDS) {
return requestClient.deleteWithMsg(`${Api.root}/${ids}`);
return requestClient.deleteWithMsg<void>(`${Api.root}/${ids}`);
}

View File

@@ -16,14 +16,29 @@ enum Api {
tenantSyncPackage = '/system/tenant/syncTenantPackage',
}
/**
* 查询租户分页列表
* @param params 参数
* @returns 分页
*/
export function tenantList(params?: PageQuery) {
return requestClient.get<Tenant[]>(Api.tenantList, { params });
}
export function tenantExport(data: any) {
/**
* 租户导出
* @param data data
* @returns void
*/
export function tenantExport(data: Partial<Tenant>) {
return commonExport(Api.tenantExport, data);
}
/**
* 查询租户信息
* @param id id
* @returns 租户信息
*/
export function tenantInfo(id: ID) {
return requestClient.get<Tenant>(`${Api.root}/${id}`);
}
@@ -33,18 +48,33 @@ export function tenantInfo(id: ID) {
* @param data data
* @returns void
*/
export function tenantAdd(data: any) {
export function tenantAdd(data: Partial<Tenant>) {
return requestClient.postWithMsg<void>(Api.root, data, { encrypt: true });
}
export function tenantUpdate(data: any) {
/**
* 租户更新
* @param data data
* @returns void
*/
export function tenantUpdate(data: Partial<Tenant>) {
return requestClient.putWithMsg<void>(Api.root, data);
}
export function tenantStatusChange(data: any) {
/**
* 租户状态更新
* @param data data
* @returns void
*/
export function tenantStatusChange(data: Partial<Tenant>) {
return requestClient.putWithMsg(Api.tenantStatus, data);
}
/**
* 租户删除
* @param ids ids
* @returns void
*/
export function tenantRemove(ids: IDS) {
return requestClient.deleteWithMsg(`${Api.root}/${ids}`);
}
@@ -70,17 +100,12 @@ export function tenantDynamicClear() {
* 租户套餐同步
* @param tenantId 租户id
* @param packageId 套餐id
* @param showMsg 是否显示成功信息
* @returns void
*/
export function tenantSyncPackage(
tenantId: string,
packageId: string,
showMsg = true,
) {
export function tenantSyncPackage(tenantId: string, packageId: string) {
return requestClient.get<void>(Api.tenantSyncPackage, {
params: { packageId, tenantId },
successMessageMode: showMsg ? 'message' : 'none',
successMessageMode: 'message',
});
}

View File

@@ -9,7 +9,7 @@ export interface Tenant {
id: number;
intro: string;
licenseNumber?: any;
packageId?: string;
packageId: string;
remark?: string;
status: string;
tenantId: string;

View File

@@ -38,7 +38,7 @@ export function userList(params?: PageQuery) {
* @param data data
* @returns blob
*/
export function userExport(data: any) {
export function userExport(data: Partial<User>) {
return commonExport(Api.userExport, data);
}
@@ -91,7 +91,7 @@ export function findUserInfo(userId?: ID) {
* @param data data
* @returns void
*/
export function userAdd(data: any) {
export function userAdd(data: Partial<User>) {
return requestClient.postWithMsg<void>(Api.root, data);
}
@@ -100,7 +100,7 @@ export function userAdd(data: any) {
* @param data data
* @returns void
*/
export function userUpdate(data: any) {
export function userUpdate(data: Partial<User>) {
return requestClient.putWithMsg<void>(Api.root, data);
}
@@ -109,7 +109,7 @@ export function userUpdate(data: any) {
* @param data data
* @returns void
*/
export function userStatusChange(data: any) {
export function userStatusChange(data: Partial<User>) {
return requestClient.putWithMsg<void>(Api.userStatusChange, data);
}

View File

@@ -1,6 +1,6 @@
import type { GenInfo } from './model';
import type { ID, IDS } from '#/api/common';
import type { ID, IDS, PageQuery } from '#/api/common';
import { ContentTypeEnum } from '#/api/helper';
import { requestClient } from '#/api/request';
@@ -19,7 +19,7 @@ enum Api {
syncDb = '/tool/gen/synchDb',
}
// 查询代码生成列表
export function generatedList(params: any) {
export function generatedList(params?: PageQuery) {
return requestClient.get(Api.generatedList, { params });
}
@@ -29,7 +29,7 @@ export function genInfo(tableId: ID) {
}
// 查询数据库列表
export function readyToGenList(params: any) {
export function readyToGenList(params?: PageQuery) {
return requestClient.get(Api.readyToGenList, { params });
}
@@ -63,6 +63,7 @@ export function editSave(data: any) {
export function genRemove(tableIds: IDS) {
return requestClient.deleteWithMsg(`${Api.root}/${tableIds}`);
}
// 预览代码
export function previewCode(tableId: ID) {
return requestClient.get<{ [key: string]: string }>(
@@ -76,8 +77,8 @@ export function genDownload(tableId: ID) {
}
// 生成代码(自定义路径)
export function genDownloadWithPath(tableId: ID) {
return requestClient.get(`${Api.download}/${tableId}`);
export function genWithPath(tableId: ID) {
return requestClient.get<void>(`${Api.genCode}/${tableId}`);
}
// 同步数据库

View File

@@ -177,6 +177,7 @@ export interface Info {
// 树表需要添加此属性
params?: any;
popupComponent?: string;
formComponent?: string;
}
export interface GenInfo {

View File

@@ -1,9 +1,22 @@
import type { CategoryForm, CategoryQuery, CategoryVO } from './model';
import type {
CategoryForm,
CategoryQuery,
CategoryTree,
CategoryVO,
} from './model';
import type { ID, IDS } from '#/api/common';
import { requestClient } from '#/api/request';
/**
* 获取流程分类树列表
* @returns tree
*/
export function categoryTree() {
return requestClient.get<CategoryTree[]>('/workflow/category/categoryTree');
}
/**
* 查询流程分类列表
* @param params

View File

@@ -30,6 +30,7 @@ export interface CategoryVO {
* 子对象
*/
children: CategoryVO[];
key: string;
}
export interface CategoryForm extends BaseEntity {
@@ -85,3 +86,12 @@ export interface CategoryQuery {
*/
params?: any;
}
export interface CategoryTree {
id: number;
parentId: number;
label: string;
weight: number;
children: CategoryTree[];
key: string;
}

View File

@@ -0,0 +1,155 @@
import type { ProcessDefinition } from './model';
import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
import { requestClient } from '#/api/request';
/**
* 全部的流程定义
* @param params 查询参数
* @returns 分页
*/
export function workflowDefinitionList(params?: PageQuery) {
return requestClient.get<PageResult<ProcessDefinition>>(
'/workflow/definition/list',
{ params },
);
}
/**
* 未发布的流程定义
* @param params 查询参数
* @returns 分页
*/
export function unPublishList(params?: PageQuery) {
return requestClient.get<PageResult<ProcessDefinition>>(
'/workflow/definition/unPublishList',
{ params },
);
}
/**
* 获取历史流程定义列表
* @param flowCode
* @returns ProcessDefinition[]
*/
export function getHisListByKey(flowCode: string) {
return requestClient.get<ProcessDefinition[]>(
`/workflow/definition/getHisListByKey/${flowCode}`,
);
}
/**
* 获取流程定义详细信息
* @param id id
* @returns ProcessDefinition
*/
export function workflowDefinitionInfo(id: ID) {
return requestClient.get<ProcessDefinition>(`/workflow/definition/${id}`);
}
/**
* 新增流程定义
* @param data
*/
export function workflowDefinitionAdd(data: any) {
return requestClient.postWithMsg<void>('/workflow/definition', data);
}
/**
* 更新流程定义
* @param data
*/
export function workflowDefinitionUpdate(data: any) {
return requestClient.putWithMsg<void>('/workflow/definition', data);
}
/**
* 发布流程定义
* @param id id
* @returns boolean
*/
export function workflowDefinitionPublish(id: ID) {
return requestClient.putWithMsg<boolean>(
`/workflow/definition/publish/${id}`,
);
}
/**
* 取消发布流程定义
* @param id id
* @returns boolean
*/
export function workflowDefinitionUnPublish(id: ID) {
return requestClient.putWithMsg<boolean>(
`/workflow/definition/unPublish/${id}`,
);
}
/**
* 删除流程定义
* @param ids idList
*/
export function workflowDefinitionDelete(ids: IDS) {
return requestClient.deleteWithMsg<void>(`/workflow/definition/${ids}`);
}
/**
* 复制流程定义
* @param id id
*/
export function workflowDefinitionCopy(id: ID) {
return requestClient.postWithMsg<void>(`/workflow/definition/copy/${id}`);
}
/**
* 导入流程定义
* @returns boolean
*/
export function workflowDefinitionImport(data: {
category: ID;
file: Blob | File;
}) {
return requestClient.postWithMsg<boolean>(
'/workflow/definition/importDef',
data,
{ headers: { 'Content-Type': 'multipart/form-data' } },
);
}
/**
* 导出流程定义
* @param id id
* @returns blob
*/
export function workflowDefinitionExport(id: ID) {
return requestClient.postWithMsg<Blob>(
`/workflow/definition/exportDef/${id}`,
{},
{
responseType: 'blob',
isTransformResponse: false,
},
);
}
/**
* 获取流程定义xml字符串
* @param id id
* @returns xml
*/
export function workflowDefinitionXml(id: ID) {
return requestClient.get<string>(`/workflow/definition/xmlString/${id}`);
}
/**
* 激活/挂起流程定义
* @param id 流程定义id
* @param active 激活/挂起
* @returns boolean
*/
export function workflowDefinitionActive(id: ID, active: boolean) {
return requestClient.putWithMsg<boolean>(
`/workflow/definition/active/${id}?active=${active}`,
);
}

View File

@@ -0,0 +1,19 @@
export interface ProcessDefinition {
id: string;
createTime: string;
updateTime: string;
tenantId: string;
delFlag: string;
flowCode: string;
flowName: string;
category: string;
categoryName: string;
version: string;
isPublish: number;
formCustom: string;
formPath: string;
activityStatus: number;
listenerType?: any;
listenerPath?: any;
ext?: any;
}

View File

@@ -0,0 +1,120 @@
import type { TaskInfo } from '../task/model';
import type { FlowInfoResponse } from './model';
import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
import { requestClient } from '#/api/request';
/**
* @param businessId 业务ID
* @returns TaskInfo
*/
export function getTaskByBusinessId(businessId: string) {
return requestClient.get<TaskInfo>(
`/workflow/instance/getInfo/${businessId}`,
);
}
/**
* 分页查询正在运行的流程实例
* @param params
* @returns
*/
export function pageByRunning(params?: PageQuery) {
return requestClient.get('/workflow/instance/pageByRunning', { params });
}
/**
* pageByFinish
* @param params
* @returns
*/
export function pageByFinish(params?: PageQuery) {
return requestClient.get('/workflow/instance/pageByFinish', { params });
}
/**
* 按照业务id删除流程实例
* @param businessIds 业务id
*/
export function deleteByBusinessIds(businessIds: IDS) {
return requestClient.deleteWithMsg<void>(
`/workflow/instance/deleteByBusinessIds${businessIds}`,
);
}
/**
* 按照实例id删除流程实例
* @param instanceIds 实例id
*/
export function deleteByInstanceIds(instanceIds: IDS) {
return requestClient.deleteWithMsg<void>(
`/workflow/instance/deleteByInstanceIds/${instanceIds}`,
);
}
/**
* 撤销流程
* @param data
*/
export function cancelProcessApply(data: { businessId: ID; message?: string }) {
return requestClient.putWithMsg<void>(
'/workflow/instance/cancelProcessApply',
data,
);
}
/**
* 激活/挂起流程实例
* @param instanceId
* @param active
*/
export function workflowInstanceActive(instanceId: ID, active: boolean) {
return requestClient.putWithMsg<void>(
`/workflow/instance/active/${instanceId}?active=${active}`,
);
}
/**
* 获取当前登录人发起的流程实例
* @param params
* @returns PageResult<Flow>
*/
export function pageByCurrent(params?: PageQuery) {
return requestClient.get<PageResult<TaskInfo>>(
'/workflow/instance/pageByCurrent',
{ params },
);
}
/**
* 获取流程图,流程记录
* @param businessId 业务标识
* @returns 流程图,流程记录
*/
export function flowInfo(businessId: string) {
return requestClient.get<FlowInfoResponse>(
`/workflow/instance/flowImage/${businessId}`,
);
}
/**
* 获取流程变量
* @param instanceId
* @returns Map<string,any>
*/
export function instanceVariable(instanceId: string) {
return requestClient.get<Record<string, any>>(
`/workflow/instance/variable/${instanceId}`,
);
}
/**
* 作废流程
*/
export function workflowInstanceInvalid(data: {
comment?: string;
id: string;
}) {
return requestClient.postWithMsg<void>('/workflow/instance/invalid', data);
}

View File

@@ -0,0 +1,41 @@
export interface Flow {
id: string;
createTime: string;
updateTime: string;
tenantId: string;
delFlag: string;
definitionId: string;
flowName?: any;
instanceId: string;
taskId: string;
cooperateType: number;
cooperateTypeName: string;
businessId?: any;
nodeCode: string;
nodeName: string;
nodeType: number;
targetNodeCode: string;
targetNodeName: string;
approver: string;
approveName: string;
collaborator?: any;
permissionList?: any;
skipType: string;
flowStatus: string;
flowTaskStatus?: any;
flowStatusName?: any;
message: string;
ext: null | string;
createBy?: any;
formCustom: string;
formPath: string;
flowCode?: any;
version?: any;
runDuration: string;
nickName?: any;
}
export interface FlowInfoResponse {
image: string;
list: Flow[];
}

View File

@@ -0,0 +1,172 @@
import type {
CompleteTaskReqData,
NextNodeInfo,
StartWorkFlowReqData,
TaskInfo,
TaskOperationData,
TaskOperationType,
} from './model';
import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
import { requestClient } from '#/api/request';
/**
* 启动任务
* @param data
*/
export function startWorkFlow(data: StartWorkFlowReqData) {
return requestClient.post<{
processInstanceId: string;
taskId: string;
}>('/workflow/task/startWorkFlow', data);
}
/**
* 办理任务
* @param data
*/
export function completeTask(data: CompleteTaskReqData) {
return requestClient.postWithMsg<void>('/workflow/task/completeTask', data);
}
/**
* 查询当前用户的待办任务
* @param params
*/
export function pageByTaskWait(params?: PageQuery) {
return requestClient.get<PageResult<TaskInfo>>(
'/workflow/task/pageByTaskWait',
{ params },
);
}
/**
* 查询当前用户的已办任务
* @param params
*/
export function pageByTaskFinish(params?: PageQuery) {
return requestClient.get<PageResult<TaskInfo>>(
'/workflow/task/pageByTaskFinish',
{ params },
);
}
/**
* 查询所有待办任务
* @param params
*/
export function pageByAllTaskWait(params?: PageQuery) {
return requestClient.get<PageResult<TaskInfo>>(
'/workflow/task/pageByAllTaskWait',
{ params },
);
}
/**
* 查询已办任务
* @param params
*/
export function pageByAllTaskFinish(params?: PageQuery) {
return requestClient.get<PageResult<TaskInfo>>(
'/workflow/task/pageByAllTaskFinish',
{ params },
);
}
/**
* 查询当前用户的抄送
* @param params
*/
export function pageByTaskCopy(params?: PageQuery) {
return requestClient.get<PageResult<TaskInfo>>(
'/workflow/task/pageByTaskCopy',
{ params },
);
}
/**
* 根据taskId查询代表任务
* @param taskId 任务id
* @returns info
*/
export function getTaskByTaskId(taskId: string) {
return requestClient.get<TaskInfo>(`/workflow/task/getTask/${taskId}`);
}
/**
* 终止任务
*/
export function terminationTask(data: { comment?: string; taskId: string }) {
return requestClient.postWithMsg<void>(
'/workflow/task/terminationTask',
data,
);
}
/**
* 任务操作
* @param taskOperationData 参数
* @param taskOperation 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature
*/
export function taskOperation(
taskOperationData: TaskOperationData,
taskOperation: TaskOperationType,
) {
return requestClient.postWithMsg<void>(
`/workflow/task/taskOperation/${taskOperation}`,
taskOperationData,
);
}
/**
* 修改任务办理人
* @param taskIdList 任务id
* @param userId 办理人id
*/
export function updateAssignee(taskIdList: IDS, userId: ID) {
return requestClient.putWithMsg<void>(
`/workflow/task/updateAssignee/${userId}`,
taskIdList,
);
}
/**
* 驳回审批
* @param data 参数
*/
export function backProcess(data: any) {
return requestClient.postWithMsg<void>('/workflow/task/backProcess', data);
}
/**
* 获取可驳回节点
* @param definitionId 流程定义ID
* @param nodeCode 当前节点编码
*/
export function getBackTaskNode(definitionId: string, nodeCode: string) {
return requestClient.get<{ nodeCode: string; nodeName: string }[]>(
`/workflow/task/getBackTaskNode/${definitionId}/${nodeCode}`,
);
}
/**
* 获取当前任务的所有办理人
* @param taskId 任务id
*/
export function currentTaskAllUser(taskId: ID) {
return requestClient.get<any>(`/workflow/task/currentTaskAllUser/${taskId}`);
}
/**
* 获取下一节点
* @param data data
* @param data.taskId taskId
* @returns NextNodeInfo
*/
export function getNextNodeList(data: { taskId: string }) {
return requestClient.post<NextNodeInfo[]>(
'/workflow/task/getNextNodeList',
data,
);
}

View File

@@ -0,0 +1,108 @@
export interface ButtonWithPermission {
code: string;
value: null | string;
show: boolean;
}
export interface TaskInfo {
id: string;
categoryName: string;
createTime: string;
updateTime: string;
tenantId: string;
delFlag?: any;
definitionId: string;
instanceId: string;
flowName: string;
businessId: string;
nodeCode: string;
nodeName: string;
nodeType: number;
permissionList?: any;
userList?: any;
formCustom: string;
formPath?: any;
flowCode: string;
version: string;
flowStatus: string;
flowStatusName: string;
assigneeIds: string;
assigneeNames: string;
processedBy: string;
type: string;
nodeRatio?: string;
createBy: string;
createByName: string;
targetNodeName?: string;
buttonList: ButtonWithPermission[];
}
export interface CompleteTaskReqData {
messageType: string[];
flowCopyList: { userId: string; userName: string }[];
taskId: ID;
taskVariables: Record<string, any>;
variables: any;
// 附件ID 1,2,3,4形式
fileId?: string;
// 选人 key为节点code value为用户ID join(,)
assigneeMap: { [key: string]: string };
}
export interface StartWorkFlowReqData {
/**
* 业务ID
*/
businessId: ID;
/**
* flowCode
*/
flowCode: string;
/**
* 流程变量
*/
variables: Record<string, any>;
}
export interface TaskOperationData {
message?: string;
taskId: ID;
// 单个操作人
userId?: ID;
// 多个操作人
userIds?: IDS;
}
/**
* 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature
*/
export type TaskOperationType =
| 'addSignature'
| 'delegateTask'
| 'reductionSignature'
| 'transferTask';
export interface NextNodeInfo {
skipList: string[];
id: string;
createTime: string;
updateTime: string;
tenantId: string;
delFlag: string;
nodeType: number;
definitionId: string;
nodeCode: string;
nodeName: string;
permissionFlag: string;
nodeRatio: string;
coordinate: string;
version: string;
anyNodeSkip: any;
listenerType: any;
listenerPath: any;
handlerType: any;
handlerPath: any;
formCustom: string;
formPath: any;
ext: string;
}

View File

@@ -1,6 +1,8 @@
import { createApp, watchEffect } from 'vue';
import { registerAccessDirective } from '@vben/access';
import { initTippy, registerLoadingDirective } from '@vben/common-ui';
import { MotionPlugin } from '@vben/plugins/motion';
import { preferences } from '@vben/preferences';
import { initStores } from '@vben/stores';
import '@vben/styles';
@@ -19,10 +21,24 @@ async function bootstrap(namespace: string) {
// 初始化组件适配器
await initComponentAdapter();
// // 设置弹窗的默认配置
// setDefaultModalProps({
// fullscreenButton: false,
// });
// // 设置抽屉的默认配置
// setDefaultDrawerProps({
// zIndex: 1020,
// });
const app = createApp(App);
// 全局组件
setupGlobalComponent(app);
// 注册v-loading指令
registerLoadingDirective(app, {
loading: 'loading', // 在这里可以自定义指令名称也可以明确提供false表示不注册这个指令
spinning: 'spinning',
});
// 国际化 i18n 配置
await setupI18n(app);
@@ -33,9 +49,15 @@ async function bootstrap(namespace: string) {
// 安装权限指令
registerAccessDirective(app);
// 初始化 tippy
initTippy(app);
// 配置路由及路由守卫
app.use(router);
// 配置Motion插件
app.use(MotionPlugin);
// 动态更新标题
watchEffect(() => {
if (preferences.app.dynamicTitle) {

View File

@@ -1,4 +1,3 @@
export { default as CropperImage } from './src/cropper.vue';
export { default as CropperAvatar } from './src/cropper-avatar.vue';
export { default as CropperImage } from './src/cropper.vue';
export type { Cropper } from './src/typing';

View File

@@ -1,18 +1,14 @@
<script lang="ts" setup>
import {
computed,
type CSSProperties,
type PropType,
ref,
unref,
watch,
watchEffect,
} from 'vue';
import type { ButtonProps } from 'ant-design-vue';
import type { CSSProperties, PropType } from 'vue';
import { computed, ref, unref, watch, watchEffect } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { $t as t } from '@vben/locales';
import { type ButtonProps, message } from 'ant-design-vue';
import { message } from 'ant-design-vue';
import cropperModal from './cropper-modal.vue';

View File

@@ -1,7 +1,9 @@
<script lang="ts" setup>
import type { PropType } from 'vue';
import type { CropendResult, Cropper } from './typing';
import { type PropType, ref } from 'vue';
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { $t as t } from '@vben/locales';

View File

@@ -1,5 +1,6 @@
<script lang="ts" setup>
import type { CSSProperties, PropType } from 'vue';
import { computed, onMounted, onUnmounted, ref, unref, useAttrs } from 'vue';
import { useDebounceFn } from '@vueuse/core';

View File

@@ -2,19 +2,11 @@
import type { CardSize } from 'ant-design-vue/es/card/Card';
import type { DescriptionsProps } from 'ant-design-vue/es/descriptions';
import type { CSSProperties, PropType, Slots } from 'vue';
import type { DescInstance, DescItem, DescriptionProps } from './typing';
import {
computed,
type CSSProperties,
defineComponent,
type PropType,
ref,
type Slots,
toRefs,
unref,
useAttrs,
} from 'vue';
import { computed, defineComponent, ref, toRefs, unref, useAttrs } from 'vue';
import { Card, Descriptions } from 'ant-design-vue';
import { get, isFunction } from 'lodash-es';

View File

@@ -1,9 +1,10 @@
import type { Recordable } from '@vben/types';
import type { DescriptionsProps } from 'ant-design-vue/es/descriptions';
import type { JSX } from 'vue/jsx-runtime';
import type { CSSProperties, VNode } from 'vue';
import type { Recordable } from '@vben/types';
export interface DescItem {
labelMinWidth?: number;
contentMinWidth?: number;

View File

@@ -1,4 +1,4 @@
import { type VNode } from 'vue';
import type { VNode } from 'vue';
import { Tag } from 'ant-design-vue';

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable eqeqeq -->
<script setup lang="ts">
import type { DictData } from '#/api/system/dict/dict-data-model';
@@ -17,7 +18,6 @@ const props = withDefaults(defineProps<Props>(), {
});
const color = computed<string>(() => {
// eslint-disable-next-line eqeqeq
const current = props.dicts.find((item) => item.dictValue == props.value);
const listClass = current?.listClass ?? '';
// 是否为默认的颜色
@@ -31,13 +31,11 @@ const color = computed<string>(() => {
});
const cssClass = computed<string>(() => {
// eslint-disable-next-line eqeqeq
const current = props.dicts.find((item) => item.dictValue == props.value);
return current?.cssClass ?? '';
});
const label = computed<number | string>(() => {
// eslint-disable-next-line eqeqeq
const current = props.dicts.find((item) => item.dictValue == props.value);
return current?.dictLabel ?? 'unknown';
});

View File

@@ -1 +1,2 @@
export { default as OptionsTag } from './src/options-tag.vue';
export { default as TableSwitch } from './src/table-switch.vue';

View File

@@ -0,0 +1,21 @@
<script setup lang="tsx">
import { computed } from 'vue';
import { Tag } from 'ant-design-vue';
defineOptions({ name: 'OptionsTag' });
const props = defineProps<{
options: { color?: string; label: string; value: number | string }[];
value: number | string;
}>();
const found = computed(() =>
props.options.find((item) => item.value === props.value),
);
</script>
<template>
<Tag v-if="found" :color="found.color">{{ found.label }}</Tag>
<span v-else>未知</span>
</template>

View File

@@ -105,11 +105,7 @@ function filterOption(input: string, option: TenantOption) {
show-search
@deselect="onDeselect"
@select="onSelected"
>
<template #suffixIcon>
<span class="icon-mdi--company"></span>
</template>
</Select>
/>
</div>
</template>

View File

@@ -2,6 +2,10 @@
import type { IPropTypes } from '@tinymce/tinymce-vue/lib/cjs/main/ts/components/EditorPropTypes';
import type { Editor as EditorType } from 'tinymce/tinymce';
import type { PropType } from 'vue';
import type { UploadResult } from '#/api/core/upload';
import {
computed,
nextTick,
@@ -9,7 +13,6 @@ import {
onBeforeUnmount,
onDeactivated,
onMounted,
type PropType,
ref,
unref,
useAttrs,
@@ -22,7 +25,7 @@ import { buildShortUUID } from '@vben/utils';
import Editor from '@tinymce/tinymce-vue';
import { isNumber } from 'lodash-es';
import { uploadApi, type UploadResult } from '#/api/core/upload';
import { uploadApi } from '#/api/core/upload';
import { bindHandlers } from './helper';
import ImgUpload from './img-upload.vue';
@@ -342,7 +345,7 @@ function handleDone(name: string, url: string) {
v-if="!initOptions.inline && init"
v-model="modelValue"
:init="initOptions"
:style="{ visibility: 'hidden' }"
:style="{ visibility: 'hidden', zIndex: 3000 }"
:tinymce-script-src="tinymceScriptSrc"
license-key="gpl"
/>
@@ -350,6 +353,17 @@ function handleDone(name: string, url: string) {
</div>
</template>
<style lang="scss">
/***
由于modal/drawer的zIndex升级后为2000
这里会造成遮挡 修改为更高的zIndex
*/
.tox.tox-silver-sink.tox-tinymce-aux {
/** 该样式默认为1300的zIndex */
z-index: 2025;
}
</style>
<style lang="scss" scoped>
/**
隐藏右上角upgrade按钮

View File

@@ -4,9 +4,9 @@ const validEvents = new Set([
'onBeforeAddUndo',
'onBeforeExecCommand',
'onBeforeGetContent',
'onBeforePaste',
'onBeforeRenderUI',
'onBeforeSetContent',
'onBeforePaste',
'onBlur',
'onChange',
'onClearUndos',
@@ -42,8 +42,8 @@ const validEvents = new Set([
'onMouseOver',
'onMouseUp',
'onNodeChange',
'onObjectResizeStart',
'onObjectResized',
'onObjectResizeStart',
'onObjectSelected',
'onPaste',
'onPostProcess',

View File

@@ -48,14 +48,6 @@ function handleChange(info: Record<string, any>) {
const name = file?.name;
switch (status) {
case 'uploading': {
if (!uploading) {
emit('uploading', name);
uploading = true;
}
break;
}
case 'done': {
// http 200会走到这里 需要再次判断
const { response } = file;
@@ -77,6 +69,14 @@ function handleChange(info: Record<string, any>) {
break;
}
case 'uploading': {
if (!uploading) {
emit('uploading', name);
uploading = true;
}
break;
}
// No default
}
}

View File

@@ -1 +1,2 @@
export { default as MenuSelectTable } from './src/menu-select-table.vue';
export { default as TreeSelectPanel } from './src/tree-select-panel.vue';

View File

@@ -0,0 +1,85 @@
import type { VxeGridProps } from '#/adapter/vxe-table';
import type { ID } from '#/api/common';
import type { MenuOption } from '#/api/system/menu/model';
import { h, markRaw } from 'vue';
import { FolderIcon, MenuIcon, OkButtonIcon, VbenIcon } from '@vben/icons';
export interface Permission {
checked: boolean;
id: ID;
label: string;
}
export interface MenuPermissionOption extends MenuOption {
permissions: Permission[];
}
const menuTypes = {
C: { icon: markRaw(MenuIcon), value: '菜单' },
F: { icon: markRaw(OkButtonIcon), value: '按钮' },
M: { icon: markRaw(FolderIcon), value: '目录' },
};
export const nodeOptions = [
{ label: '节点关联', value: true },
{ label: '节点独立', value: false },
];
export const columns: VxeGridProps['columns'] = [
{
type: 'checkbox',
title: '菜单名称',
field: 'label',
treeNode: true,
headerAlign: 'left',
align: 'left',
width: 230,
},
{
title: '图标',
field: 'icon',
width: 80,
slots: {
default: ({ row }) => {
if (row?.icon === '#') {
return '';
}
return (
<span class={'flex justify-center'}>
<VbenIcon icon={row.icon} />
</span>
);
},
},
},
{
title: '类型',
field: 'menuType',
width: 80,
slots: {
default: ({ row }) => {
const current = menuTypes[row.menuType as 'C' | 'F' | 'M'];
if (!current) {
return '未知';
}
return (
<span class="flex items-center justify-center gap-1">
{h(current.icon, { class: 'size-[18px]' })}
<span>{current.value}</span>
</span>
);
},
},
},
{
title: '权限标识',
field: 'permissions',
headerAlign: 'left',
align: 'left',
slots: {
default: 'permissions',
},
},
];

View File

@@ -0,0 +1,133 @@
import type { MenuPermissionOption } from './data';
import type { useVbenVxeGrid } from '#/adapter/vxe-table';
import type { MenuOption } from '#/api/system/menu/model';
import { eachTree, treeToList } from '@vben/utils';
import { difference, isEmpty, isUndefined } from 'lodash-es';
/**
* 权限列设置是否全选
* @param record 行记录
* @param checked 是否选中
*/
export function setPermissionsChecked(
record: MenuPermissionOption,
checked: boolean,
) {
if (record?.permissions?.length > 0) {
// 全部设置为选中
record.permissions.forEach((permission) => {
permission.checked = checked;
});
}
}
/**
* 设置当前行 & 所有子节点选中状态
* @param record 行
* @param checked 是否选中
*/
export function rowAndChildrenChecked(
record: MenuPermissionOption,
checked: boolean,
) {
// 当前行选中
setPermissionsChecked(record, checked);
// 所有子节点选中
record?.children?.forEach?.((permission) => {
rowAndChildrenChecked(permission as MenuPermissionOption, checked);
});
}
/**
* void方法 会直接修改原始数据
* 将树结构转为 tree+permissions结构
* @param menus 后台返回的menu
*/
export function menusWithPermissions(menus: MenuOption[]) {
eachTree(menus, (item: MenuPermissionOption) => {
if (item.children && item.children.length > 0) {
/**
* 所有为按钮的节点提取出来
* 需要注意 这里需要过滤目录下直接是按钮的情况item.menuType !== 'M'
* 将按钮往children添加而非加到permissions
*/
const permissions = item.children.filter(
(child: MenuOption) => child.menuType === 'F' && item.menuType !== 'M',
);
// 取差集
const diffCollection = difference(item.children, permissions);
// 更新后的children 即去除按钮
item.children = diffCollection;
// permissions作为字段添加到item
const permissionsArr = permissions.map((permission) => {
return {
id: permission.id,
label: permission.label,
checked: false,
};
});
item.permissions = permissionsArr;
}
});
}
/**
* 设置表格选中
* @param checkedKeys 选中的keys
* @param menus 菜单 转换后的菜单
* @param tableApi api
* @param association 是否节点关联
*/
export function setTableChecked(
checkedKeys: (number | string)[],
menus: MenuPermissionOption[],
tableApi: ReturnType<typeof useVbenVxeGrid>['1'],
association: boolean,
) {
// tree转list
const menuList: MenuPermissionOption[] = treeToList(menus);
// 拿到勾选的行数据
let checkedRows = menuList.filter((item) => checkedKeys.includes(item.id));
/**
* 节点独立切换到节点关联 只需要最末尾的数据 即children为空
*/
if (!association) {
checkedRows = checkedRows.filter(
(item) => isUndefined(item.children) || isEmpty(item.children),
);
}
// 设置行选中 & permissions选中
checkedRows.forEach((item) => {
tableApi.grid.setCheckboxRow(item, true);
if (item?.permissions?.length > 0) {
item.permissions.forEach((permission) => {
if (checkedKeys.includes(permission.id)) {
permission.checked = true;
}
});
}
});
/**
* 节点独立切换到节点关联
* 勾选后还需要过滤权限没有任何勾选的情况 这时候取消行的勾选
*/
if (!association) {
const emptyRows = checkedRows.filter((item) => {
if (isUndefined(item.permissions) || isEmpty(item.permissions)) {
return false;
}
return item.permissions.every(
(permission) => permission.checked === false,
);
});
// 设置为不选中
tableApi.grid.setCheckboxRow(emptyRows, false);
}
}

View File

@@ -0,0 +1,62 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import type { TourProps } from 'ant-design-vue';
import { defineComponent, ref } from 'vue';
import { useLocalStorage } from '@vueuse/core';
import { Tour } from 'ant-design-vue';
/**
* 全屏引导
* @returns value
*/
export function useFullScreenGuide() {
const open = ref(false);
/**
* 是否已读 只显示一次
*/
const read = useLocalStorage('menu_select_fullscreen_read', false);
function openGuide() {
if (!read.value) {
open.value = true;
}
}
function closeGuide() {
open.value = false;
read.value = true;
}
const steps: TourProps['steps'] = [
{
title: '提示',
description: '点击这里可以全屏',
target: () =>
document.querySelector(
'div#menu-select-table .vxe-tools--operate > button[title="全屏"]',
)!,
},
];
const FullScreenGuide = defineComponent({
name: 'FullScreenGuide',
inheritAttrs: false,
setup() {
return () => (
<Tour
onClose={closeGuide}
open={open.value}
steps={steps}
zIndex={9999}
/>
);
},
});
return {
FullScreenGuide,
openGuide,
closeGuide,
};
}

View File

@@ -0,0 +1,408 @@
<!--
不兼容也不会兼容一些错误用法
比如: 菜单下放目录 菜单下放菜单
比如: 按钮下放目录 按钮下放菜单 按钮下放按钮
-->
<script setup lang="tsx">
import type { RadioChangeEvent } from 'ant-design-vue';
import type { MenuPermissionOption } from './data';
import type { VxeGridProps } from '#/adapter/vxe-table';
import type { MenuOption } from '#/api/system/menu/model';
import { nextTick, onMounted, ref, shallowRef, watch } from 'vue';
import { cloneDeep, findGroupParentIds } from '@vben/utils';
import { Alert, Checkbox, RadioGroup, Space } from 'ant-design-vue';
import { uniq } from 'lodash-es';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { columns, nodeOptions } from './data';
import {
menusWithPermissions,
rowAndChildrenChecked,
setPermissionsChecked,
setTableChecked,
} from './helper';
import { useFullScreenGuide } from './hook';
defineOptions({
name: 'MenuSelectTable',
inheritAttrs: false,
});
const props = withDefaults(
defineProps<{
checkedKeys: (number | string)[];
defaultExpandAll?: boolean;
menus: MenuOption[];
}>(),
{
/**
* 是否默认展开全部
*/
defaultExpandAll: true,
/**
* 注意这里不是双向绑定 需要调用getCheckedKeys实例方法来获取真正选中的节点
*/
checkedKeys: () => [],
},
);
/**
* 是否节点关联
*/
const association = defineModel('association', {
type: Boolean,
default: true,
});
const gridOptions: VxeGridProps = {
checkboxConfig: {
// checkbox显示的字段
labelField: 'label',
// 是否严格模式 即节点不关联
checkStrictly: !association.value,
},
size: 'small',
columns,
height: 'auto',
keepSource: true,
pagerConfig: {
enabled: false,
},
proxyConfig: {
enabled: false,
},
toolbarConfig: {
refresh: false,
custom: false,
},
rowConfig: {
isHover: false,
isCurrent: false,
keyField: 'id',
},
/**
* 开启虚拟滚动
* 数据量小可以选择关闭
* 如果遇到样式问题(空白、错位 滚动等)可以选择关闭虚拟滚动
*/
scrollY: {
enabled: true,
gt: 0,
},
treeConfig: {
parentField: 'parentId',
rowField: 'id',
transform: false,
},
// 溢出换行显示
showOverflow: false,
};
/**
* 用于界面显示选中的数量
*/
const checkedNum = ref(0);
/**
* 更新选中的数量
*/
function updateCheckedNumber() {
checkedNum.value = getCheckedKeys().length;
}
const [BasicTable, tableApi] = useVbenVxeGrid({
gridOptions,
gridEvents: {
// 勾选事件
checkboxChange: (params) => {
// 选中还是取消选中
const checked = params.checked;
// 行
const record = params.row;
if (association.value) {
// 节点关联
// 设置所有子节点选中状态
rowAndChildrenChecked(record, checked);
} else {
// 节点独立
// 点行会勾选/取消全部权限 点权限不会勾选行
setPermissionsChecked(record, checked);
}
updateCheckedNumber();
},
// 全选事件
checkboxAll: (params) => {
const records = params.$grid.getData();
records.forEach((item) => {
rowAndChildrenChecked(item, params.checked);
});
updateCheckedNumber();
},
},
});
/**
* 设置表格选中
* @param menus menu
* @param keys 选中的key
* @param triggerOnchange 节点独立情况 不需要触发onChange(false)
*/
function setCheckedByKeys(
menus: MenuPermissionOption[],
keys: (number | string)[],
triggerOnchange: boolean,
) {
menus.forEach((item) => {
// 设置行选中
if (keys.includes(item.id)) {
tableApi.grid.setCheckboxRow(item, true);
}
// 设置权限columns选中
if (item.permissions && item.permissions.length > 0) {
// 遍历 设置勾选
item.permissions.forEach((permission) => {
if (keys.includes(permission.id)) {
permission.checked = true;
// 手动触发onChange来选中 节点独立情况不需要处理
triggerOnchange && handlePermissionChange(item);
}
});
}
// 设置children选中
if (item.children && item.children.length > 0) {
setCheckedByKeys(item.children as any, keys, triggerOnchange);
}
});
}
const { FullScreenGuide, openGuide } = useFullScreenGuide();
onMounted(() => {
/**
* 加载表格数据 转为指定结构
*/
watch(
() => props.menus,
async (menus) => {
const clonedMenus = cloneDeep(menus);
menusWithPermissions(clonedMenus);
// console.log(clonedMenus);
await tableApi.grid.loadData(clonedMenus);
// 展开全部 默认true
if (props.defaultExpandAll) {
await nextTick();
setExpandOrCollapse(true);
}
},
);
/**
* 节点关联变动 更新表格勾选效果
*/
watch(association, (value) => {
tableApi.setGridOptions({
checkboxConfig: {
checkStrictly: !value,
},
});
});
/**
* checkedKeys依赖menus
* 要注意加载顺序
* !!!要在外部确保menus先加载!!!
*/
watch(
() => props.checkedKeys,
(value) => {
const allCheckedKeys = uniq([...value]);
// 获取表格data 如果checkedKeys在menus的watch之前触发 这里会拿到空 导致勾选异常
const records = tableApi.grid.getData();
setCheckedByKeys(records, allCheckedKeys, association.value);
updateCheckedNumber();
// 全屏引导
setTimeout(openGuide, 1000);
},
);
});
// 缓存上次(切换节点关系前)选中的keys
const lastCheckedKeys = shallowRef<(number | string)[]>([]);
/**
* 节点关联变动 事件
*/
async function handleAssociationChange(e: RadioChangeEvent) {
lastCheckedKeys.value = getCheckedKeys();
// 清空全部permissions选中
const records = tableApi.grid.getData();
records.forEach((item) => {
rowAndChildrenChecked(item, false);
});
// 需要清空全部勾选
await tableApi.grid.clearCheckboxRow();
// 滚动到顶部
await tableApi.grid.scrollTo(0, 0);
// 节点切换 不同的选中
setTableChecked(lastCheckedKeys.value, records, tableApi, !e.target.value);
updateCheckedNumber();
}
/**
* 全部展开/折叠
* @param expand 是否展开
*/
function setExpandOrCollapse(expand: boolean) {
tableApi.grid?.setAllTreeExpand(expand);
}
/**
* 权限列表 checkbox勾选的事件
* @param row 行
*/
function handlePermissionChange(row: any) {
// 节点关联
if (association.value) {
const checkedPermissions = row.permissions.filter(
(item: any) => item.checked === true,
);
// 有一条选中 则整个行选中
if (checkedPermissions.length > 0) {
tableApi.grid.setCheckboxRow(row, true);
}
// 无任何选中 则整个行不选中
if (checkedPermissions.length === 0) {
tableApi.grid.setCheckboxRow(row, false);
}
}
// 节点独立 不处理
updateCheckedNumber();
}
/**
* 获取勾选的key
* @param records 行记录列表
* @param addCurrent 是否添加当前行的id
*/
function getKeys(records: MenuPermissionOption[], addCurrent: boolean) {
const allKeys: (number | string)[] = [];
records.forEach((item) => {
// 处理children
if (item.children && item.children.length > 0) {
const keys = getKeys(item.children as MenuPermissionOption[], addCurrent);
allKeys.push(...keys);
} else {
// 当前行的id
addCurrent && allKeys.push(item.id);
// 当前行权限id 获取已经选中的
if (item.permissions && item.permissions.length > 0) {
const ids = item.permissions
.filter((m) => m.checked === true)
.map((m) => m.id);
allKeys.push(...ids);
}
}
});
return uniq(allKeys);
}
/**
* 获取选中的key
*/
function getCheckedKeys() {
// 节点关联
if (association.value) {
const records = tableApi?.grid?.getCheckboxRecords?.() ?? [];
// 子节点
const nodeKeys = getKeys(records, true);
// 所有父节点
const parentIds = findGroupParentIds(props.menus, nodeKeys as number[]);
// 拼接 去重
const realKeys = uniq([...parentIds, ...nodeKeys]);
return realKeys;
}
// 节点独立
// 勾选的行
const records = tableApi?.grid?.getCheckboxRecords?.() ?? [];
// 全部数据 用于获取permissions
const allRecords = tableApi?.grid?.getData?.() ?? [];
// 表格已经选中的行ids
const checkedIds = records.map((item) => item.id);
// 所有已经勾选权限的ids
const permissionIds = getKeys(allRecords, false);
// 合并 去重
const allIds = uniq([...checkedIds, ...permissionIds]);
return allIds;
}
/**
* 暴露给外部使用 获取已选中的key
*/
defineExpose({
getCheckedKeys,
});
</script>
<template>
<div class="flex h-full flex-col" id="menu-select-table">
<BasicTable>
<template #toolbar-actions>
<RadioGroup
v-model:value="association"
:options="nodeOptions"
button-style="solid"
option-type="button"
@change="handleAssociationChange"
/>
<Alert class="mx-2" type="info">
<template #message>
<div>
已选中
<span class="text-primary mx-1 font-semibold">
{{ checkedNum }}
</span>
个节点
</div>
</template>
</Alert>
</template>
<template #toolbar-tools>
<Space>
<a-button @click="setExpandOrCollapse(false)">
{{ $t('pages.common.collapse') }}
</a-button>
<a-button @click="setExpandOrCollapse(true)">
{{ $t('pages.common.expand') }}
</a-button>
</Space>
</template>
<template #permissions="{ row }">
<div class="flex flex-wrap gap-x-3 gap-y-1">
<Checkbox
v-for="permission in row.permissions"
:key="permission.id"
v-model:checked="permission.checked"
@change="() => handlePermissionChange(row)"
>
{{ permission.label }}
</Checkbox>
</div>
</template>
</BasicTable>
<!-- 全屏引导 -->
<FullScreenGuide />
</div>
</template>
<style scoped>
:deep(.ant-alert) {
padding: 4px 8px;
}
</style>

View File

@@ -3,11 +3,14 @@ import type { CheckboxChangeEvent } from 'ant-design-vue/es/checkbox/interface';
import type { DataNode } from 'ant-design-vue/es/tree';
import type { CheckInfo } from 'ant-design-vue/es/vc-tree/props';
import { computed, nextTick, onMounted, type PropType, ref, watch } from 'vue';
import type { PropType, SetupContext } from 'vue';
import { computed, nextTick, onMounted, ref, useSlots, watch } from 'vue';
import { findGroupParentIds, treeToList } from '@vben/utils';
import { Checkbox, Tree } from 'ant-design-vue';
import { uniq } from 'lodash-es';
/** 需要禁止透传 */
defineOptions({ inheritAttrs: false });
@@ -73,6 +76,8 @@ const checkedRealKeys = ref<(number | string)[]>([]);
/**
* 取第一次的menuTree id 设置到checkedMenuKeys
* 主要为了解决没有任何修改 直接点击保存的情况
*
* length为0情况(即新增时候没有勾选节点) 勾选这里会延迟触发 节点会拼接上父节点 导致ID重复
*/
const stop = watch([checkedKeys, () => props.treeData], () => {
if (
@@ -86,7 +91,10 @@ const stop = watch([checkedKeys, () => props.treeData], () => {
checkedKeys.value as any,
{ id: props.fieldNames.key },
);
checkedRealKeys.value = [...parentIds, ...checkedKeys.value];
/**
* uniq 解决上面的id重复问题
*/
checkedRealKeys.value = uniq([...parentIds, ...checkedKeys.value]);
stop();
}
if (!props.checkStrictly && checkedKeys.value.length > 0) {
@@ -98,19 +106,21 @@ const stop = watch([checkedKeys, () => props.treeData], () => {
/**
*
* @param checkedKeys 已经选中的子节点的ID
* @param checkedStateKeys 已经选中的子节点的ID
* @param info info.halfCheckedKeys为父节点的ID
*/
type CheckedState<T = number | string> =
| { checked: T[]; halfChecked: T[] }
| T[];
function handleChecked(checkedKeys: CheckedState, info: CheckInfo) {
| T[]
| { checked: T[]; halfChecked: T[] };
function handleChecked(checkedStateKeys: CheckedState, info: CheckInfo) {
// 数组的话为节点关联
if (Array.isArray(checkedKeys)) {
if (Array.isArray(checkedStateKeys)) {
const halfCheckedKeys: number[] = (info.halfCheckedKeys || []) as number[];
checkedRealKeys.value = [...halfCheckedKeys, ...checkedKeys];
checkedRealKeys.value = [...halfCheckedKeys, ...checkedStateKeys];
} else {
checkedRealKeys.value = [...checkedKeys.checked];
checkedRealKeys.value = [...checkedStateKeys.checked];
// fix: Invalid prop: type check failed for prop "value". Expected Array, got Object
checkedKeys.value = [...checkedStateKeys.checked];
}
}
@@ -137,9 +147,10 @@ function handleCheckStrictlyChange(e: CheckboxChangeEvent) {
/**
* 暴露方法来获取用于提交的全部节点
* uniq去重(保险方案)
*/
defineExpose({
getCheckedKeys: () => checkedRealKeys.value,
getCheckedKeys: () => uniq(checkedRealKeys.value),
});
onMounted(async () => {
@@ -148,6 +159,8 @@ onMounted(async () => {
expandedKeys.value = allKeys.value;
}
});
const slots = useSlots() as SetupContext['slots'];
</script>
<template>
@@ -196,7 +209,7 @@ onMounted(async () => {
@check="handleChecked"
>
<template
v-for="slotName in Object.keys($slots)"
v-for="slotName in Object.keys(slots)"
:key="slotName"
#[slotName]="data"
>

View File

@@ -2,6 +2,10 @@
import type { UploadFile, UploadProps } from 'ant-design-vue';
import type { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
import type { AxiosResponse } from '@vben/request';
import type { AxiosProgressEvent } from '#/api';
import { ref, toRefs, watch } from 'vue';
import { $t } from '@vben/locales';
@@ -26,7 +30,10 @@ const props = withDefaults(
* 需自行改造 ./helper/checkFileType方法
*/
accept?: string[];
api?: (...args: any[]) => Promise<any>;
api?: (
file: Blob | File,
onUploadProgress?: AxiosProgressEvent,
) => Promise<AxiosResponse<any>>;
disabled?: boolean;
helpText?: string;
// 最大数量的文件Infinity不限制
@@ -38,6 +45,10 @@ const props = withDefaults(
// support xxx.xxx.xx
// 返回的字段 默认url
resultField?: 'fileName' | 'ossId' | 'url' | string;
/**
* 是否显示下面的描述
*/
showDescription?: boolean;
value?: string[];
}>(),
{
@@ -50,6 +61,7 @@ const props = withDefaults(
multiple: false,
api: uploadApi,
resultField: '',
showDescription: true,
},
);
const emit = defineEmits(['change', 'update:value', 'delete']);
@@ -144,12 +156,19 @@ async function customRequest(info: UploadRequestOption<any>) {
return;
}
try {
const res = await api?.(info.file);
// 进度条事件
const progressEvent: AxiosProgressEvent = (e) => {
const percent = Math.trunc((e.loaded / e.total!) * 100);
info.onProgress!({ percent });
};
const res = await api?.(info.file as File, progressEvent);
/**
* 由getValue处理 传对象过去
* 直接传string(id)会被转为Number
* 内部的逻辑由requestClient.upload处理 这里不用判断业务状态码 不符合会自动reject
*/
info.onSuccess!(res);
message.success($t('component.upload.uploadSuccess'));
// 获取
const value = getValue();
isInnerOperate.value = true;
@@ -191,6 +210,7 @@ function getValue() {
:max-count="maxNumber"
:multiple="multiple"
list-type="text"
:progress="{ showInfo: true }"
@remove="handleRemove"
>
<div v-if="fileList && fileList.length < maxNumber">
@@ -199,14 +219,21 @@ function getValue() {
{{ $t('component.upload.upload') }}
</a-button>
</div>
<div v-if="showDescription" class="mt-2 flex flex-wrap items-center">
请上传不超过
<div class="text-primary mx-1 font-bold">{{ maxSize }}MB</div>
<div class="text-primary mx-1 font-bold">{{ accept.join('/') }}</div>
格式文件
</div>
</Upload>
</div>
</template>
<style lang="less">
<style>
.ant-upload-select-picture-card i {
color: #999;
font-size: 32px;
color: #999;
}
.ant-upload-select-picture-card .ant-upload-text {

View File

@@ -2,15 +2,20 @@
import type { UploadFile, UploadProps } from 'ant-design-vue';
import type { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
import type { AxiosResponse } from '@vben/request';
import type { AxiosProgressEvent } from '#/api';
import { ref, toRefs, watch } from 'vue';
import { $t } from '@vben/locales';
import { PlusOutlined } from '@ant-design/icons-vue';
import { message, Modal, Upload } from 'ant-design-vue';
import { isArray, isFunction, isObject, isString } from 'lodash-es';
import { isArray, isFunction, isObject, isString, uniqueId } from 'lodash-es';
import { uploadApi } from '#/api';
import { ossInfo } from '#/api/system/oss';
import { checkImageFileType, defaultImageAccept } from './helper';
import { UploadResultStatus } from './typing';
@@ -24,7 +29,10 @@ const props = withDefaults(
* 包括拓展名(不带点) 文件头(image/png等 不包括泛写法即image/*)
*/
accept?: string[];
api?: (...args: any[]) => Promise<any>;
api?: (
file: Blob | File,
onUploadProgress?: AxiosProgressEvent,
) => Promise<AxiosResponse<any>>;
disabled?: boolean;
helpText?: string;
// eslint-disable-next-line no-use-before-define
@@ -37,7 +45,11 @@ const props = withDefaults(
multiple?: boolean;
// support xxx.xxx.xx
// 返回的字段 默认url
resultField?: 'fileName' | 'ossId' | 'url' | string;
resultField?: 'fileName' | 'ossId' | 'url';
/**
* 是否显示下面的描述
*/
showDescription?: boolean;
value?: string | string[];
}>(),
{
@@ -50,7 +62,8 @@ const props = withDefaults(
accept: () => defaultImageAccept,
multiple: false,
api: uploadApi,
resultField: '',
resultField: 'url',
showDescription: true,
},
);
const emit = defineEmits(['change', 'update:value', 'delete']);
@@ -74,7 +87,7 @@ const isFirstRender = ref<boolean>(true);
watch(
() => props.value,
(v) => {
async (v) => {
if (isInnerOperate.value) {
isInnerOperate.value = false;
return;
@@ -90,19 +103,40 @@ watch(
}
// 直接赋值 可能为string | string[]
value = v;
fileList.value = _fileList.map((item, i) => {
if (item && isString(item)) {
return {
uid: `${-i}`,
name: item.slice(Math.max(0, item.lastIndexOf('/') + 1)),
status: 'done',
url: item,
};
} else if (item && isObject(item)) {
return item;
const withUrlList: UploadProps['fileList'] = [];
for (const item of _fileList) {
// ossId情况
if (props.resultField === 'ossId') {
const resp = await ossInfo([item]);
if (item && isString(item)) {
withUrlList.push({
uid: item, // ossId作为uid 方便getValue获取
name: item.slice(Math.max(0, item.lastIndexOf('/') + 1)),
status: 'done',
url: resp?.[0]?.url,
});
} else if (item && isObject(item)) {
withUrlList.push({
...(item as any),
uid: item,
url: resp?.[0]?.url,
});
}
} else {
// 非ossId情况
if (item && isString(item)) {
withUrlList.push({
uid: uniqueId(),
name: item.slice(Math.max(0, item.lastIndexOf('/') + 1)),
status: 'done',
url: item,
});
} else if (item && isObject(item)) {
withUrlList.push(item);
}
}
return null;
}) as UploadProps['fileList'];
}
fileList.value = withUrlList;
}
if (!isFirstRender.value) {
emit('change', value);
@@ -182,12 +216,19 @@ async function customRequest(info: UploadRequestOption<any>) {
return;
}
try {
const res = await api?.(info.file);
// 进度条事件
const progressEvent: AxiosProgressEvent = (e) => {
const percent = Math.trunc((e.loaded / e.total!) * 100);
info.onProgress!({ percent });
};
const res = await api?.(info.file as File, progressEvent);
/**
* 由getValue处理 传对象过去
* 直接传string(id)会被转为Number
* 内部的逻辑由requestClient.upload处理 这里不用判断业务状态码 不符合会自动reject
*/
info.onSuccess!(res);
message.success($t('component.upload.uploadSuccess'));
// 获取
const value = getValue();
isInnerOperate.value = true;
@@ -200,12 +241,17 @@ async function customRequest(info: UploadRequestOption<any>) {
}
function getValue() {
console.log(fileList.value);
const list = (fileList.value || [])
.filter((item) => item?.status === UploadResultStatus.DONE)
.map((item: any) => {
if (item?.response && props?.resultField) {
return item?.response?.[props.resultField];
}
// ossId兼容 uid为ossId直接返回
if (props.resultField === 'ossId' && item.uid) {
return item.uid;
}
// 适用于已经有图片 回显的情况 会默认在init处理为{url: 'xx'}
if (item?.url) {
return item.url;
@@ -237,6 +283,7 @@ function getValue() {
:list-type="listType"
:max-count="maxNumber"
:multiple="multiple"
:progress="{ showInfo: true }"
@preview="handlePreview"
@remove="handleRemove"
>
@@ -245,6 +292,16 @@ function getValue() {
<div style="margin-top: 8px">{{ $t('component.upload.upload') }}</div>
</div>
</Upload>
<div
v-if="showDescription"
class="mt-2 flex flex-wrap items-center text-[14px]"
>
请上传不超过
<div class="text-primary mx-1 font-bold">{{ maxSize }}MB</div>
<div class="text-primary mx-1 font-bold">{{ accept.join('/') }}</div>
格式文件
</div>
<Modal
:footer="null"
:open="previewOpen"
@@ -256,10 +313,10 @@ function getValue() {
</div>
</template>
<style lang="less">
<style>
.ant-upload-select-picture-card i {
color: #999;
font-size: 32px;
color: #999;
}
.ant-upload-select-picture-card .ant-upload-text {

View File

@@ -15,7 +15,7 @@ export interface FileItem {
percent: number;
file: File;
status?: UploadResultStatus;
response?: { fileName: string; ossId: string; url: string } | Recordable<any>;
response?: Recordable<any> | { fileName: string; ossId: string; url: string };
uuid: string;
}

View File

@@ -1,6 +1,7 @@
import { computed, unref } from 'vue';
import type { Ref } from 'vue';
import { computed, unref } from 'vue';
import { $t } from '@vben/locales';
export function useUploadType({

View File

@@ -1,5 +1,5 @@
<script lang="ts" setup>
import { computed, onMounted, watch } from 'vue';
import { computed, h, onMounted, watch } from 'vue';
import { useRouter } from 'vue-router';
import { AuthenticationLoginExpiredModal } from '@vben/common-ui';
@@ -8,6 +8,7 @@ import { useWatermark } from '@vben/hooks';
import {
BookOpenText,
CircleHelp,
GiteeIcon,
GitHubOutlined,
UserOutlined,
} from '@vben/icons';
@@ -55,6 +56,15 @@ const menus = computed(() => {
icon: UserOutlined,
text: $t('ui.widgets.profile'),
},
{
handler: () => {
openWindow('https://gitee.com/dapppp/ruoyi-plus-vben5', {
target: '_blank',
});
},
icon: () => h(GiteeIcon, { class: 'text-red-800' }),
text: 'Gitee项目地址',
},
{
handler: () => {
openWindow(VBEN_GITHUB_URL, {
@@ -62,7 +72,7 @@ const menus = computed(() => {
});
},
icon: GitHubOutlined,
text: 'GitHub',
text: 'Vben官方地址',
},
{
handler: () => {
@@ -84,11 +94,14 @@ const menus = computed(() => {
});
const avatar = computed(() => {
return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;
return userStore.userInfo?.avatar || preferences.app.defaultAvatar;
});
async function handleLogout() {
await authStore.logout();
/**
* 主动登出不需要带跳转地址
*/
await authStore.logout(false);
resetRoutes();
}

View File

@@ -1,7 +1,9 @@
import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';
import type { Locale } from 'ant-design-vue/es/locale';
import type { App } from 'vue';
import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';
import { ref } from 'vue';
import {
@@ -30,7 +32,8 @@ const localesMap = loadLocalesMapFromDir(
*/
async function loadMessages(lang: SupportedLanguagesType) {
const [appLocaleMessages] = await Promise.all([
localesMap[lang](),
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
localesMap[lang]!(),
loadThirdPartyMessage(lang),
]);
return appLocaleMessages.default;

View File

@@ -0,0 +1,7 @@
{
"apiRequestFailed": "Operation failed",
"operationSuccess": "Operation Success",
"successTip": "Success Tip",
"errorTip": "Error Tip",
"loginTimeout": "Login timeout, please log in again"
}

View File

@@ -0,0 +1,7 @@
{
"apiRequestFailed": "请求出错,请稍候重试",
"operationSuccess": "操作成功",
"successTip": "成功提示",
"errorTip": "错误提示",
"loginTimeout": "登录超时, 请重新登录"
}

View File

@@ -47,4 +47,18 @@ export const overridesPreferences = defineOverridesPreferences({
*/
semiDarkSidebar: false,
},
/**
* !!! 更改配置后请清空浏览器缓存
* 在这里更换logo
* source可选值
* 1. 本地public目录下的图片 需要加上/ 比如:/logo.png
* 2. 网络图片链接
* 3. vite导入的图片 import xxx from 'xxx.png'
*
* !!! 更改配置后请清空浏览器缓存
*/
// logo: {
// enable: true,
// source: '',
// },
});

View File

@@ -4,13 +4,15 @@ import type {
RouteRecordStringComponent,
} from '@vben/types';
import type { Menu } from '#/api';
import { generateAccessible } from '@vben/access';
import { preferences } from '@vben/preferences';
import { message } from 'ant-design-vue';
import { cloneDeep } from 'lodash-es';
import { getAllMenusApi, type Menu } from '#/api';
import { getAllMenusApi } from '#/api';
import { BasicLayout, IFrameView } from '#/layouts';
import { $t } from '#/locales';
@@ -207,7 +209,7 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) {
const vbenMenuList = backMenuToVbenMenu(backMenuList);
// 特别注意 这里要深拷贝
const menuList = [...cloneDeep(localMenuList), ...vbenMenuList];
console.log('menuList', menuList);
// console.log('menuList', menuList);
return menuList;
},
// 可以指定没有权限跳转403页面

View File

@@ -54,7 +54,9 @@ function setupAccessGuard(router: Router) {
if (coreRouteNames.includes(to.name as string)) {
if (to.path === LOGIN_PATH && accessStore.accessToken) {
return decodeURIComponent(
(to.query?.redirect as string) || DEFAULT_HOME_PATH,
(to.query?.redirect as string) ||
userStore.userInfo?.homePath ||
DEFAULT_HOME_PATH,
);
}
return true;
@@ -72,7 +74,10 @@ function setupAccessGuard(router: Router) {
return {
path: LOGIN_PATH,
// 如不需要,直接删除 query
query: { redirect: encodeURIComponent(to.fullPath) },
query:
to.fullPath === DEFAULT_HOME_PATH
? {}
: { redirect: encodeURIComponent(to.fullPath) },
// 携带当前跳转的页面,登录后重新跳转该页面
replace: true,
};
@@ -102,7 +107,10 @@ function setupAccessGuard(router: Router) {
accessStore.setAccessMenus(accessibleMenus);
accessStore.setAccessRoutes(accessibleRoutes);
accessStore.setIsAccessChecked(true);
const redirectPath = (from.query.redirect ?? to.fullPath) as string;
const redirectPath = (from.query.redirect ??
(to.path === DEFAULT_HOME_PATH
? userInfo.homePath || DEFAULT_HOME_PATH
: to.fullPath)) as string;
return {
...router.resolve(decodeURIComponent(redirectPath)),

View File

@@ -2,7 +2,7 @@ import type { RouteRecordRaw } from 'vue-router';
import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
import { AuthPageLayout } from '#/layouts';
import { AuthPageLayout, BasicLayout } from '#/layouts';
import { $t } from '#/locales';
import Login from '#/views/_core/authentication/login.vue';
@@ -21,13 +21,21 @@ const fallbackNotFoundRoute: RouteRecordRaw = {
/** 基本路由,这些路由是必须存在的 */
const coreRoutes: RouteRecordRaw[] = [
/**
* 根路由
* 使用基础布局作为所有页面的父级容器子级就不必配置BasicLayout。
* 此路由必须存在,且不应修改
*/
{
component: BasicLayout,
meta: {
hideInBreadcrumb: true,
title: 'Root',
},
name: 'Root',
path: '/',
redirect: DEFAULT_HOME_PATH,
children: [],
},
{
component: () => import('#/views/_core/social-callback/index.vue'),

View File

@@ -3,6 +3,7 @@ import type { RouteRecordRaw } from 'vue-router';
import { mergeRouteModules, traverseTreeValues } from '@vben/utils';
import { coreRoutes, fallbackNotFoundRoute } from './core';
import { workflowIframeRoutes } from './workflow-iframe';
const dynamicRouteFiles = import.meta.glob('./modules/**/*.ts', {
eager: true,
@@ -17,20 +18,24 @@ const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);
/** 外部路由列表访问这些页面可以不需要Layout可能用于内嵌在别的系统(不会显示在菜单中) */
// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles);
/** 不需要权限的菜单列表(会显示在菜单中) */
// const staticRoutes: RouteRecordRaw[] = mergeRouteModules(staticRouteFiles);
const staticRoutes: RouteRecordRaw[] = [];
const externalRoutes: RouteRecordRaw[] = [];
/** 路由列表,由基本路由+静态路由组成 */
/** 路由列表,由基本路由、外部路由和404兜底路由组成
* 无需走权限验证(会一直显示在菜单中) */
const routes: RouteRecordRaw[] = [
...coreRoutes,
...externalRoutes,
...workflowIframeRoutes,
fallbackNotFoundRoute,
];
/** 基本路由(登录, 第三方登录, 注册等) + workflowIframe路由不需要拦截 */
const basicRoutes = [...coreRoutes, ...workflowIframeRoutes];
/** 基本路由列表,这些路由不需要进入权限拦截 */
const coreRouteNames = traverseTreeValues(coreRoutes, (route) => route.name);
const coreRouteNames = traverseTreeValues(basicRoutes, (route) => route.name);
/** 有权限校验的路由列表,包含动态路由和静态路由 */
const accessRoutes = [...dynamicRoutes, ...staticRoutes];
export { accessRoutes, coreRouteNames, routes };

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