211 Commits
Author SHA1 Message Date
YunaiV 40a93caf89 发布 1.8.0 版本 2023-07-27 07:59:57 +08:00
芋道源码 b41d8f06ce !184 同步最新商城实现
Merge pull request !184 from 芋道源码/dev
2023-07-26 23:32:27 +00:00
YunaiV a003b59e39 review 秒杀、拼团活动的 CRUD 2023-07-26 19:22:26 +08:00
芋道源码 d7f0554f97 !179 完成拼团活动和秒杀活动相关表单操作和列表展示
Merge pull request !179 from puhui999/dev-to-dev
2023-07-26 04:59:47 +00:00
芋道源码 f908c12963 !183 同步商城实现
Merge pull request !183 from 芋道源码/dev
2023-07-26 04:56:22 +00:00
芋道源码 59de1d68ba !182 update src/views/Login/components/MobileForm.vue.
Merge pull request !182 from water/N/A
2023-07-26 04:52:34 +00:00
芋道源码 399d8af0b1 !180 定时任务,删除功能报错
Merge pull request !180 from 死歌/master
2023-07-26 04:50:22 +00:00
puhui999 dc39ad0cd1 fix: 完善拼团活动 CRUD 2023-07-14 17:35:35 +08:00
water b061c8f32b update src/views/Login/components/MobileForm.vue.
我发现,这个手机号登陆时,登陆成功了但是没有自动跳转,我手动路由到/,又自动跳转到登陆页面,应该是token没存进去,我就照这loginform的逻辑修改了一下

Signed-off-by: water <2778335106@qq.com>
2023-07-12 07:35:48 +00:00
蔚文纲 51198e12a2 fix: 修复src/views.infra/job/index中删除按钮因为传参错误导致删除功能报错 2023-07-10 17:51:10 +08:00
puhui999 3fd9f1b43e fix: mall SeckillConfig 2023-07-10 16:39:22 +08:00
xingyu 44efb13c0e fix: login error 2023-07-10 11:16:42 +08:00
xingyu ba1254f397 fix: eslint 2023-07-08 11:13:36 +08:00
xingyu 540d8496b3 chore: update deps 2023-07-08 11:13:28 +08:00
puhui999 b67fabcf1f fix: mall SeckillActivity 2023-07-05 22:26:18 +08:00
puhui999 4057130275 fix: mall SeckillActivity and CombinationActivity 2023-07-05 18:24:32 +08:00
puhui999 ce3ca7c6ce fix: mall SeckillActivity 2023-07-05 17:12:53 +08:00
puhui999 36c0bce184 fix: mall SeckillActivity 2023-07-05 11:32:32 +08:00
puhui999 b98149f1a7 fix: mall SeckillActivity 2023-07-03 12:07:19 +08:00
puhui999 a5330958ba Merge remote-tracking branch 'yudao/dev' into dev-to-dev 2023-07-03 07:59:34 +08:00
YunaiV c85c57ce9a Merge branch 'master' of https://github.com/yudaocode/yudao-ui-admin-vue3 2023-07-02 23:27:19 +08:00
芋道源码 13e0ede788 !155 fix: 处理 window.bpmnInstances 有时候为 undefined 问题
Merge pull request !155 from OlyLis/master
2023-07-02 15:23:12 +00:00
YunaiV 4571f893ed review 积分配置 2023-07-02 23:18:45 +08:00
芋道源码 032d5a0a06 !178 会员中心(积分、签到)优化
Merge pull request !178 from QingX/dev
2023-07-02 13:48:08 +00:00
YunaiV b1ce2672e4 review 秒杀活动 2023-07-02 21:46:04 +08:00
芋道源码 a6fc5f775a !176 mall seckillActivity
Merge pull request !176 from puhui999/dev-to-dev
2023-07-02 12:40:33 +00:00
芋道源码 c0bf357d7a !177 修复useTable在total为0时的bug
Merge pull request !177 from nullcache/bug/add-fix-useTable
2023-07-02 12:40:04 +00:00
芋道源码 9f8e12de51 Merge pull request #10 from nullcache/bug/add-fix-useTable
修复useTable在total为0时的bug
2023-07-02 20:38:29 +08:00
puhui999 2e96b1c984 feat: mall CombinationActivity 2023-07-02 19:22:57 +08:00
xiaqing 4251dc5d61 会员中心代码
1.合并积分模块只member module
3.添加会员中/会员积分、会员签到/xxx层级目录
4.删除无用的接口代码
2023-06-28 22:50:31 +08:00
nullcache 073679875b 修复useTable在total为0时的bug 2023-06-27 04:06:01 +00:00
nullcache 69c4995b52 修复useTable在total为0时的bug 2023-06-27 11:54:59 +08:00
puhui999 341303b014 fix: 完善 mall seckillActivity add 2023-06-25 17:16:26 +08:00
puhui999 51e79f29cc fix: 封装 SpuSelect SpuAndSkuList 为商品活动商品选择商品编辑通用组件 2023-06-25 16:43:49 +08:00
puhui999 76ccc54a35 fix: 修复 spu 详情查看错误,同步 mall seckill 组件 name 配置方式 2023-06-25 09:35:20 +08:00
YunaiV 5d613e69b3 review 营销活动 2023-06-24 18:53:57 +08:00
芋道源码 fa71d3e7dd !175 mall seckill
Merge pull request !175 from puhui999/dev-to-dev
2023-06-24 04:57:14 +00:00
puhui999 c9ae0fbdbe Merge remote-tracking branch 'yudao/dev' into dev-to-dev 2023-06-24 01:48:36 +08:00
puhui999 b1e7f14963 fix:完善秒杀活动管理① 2023-06-24 01:48:07 +08:00
YunaiV 0395b8f138 review 订单 2023-06-23 21:28:41 +08:00
芋道源码 70a6d28edd !174 订单列表和详情 页面
Merge pull request !174 from 矿泉水/dev
2023-06-23 13:23:02 +00:00
YunaiV e1b1c134d9 合并 master 代码的冲突 2023-06-23 14:08:09 +08:00
YunaiV b159240824 Merge branch 'master' of https://gitee.com/yudaocode/yudao-ui-admin-vue3 into dev
 Conflicts:
	src/views/infra/build/index.vue
	src/views/mall/product/spu/components/DescriptionForm.vue
	src/views/mall/product/spu/components/OtherSettingsForm.vue
	src/views/mall/product/spu/components/ProductPropertyAddForm.vue
	src/views/mall/product/spu/components/SkuList.vue
2023-06-23 13:54:43 +08:00
puhui999 3d47d6744e feat:添加秒杀活动管理 2023-06-22 17:31:36 +08:00
xingyu c1a4edf7b1 refactor: 统一 setup 格式 2023-06-21 19:35:11 +08:00
xingyu 9ac17b3ce2 chore: build size 2023-06-21 19:27:27 +08:00
xingyu 82c51e0c3e fix: eslint 2023-06-21 19:27:16 +08:00
xingyu d639401646 fix: style lint 2023-06-21 19:26:14 +08:00
xingyu 64dbcdabe0 docs: version 2023-06-21 19:24:14 +08:00
xingyu 33c460ad55 chore: remove vueSetupExtend 2023-06-21 19:24:09 +08:00
xingyu f2992ce8e8 fix: eslint 2023-06-21 19:18:05 +08:00
xingyu 922f83d99c refactor: vue3.3 defineOptions 2023-06-21 19:14:34 +08:00
puhui999 f3622d423a fix: 使 Table 组件支持列宽和固定列配置 2023-06-21 15:27:35 +08:00
puhui999 5064845d4e fix: 使 Dialog 组件支持 Dialog 内部嵌套另一个 Dialog,需要使用 append-to-body 属性 2023-06-21 15:26:43 +08:00
xingyu a5c7c886ee chore: stylelint 2023-06-21 11:15:30 +08:00
xingyu c05fbd7fdc fix: locales 2023-06-21 11:10:15 +08:00
xingyu 952f7b6268 chore: vscode setting 2023-06-21 11:07:46 +08:00
xingyu 37c41aeecc chore: eslint 2023-06-21 11:07:33 +08:00
xingyu 3d39b42e96 chore: eslint 2023-06-21 10:55:37 +08:00
xingyu 2df15acb26 chore: vscode setting use pnpm 2023-06-21 10:50:03 +08:00
xingyu 458bb22163 docs: readme 2023-06-21 10:48:18 +08:00
xingyu ca8238a84b chore: packageManager use pnpm 2023-06-21 10:45:35 +08:00
xingyu 91a015828d chore: update deps 2023-06-21 10:44:39 +08:00
xiaobai ca01b16096 提交订单列表和详情20230619 2023-06-19 15:57:20 +08:00
xiaobai 42a7aec0b5 提交订单页面和详情页面 20230619 2023-06-19 12:42:43 +08:00
puhui999 f7b195b226 feat: 完事秒杀时段管理 2023-06-19 10:20:43 +08:00
puhui999 ee698fd8b2 Merge remote-tracking branch 'yudao/dev' into dev-to-dev 2023-06-17 21:21:33 +08:00
puhui999 a75720ec06 feat: 秒杀时段管理 2023-06-17 21:20:28 +08:00
YunaiV 91c53e2e3f code review:订单详情 2023-06-17 21:12:20 +08:00
YunaiV e3f250fff0 code review:订单列表 2023-06-17 21:02:29 +08:00
芋道源码 867c47de61 !165 trade-order 列表和详情初版
Merge pull request !165 from 矿泉水/dev
2023-06-17 11:04:12 +00:00
芋道源码 1e49a8eaf0 !170 Expiration time should not set on the refresh token
Merge pull request !170 from 呵呵大/N/A
2023-06-17 11:02:27 +00:00
芋道源码 226cc03d65 !167 修复授权类型选项bug
Merge pull request !167 from wangzhaoqiang/dev_
2023-06-17 10:57:00 +00:00
YunaiV 467256cece 修复 SmsChannelForm.vue 排版报错问题 2023-06-17 18:54:57 +08:00
YunaiV ae69492b53 code review:spu todo 去掉 2023-06-17 18:48:49 +08:00
芋道源码 8ed92bcd46 !166 短信渠道提交失败
Merge pull request !166 from 圆梦巨人/master
2023-06-17 10:48:26 +00:00
YunaiV 7908160e68 Merge branch 'dev-to-dev' of https://gitee.com/puhui999/yudao-ui-admin-vue3 into dev
 Conflicts:
	src/utils/dict.ts
2023-06-17 18:45:05 +08:00
YunaiV 5eaf054646 code review:会员积分配置 2023-06-17 18:33:07 +08:00
YunaiV 023539b0db Merge branch 'master' of https://gitee.com/yudaocode/yudao-ui-admin-vue3 into dev
 Conflicts:
	package.json
	src/utils/dict.ts
2023-06-17 17:40:29 +08:00
YunaiV 8666307d47 code review:处理字典数据的冲突 2023-06-17 17:38:20 +08:00
芋道源码 b809945c19 !171 积分模块
Merge pull request !171 from QingX/master
2023-06-17 09:37:15 +00:00
xiaqing 1dca8476b3 初始化积分模块
1.积分设置管理
2.积分签到规则管理
3.用户积分记录管理
4.用户签到积分管理
2023-06-10 20:57:16 +08:00
呵呵大 5554d7c995 Expiration time should not set on the refresh token
登录接口返回的过期时间是`access token` 的过期时间,但是被错误地设置在了`refresh token` 上,这导致过了几分钟登录状态便失效要求重新登录
2023-06-10 03:19:03 +00:00
wangzhaoqiang 119b499a92 修复授权类型选项bug 2023-06-08 16:25:32 +08:00
puhui999 d31ade7a5f fix: 完善 SPU 相关路由 review 2023-06-07 18:31:28 +08:00
lwf bc34a73c9e 短信渠道提交失败 2023-06-07 13:45:33 +08:00
puhui999 20f3f72670 fix: 数组操作添加 ? 可选操作符,避免属性值为 null 时报错 2023-06-07 08:59:03 +08:00
puhui999 b89db1af55 fix: review 2023-06-06 16:22:58 +08:00
xiaobai e2d795f49d add trade order 20230606 2023-06-06 01:36:22 +08:00
xiaobai ec3b028d55 sync dev-20230606 2023-06-06 01:25:22 +08:00
xiaobai 985d764f62 20230606 add trade-order and details 2023-06-06 01:08:38 +08:00
puhui999 7fe8dee9ed Merge remote-tracking branch 'yudao/dev' into dev-to-dev 2023-06-05 08:35:39 +08:00
YunaiV 51e76ffd53 code review:优惠劵管理 2023-06-03 23:15:11 +08:00
芋道源码 7c6d7e8061 !164 优惠券迁移vue3
Merge pull request !164 from dhb52/dev
2023-06-03 15:02:05 +00:00
puhui999 a1b45f80bc fix: 优化 spu 相关路由配置 2023-06-03 21:21:43 +08:00
YunaiV 158585670c code review:商品管理 2023-06-03 20:50:07 +08:00
芋道源码 541b23c8c1 !159 完善商品查看详情,修改了一些问题
Merge pull request !159 from puhui999/dev-to-dev
2023-06-03 12:09:43 +00:00
YunaiV 60c1604d49 code review:门店自提、快递运费 2023-06-03 19:52:14 +08:00
xiaobai 505f5cfa0c 临时提交 2023-06-02 16:10:33 +08:00
dhb52 c5a7d05821 style: 添加VO 2023-06-01 18:08:23 +08:00
puhui999 91a5f8044c Merge remote-tracking branch 'yudao/dev' into dev-to-dev 2023-06-01 11:55:22 +08:00
puhui999 7fb6258bed fix: 修复善品测试发现的问题 2023-06-01 11:54:39 +08:00
puhui999 6a10a81f58 fix: 引入 v-dompurify-html 指令解决 v-html 的安全隐患 2023-05-31 15:58:35 +08:00
puhui999 2ddb605076 fix: 完善 SPU 选择快递模版的功能 2023-05-31 15:37:26 +08:00
puhui999 39c92cb944 fix: 完善 SPU 查看详情 2023-05-31 14:42:45 +08:00
jason 000aa95012 新增门店自提管理 2023-05-30 21:21:04 +08:00
puhui999 e555977757 fix: 修改 review 提到的问题,完善分类选择层级校验、完整层级展示 2023-05-30 18:14:40 +08:00
puhui999 820d8ab76a fix: pnpm 仓库中没有 video.js 8.0.4 这个版本,更改为 8.3.0 2023-05-30 10:00:04 +08:00
YunaiV 3e549a6862 v1.7.3 版本发布! 2023-05-29 23:04:11 +08:00
芋道源码 fa6bcacaef !157 合并商城部分功能
Merge pull request !157 from 芋道源码/dev
2023-05-29 15:03:34 +00:00
YunaiV ee12fa01c9 Merge branch 'master' of https://github.com/yudaocode/yudao-ui-admin-vue3
 Conflicts:
	package.json
2023-05-29 22:34:07 +08:00
芋道源码 20426c43e3 !156 新增 路由搜索
Merge pull request !156 from 卡农ding/addRouterSearch
2023-05-29 14:33:03 +00:00
芋道源码 22c022bf90 Merge pull request #8 from HarryQQ/master
fix: 解决vue版本与pinia版本兼容问题
2023-05-29 22:31:56 +08:00
芋道源码 22eeb9c7c8 Merge pull request #9 from cn3lfs/master
fix: 公告内容不能为空
2023-05-29 22:29:05 +08:00
lour6498 257ad9f79f fix: 公告内容不能为空 2023-05-29 18:44:55 +08:00
dhb52 c3b0403ade Merge remote-tracking branch 'yudao/dev' into dev 2023-05-29 18:23:18 +08:00
qiuhuanran 12e6f08f1f fix: 解决vue版本与pinia版本兼容问题 2023-05-29 16:58:56 +08:00
wangding 43f3c67434 add router search 2023-05-29 11:26:51 +08:00
wangding 6768cdea05 新增路由搜索功能 2023-05-29 11:05:46 +08:00
jason 70c5082776 运费模板区域改成多选 2023-05-27 11:32:16 +08:00
dhb52 ed9f042975 feat: mall 优惠券 初稿 2023-05-26 18:19:39 +08:00
duxz 6b3de50c69 fix: 处理 window.bpmnInstances 有时候为 undefined 问题 2023-05-25 15:34:13 +08:00
YunaiV b12aefe46e review + mall:快递公司管理 2023-05-24 23:40:46 +08:00
YunaiV 349a39e72f review + mall:商品管理 2023-05-24 20:32:38 +08:00
YunaiV ae49aaffcf Merge branch 'dev-to-dev' of https://gitee.com/puhui999/yudao-ui-admin-vue3 into dev
 Conflicts:
	src/views/mall/product/spu/index.vue
2023-05-24 20:31:56 +08:00
YunaiV 0fba3fd503 review + mall:商品管理 2023-05-24 20:27:45 +08:00
puhui999 d877bfd26e fix: 完善善品导出 2023-05-23 12:04:21 +08:00
jason c296c9e53d 运费模板表格样式调整 2023-05-22 23:57:41 +08:00
jason af2fb4bf5f 运费模板性能优化。区域选择使用懒加载 2023-05-22 23:10:22 +08:00
芋道源码 855e4d3d02 !153 提交商品管理第二版
Merge pull request !153 from puhui999/dev-to-dev
2023-05-21 16:01:53 +00:00
jason 4e69f15128 mall: 订单中心->运费模板(第一版 性能有问题) 2023-05-21 23:41:36 +08:00
puhui999 39e329b8a3 Merge remote-tracking branch 'yudao/dev' into dev-to-dev 2023-05-20 12:06:00 +08:00
puhui999 38545e89c6 fix: 优化相关逻辑,修复遗留bug 2023-05-20 12:05:18 +08:00
puhui999 0c42b76a52 fix:解决商品上一版遗留的各种小bug关键部分已添加fix注释。完成的TODO也已添加fix标记 2023-05-19 17:04:13 +08:00
xingyu 9f0065f89f fix: echart color 2023-05-19 15:37:01 +08:00
xingyu 8b3980400a chore: preview 2023-05-19 15:27:07 +08:00
xingyu ba33d8bfd5 docs: update deps 2023-05-19 15:25:09 +08:00
xingyu 45ee4116b7 fix: echart 2023-05-19 15:24:01 +08:00
xingyu 2bd750a3d6 chore: update deps 2023-05-19 15:23:41 +08:00
jason b0984c9013 新增快递公司菜单 2023-05-18 23:40:39 +08:00
puhui999 4ddba9d454 fix: 解决商品上一版遗留的各种小bug关键部分已添加fix注释。完成的TODO也已添加fix标记 2023-05-17 18:24:34 +08:00
puhui999 3c4a39df01 fix: 修复 OtherSettingsForm TODO 优化相关算法,解决上一版本遗留的bug 2023-05-17 01:41:30 +08:00
puhui999 9c06832d7e fix: 修复 SkuList TODO 优化相关算法 2023-05-17 01:39:51 +08:00
puhui999 6ac8c78d57 fix: 添加商品属性去掉备注 2023-05-17 01:37:21 +08:00
puhui999 52bfc4dac0 fix: 进一步完善商品列表,修复TODO 2023-05-17 01:17:17 +08:00
puhui999 50b181318b fix: 整合spu,移动相关类型到spu删除对应文件和文件夹 2023-05-16 10:53:36 +08:00
puhui999 43e541f944 fix: 移动copyValueToTarget方法到utils/index中 2023-05-16 10:12:10 +08:00
芋道源码 47f20e6d4c !152 合并最新的 Vue3 重构
Merge pull request !152 from 芋道源码/dev
2023-05-15 15:00:12 +00:00
YunaiV 16561b1238 Merge branch 'master' of https://gitee.com/yudaocode/yudao-ui-admin-vue3 into dev
 Conflicts:
	build/vite/optimize.ts
2023-05-15 22:58:36 +08:00
YunaiV 3feb4828cd !148 【重构】Vue3 管理后台:[基础管理 -> Redis监控] 使用Echart组件实现 2023-05-15 22:57:31 +08:00
芋道源码 ab7032f1ca !148 【重构】Vue3 管理后台:[基础管理 -> Redis监控] 使用Echart组件实现
Merge pull request !148 from Chika/dev
2023-05-15 14:51:53 +00:00
芋道源码 c47cc18b24 !147 refactor: mp/autoReply 拆分ReplyForm组件
Merge pull request !147 from dhb52/dev
2023-05-15 14:49:49 +00:00
芋道源码 fa618ca44a !151 修复后台”在线用户强退“功能
Merge pull request !151 from cxr/master
2023-05-15 14:47:49 +00:00
cxr01 a788921d51 修复后台”在线用户强退“功能 2023-05-14 13:46:09 +08:00
Chika fbac522149 Redis监控用Echart组件整改 2023-05-12 16:10:14 +08:00
Chika 8456c671e8 Merge branch 'dev' of https://gitee.com/wangbosheng/yudao-ui-admin-vue3 into dev 2023-05-12 15:50:45 +08:00
Chika bf629a9554 Redis监控图标使用Echart组件整合 2023-05-12 15:30:01 +08:00
YunaiV e92361ed40 code review 商品管理的实现 2023-05-06 22:54:41 +08:00
dhb52 be49c381f6 refactor: mp/autoReply 拆分ReplyForm组件 2023-05-05 23:04:47 +08:00
芋道源码 4a965b8c14 !141 商品管理: 打通所有接口(第一版)
Merge pull request !141 from puhui999/dev-to-dev
2023-05-05 11:03:28 +00:00
芋道源码 f1cf125f0d !146 refactor: mp/wx-msg拆分Msg组件
Merge pull request !146 from dhb52/dev
2023-05-05 11:02:19 +00:00
芋道源码 63cb62e697 !139 fix(styles/index): Update .el-scrollbar__bar style
Merge pull request !139 from AhJindeg/fix_tab-scrollbar-style
2023-05-05 11:00:53 +00:00
芋道源码 7a64bbdea0 !145 修复【站内信】测试模板消息发送,接口调用错误问题
Merge pull request !145 from ZanGe丶/master
2023-05-05 10:54:50 +00:00
dhb52 2b84489969 refactor: mp/wx-msg拆分Msg组件 2023-05-04 22:45:12 +08:00
YunaiV 1c77ba8e04 code review 微信的实现 2023-05-04 21:00:49 +08:00
puhui999 0c6e3a39c9 商品管理: 打通所有接口(第一版) 2023-05-04 01:38:53 +08:00
puhui999 9ee35fc165 商品管理: 调整相关组件优化逻辑,完成表单保存和数据回显 2023-05-03 02:28:35 +08:00
puhui999 1116fb278b 商品管理: 调整相关组件优化逻辑 2023-05-02 02:20:58 +08:00
puhui999 6478d295df 商品管理: 调整相关组件优化逻辑 2023-05-01 19:01:24 +08:00
puhui999 64f6f67ddd 商品管理: 完成商品属性批量添加 2023-04-30 17:28:16 +08:00
puhui999 ab1120b0ff 商品管理: 完成商品属性排列组合算法生成对应表数据 2023-04-30 17:06:30 +08:00
puhui999 35c3545e7c 商品管理: 保存属性值到数据库 2023-04-30 17:04:31 +08:00
puhui999 538d1e0b6c 商品管理: fix:根据商品属性动态生成表格值 2023-04-30 02:26:35 +08:00
puhui999 7a64eb5198 商品管理: 修正添加属性和添加属性值时输入框显隐控制、输入框焦点获取错乱等bug 2023-04-29 23:10:18 +08:00
puhui999 61218ae711 商品管理: 初步完成相关组件 2023-04-29 21:39:25 +08:00
咱哥丶 d3b5535df9 修复【站内信】测试模板消息发送,接口调用错误问题 2023-04-29 16:44:58 +08:00
puhui999 ab1685a741 商品管理: 完善选择商品分类 2023-04-26 17:53:17 +08:00
puhui999 5c52c17227 Merge remote-tracking branch 'yudao/dev' into dev-to-dev 2023-04-26 17:21:46 +08:00
puhui999 c38abc365c 商品管理: 完善表单校验,优化信息提示,完成新建、编辑、提交逻辑 2023-04-26 17:17:39 +08:00
芋道源码 0ceddc9c91 !137 MP模块重构,功能增强
Merge pull request !137 from dhb52/dev
2023-04-25 13:38:22 +00:00
YunaiV 9680a204ca 调整商品分类的实现 2023-04-25 21:02:35 +08:00
AhJindeg ace8f9e302 🐞 fix(styles/index): Update .el-scrollbar__bar style
- 解决表格内容超过表格总宽度后,横向滚动条前端顶不到表格边缘的问题
2023-04-24 11:50:30 +08:00
puhui999 a0014bed65 商品管理初始界面结构设计 2023-04-24 11:42:44 +08:00
YunaiV 2ab8ea45da 增加 vben 预览 2023-04-24 09:13:31 +08:00
xingyu 53b6f0bdf4 docs: update deps 2023-04-23 19:36:34 +08:00
xingyu fc366f18c8 fix: type warn 2023-04-23 19:35:14 +08:00
xingyu 6b7d092c29 fix: api error 2023-04-23 19:35:06 +08:00
xingyu 148602556a fix: type error 2023-04-23 19:00:25 +08:00
xingyu 4b6103a6f7 chore: optimize 2023-04-23 18:59:09 +08:00
xingyu 462b5b55d8 chore: remove stylelint-config-prettier 2023-04-23 18:48:11 +08:00
xingyu e31f922b82 chore: update deps 2023-04-23 18:46:40 +08:00
AhJindeg 9dc361e708 🌈 style(Form/src): Modifying word spelling errors
- 修改ts类型 PlaceholderModel单词拼写
- 修改initModel方法 FormModel注释拼写
2023-04-23 11:44:03 +08:00
dhb52 88f4502715 Merge remote-tracking branch 'yudao/dev' into dev 2023-04-22 23:46:32 +08:00
dhb52 cb4527748e refactor: mp/wx-msg 采用ref来实现滚动 2023-04-22 23:45:14 +08:00
dhb52 198752868c refactor: mp模块统一accountId未初始化值为-1,删除QueryParams定义 2023-04-22 23:43:35 +08:00
芋道源码 118f32ad83 !136 同步 2023-04-22 最新迭代的内容
Merge pull request !136 from 芋道源码/dev
2023-04-22 13:22:52 +00:00
YunaiV c14b5c5bff 登录界面,增加“萌新必读” 2023-04-22 21:21:45 +08:00
dhb52 036c9b3366 fix: mp模块的一些小修复 2023-04-22 20:52:11 +08:00
芋道源码 4cf734d244 !135 MP模块重构,功能增强
Merge pull request !135 from dhb52/dev
2023-04-22 12:51:56 +00:00
dhb52 f848f3ba91 refactor: mp/wx-msg 拆分组件 2023-04-22 20:51:25 +08:00
dhb52 917b9d180a fix: mp/menu菜单拖动后激活菜单 2023-04-22 20:45:03 +08:00
YunaiV f27b93db59 菜单管理:添加刷新菜单缓存按钮 2023-04-22 20:44:32 +08:00
YunaiV 9f35ea9e82 Merge branch 'master' of https://gitee.com/yudaocode/yudao-ui-admin-vue3 into dev 2023-04-22 19:48:58 +08:00
芋道源码 36d0916f56 !134 菜单管理:添加刷新菜单缓存按钮
Merge pull request !134 from puhui999/dev-to-dev
2023-04-22 11:48:35 +00:00
dhb52 ebacbbb9cf perf: mp/menu使用vuedraggable替换拖动的原生实现 2023-04-22 09:04:21 +08:00
dhb52 08eb72e568 style: mp/WxReply objCache => tabCache 2023-04-22 01:23:52 +08:00
dhb52 d99f9e98fb feat: mp/menu 拖动排序 2023-04-21 23:35:31 +08:00
dhb52 4925a66cc5 style: mp模块stylelint 2023-04-21 23:19:04 +08:00
dhb52 b45b85984c refactor: mp模块,一个大大的重构+fix 2023-04-21 20:22:11 +08:00
puhui999 ab52f8b18f 菜单管理:添加刷新菜单缓存按钮,提高易用性 2023-04-20 14:17:21 +08:00
dhb52 6662b04d12 Merge remote-tracking branch 'yudao/dev' into dev 2023-04-19 23:12:11 +08:00
372 changed files with 12537 additions and 2024 deletions

No files matched your search

+3 -3
View File
@@ -1,5 +1,5 @@
# 开发环境 # 开发环境
NODE_ENV=production NODE_ENV=development
VITE_DEV=false VITE_DEV=false
@@ -19,13 +19,13 @@ VITE_API_URL=/admin-api
VITE_BASE_PATH=/ VITE_BASE_PATH=/
# 是否删除debugger # 是否删除debugger
VITE_DROP_DEBUGGER=false VITE_DROP_DEBUGGER=true
# 是否删除console.log # 是否删除console.log
VITE_DROP_CONSOLE=false VITE_DROP_CONSOLE=false
# 是否sourcemap # 是否sourcemap
VITE_SOURCEMAP=true VITE_SOURCEMAP=false
# 输出路径 # 输出路径
VITE_OUT_DIR=dist-dev VITE_OUT_DIR=dist-dev
+18 -14
View File
@@ -1,6 +1,4 @@
// @ts-check module.exports = {
const { defineConfig } = require('eslint-define-config')
module.exports = defineConfig({
root: true, root: true,
env: { env: {
browser: true, browser: true,
@@ -8,6 +6,7 @@ module.exports = defineConfig({
es6: true es6: true
}, },
parser: 'vue-eslint-parser', parser: 'vue-eslint-parser',
plugins: ['vue'],
parserOptions: { parserOptions: {
parser: '@typescript-eslint/parser', parser: '@typescript-eslint/parser',
ecmaVersion: 2020, ecmaVersion: 2020,
@@ -17,16 +16,9 @@ module.exports = defineConfig({
jsx: true jsx: true
} }
}, },
extends: [ extends: ['plugin:vue/vue3-recommended', 'prettier', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
'plugin:vue/vue3-recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
'plugin:prettier/recommended',
'./.eslintrc-auto-import.json'
],
rules: { rules: {
'vue/script-setup-uses-vars': 'error', 'vue/script-setup-uses-vars': 'error',
'vue/no-reserved-component-names': 'off',
'@typescript-eslint/ban-ts-ignore': 'off', '@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-explicit-any': 'off',
@@ -39,8 +31,20 @@ module.exports = defineConfig({
'@typescript-eslint/ban-types': 'off', '@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-non-null-assertion': 'off', '@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-unused-vars': 'error', '@typescript-eslint/no-unused-vars': [
'no-unused-vars': 'error', 'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_'
}
],
'no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_'
}
],
'space-before-function-paren': 'off', 'space-before-function-paren': 'off',
'vue/attributes-order': 'off', 'vue/attributes-order': 'off',
@@ -66,4 +70,4 @@ module.exports = defineConfig({
], ],
'vue/multi-word-component-names': 'off' 'vue/multi-word-component-names': 'off'
} }
}) }
+137 -22
View File
@@ -1,36 +1,98 @@
{ {
"typescript.tsdk": "node_modules/typescript/lib", "typescript.tsdk": "./node_modules/typescript/lib",
"prettier.enable": true, "volar.tsPlugin": true,
"editor.formatOnType": true, "volar.tsPluginStatus": false,
"editor.formatOnSave": true, "npm.packageManager": "pnpm",
"editor.formatOnPaste": true, "editor.tabSize": 2,
"editor.codeActionsOnSave": { "prettier.printWidth": 100, // 超过最大值换行
"source.fixAll.eslint": true "editor.defaultFormatter": "esbenp.prettier-vscode",
"files.eol": "\n",
"search.exclude": {
"**/node_modules": true,
"**/*.log": true,
"**/*.log*": true,
"**/bower_components": true,
"**/dist": true,
"**/elehukouben": true,
"**/.git": true,
"**/.gitignore": true,
"**/.svn": true,
"**/.DS_Store": true,
"**/.idea": true,
"**/.vscode": false,
"**/yarn.lock": true,
"**/tmp": true,
"out": true,
"dist": true,
"node_modules": true,
"CHANGELOG.md": true,
"examples": true,
"res": true,
"screenshots": true,
"yarn-error.log": true,
"**/.yarn": true
}, },
"[vue]": { "files.exclude": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "**/.cache": true,
"**/.editorconfig": true,
"**/.eslintcache": true,
"**/bower_components": true,
"**/.idea": true,
"**/tmp": true,
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true
}, },
"[javascript]": { "files.watcherExclude": {
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/.vscode/**": true,
"**/node_modules/**": true,
"**/tmp/**": true,
"**/bower_components/**": true,
"**/dist/**": true,
"**/yarn.lock": true
},
"stylelint.enable": true,
"stylelint.validate": ["css", "less", "postcss", "scss", "vue", "sass"],
"path-intellisense.mappings": {
"@/": "${workspaceRoot}/src"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"[typescript]": { "[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
}, },
"[json]": { "[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"[html]": { "[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"[css]": { "[css]": {
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
},
"[less]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"[scss]": { "[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"[vue]": {
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.fixAll.stylelint": true
}
},
"i18n-ally.localesPaths": ["src/locales"], "i18n-ally.localesPaths": ["src/locales"],
"i18n-ally.keystyle": "nested", "i18n-ally.keystyle": "nested",
"i18n-ally.sortKeys": true, "i18n-ally.sortKeys": true,
@@ -39,16 +101,69 @@
"i18n-ally.sourceLanguage": "en", "i18n-ally.sourceLanguage": "en",
"i18n-ally.displayLanguage": "zh-CN", "i18n-ally.displayLanguage": "zh-CN",
"i18n-ally.enabledFrameworks": ["vue", "react"], "i18n-ally.enabledFrameworks": ["vue", "react"],
"god.tsconfig": "./tsconfig.json", "cSpell.words": [
"vue-i18n.i18nPaths": "src/locales", "vben",
"windicss",
"tailwind",
"browserslist",
"tailwindcss",
"esnext",
"antv",
"tinymce",
"qrcode",
"sider",
"pinia",
"sider",
"nprogress",
"INTLIFY",
"stylelint",
"esno",
"vitejs",
"sortablejs",
"codemirror",
"iconify",
"commitlint",
"vditor",
"echarts",
"cropperjs",
"logicflow",
"vueuse",
"zxcvbn",
"lintstagedrc",
"brotli",
"sider",
"pnpm",
"antd"
],
"vetur.format.scriptInitialIndent": true,
"vetur.format.styleInitialIndent": true,
"vetur.validation.script": false,
"MicroPython.executeButton": [
{
"text": "▶",
"tooltip": "运行",
"alignment": "left",
"command": "extension.executeFile",
"priority": 3.5
}
],
"MicroPython.syncButton": [
{
"text": "$(sync)",
"tooltip": "同步",
"alignment": "left",
"command": "extension.execute",
"priority": 4
}
],
// 控制相关文件嵌套展示
"explorer.fileNesting.enabled": true, "explorer.fileNesting.enabled": true,
"explorer.fileNesting.expand": false, "explorer.fileNesting.expand": false,
"explorer.fileNesting.patterns": { "explorer.fileNesting.patterns": {
"*.ts": "$(capture).test.ts, $(capture).test.tsx", "*.ts": "$(capture).test.ts, $(capture).test.tsx",
"*.tsx": "$(capture).test.ts, $(capture).test.tsx", "*.tsx": "$(capture).test.ts, $(capture).test.tsx",
"*.env": "$(capture).env.*", "*.env": "$(capture).env.*",
"CHANGELOG.md": "CHANGELOG*", "package.json": "pnpm-lock.yaml,yarn.lock,LICENSE,README*,CHANGELOG*,CNAME,.gitattributes,.gitignore,prettier.config.js,stylelint.config.js,commitlint.config.js,.stylelintignore,.prettierignore,.gitpod.yml,.eslintrc.js,.eslintignore"
"package.json": "pnpm-lock.yaml,pnpm-workspace.yaml,LICENSE,.gitattributes,.gitignore,.gitpod.yml,CNAME,README*,.npmrc,.browserslistrc,vite.config.*,windi.*,tailwind.*,tsconfig.*,postcss*", },
".eslintrc.js": ".eslintignore,.eslintrc-*,.prettierignore,.stylelintignore,.commitlintrc.js,.prettierrc.js,.stylelint*,stylelint*,prettier.*,.editorconfig" "terminal.integrated.scrollback": 10000
}
} }
+12 -11
View File
@@ -9,8 +9,9 @@
## 🐶 新手必读 ## 🐶 新手必读
* nodejs > 16.0.0 && pnpm > 7.30.0 * nodejs > 16.0.0 && pnpm > 8.6.0 (强制使用pnpm)
* 演示地址【Vue3 + element-plus】:<http://dashboard-vue3.yudao.iocoder.cn> * 演示地址【Vue3 + element-plus】:<http://dashboard-vue3.yudao.iocoder.cn>
* 演示地址【Vue3 + vben(ant-design-vue)】:<http://dashboard-vben.yudao.iocoder.cn>
* 演示地址【Vue2 + element-ui】:<http://dashboard.yudao.iocoder.cn> * 演示地址【Vue2 + element-ui】:<http://dashboard.yudao.iocoder.cn>
* 启动文档:<https://doc.iocoder.cn/quick-start/> * 启动文档:<https://doc.iocoder.cn/quick-start/>
* 视频教程:<https://doc.iocoder.cn/video/> * 视频教程:<https://doc.iocoder.cn/video/>
@@ -19,8 +20,8 @@
**芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。 **芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。
* 采用 [vue-element-plus-admin](https://gitee.com/kailong110120130/vue-element-plus-admin) * 采用 [vue-element-plus-admin](https://gitee.com/kailong110120130/vue-element-plus-admin) 实现
* 改换saas,自动引入等功能 [vue-element-plus-admin](https://gitee.com/yudaocode/vue-element-plus-admin) * 改换 saas,自动引入等功能
* 使用 Element Plus 免费开源的中后台模版,具备如下特性: * 使用 Element Plus 免费开源的中后台模版,具备如下特性:
![首页](preview/home.png) ![首页](preview/home.png)
@@ -37,14 +38,14 @@
| 框架 | 说明 | 版本 | | 框架 | 说明 | 版本 |
|----------------------------------------------------------------------|------------------|--------| |----------------------------------------------------------------------|------------------|--------|
| [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.2.47 | | [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.3.4 |
| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 4.1.4 | | [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 4.3.9 |
| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.34 | | [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.3.7 |
| [TypeScript](https://www.typescriptlang.org/docs/) | JavaScript 的超集 | 4.9.5 | | [TypeScript](https://www.typescriptlang.org/docs/) | JavaScript 的超集 | 5.0.4 |
| [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.0.33 | | [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.1.4 |
| [vueuse](https://vueuse.org/) | 常用工具集 | 9.13.0 | | [vueuse](https://vueuse.org/) | 常用工具集 | 10.2.0 |
| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.2 | | [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.2 |
| [vue-router](https://router.vuejs.org/) | Vue 路由 | 4.1.6 | | [vue-router](https://router.vuejs.org/) | Vue 路由 | 4.2.1 |
| [windicss](https://cn.windicss.org/) | 下一代工具优先的 CSS 框架 | 3.5.6 | | [windicss](https://cn.windicss.org/) | 下一代工具优先的 CSS 框架 | 3.5.6 |
| [iconify](https://icon-sets.iconify.design/) | 在线图标库 | 3.1.0 | | [iconify](https://icon-sets.iconify.design/) | 在线图标库 | 3.1.0 |
| [wangeditor](https://www.wangeditor.com/) | 富文本编辑器 | 5.1.23 | | [wangeditor](https://www.wangeditor.com/) | 富文本编辑器 | 5.1.23 |
@@ -135,7 +136,7 @@ ps:核心功能已经实现,正在对接微信小程序中...
| | 表单构建 | 拖动表单元素生成相应的 HTML 代码,支持导出 JSON、Vue 文件 | | | 表单构建 | 拖动表单元素生成相应的 HTML 代码,支持导出 JSON、Vue 文件 |
| 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 | | 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 |
| ⭐️ | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 | | ⭐️ | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 |
| 🚀 | 文件服务 | 支持将文件存储到 S3(MinIO、阿里云、腾讯云、七牛云)、本地、FTP、数据库等 | | 🚀 | 文件服务 | 支持将文件存储到 S3(MinIO、阿里云、腾讯云、七牛云)、本地、FTP、数据库等 |
| 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 | | 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 |
| | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 | | | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 |
| | Redis 监控 | 监控 Redis 数据库的使用情况,使用的 Redis Key 管理 | | | Redis 监控 | 监控 Redis 数据库的使用情况,使用的 Redis Key 管理 |
-2
View File
@@ -13,7 +13,6 @@ import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import viteCompression from 'vite-plugin-compression' import viteCompression from 'vite-plugin-compression'
import topLevelAwait from 'vite-plugin-top-level-await' import topLevelAwait from 'vite-plugin-top-level-await'
import vueSetupExtend from 'vite-plugin-vue-setup-extend-plus'
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite' import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
@@ -31,7 +30,6 @@ export function createVitePlugins() {
WindiCSS(), WindiCSS(),
progress(), progress(),
PurgeIcons(), PurgeIcons(),
vueSetupExtend(),
ElementPlus({}), ElementPlus({}),
AutoImport({ AutoImport({
include: [ include: [
+60 -34
View File
@@ -12,12 +12,10 @@ const include = [
'vue-router', 'vue-router',
'vue-types', 'vue-types',
'vue-i18n', 'vue-i18n',
'xe-utils',
'crypto-js', 'crypto-js',
'cropperjs', 'cropperjs',
'lodash-es', 'lodash-es',
'nprogress', 'nprogress',
'animate.css',
'web-storage-cache', 'web-storage-cache',
'@iconify/iconify', '@iconify/iconify',
'@vueuse/core', '@vueuse/core',
@@ -33,37 +31,58 @@ const include = [
'element-plus/es', 'element-plus/es',
'element-plus/es/locale/lang/zh-cn', 'element-plus/es/locale/lang/zh-cn',
'element-plus/es/locale/lang/en', 'element-plus/es/locale/lang/en',
'element-plus/es/components/backtop/style/index', 'element-plus/es/components/backtop/style/css',
'element-plus/es/components/form/style/index', 'element-plus/es/components/form/style/css',
'element-plus/es/components/radio-group/style/index', 'element-plus/es/components/radio-group/style/css',
'element-plus/es/components/radio/style/index', 'element-plus/es/components/radio/style/css',
'element-plus/es/components/checkbox/style/index', 'element-plus/es/components/checkbox/style/css',
'element-plus/es/components/checkbox-group/style/index', 'element-plus/es/components/checkbox-group/style/css',
'element-plus/es/components/switch/style/index', 'element-plus/es/components/switch/style/css',
'element-plus/es/components/time-picker/style/index', 'element-plus/es/components/time-picker/style/css',
'element-plus/es/components/date-picker/style/index', 'element-plus/es/components/date-picker/style/css',
'element-plus/es/components/col/style/index', 'element-plus/es/components/descriptions/style/css',
'element-plus/es/components/form-item/style/index', 'element-plus/es/components/descriptions-item/style/css',
'element-plus/es/components/alert/style/index', 'element-plus/es/components/link/style/css',
'element-plus/es/components/breadcrumb/style/index', 'element-plus/es/components/tooltip/style/css',
'element-plus/es/components/select/style/index', 'element-plus/es/components/drawer/style/css',
'element-plus/es/components/input/style/index', 'element-plus/es/components/dialog/style/css',
'element-plus/es/components/breadcrumb-item/style/index', 'element-plus/es/components/checkbox-button/style/css',
'element-plus/es/components/tag/style/index', 'element-plus/es/components/option-group/style/css',
'element-plus/es/components/pagination/style/index', 'element-plus/es/components/radio-button/style/css',
'element-plus/es/components/table/style/index', 'element-plus/es/components/cascader/style/css',
'element-plus/es/components/table-column/style/index', 'element-plus/es/components/color-picker/style/css',
'element-plus/es/components/card/style/index', 'element-plus/es/components/input-number/style/css',
'element-plus/es/components/row/style/index', 'element-plus/es/components/rate/style/css',
'element-plus/es/components/button/style/index', 'element-plus/es/components/select-v2/style/css',
'element-plus/es/components/menu/style/index', 'element-plus/es/components/tree-select/style/css',
'element-plus/es/components/sub-menu/style/index', 'element-plus/es/components/slider/style/css',
'element-plus/es/components/menu-item/style/index', 'element-plus/es/components/time-select/style/css',
'element-plus/es/components/option/style/index', 'element-plus/es/components/autocomplete/style/css',
'element-plus/es/components/dropdown/style/index', 'element-plus/es/components/image-viewer/style/css',
'element-plus/es/components/dropdown-menu/style/index', 'element-plus/es/components/upload/style/css',
'element-plus/es/components/dropdown-item/style/index', 'element-plus/es/components/col/style/css',
'element-plus/es/components/skeleton/style/index', 'element-plus/es/components/form-item/style/css',
'element-plus/es/components/alert/style/css',
'element-plus/es/components/breadcrumb/style/css',
'element-plus/es/components/select/style/css',
'element-plus/es/components/input/style/css',
'element-plus/es/components/breadcrumb-item/style/css',
'element-plus/es/components/tag/style/css',
'element-plus/es/components/pagination/style/css',
'element-plus/es/components/table/style/css',
'element-plus/es/components/table-v2/style/css',
'element-plus/es/components/table-column/style/css',
'element-plus/es/components/card/style/css',
'element-plus/es/components/row/style/css',
'element-plus/es/components/button/style/css',
'element-plus/es/components/menu/style/css',
'element-plus/es/components/sub-menu/style/css',
'element-plus/es/components/menu-item/style/css',
'element-plus/es/components/option/style/css',
'element-plus/es/components/dropdown/style/css',
'element-plus/es/components/dropdown-menu/style/css',
'element-plus/es/components/dropdown-item/style/css',
'element-plus/es/components/skeleton/style/css',
'element-plus/es/components/skeleton/style/css', 'element-plus/es/components/skeleton/style/css',
'element-plus/es/components/backtop/style/css', 'element-plus/es/components/backtop/style/css',
'element-plus/es/components/menu/style/css', 'element-plus/es/components/menu/style/css',
@@ -76,7 +95,14 @@ const include = [
'element-plus/es/components/badge/style/css', 'element-plus/es/components/badge/style/css',
'element-plus/es/components/breadcrumb/style/css', 'element-plus/es/components/breadcrumb/style/css',
'element-plus/es/components/breadcrumb-item/style/css', 'element-plus/es/components/breadcrumb-item/style/css',
'element-plus/es/components/image/style/css' 'element-plus/es/components/image/style/css',
'element-plus/es/components/collapse-transition/style/css',
'element-plus/es/components/timeline/style/css',
'element-plus/es/components/timeline-item/style/css',
'element-plus/es/components/collapse/style/css',
'element-plus/es/components/collapse-item/style/css',
'element-plus/es/components/button-group/style/css',
'element-plus/es/components/text/style/css'
] ]
const exclude = ['@iconify/json'] const exclude = ['@iconify/json']
+68 -67
View File
@@ -1,6 +1,6 @@
{ {
"name": "yudao-ui-admin-vue3", "name": "yudao-ui-admin-vue3",
"version": "1.7.2-snapshot", "version": "1.8.0-snapshot",
"description": "基于vue3、vite4、element-plus、typesScript", "description": "基于vue3、vite4、element-plus、typesScript",
"author": "xingyu", "author": "xingyu",
"private": false, "private": false,
@@ -9,15 +9,16 @@
"dev": "vite --mode base", "dev": "vite --mode base",
"front": "vite --mode front", "front": "vite --mode front",
"ts:check": "vue-tsc --noEmit", "ts:check": "vue-tsc --noEmit",
"build:pro": "node --max_old_space_size=8000 ./node_modules/vite/bin/vite.js build --mode pro", "build:pro": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode pro",
"build:dev": "node --max_old_space_size=8000 ./node_modules/vite/bin/vite.js build --mode dev", "build:dev": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode dev",
"build:stage": "node --max_old_space_size=8000 ./node_modules/vite/bin/vite.js build --mode stage", "build:stage": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode stage",
"build:test": "node --max_old_space_size=8000 ./node_modules/vite/bin/vite.js build --mode test", "build:test": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode test",
"build:static": "node --max_old_space_size=8000 ./node_modules/vite/bin/vite.js build --mode static", "build:static": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode static",
"build:front": "node --max_old_space_size=8000 ./node_modules/vite/bin/vite.js build --mode front", "build:front": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode front",
"serve:pro": "vite preview --mode pro", "serve:pro": "vite preview --mode pro",
"serve:dev": "vite preview --mode dev", "serve:dev": "vite preview --mode dev",
"serve:test": "vite preview --mode test", "serve:test": "vite preview --mode test",
"preview": "pnpm build && vite preview",
"npm:check": "npx npm-check-updates", "npm:check": "npx npm-check-updates",
"clean": "npx rimraf node_modules", "clean": "npx rimraf node_modules",
"clean:cache": "npx rimraf node_modules/.cache", "clean:cache": "npx rimraf node_modules/.cache",
@@ -31,108 +32,103 @@
"@element-plus/icons-vue": "^2.1.0", "@element-plus/icons-vue": "^2.1.0",
"@form-create/designer": "^3.1.0", "@form-create/designer": "^3.1.0",
"@form-create/element-ui": "^3.1.17", "@form-create/element-ui": "^3.1.17",
"@iconify/iconify": "^3.1.0", "@iconify/iconify": "^3.1.1",
"@videojs-player/vue": "^1.0.0", "@videojs-player/vue": "^1.0.0",
"@vueuse/core": "^9.13.0", "@vueuse/core": "^10.2.1",
"@wangeditor/editor": "^5.1.23", "@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.10", "@wangeditor/editor-for-vue": "^5.1.10",
"@zxcvbn-ts/core": "^2.2.1", "@zxcvbn-ts/core": "^3.0.2",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
"axios": "^1.3.5", "axios": "^1.4.0",
"benz-amr-recorder": "^1.1.5", "benz-amr-recorder": "^1.1.5",
"bpmn-js-token-simulation": "^0.10.0", "bpmn-js-token-simulation": "^0.10.0",
"camunda-bpmn-moddle": "^7.0.1", "camunda-bpmn-moddle": "^7.0.1",
"cropperjs": "^1.5.13", "cropperjs": "^1.5.13",
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"dayjs": "^1.11.7", "dayjs": "^1.11.9",
"diagram-js": "^11.6.0", "diagram-js": "^11.6.0",
"echarts": "^5.4.1", "echarts": "^5.4.2",
"echarts-wordcloud": "^2.1.0", "echarts-wordcloud": "^2.1.0",
"element-plus": "2.3.3", "element-plus": "2.3.7",
"fast-xml-parser": "^4.1.3", "fast-xml-parser": "^4.2.5",
"highlight.js": "^11.7.0", "highlight.js": "^11.8.0",
"intro.js": "^7.0.1", "intro.js": "^7.0.1",
"jsencrypt": "^3.3.2", "jsencrypt": "^3.3.2",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"min-dash": "^4.0.0", "min-dash": "^4.1.1",
"mitt": "^3.0.0", "mitt": "^3.0.1",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"pinia": "^2.0.34", "pinia": "^2.1.4",
"qrcode": "^1.5.1", "qrcode": "^1.5.3",
"qs": "^6.11.1", "qs": "^6.11.2",
"steady-xml": "^0.1.0", "steady-xml": "^0.1.0",
"url": "^0.11.0", "url": "^0.11.1",
"video.js": "^8.0.4", "video.js": "^8.3.0",
"vue": "3.2.47", "vue": "3.3.4",
"vue-dompurify-html": "^4.1.4",
"vue-i18n": "9.2.2", "vue-i18n": "9.2.2",
"vue-router": "^4.1.6", "vue-router": "^4.2.4",
"vue-types": "^5.0.2", "vue-types": "^5.1.0",
"vuedraggable": "^4.1.0", "vuedraggable": "^4.1.0",
"web-storage-cache": "^1.1.1", "web-storage-cache": "^1.1.1",
"xe-utils": "^3.5.7",
"xml-js": "^1.6.11" "xml-js": "^1.6.11"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^17.5.0", "@commitlint/cli": "^17.6.6",
"@commitlint/config-conventional": "^17.4.4", "@commitlint/config-conventional": "^17.6.6",
"@iconify/json": "^2.2.38", "@iconify/json": "^2.2.87",
"@intlify/unplugin-vue-i18n": "^0.10.0", "@intlify/unplugin-vue-i18n": "^0.12.1",
"@purge-icons/generated": "^0.9.0", "@purge-icons/generated": "^0.9.0",
"@types/intro.js": "^5.1.1", "@types/intro.js": "^5.1.1",
"@types/lodash-es": "^4.17.7", "@types/lodash-es": "^4.17.7",
"@types/node": "^18.15.5", "@types/node": "^20.4.1",
"@types/nprogress": "^0.2.0", "@types/nprogress": "^0.2.0",
"@types/qrcode": "^1.5.0", "@types/qrcode": "^1.5.1",
"@types/qs": "^6.9.7", "@types/qs": "^6.9.7",
"@typescript-eslint/eslint-plugin": "^5.56.0", "@typescript-eslint/eslint-plugin": "^5.61.0",
"@typescript-eslint/parser": "^5.56.0", "@typescript-eslint/parser": "^5.61.0",
"@vitejs/plugin-legacy": "^4.0.2", "@vitejs/plugin-legacy": "^4.1.0",
"@vitejs/plugin-vue": "^4.1.0", "@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.1", "@vitejs/plugin-vue-jsx": "^3.0.1",
"autoprefixer": "^10.4.14", "autoprefixer": "^10.4.14",
"bpmn-js": "^8.9.0", "bpmn-js": "^8.9.0",
"bpmn-js-properties-panel": "^0.46.0", "bpmn-js-properties-panel": "^0.46.0",
"consola": "^2.15.3", "consola": "^3.2.3",
"eslint": "^8.36.0", "eslint": "^8.44.0",
"eslint-config-prettier": "^8.8.0", "eslint-config-prettier": "^8.8.0",
"eslint-define-config": "^1.17.0", "eslint-define-config": "^1.21.0",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.9.0", "eslint-plugin-vue": "^9.15.1",
"lint-staged": "^13.2.0", "lint-staged": "^13.2.3",
"postcss": "^8.4.21", "postcss": "^8.4.25",
"postcss-html": "^1.5.0", "postcss-html": "^1.5.0",
"postcss-scss": "^4.0.6", "postcss-scss": "^4.0.6",
"prettier": "^2.8.6", "prettier": "^2.8.8",
"rimraf": "^4.4.1", "rimraf": "^5.0.1",
"rollup": "^3.20.0", "rollup": "^3.26.2",
"sass": "^1.59.3", "sass": "^1.63.6",
"stylelint": "^15.3.0", "stylelint": "^15.10.1",
"stylelint-config-html": "^1.1.0", "stylelint-config-recommended": "^13.0.0",
"stylelint-config-prettier": "^9.0.5", "stylelint-config-recommended-vue": "^1.4.0",
"stylelint-config-recommended": "^11.0.0", "stylelint-config-standard": "^34.0.0",
"stylelint-config-standard": "^31.0.0",
"stylelint-order": "^6.0.3", "stylelint-order": "^6.0.3",
"terser": "^5.16.6", "terser": "^5.18.2",
"typescript": "5.0.2", "typescript": "5.1.6",
"unplugin-auto-import": "^0.15.1", "unplugin-auto-import": "^0.16.6",
"unplugin-element-plus": "^0.7.0", "unplugin-element-plus": "^0.7.2",
"unplugin-vue-components": "^0.24.1", "unplugin-vue-components": "^0.25.1",
"vite": "4.2.1", "vite": "4.4.2",
"vite-plugin-compression": "^0.5.1", "vite-plugin-compression": "^0.5.1",
"vite-plugin-ejs": "^1.6.4", "vite-plugin-ejs": "^1.6.4",
"vite-plugin-eslint": "^1.8.1", "vite-plugin-eslint": "^1.8.1",
"vite-plugin-progress": "^0.0.6", "vite-plugin-progress": "^0.0.7",
"vite-plugin-purge-icons": "^0.9.2", "vite-plugin-purge-icons": "^0.9.2",
"vite-plugin-svg-icons": "^2.0.1", "vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-top-level-await": "^1.3.0", "vite-plugin-top-level-await": "^1.3.1",
"vite-plugin-vue-setup-extend-plus": "^0.1.0", "vite-plugin-windicss": "^1.9.0",
"vite-plugin-windicss": "^1.8.10", "vue-tsc": "^1.8.4",
"vue-tsc": "^1.2.0",
"windicss": "^3.5.6" "windicss": "^3.5.6"
}, },
"engines": {
"node": ">=16.0.0"
},
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -141,5 +137,10 @@
"bugs": { "bugs": {
"url": "https://gitee.com/yudaocode/yudao-ui-admin-vue3/issues" "url": "https://gitee.com/yudaocode/yudao-ui-admin-vue3/issues"
}, },
"homepage": "https://gitee.com/yudaocode/yudao-ui-admin-vue3" "homepage": "https://gitee.com/yudaocode/yudao-ui-admin-vue3",
"packageManager": "pnpm@8.6.0",
"engines": {
"node": ">= 16.0.0",
"pnpm": ">=8.6.0"
}
} }
+8 -2
View File
@@ -1,8 +1,11 @@
<script lang="ts" name="APP" setup> <script lang="ts" setup>
import { isDark } from '@/utils/is' import { isDark } from '@/utils/is'
import { useAppStore } from '@/store/modules/app' import { useAppStore } from '@/store/modules/app'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
import { CACHE_KEY, useCache } from '@/hooks/web/useCache' import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
import routerSearch from '@/components/RouterSearch/index.vue'
defineOptions({ name: 'APP' })
const { getPrefixCls } = useDesign() const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('app') const prefixCls = getPrefixCls('app')
@@ -24,10 +27,12 @@ setDefaultTheme()
<template> <template>
<ConfigGlobal :size="currentSize"> <ConfigGlobal :size="currentSize">
<RouterView :class="greyMode ? `${prefixCls}-grey-mode` : ''" /> <RouterView :class="greyMode ? `${prefixCls}-grey-mode` : ''" />
<routerSearch />
</ConfigGlobal> </ConfigGlobal>
</template> </template>
<style lang="scss"> <style lang="scss">
$prefix-cls: #{$namespace}-app; $prefix-cls: #{$namespace}-app;
.size { .size {
width: 100%; width: 100%;
height: 100%; height: 100%;
@@ -35,10 +40,11 @@ $prefix-cls: #{$namespace}-app;
html, html,
body { body {
@extend .size;
padding: 0 !important; padding: 0 !important;
margin: 0; margin: 0;
overflow: hidden; overflow: hidden;
@extend .size;
#app { #app {
@extend .size; @extend .size;
+5
View File
@@ -54,3 +54,8 @@ export const getBrand = (id: number) => {
export const getBrandParam = (params: PageParam) => { export const getBrandParam = (params: PageParam) => {
return request.get({ url: '/product/brand/page', params }) return request.get({ url: '/product/brand/page', params })
} }
// 获得商品品牌精简信息列表
export const getSimpleBrandList = () => {
return request.get({ url: '/product/brand/list-all-simple' })
}
+6 -6
View File
@@ -17,17 +17,17 @@ export interface CategoryVO {
*/ */
name: string name: string
/** /**
* 分类图片 * 移动端分类图
*/ */
picUrl: string picUrl: string
/**
* PC 端分类图
*/
bigPicUrl?: string
/** /**
* 分类排序 * 分类排序
*/ */
sort?: number sort: number
/**
* 分类描述
*/
description?: string
/** /**
* 开启状态 * 开启状态
*/ */
+2 -2
View File
@@ -71,8 +71,8 @@ export const getPropertyList = (params: any) => {
} }
// 获得属性项列表 // 获得属性项列表
export const getPropertyListAndValue = (params: any) => { export const getPropertyListAndValue = (data: any) => {
return request.get({ url: '/product/property/get-value-list', params }) return request.post({ url: '/product/property/get-value-list', data })
} }
// ------------------------ 属性值 ------------------- // ------------------------ 属性值 -------------------
+107
View File
@@ -0,0 +1,107 @@
import request from '@/config/axios'
export interface Property {
propertyId?: number // 属性编号
propertyName?: string // 属性名称
valueId?: number // 属性值编号
valueName?: string // 属性值名称
}
export interface Sku {
id?: number // 商品 SKU 编号
spuId?: number // SPU 编号
properties?: Property[] // 属性数组
price?: number // 商品价格
marketPrice?: number // 市场价
costPrice?: number // 成本价
barCode?: string // 商品条码
picUrl?: string // 图片地址
stock?: number // 库存
weight?: number // 商品重量,单位:kg 千克
volume?: number // 商品体积,单位:m^3 平米
subCommissionFirstPrice?: number // 一级分销的佣金
subCommissionSecondPrice?: number // 二级分销的佣金
salesCount?: number // 商品销量
}
export interface Spu {
id?: number
name?: string // 商品名称
categoryId?: number | null // 商品分类
keyword?: string // 关键字
unit?: number | null // 单位
picUrl?: string // 商品封面图
sliderPicUrls?: string[] // 商品轮播图
introduction?: string // 商品简介
deliveryTemplateId?: number | null // 运费模版
brandId?: number | null // 商品品牌编号
specType?: boolean // 商品规格
subCommissionType?: boolean // 分销类型
skus?: Sku[] // sku数组
description?: string // 商品详情
sort?: number // 商品排序
giveIntegral?: number // 赠送积分
virtualSalesCount?: number // 虚拟销量
recommendHot?: boolean // 是否热卖
recommendBenefit?: boolean // 是否优惠
recommendBest?: boolean // 是否精品
recommendNew?: boolean // 是否新品
recommendGood?: boolean // 是否优品
price?: number // 商品价格
salesCount?: number // 商品销量
marketPrice?: number // 市场价
costPrice?: number // 成本价
stock?: number // 商品库存
createTime?: Date // 商品创建时间
status?: number // 商品状态
}
// 获得 Spu 列表
export const getSpuPage = (params: PageParam) => {
return request.get({ url: '/product/spu/page', params })
}
// 获得 Spu 列表 tabsCount
export const getTabsCount = () => {
return request.get({ url: '/product/spu/get-count' })
}
// 创建商品 Spu
export const createSpu = (data: Spu) => {
return request.post({ url: '/product/spu/create', data })
}
// 更新商品 Spu
export const updateSpu = (data: Spu) => {
return request.put({ url: '/product/spu/update', data })
}
// 更新商品 Spu status
export const updateStatus = (data: { id: number; status: number }) => {
return request.put({ url: '/product/spu/update-status', data })
}
// 获得商品 Spu
export const getSpu = (id: number) => {
return request.get({ url: `/product/spu/get-detail?id=${id}` })
}
// 获得商品 Spu 详情列表
export const getSpuDetailList = (ids: number[]) => {
return request.get({ url: `/product/spu/list?spuIds=${ids}` })
}
// 删除商品 Spu
export const deleteSpu = (id: number) => {
return request.delete({ url: `/product/spu/delete?id=${id}` })
}
// 导出商品 Spu Excel
export const exportSpu = async (params) => {
return await request.download({ url: '/product/spu/export', params })
}
// 获得商品 SPU 精简列表
export const getSpuSimpleList = async () => {
return request.get({ url: '/product/spu/get-simple-list' })
}
@@ -0,0 +1,63 @@
import request from '@/config/axios'
import { Sku, Spu } from '@/api/mall/product/spu'
// TODO @puhui999: combinationActivity.ts
export interface CombinationActivityVO {
id?: number
name?: string
spuId?: number
totalLimitCount?: number
singleLimitCount?: number
startTime?: Date
endTime?: Date
userSize?: number
totalNum?: number
successNum?: number
orderUserCount?: number
virtualGroup?: number
status?: number
limitDuration?: number
products: CombinationProductVO[]
}
// 拼团活动所需属性
export interface CombinationProductVO {
spuId: number
skuId: number
activePrice: number // 拼团价格
}
// 扩展 Sku 配置
export type SkuExtension = Sku & {
productConfig: CombinationProductVO
}
export interface SpuExtension extends Spu {
skus: SkuExtension[] // 重写类型
}
// 查询拼团活动列表
export const getCombinationActivityPage = async (params) => {
return await request.get({ url: '/promotion/combination-activity/page', params })
}
// 查询拼团活动详情
export const getCombinationActivity = async (id: number) => {
return await request.get({ url: '/promotion/combination-activity/get?id=' + id })
}
// 新增拼团活动
export const createCombinationActivity = async (data: CombinationActivityVO) => {
return await request.post({ url: '/promotion/combination-activity/create', data })
}
// 修改拼团活动
export const updateCombinationActivity = async (data: CombinationActivityVO) => {
return await request.put({ url: '/promotion/combination-activity/update', data })
}
// 删除拼团活动
export const deleteCombinationActivity = async (id: number) => {
return await request.delete({ url: '/promotion/combination-activity/delete?id=' + id })
}
+18
View File
@@ -0,0 +1,18 @@
import request from '@/config/axios'
// TODO @dhb52:vo 缺少
// 删除优惠劵
export const deleteCoupon = async (id: number) => {
return request.delete({
url: `/promotion/coupon/delete?id=${id}`
})
}
// 获得优惠劵分页
export const getCouponPage = async (params: PageParam) => {
return request.get({
url: '/promotion/coupon/page',
params: params
})
}
+83
View File
@@ -0,0 +1,83 @@
import request from '@/config/axios'
export interface CouponTemplateVO {
id: number
name: string
status: number
totalCount: number
takeLimitCount: number
takeType: number
usePrice: number
productScope: number
productSpuIds: string
validityType: number
validStartTime: Date
validEndTime: Date
fixedStartTerm: number
fixedEndTerm: number
discountType: number
discountPercent: number
discountPrice: number
discountLimitPrice: number
takeCount: number
useCount: number
}
// 创建优惠劵模板
export function createCouponTemplate(data: CouponTemplateVO) {
return request.post({
url: '/promotion/coupon-template/create',
data: data
})
}
// 更新优惠劵模板
export function updateCouponTemplate(data: CouponTemplateVO) {
return request.put({
url: '/promotion/coupon-template/update',
data: data
})
}
// 更新优惠劵模板的状态
export function updateCouponTemplateStatus(id: number, status: [0, 1]) {
const data = {
id,
status
}
return request.put({
url: '/promotion/coupon-template/update-status',
data: data
})
}
// 删除优惠劵模板
export function deleteCouponTemplate(id: number) {
return request.delete({
url: '/promotion/coupon-template/delete?id=' + id
})
}
// 获得优惠劵模板
export function getCouponTemplate(id: number) {
return request.get({
url: '/promotion/coupon-template/get?id=' + id
})
}
// 获得优惠劵模板分页
export function getCouponTemplatePage(params: PageParam) {
return request.get({
url: '/promotion/coupon-template/page',
params: params
})
}
// 导出优惠劵模板 Excel
export function exportCouponTemplateExcel(params: PageParam) {
return request.get({
url: '/promotion/coupon-template/export-excel',
params: params,
responseType: 'blob'
})
}
@@ -0,0 +1,63 @@
import request from '@/config/axios'
import { Sku, Spu } from '@/api/mall/product/spu'
export interface SeckillActivityVO {
id?: number
spuId?: number
name?: string
status?: number
remark?: string
startTime?: Date
endTime?: Date
sort?: number
configIds?: string
orderCount?: number
userCount?: number
totalPrice?: number
totalLimitCount?: number
singleLimitCount?: number
stock?: number
totalStock?: number
products?: SeckillProductVO[]
}
// 秒杀活动所需属性
export interface SeckillProductVO {
skuId: number
seckillPrice: number
stock: number
}
// 扩展 Sku 配置
export type SkuExtension = Sku & {
productConfig: SeckillProductVO
}
export interface SpuExtension extends Spu {
skus: SkuExtension[] // 重写类型
}
// 查询秒杀活动列表
export const getSeckillActivityPage = async (params) => {
return await request.get({ url: '/promotion/seckill-activity/page', params })
}
// 查询秒杀活动详情
export const getSeckillActivity = async (id: number) => {
return await request.get({ url: '/promotion/seckill-activity/get?id=' + id })
}
// 新增秒杀活动
export const createSeckillActivity = async (data: SeckillActivityVO) => {
return await request.post({ url: '/promotion/seckill-activity/create', data })
}
// 修改秒杀活动
export const updateSeckillActivity = async (data: SeckillActivityVO) => {
return await request.put({ url: '/promotion/seckill-activity/update', data })
}
// 删除秒杀活动
export const deleteSeckillActivity = async (id: number) => {
return await request.delete({ url: '/promotion/seckill-activity/delete?id=' + id })
}
@@ -0,0 +1,49 @@
import request from '@/config/axios'
export interface SeckillConfigVO {
id: number
name: string
startTime: string
endTime: string
sliderPicUrls: string[]
status: number
}
// 查询秒杀时段配置列表
export const getSeckillConfigPage = async (params) => {
return await request.get({ url: '/promotion/seckill-config/page', params })
}
// 查询秒杀时段配置详情
export const getSeckillConfig = async (id: number) => {
return await request.get({ url: '/promotion/seckill-config/get?id=' + id })
}
// 获得所有开启状态的秒杀时段精简列表
export const getListAllSimple = async () => {
return await request.get({ url: '/promotion/seckill-config/list-all-simple' })
}
// 新增秒杀时段配置
export const createSeckillConfig = async (data: SeckillConfigVO) => {
return await request.post({ url: '/promotion/seckill-config/create', data })
}
// 修改秒杀时段配置
export const updateSeckillConfig = async (data: SeckillConfigVO) => {
return await request.put({ url: '/promotion/seckill-config/update', data })
}
// 修改时段配置状态
export const updateSeckillConfigStatus = (id: number, status: number) => {
const data = {
id,
status
}
return request.put({ url: '/promotion/seckill-config/update-status', data: data })
}
// 删除秒杀时段配置
export const deleteSeckillConfig = async (id: number) => {
return await request.delete({ url: '/promotion/seckill-config/delete?id=' + id })
}
@@ -0,0 +1,40 @@
import request from '@/config/axios'
export interface DeliveryExpressVO {
id: number
code: string
name: string
logo: string
sort: number
status: number
}
// 查询快递公司列表
export const getDeliveryExpressPage = async (params: PageParam) => {
return await request.get({ url: '/trade/delivery/express/page', params })
}
// 查询快递公司详情
export const getDeliveryExpress = async (id: number) => {
return await request.get({ url: '/trade/delivery/express/get?id=' + id })
}
// 新增快递公司
export const createDeliveryExpress = async (data: DeliveryExpressVO) => {
return await request.post({ url: '/trade/delivery/express/create', data })
}
// 修改快递公司
export const updateDeliveryExpress = async (data: DeliveryExpressVO) => {
return await request.put({ url: '/trade/delivery/express/update', data })
}
// 删除快递公司
export const deleteDeliveryExpress = async (id: number) => {
return await request.delete({ url: '/trade/delivery/express/delete?id=' + id })
}
// 导出快递公司 Excel
export const exportDeliveryExpressApi = async (params) => {
return await request.download({ url: '/trade/delivery/express/export-excel', params })
}
@@ -0,0 +1,54 @@
import request from '@/config/axios'
export interface DeliveryExpressTemplateVO {
id: number
name: string
chargeMode: number
sort: number
templateCharge: ExpressTemplateChargeVO[]
templateFree: ExpressTemplateFreeVO[]
}
export declare type ExpressTemplateChargeVO = {
areaIds: number[]
startCount: number
startPrice: number
extraCount: number
extraPrice: number
}
export declare type ExpressTemplateFreeVO = {
areaIds: number[]
freeCount: number
freePrice: number
}
// 查询快递运费模板列表
export const getDeliveryExpressTemplatePage = async (params: PageParam) => {
return await request.get({ url: '/trade/delivery/express-template/page', params })
}
// 查询快递运费模板详情
export const getDeliveryExpressTemplate = async (id: number) => {
return await request.get({ url: '/trade/delivery/express-template/get?id=' + id })
}
// 查询快递运费模板详情
export const getSimpleTemplateList = async () => {
return await request.get({ url: '/trade/delivery/express-template/list-all-simple' })
}
// 新增快递运费模板
export const createDeliveryExpressTemplate = async (data: DeliveryExpressTemplateVO) => {
return await request.post({ url: '/trade/delivery/express-template/create', data })
}
// 修改快递运费模板
export const updateDeliveryExpressTemplate = async (data: DeliveryExpressTemplateVO) => {
return await request.put({ url: '/trade/delivery/express-template/update', data })
}
// 删除快递运费模板
export const deleteDeliveryExpressTemplate = async (id: number) => {
return await request.delete({ url: '/trade/delivery/express-template/delete?id=' + id })
}
@@ -0,0 +1,46 @@
import request from '@/config/axios'
export interface DeliveryPickUpStoreVO {
id: number
name: string
introduction: string
phone: string
areaId: number
detailAddress: string
logo: string
openingTime: string
closingTime: string
latitude: number
longitude: number
status: number
}
// 查询自提门店列表
export const getDeliveryPickUpStorePage = async (params: DeliveryPickUpStorePageReqVO) => {
return await request.get({ url: '/trade/delivery/pick-up-store/page', params })
}
// 查询自提门店详情
export const getDeliveryPickUpStore = async (id: number) => {
return await request.get({ url: '/trade/delivery/pick-up-store/get?id=' + id })
}
// 新增自提门店
export const createDeliveryPickUpStore = async (data: DeliveryPickUpStoreVO) => {
return await request.post({ url: '/trade/delivery/pick-up-store/create', data })
}
// 修改自提门店
export const updateDeliveryPickUpStore = async (data: DeliveryPickUpStoreVO) => {
return await request.put({ url: '/trade/delivery/pick-up-store/update', data })
}
// 删除自提门店
export const deleteDeliveryPickUpStore = async (id: number) => {
return await request.delete({ url: '/trade/delivery/pick-up-store/delete?id=' + id })
}
// 导出自提门店 Excel
export const exportDeliveryPickUpStoreApi = async (params) => {
return await request.download({ url: '/trade/delivery/pick-up-store/export-excel', params })
}
+12
View File
@@ -0,0 +1,12 @@
import request from '@/config/axios'
// 获得交易订单分页
// TODO @xiaobai:改成 getOrderPage
export const getOrderList = (params: PageParam) => {
return request.get({ url: '/trade/order/page', params })
}
// 获得交易订单详情
export const getOrderDetail = (id: number) => {
return request.get({ url: '/trade/order/get-detail?id=' + id })
}
+228
View File
@@ -0,0 +1,228 @@
// TODO @xiaobai:这个放到 order/index.ts 里哈
// TODO @xiaobai:注释放到变量后面,这样简洁一点
// TODO @xiaobai:这个改成 TradeOrderRespVO
export interface TradeOrderPageItemRespVO {
// 订单编号
id?: number
// 订单流水号
no?: string
// 下单时间
createTime?: Date
// 订单类型
type?: number
// 订单来源
terminal?: number
// 用户编号
userId?: number
// 用户 IP
userIp?: string
// 用户备注
userRemark?: string
// 订单状态
status?: number
// 购买的商品数量
productCount?: number
// 订单完成时间
finishTime?: Date
// 订单取消时间
cancelTime?: Date
// 取消类型
cancelType?: number
// 商家备注
remark?: string
// 支付订单编号
payOrderId: number
// 是否已支付
payed?: boolean
// 付款时间
payTime?: Date
// 支付渠道
payChannelCode?: string
// 商品原价(总)
originalPrice?: number
// 订单原价(总)
orderPrice?: number
// 订单优惠(总)
discountPrice?: number
// 运费金额
deliveryPrice?: number
// 订单调价(总)
adjustPrice?: number
// 应付金额(总)
payPrice?: number
// 配送模板编号
deliveryTemplateId?: number
// 发货物流公司编号
logisticsId?: number
// 发货物流单号
logisticsNo?: string
// 发货状态
deliveryStatus?: number
// 发货时间
deliveryTime?: Date
// 收货时间
receiveTime?: Date
// 收件人名称
receiverName?: string
// 收件人手机
receiverMobile?: string
// 收件人地区编号
receiverAreaId?: number
// 收件人邮编
receiverPostCode?: number
// 收件人详细地址
receiverDetailAddress?: string
// 售后状态
afterSaleStatus?: number
// 退款金额
refundPrice?: number
// 优惠劵编号
couponId?: number
// 优惠劵减免金额
couponPrice?: number
// 积分抵扣的金额
pointPrice?: number
//收件人地区名字
receiverAreaName?: string
// 订单项列表
items?: TradeOrderItemBaseVO[]
//用户信息
user?: MemberUserRespDTO
}
// TODO @xiaobai:这个改成 TradeOrderItemRespVO
/**
* 交易订单项 Base VO,提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
export interface TradeOrderItemBaseVO {
// ========== 订单项基本信息 ==========
/**
* 编号
*/
id?: number
/**
* 用户编号
*/
userId?: number
/**
* 订单编号
*/
orderId?: number
// ========== 商品基本信息 ==========
/**
* 商品 SPU 编号
*/
spuId?: number
/**
* 商品 SPU 名称
*/
spuName?: string
/**
* 商品 SKU 编号
*/
skuId?: number
/**
* 商品图片
*/
picUrl?: string
/**
* 购买数量
*/
count?: number
// ========== 价格 + 支付基本信息 ==========
/**
* 商品原价(总)
*/
originalPrice?: number
/**
* 商品原价(单)
*/
originalUnitPrice?: number
/**
* 商品优惠(总)
*/
discountPrice?: number
/**
* 商品实付金额(总)
*/
payPrice?: number
/**
* 子订单分摊金额(总)
*/
orderPartPrice?: number
/**
* 分摊后子订单实付金额(总)
*/
orderDividePrice?: number
// ========== 营销基本信息 ==========
// TODO 芋艿:在捉摸一下
// ========== 售后基本信息 ==========
/**
* 售后状态
*/
afterSaleStatus?: number
//属性数组
properties?: ProductPropertyValueDetailRespVO[]
}
/**
* 管理后台 - 商品属性值的明细 Response VO
*/
export interface ProductPropertyValueDetailRespVO {
/**
* 属性的编号
*/
propertyId?: number
/**
* 属性的名称
*/
propertyName?: string
/**
* 属性值的编号
*/
valueId?: number
/**
* 属性值的名称
*/
valueName?: string
}
/**
* 订单详情查询 请求
*/
export interface TradeOrderPageReqVO {
pageNo: number
pageSize: number
no?: string
userId?: string
userNickname?: string
userMobile?: string
receiverName?: string
receiverMobile?: string
terminal?: string
type?: number
status?: number
payChannelCode?: string
createTime?: [Date, Date]
spuName?: string
itemCount?: string
all?: string
}
//用户信息
export interface MemberUserRespDTO {
id?: number
nickname?: string
status?: number
avatar?: string
mobile?: string
}
//订单详情选中type
export interface SelectType {
queryParams: TradeOrderPageReqVO
selectTotal: number //选中的数量
selectAllFlag: boolean //全选标识
selectData: Map<number, Set<string>> //存放涉及选中得页面以及每页选中得数据订单号 全选时根据条件查询 排除取消的list订单
unSelectList: Set<string> //登记取消的list 全选标识为true 时登记单独取消的list,再次选中时排除, 全选标识为false 时清空list
}
+1 -1
View File
@@ -1,7 +1,7 @@
import request from '@/config/axios' import request from '@/config/axios'
export interface AccountVO { export interface AccountVO {
id?: number id: number
name: string name: string
} }
+19
View File
@@ -0,0 +1,19 @@
import request from '@/config/axios'
export interface ConfigVO {
id: number
tradeDeductEnable: number
tradeDeductUnitPrice: number
tradeDeductMaxPrice: number
tradeGivePoint: number
}
// 查询积分设置详情
export const getConfig = async () => {
return await request.get({ url: `/point/config/get` })
}
// 新增修改积分设置
export const saveConfig = async (data: ConfigVO) => {
return await request.put({ url: `/point/config/save`, data })
}
+47
View File
@@ -0,0 +1,47 @@
import request from '@/config/axios'
export interface RecordVO {
id: number
bizId: string
bizType: string
type: string
title: string
description: string
point: number
totalPoint: number
status: number
userId: number
freezingTime: Date
thawingTime: Date
createDate: Date
}
// 查询用户积分记录列表
export const getRecordPage = async (params) => {
return await request.get({ url: `/point/record/page`, params })
}
// 查询用户积分记录详情
export const getRecord = async (id: number) => {
return await request.get({ url: `/point/record/get?id=` + id })
}
// 新增用户积分记录
export const createRecord = async (data: RecordVO) => {
return await request.post({ url: `/point/record/create`, data })
}
// 修改用户积分记录
export const updateRecord = async (data: RecordVO) => {
return await request.put({ url: `/point/record/update`, data })
}
// 删除用户积分记录
export const deleteRecord = async (id: number) => {
return await request.delete({ url: `/point/record/delete?id=` + id })
}
// 导出用户积分记录 Excel
export const exportRecord = async (params) => {
return await request.download({ url: `/point/record/export-excel`, params })
}
+37
View File
@@ -0,0 +1,37 @@
import request from '@/config/axios'
export interface SignInConfigVO {
id: number
day: number
point: number
}
// 查询积分签到规则列表
export const getSignInConfigPage = async (params) => {
return await request.get({ url: `/point/sign-in-config/page`, params })
}
// 查询积分签到规则详情
export const getSignInConfig = async (id: number) => {
return await request.get({ url: `/point/sign-in-config/get?id=` + id })
}
// 新增积分签到规则
export const createSignInConfig = async (data: SignInConfigVO) => {
return await request.post({ url: `/point/sign-in-config/create`, data })
}
// 修改积分签到规则
export const updateSignInConfig = async (data: SignInConfigVO) => {
return await request.put({ url: `/point/sign-in-config/update`, data })
}
// 删除积分签到规则
export const deleteSignInConfig = async (id: number) => {
return await request.delete({ url: `/point/sign-in-config/delete?id=` + id })
}
// 导出积分签到规则 Excel
export const exportSignInConfig = async (params) => {
return await request.download({ url: `/point/sign-in-config/export-excel`, params })
}
+38
View File
@@ -0,0 +1,38 @@
import request from '@/config/axios'
export interface SignInRecordVO {
id: number
userId: number
day: number
point: number
}
// 查询用户签到积分列表
export const getSignInRecordPage = async (params) => {
return await request.get({ url: `/point/sign-in-record/page`, params })
}
// 查询用户签到积分详情
export const getSignInRecord = async (id: number) => {
return await request.get({ url: `/point/sign-in-record/get?id=` + id })
}
// 新增用户签到积分
export const createSignInRecord = async (data: SignInRecordVO) => {
return await request.post({ url: `/point/sign-in-record/create`, data })
}
// 修改用户签到积分
export const updateSignInRecord = async (data: SignInRecordVO) => {
return await request.put({ url: `/point/sign-in-record/update`, data })
}
// 删除用户签到积分
export const deleteSignInRecord = async (id: number) => {
return await request.delete({ url: `/point/sign-in-record/delete?id=` + id })
}
// 导出用户签到积分 Excel
export const exportSignInRecord = async (params) => {
return await request.download({ url: `/point/sign-in-record/export-excel`, params })
}
+8
View File
@@ -5,6 +5,14 @@ export const getAreaTree = async () => {
return await request.get({ url: '/system/area/tree' }) return await request.get({ url: '/system/area/tree' })
} }
export const getChildrenArea = async (id: number) => {
return await request.get({ url: '/system/area/get-children?id=' + id })
}
export const getAreaListByIds = async (ids) => {
return await request.get({ url: '/system/area/get-by-ids?ids=' + ids })
}
// 获得 IP 对应的地区名 // 获得 IP 对应的地区名
export const getAreaByIp = async (ip: string) => { export const getAreaByIp = async (ip: string) => {
return await request.get({ url: '/system/area/get-by-ip?ip=' + ip }) return await request.get({ url: '/system/area/get-by-ip?ip=' + ip })
+1 -1
View File
@@ -39,7 +39,7 @@ export const updateNotifyTemplate = async (data: NotifyTemplateVO) => {
} }
// 删除站内信模板 // 删除站内信模板
export const deleteNotifyTemplateApi = async (id: number) => { export const deleteNotifyTemplate = async (id: number) => {
return await request.delete({ url: '/system/notify-template/delete?id=' + id }) return await request.delete({ url: '/system/notify-template/delete?id=' + id })
} }
+1 -1
View File
@@ -17,6 +17,6 @@ export const getAccessTokenPage = (params: PageParam) => {
} }
// 删除 token // 删除 token
export const deleteAccessToken = (accessToken: number) => { export const deleteAccessToken = (accessToken: string) => {
return request.delete({ url: '/system/oauth2-token/delete?accessToken=' + accessToken }) return request.delete({ url: '/system/oauth2-token/delete?accessToken=' + accessToken })
} }
+3 -1
View File
@@ -1,7 +1,9 @@
<script lang="ts" name="BackTop" setup> <script lang="ts" setup>
import { ElBacktop } from 'element-plus' import { ElBacktop } from 'element-plus'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
defineOptions({ name: 'BackTop' })
const { getPrefixCls, variables } = useDesign() const { getPrefixCls, variables } = useDesign()
const prefixCls = getPrefixCls('backtop') const prefixCls = getPrefixCls('backtop')
@@ -1,4 +1,4 @@
<script lang="ts" name="ConfigGlobal" setup> <script lang="ts" setup>
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { useLocaleStore } from '@/store/modules/locale' import { useLocaleStore } from '@/store/modules/locale'
import { useAppStore } from '@/store/modules/app' import { useAppStore } from '@/store/modules/app'
@@ -7,6 +7,8 @@ import { useDesign } from '@/hooks/web/useDesign'
import { ElementPlusSize } from '@/types/elementPlus' import { ElementPlusSize } from '@/types/elementPlus'
import { useWindowSize } from '@vueuse/core' import { useWindowSize } from '@vueuse/core'
defineOptions({ name: 'ConfigGlobal' })
const { variables } = useDesign() const { variables } = useDesign()
const appStore = useAppStore() const appStore = useAppStore()
@@ -1,7 +1,9 @@
<script lang="ts" name="ContentDetailWrap" setup> <script lang="ts" setup>
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
defineOptions({ name: 'ContentDetailWrap' })
const { t } = useI18n() const { t } = useI18n()
const { getPrefixCls } = useDesign() const { getPrefixCls } = useDesign()
@@ -1,7 +1,9 @@
<script lang="ts" name="ContentWrap" setup> <script lang="ts" setup>
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
defineOptions({ name: 'ContentWrap' })
const { getPrefixCls } = useDesign() const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('content-wrap') const prefixCls = getPrefixCls('content-wrap')
+3 -1
View File
@@ -1,9 +1,11 @@
<script lang="ts" name="CountTo" setup> <script lang="ts" setup>
import { PropType } from 'vue' import { PropType } from 'vue'
import { isNumber } from '@/utils/is' import { isNumber } from '@/utils/is'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
defineOptions({ name: 'CountTo' })
const { getPrefixCls } = useDesign() const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('count-to') const prefixCls = getPrefixCls('count-to')
+11 -9
View File
@@ -1,7 +1,9 @@
<script lang="ts" name="Crontab" setup> <script lang="ts" setup>
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { PropType } from 'vue' import { PropType } from 'vue'
defineOptions({ name: 'Crontab' })
interface shortcutsType { interface shortcutsType {
text: string text: string
value: string value: string
@@ -966,37 +968,37 @@ const submit = () => {
<style scoped> <style scoped>
.sc-cron:deep(.el-tabs__item) { .sc-cron:deep(.el-tabs__item) {
height: auto; height: auto;
line-height: 1;
padding: 0 7px; padding: 0 7px;
line-height: 1;
vertical-align: bottom; vertical-align: bottom;
} }
.sc-cron-num { .sc-cron-num {
text-align: center;
margin-bottom: 15px;
width: 100%; width: 100%;
margin-bottom: 15px;
text-align: center;
} }
.sc-cron-num h2 { .sc-cron-num h2 {
font-size: 12px;
margin-bottom: 15px; margin-bottom: 15px;
font-size: 12px;
font-weight: normal; font-weight: normal;
} }
.sc-cron-num h4 { .sc-cron-num h4 {
display: block; display: block;
height: 32px;
line-height: 30px;
width: 100%; width: 100%;
font-size: 12px; height: 32px;
padding: 0 15px; padding: 0 15px;
font-size: 12px;
line-height: 30px;
background: var(--el-color-primary-light-9); background: var(--el-color-primary-light-9);
border-radius: 4px; border-radius: 4px;
} }
.sc-cron:deep(.el-tabs__item.is-active) .sc-cron-num h4 { .sc-cron:deep(.el-tabs__item.is-active) .sc-cron-num h4 {
background: var(--el-color-primary);
color: #fff; color: #fff;
background: var(--el-color-primary);
} }
[data-theme='dark'] .sc-cron-num h4 { [data-theme='dark'] .sc-cron-num h4 {
+3 -1
View File
@@ -113,7 +113,7 @@
</Dialog> </Dialog>
</div> </div>
</template> </template>
<script lang="ts" name="CopperModal" setup> <script lang="ts" setup>
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
import { dataURLtoBlob } from '@/utils/filt' import { dataURLtoBlob } from '@/utils/filt'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
@@ -121,6 +121,8 @@ import type { CropendResult, Cropper } from './types'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { CropperImage } from '@/components/Cropper' import { CropperImage } from '@/components/Cropper'
defineOptions({ name: 'CopperModal' })
const props = defineProps({ const props = defineProps({
srcValue: propTypes.string.def(''), srcValue: propTypes.string.def(''),
circled: propTypes.bool.def(true) circled: propTypes.bool.def(true)
+3 -1
View File
@@ -10,7 +10,7 @@
/> />
</div> </div>
</template> </template>
<script lang="ts" name="Cropper" setup> <script lang="ts" setup>
import { CSSProperties, PropType } from 'vue' import { CSSProperties, PropType } from 'vue'
import Cropper from 'cropperjs' import Cropper from 'cropperjs'
import 'cropperjs/dist/cropper.css' import 'cropperjs/dist/cropper.css'
@@ -18,6 +18,8 @@ import { useDesign } from '@/hooks/web/useDesign'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { useDebounceFn } from '@vueuse/core' import { useDebounceFn } from '@vueuse/core'
defineOptions({ name: 'Cropper' })
type Options = Cropper.Options type Options = Cropper.Options
const defaultOptions: Options = { const defaultOptions: Options = {
+15 -16
View File
@@ -11,13 +11,15 @@
/> />
</div> </div>
</template> </template>
<script lang="ts" name="CropperAvatar" setup> <script lang="ts" setup>
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import CopperModal from './CopperModal.vue' import CopperModal from './CopperModal.vue'
defineOptions({ name: 'CropperAvatar' })
const props = defineProps({ const props = defineProps({
width: propTypes.string.def('200px'), width: propTypes.string.def('200px'),
value: propTypes.string.def(''), value: propTypes.string.def(''),
@@ -83,14 +85,14 @@ $prefix-cls: #{$namespace}--cropper-avatar;
} }
&-image-mask { &-image-mask {
opacity: 0%;
position: absolute; position: absolute;
width: inherit; width: inherit;
height: inherit; height: inherit;
border-radius: inherit;
border: inherit;
background: rgb(0 0 0 / 40%);
cursor: pointer; cursor: pointer;
background: rgb(0 0 0 / 40%);
border: inherit;
border-radius: inherit;
opacity: 0;
transition: opacity 0.4s; transition: opacity 0.4s;
::v-deep(svg) { ::v-deep(svg) {
@@ -99,7 +101,7 @@ $prefix-cls: #{$namespace}--cropper-avatar;
} }
&-image-mask:hover { &-image-mask:hover {
opacity: 4000%; opacity: 40;
} }
&-upload-btn { &-upload-btn {
@@ -121,21 +123,18 @@ $prefix-cls: #{$namespace}--cropper-avatar;
height: 120px; height: 120px;
} }
.user-info-head:hover:after { .user-info-head:hover::after {
content: '+';
position: absolute; position: absolute;
left: 0; inset: 0;
right: 0;
top: 0;
bottom: 0;
color: #eee;
background: rgba(0, 0, 0, 0.5);
font-size: 24px; font-size: 24px;
font-style: normal;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
cursor: pointer; font-style: normal;
line-height: 110px; line-height: 110px;
color: #eee;
cursor: pointer;
background: rgb(0 0 0 / 50%);
border-radius: 50%; border-radius: 50%;
content: '+';
} }
</style> </style>
@@ -1,4 +1,4 @@
<script lang="ts" name="Descriptions" setup> <script lang="ts" setup>
import { PropType } from 'vue' import { PropType } from 'vue'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
@@ -6,6 +6,8 @@ import { propTypes } from '@/utils/propTypes'
import { useAppStore } from '@/store/modules/app' import { useAppStore } from '@/store/modules/app'
import { DescriptionsSchema } from '@/types/descriptions' import { DescriptionsSchema } from '@/types/descriptions'
defineOptions({ name: 'Descriptions' })
const appStore = useAppStore() const appStore = useAppStore()
const mobile = computed(() => appStore.getMobile) const mobile = computed(() => appStore.getMobile)
+5 -2
View File
@@ -1,7 +1,10 @@
<script lang="ts" name="Dialog" setup> <script lang="ts" setup>
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { isNumber } from '@/utils/is' import { isNumber } from '@/utils/is'
// eslint-disable-next-line vue/no-reserved-component-names
defineOptions({ name: 'Dialog' })
const slots = useSlots() const slots = useSlots()
const props = defineProps({ const props = defineProps({
@@ -14,7 +17,7 @@ const props = defineProps({
}) })
const getBindValue = computed(() => { const getBindValue = computed(() => {
const delArr: string[] = ['fullscreen', 'title', 'maxHeight'] const delArr: string[] = ['fullscreen', 'title', 'maxHeight', 'appendToBody']
const attrs = useAttrs() const attrs = useAttrs()
const obj = { ...attrs, ...props } const obj = { ...attrs, ...props }
for (const key in obj) { for (const key in obj) {
+4 -2
View File
@@ -5,9 +5,11 @@
</template> </template>
</el-alert> </el-alert>
</template> </template>
<script setup lang="tsx" name="DocAlert"> <script setup lang="tsx">
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
defineOptions({ name: 'DocAlert' })
const props = defineProps({ const props = defineProps({
title: propTypes.string, title: propTypes.string,
url: propTypes.string url: propTypes.string
@@ -25,8 +27,8 @@ const getEnable = () => {
</script> </script>
<style scoped> <style scoped>
.el-alert--success.is-light { .el-alert--success.is-light {
border: 1px solid green;
margin-bottom: 10px; margin-bottom: 10px;
cursor: pointer; cursor: pointer;
border: 1px solid green;
} }
</style> </style>
+3 -1
View File
@@ -1,4 +1,4 @@
<script lang="ts" name="EChart" setup> <script lang="ts" setup>
import type { EChartsOption } from 'echarts' import type { EChartsOption } from 'echarts'
import echarts from '@/plugins/echarts' import echarts from '@/plugins/echarts'
import { debounce } from 'lodash-es' import { debounce } from 'lodash-es'
@@ -9,6 +9,8 @@ import { useAppStore } from '@/store/modules/app'
import { isString } from '@/utils/is' import { isString } from '@/utils/is'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
defineOptions({ name: 'EChart' })
const { getPrefixCls, variables } = useDesign() const { getPrefixCls, variables } = useDesign()
const prefixCls = getPrefixCls('echart') const prefixCls = getPrefixCls('echart')
+3 -1
View File
@@ -1,4 +1,4 @@
<script lang="ts" name="Editor" setup> <script lang="ts" setup>
import { PropType } from 'vue' import { PropType } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue' import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { i18nChangeLanguage, IDomEditor, IEditorConfig } from '@wangeditor/editor' import { i18nChangeLanguage, IDomEditor, IEditorConfig } from '@wangeditor/editor'
@@ -8,6 +8,8 @@ import { ElMessage } from 'element-plus'
import { useLocaleStore } from '@/store/modules/locale' import { useLocaleStore } from '@/store/modules/locale'
import { getAccessToken, getTenantId } from '@/utils/auth' import { getAccessToken, getTenantId } from '@/utils/auth'
defineOptions({ name: 'Editor' })
type InsertFnType = (url: string, alt: string, href: string) => void type InsertFnType = (url: string, alt: string, href: string) => void
const localeStore = useLocaleStore() const localeStore = useLocaleStore()
+3 -1
View File
@@ -1,9 +1,11 @@
<script lang="ts" name="Error" setup> <script lang="ts" setup>
import pageError from '@/assets/svgs/404.svg' import pageError from '@/assets/svgs/404.svg'
import networkError from '@/assets/svgs/500.svg' import networkError from '@/assets/svgs/500.svg'
import noPermission from '@/assets/svgs/403.svg' import noPermission from '@/assets/svgs/403.svg'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
defineOptions({ name: 'Error' })
interface ErrorMap { interface ErrorMap {
url: string url: string
message: string message: string
+9 -8
View File
@@ -1,16 +1,16 @@
<script lang="tsx"> <script lang="tsx">
import { PropType, defineComponent, ref, computed, unref, watch, onMounted } from 'vue' import { computed, defineComponent, onMounted, PropType, ref, unref, watch } from 'vue'
import { ElForm, ElFormItem, ElRow, ElCol, ElTooltip } from 'element-plus' import { ElCol, ElForm, ElFormItem, ElRow, ElTooltip } from 'element-plus'
import { componentMap } from './componentMap' import { componentMap } from './componentMap'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { getSlot } from '@/utils/tsxHelper' import { getSlot } from '@/utils/tsxHelper'
import { import {
setTextPlaceholder,
setGridProp,
setComponentProps,
setItemComponentSlots,
initModel, initModel,
setFormItemSlots setComponentProps,
setFormItemSlots,
setGridProp,
setItemComponentSlots,
setTextPlaceholder
} from './helper' } from './helper'
import { useRenderSelect } from './components/useRenderSelect' import { useRenderSelect } from './components/useRenderSelect'
import { useRenderRadio } from './components/useRenderRadio' import { useRenderRadio } from './components/useRenderRadio'
@@ -27,6 +27,7 @@ const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('form') const prefixCls = getPrefixCls('form')
export default defineComponent({ export default defineComponent({
// eslint-disable-next-line vue/no-reserved-component-names
name: 'Form', name: 'Form',
props: { props: {
// 生成Form的布局结构数组 // 生成Form的布局结构数组
@@ -196,7 +197,7 @@ export default defineComponent({
<span>{item.label}</span> <span>{item.label}</span>
<ElTooltip placement="right" raw-content> <ElTooltip placement="right" raw-content>
{{ {{
content: () => <span v-html={item.labelMessage}></span>, content: () => <span v-dompurify-html={item.labelMessage}></span>,
default: () => ( default: () => (
<Icon <Icon
icon="ep:warning" icon="ep:warning"
+4 -4
View File
@@ -1,6 +1,6 @@
import type { Slots } from 'vue' import type { Slots } from 'vue'
import { getSlot } from '@/utils/tsxHelper' import { getSlot } from '@/utils/tsxHelper'
import { PlaceholderMoel } from './types' import { PlaceholderModel } from './types'
import { FormSchema } from '@/types/form' import { FormSchema } from '@/types/form'
import { ColProps } from '@/types/components' import { ColProps } from '@/types/components'
@@ -10,7 +10,7 @@ import { ColProps } from '@/types/components'
* @returns 返回提示信息对象 * @returns 返回提示信息对象
* @description 用于自动设置placeholder * @description 用于自动设置placeholder
*/ */
export const setTextPlaceholder = (schema: FormSchema): PlaceholderMoel => { export const setTextPlaceholder = (schema: FormSchema): PlaceholderModel => {
const { t } = useI18n() const { t } = useI18n()
const textMap = ['Input', 'Autocomplete', 'InputNumber', 'InputPassword'] const textMap = ['Input', 'Autocomplete', 'InputNumber', 'InputPassword']
const selectMap = ['Select', 'SelectV2', 'TimePicker', 'DatePicker', 'TimeSelect', 'TimeSelect'] const selectMap = ['Select', 'SelectV2', 'TimePicker', 'DatePicker', 'TimeSelect', 'TimeSelect']
@@ -108,8 +108,8 @@ export const setItemComponentSlots = (
/** /**
* *
* @param schema Form表单结构化数组 * @param schema Form表单结构化数组
* @param formModel FormMoel * @param formModel FormModel
* @returns FormMoel * @returns FormModel
* @description 生成对应的formModel * @description 生成对应的formModel
*/ */
export const initModel = (schema: FormSchema[], formModel: Recordable) => { export const initModel = (schema: FormSchema[], formModel: Recordable) => {
+1 -1
View File
@@ -1,6 +1,6 @@
import { FormSchema } from '@/types/form' import { FormSchema } from '@/types/form'
export interface PlaceholderMoel { export interface PlaceholderModel {
placeholder?: string placeholder?: string
startPlaceholder?: string startPlaceholder?: string
endPlaceholder?: string endPlaceholder?: string
+3 -1
View File
@@ -1,6 +1,8 @@
<script lang="ts" name="IFrame" setup> <script lang="ts" setup>
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
defineOptions({ name: 'IFrame' })
const props = defineProps({ const props = defineProps({
src: propTypes.string.def('') src: propTypes.string.def('')
}) })
+3 -1
View File
@@ -1,8 +1,10 @@
<script lang="ts" name="Icon" setup> <script lang="ts" setup>
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import Iconify from '@purge-icons/generated' import Iconify from '@purge-icons/generated'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
defineOptions({ name: 'Icon' })
const { getPrefixCls } = useDesign() const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('icon') const prefixCls = getPrefixCls('icon')
+7 -5
View File
@@ -1,8 +1,10 @@
<script lang="ts" name="IconSelect" setup> <script lang="ts" setup>
import { CSSProperties } from 'vue' import { CSSProperties } from 'vue'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
import { IconJson } from '@/components/Icon/src/data' import { IconJson } from '@/components/Icon/src/data'
defineOptions({ name: 'IconSelect' })
type ParameterCSSProperties = (item?: string) => CSSProperties | undefined type ParameterCSSProperties = (item?: string) => CSSProperties | undefined
const props = defineProps({ const props = defineProps({
@@ -189,10 +191,10 @@ watch(
.icon-item { .icon-item {
&:hover { &:hover {
border-color: var(--el-color-primary);
color: var(--el-color-primary); color: var(--el-color-primary);
transition: all 0.4s; border-color: var(--el-color-primary);
transform: scaleX(1.05); transform: scaleX(1.05);
transition: all 0.4s;
} }
} }
@@ -213,15 +215,15 @@ watch(
} }
:deep(.el-tabs__item) { :deep(.el-tabs__item) {
height: 30px;
font-size: 12px; font-size: 12px;
font-weight: normal; font-weight: normal;
height: 30px;
line-height: 30px; line-height: 30px;
} }
:deep(.el-tabs__header), :deep(.el-tabs__header),
:deep(.el-tabs__nav-wrap) { :deep(.el-tabs__nav-wrap) {
margin: 0;
position: static; position: static;
margin: 0;
} }
</style> </style>
@@ -1,7 +1,9 @@
<script lang="ts" name="ImageViewer" setup> <script lang="ts" setup>
import { PropType } from 'vue' import { PropType } from 'vue'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
defineOptions({ name: 'ImageViewer' })
const props = defineProps({ const props = defineProps({
urlList: { urlList: {
type: Array as PropType<string[]>, type: Array as PropType<string[]>,
+3 -1
View File
@@ -1,9 +1,11 @@
<script lang="ts" name="InfoTip" setup> <script lang="ts" setup>
import { PropType } from 'vue' import { PropType } from 'vue'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { TipSchema } from '@/types/infoTip' import { TipSchema } from '@/types/infoTip'
defineOptions({ name: 'InfoTip' })
const { getPrefixCls } = useDesign() const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('infotip') const prefixCls = getPrefixCls('infotip')
@@ -1,10 +1,12 @@
<script lang="ts" name="InputPassword" setup> <script lang="ts" setup>
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { useConfigGlobal } from '@/hooks/web/useConfigGlobal' import { useConfigGlobal } from '@/hooks/web/useConfigGlobal'
import type { ZxcvbnResult } from '@zxcvbn-ts/core' import type { ZxcvbnResult } from '@zxcvbn-ts/core'
import { zxcvbn } from '@zxcvbn-ts/core' import { zxcvbn } from '@zxcvbn-ts/core'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
defineOptions({ name: 'InputPassword' })
const { getPrefixCls } = useDesign() const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('input-password') const prefixCls = getPrefixCls('input-password')
@@ -94,7 +96,7 @@ $prefix-cls: #{$namespace}-input-password;
background-color: transparent; background-color: transparent;
border-color: var(--el-color-white); border-color: var(--el-color-white);
border-style: solid; border-style: solid;
border-width: 0 5px 0 5px; border-width: 0 5px;
content: ''; content: '';
} }
+3 -1
View File
@@ -14,9 +14,11 @@
@current-change="handleCurrentChange" @current-change="handleCurrentChange"
/> />
</template> </template>
<script name="Pagination" setup> <script lang="ts" setup>
import { computed } from 'vue' import { computed } from 'vue'
defineOptions({ name: 'Pagination' })
const props = defineProps({ const props = defineProps({
// 总条目数 // 总条目数
total: { total: {
+4 -2
View File
@@ -1,4 +1,4 @@
<script lang="ts" name="Qrcode" setup> <script lang="ts" setup>
import { computed, nextTick, PropType, ref, unref, watch } from 'vue' import { computed, nextTick, PropType, ref, unref, watch } from 'vue'
import QRCode, { QRCodeRenderersOptions } from 'qrcode' import QRCode, { QRCodeRenderersOptions } from 'qrcode'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
@@ -7,6 +7,8 @@ import { useDesign } from '@/hooks/web/useDesign'
import { isString } from '@/utils/is' import { isString } from '@/utils/is'
import { QrcodeLogo } from '@/types/qrcode' import { QrcodeLogo } from '@/types/qrcode'
defineOptions({ name: 'Qrcode' })
const props = defineProps({ const props = defineProps({
// img 或者 canvas,img不支持logo嵌套 // img 或者 canvas,img不支持logo嵌套
tag: propTypes.string.validate((v: string) => ['canvas', 'img'].includes(v)).def('canvas'), tag: propTypes.string.validate((v: string) => ['canvas', 'img'].includes(v)).def('canvas'),
@@ -241,7 +243,7 @@ $prefix-cls: #{$namespace}-qrcode;
.#{$prefix-cls} { .#{$prefix-cls} {
&--disabled { &--disabled {
background: rgba(255, 255, 255, 0.95); background: rgb(255 255 255 / 95%);
& > div { & > div {
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
+76
View File
@@ -0,0 +1,76 @@
<template>
<ElDialog v-model="showSearch" :show-close="false" title="菜单搜索">
<el-select
filterable
:reserve-keyword="false"
remote
placeholder="请输入菜单内容"
:remote-method="remoteMethod"
style="width: 100%"
@change="handleChange"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</ElDialog>
</template>
<script lang="ts" setup>
const router = useRouter() // 路由对象
const showSearch = ref(false) // 是否显示弹框
const value: Ref = ref('') // 用户输入的值
const routers = router.getRoutes() // 路由对象
const options = computed(() => {
// 提示选项
if (!value.value) {
return []
}
const list = routers.filter((item: any) => {
if (item.meta.title?.indexOf(value.value) > -1 || item.path.indexOf(value.value) > -1) {
return true
}
})
return list.map((item) => {
return {
label: `${item.meta.title}${item.path}`,
value: item.path
}
})
})
function remoteMethod(data) {
// 这里可以执行相应的操作(例如打开搜索框等)
value.value = data
}
function handleChange(path) {
router.push({ path })
}
onMounted(() => {
window.addEventListener('keydown', listenKey)
})
onUnmounted(() => {
window.removeEventListener('keydown', listenKey)
})
// 监听 ctrl + k
function listenKey(event) {
if ((event.ctrlKey || event.metaKey) && event.key === 'k') {
showSearch.value = !showSearch.value
// 这里可以执行相应的操作(例如打开搜索框等)
}
}
defineExpose({
openSearch: () => {
showSearch.value = true
}
})
</script>
+3 -1
View File
@@ -1,4 +1,4 @@
<script lang="ts" name="Search" setup> <script lang="ts" setup>
import { PropType } from 'vue' import { PropType } from 'vue'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
@@ -7,6 +7,8 @@ import { findIndex } from '@/utils'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
import { FormSchema } from '@/types/form' import { FormSchema } from '@/types/form'
defineOptions({ name: 'Search' })
const { t } = useI18n() const { t } = useI18n()
const props = defineProps({ const props = defineProps({
+3 -1
View File
@@ -1,8 +1,10 @@
<script lang="ts" name="Sticky" setup> <script lang="ts" setup>
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { isClient, useEventListener, useWindowSize } from '@vueuse/core' import { isClient, useEventListener, useWindowSize } from '@vueuse/core'
import type { CSSProperties } from 'vue' import type { CSSProperties } from 'vue'
defineOptions({ name: 'Sticky' })
const props = defineProps({ const props = defineProps({
// 距离顶部或者底部的距离(单位px) // 距离顶部或者底部的距离(单位px)
offset: propTypes.number.def(0), offset: propTypes.number.def(0),
+2
View File
@@ -9,6 +9,7 @@ import { set } from 'lodash-es'
import { Pagination, TableColumn, TableSetPropsType, TableSlotDefault } from '@/types/table' import { Pagination, TableColumn, TableSetPropsType, TableSlotDefault } from '@/types/table'
export default defineComponent({ export default defineComponent({
// eslint-disable-next-line vue/no-reserved-component-names
name: 'Table', name: 'Table',
props: { props: {
pageSize: propTypes.number.def(10), pageSize: propTypes.number.def(10),
@@ -302,6 +303,7 @@ export default defineComponent({
margin-left: 0; margin-left: 0;
padding: 8px 4px; padding: 8px 4px;
} }
:deep(.el-button.is-link) { :deep(.el-button.is-link) {
margin-left: 0; margin-left: 0;
padding: 8px 4px; padding: 8px 4px;
+3 -1
View File
@@ -1,6 +1,8 @@
<script lang="ts" name="Tooltip" setup> <script lang="ts" setup>
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
defineOptions({ name: 'Tooltip' })
defineProps({ defineProps({
titel: propTypes.string.def(''), titel: propTypes.string.def(''),
message: propTypes.string.def(''), message: propTypes.string.def(''),
+7 -1
View File
@@ -32,13 +32,15 @@
</el-upload> </el-upload>
</div> </div>
</template> </template>
<script setup lang="ts" name="UploadFile"> <script lang="ts" setup>
import { PropType } from 'vue' import { PropType } from 'vue'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { getAccessToken, getTenantId } from '@/utils/auth' import { getAccessToken, getTenantId } from '@/utils/auth'
import type { UploadInstance, UploadUserFile, UploadProps, UploadRawFile } from 'element-plus' import type { UploadInstance, UploadUserFile, UploadProps, UploadRawFile } from 'element-plus'
defineOptions({ name: 'UploadFile' })
const message = useMessage() // 消息弹窗 const message = useMessage() // 消息弹窗
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
@@ -143,21 +145,25 @@ const listToString = (list: UploadUserFile[], separator?: string) => {
.upload-file-uploader { .upload-file-uploader {
margin-bottom: 5px; margin-bottom: 5px;
} }
:deep(.upload-file-list .el-upload-list__item) { :deep(.upload-file-list .el-upload-list__item) {
border: 1px solid #e4e7ed; border: 1px solid #e4e7ed;
line-height: 2; line-height: 2;
margin-bottom: 10px; margin-bottom: 10px;
position: relative; position: relative;
} }
:deep(.el-upload-list__item-file-name) { :deep(.el-upload-list__item-file-name) {
max-width: 250px; max-width: 250px;
} }
:deep(.upload-file-list .ele-upload-list__item-content) { :deep(.upload-file-list .ele-upload-list__item-content) {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
color: inherit; color: inherit;
} }
:deep(.ele-upload-list__item-content-action .el-link) { :deep(.ele-upload-list__item-content-action .el-link) {
margin-right: 10px; margin-right: 10px;
} }
+24 -4
View File
@@ -50,13 +50,15 @@
</div> </div>
</template> </template>
<script setup lang="ts" name="UploadImg"> <script lang="ts" setup>
import type { UploadProps } from 'element-plus' import type { UploadProps } from 'element-plus'
import { generateUUID } from '@/utils' import { generateUUID } from '@/utils'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { getAccessToken, getTenantId } from '@/utils/auth' import { getAccessToken, getTenantId } from '@/utils/auth'
defineOptions({ name: 'UploadImg' })
type FileTypes = type FileTypes =
| 'image/apng' | 'image/apng'
| 'image/bmp' | 'image/bmp'
@@ -79,7 +81,7 @@ const props = defineProps({
fileType: propTypes.array.def(['image/jpeg', 'image/png', 'image/gif']), // 图片类型限制 ==> 非必传(默认为 ["image/jpeg", "image/png", "image/gif"]) fileType: propTypes.array.def(['image/jpeg', 'image/png', 'image/gif']), // 图片类型限制 ==> 非必传(默认为 ["image/jpeg", "image/png", "image/gif"])
height: propTypes.string.def('150px'), // 组件高度 ==> 非必传(默认为 150px) height: propTypes.string.def('150px'), // 组件高度 ==> 非必传(默认为 150px)
width: propTypes.string.def('150px'), // 组件宽度 ==> 非必传(默认为 150px) width: propTypes.string.def('150px'), // 组件宽度 ==> 非必传(默认为 150px)
borderRadius: propTypes.string.def('8px') // 组件边框圆角 ==> 非必传(默认为 8px) borderradius: propTypes.string.def('8px') // 组件边框圆角 ==> 非必传(默认为 8px)
}) })
const { t } = useI18n() // 国际化 const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗 const message = useMessage() // 消息弹窗
@@ -130,29 +132,34 @@ const uploadError = () => {
:deep(.el-upload), :deep(.el-upload),
:deep(.el-upload-dragger) { :deep(.el-upload-dragger) {
border: 1px dashed var(--el-color-danger) !important; border: 1px dashed var(--el-color-danger) !important;
&:hover { &:hover {
border-color: var(--el-color-primary) !important; border-color: var(--el-color-primary) !important;
} }
} }
} }
} }
:deep(.disabled) { :deep(.disabled) {
.el-upload, .el-upload,
.el-upload-dragger { .el-upload-dragger {
cursor: not-allowed !important; cursor: not-allowed !important;
background: var(--el-disabled-bg-color); background: var(--el-disabled-bg-color);
border: 1px dashed var(--el-border-color-darker) !important; border: 1px dashed var(--el-border-color-darker) !important;
&:hover { &:hover {
border: 1px dashed var(--el-border-color-darker) !important; border: 1px dashed var(--el-border-color-darker) !important;
} }
} }
} }
.upload-box { .upload-box {
.no-border { .no-border {
:deep(.el-upload) { :deep(.el-upload) {
border: none !important; border: none !important;
} }
} }
:deep(.upload) { :deep(.upload) {
.el-upload { .el-upload {
position: relative; position: relative;
@@ -163,14 +170,17 @@ const uploadError = () => {
height: v-bind(height); height: v-bind(height);
overflow: hidden; overflow: hidden;
border: 1px dashed var(--el-border-color-darker); border: 1px dashed var(--el-border-color-darker);
border-radius: v-bind(borderRadius); border-radius: v-bind(borderradius);
transition: var(--el-transition-duration-fast); transition: var(--el-transition-duration-fast);
&:hover { &:hover {
border-color: var(--el-color-primary); border-color: var(--el-color-primary);
.upload-handle { .upload-handle {
opacity: 1; opacity: 1;
} }
} }
.el-upload-dragger { .el-upload-dragger {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -181,20 +191,24 @@ const uploadError = () => {
overflow: hidden; overflow: hidden;
background-color: transparent; background-color: transparent;
border: 1px dashed var(--el-border-color-darker); border: 1px dashed var(--el-border-color-darker);
border-radius: v-bind(borderRadius); border-radius: v-bind(borderradius);
&:hover { &:hover {
border: 1px dashed var(--el-color-primary); border: 1px dashed var(--el-color-primary);
} }
} }
.el-upload-dragger.is-dragover { .el-upload-dragger.is-dragover {
background-color: var(--el-color-primary-light-9); background-color: var(--el-color-primary-light-9);
border: 2px dashed var(--el-color-primary) !important; border: 2px dashed var(--el-color-primary) !important;
} }
.upload-image { .upload-image {
width: 100%; width: 100%;
height: 100%; height: 100%;
object-fit: contain; object-fit: contain;
} }
.upload-empty { .upload-empty {
position: relative; position: relative;
display: flex; display: flex;
@@ -204,11 +218,13 @@ const uploadError = () => {
font-size: 12px; font-size: 12px;
line-height: 30px; line-height: 30px;
color: var(--el-color-info); color: var(--el-color-info);
.el-icon { .el-icon {
font-size: 28px; font-size: 28px;
color: var(--el-text-color-secondary); color: var(--el-text-color-secondary);
} }
} }
.upload-handle { .upload-handle {
position: absolute; position: absolute;
top: 0; top: 0;
@@ -223,6 +239,7 @@ const uploadError = () => {
background: rgb(0 0 0 / 60%); background: rgb(0 0 0 / 60%);
opacity: 0; opacity: 0;
transition: var(--el-transition-duration-fast); transition: var(--el-transition-duration-fast);
.handle-icon { .handle-icon {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -230,11 +247,13 @@ const uploadError = () => {
justify-content: center; justify-content: center;
padding: 0 6%; padding: 0 6%;
color: aliceblue; color: aliceblue;
.el-icon { .el-icon {
margin-bottom: 40%; margin-bottom: 40%;
font-size: 130%; font-size: 130%;
line-height: 130%; line-height: 130%;
} }
span { span {
font-size: 85%; font-size: 85%;
line-height: 85%; line-height: 85%;
@@ -243,6 +262,7 @@ const uploadError = () => {
} }
} }
} }
.el-upload__tip { .el-upload__tip {
line-height: 18px; line-height: 18px;
text-align: center; text-align: center;
+50 -18
View File
@@ -1,19 +1,19 @@
<template> <template>
<div class="upload-box"> <div class="upload-box">
<el-upload <el-upload
:action="updateUrl"
list-type="picture-card"
:class="['upload', drag ? 'no-border' : '']"
v-model:file-list="fileList" v-model:file-list="fileList"
:multiple="true" :accept="fileType.join(',')"
:limit="limit" :action="updateUrl"
:headers="uploadHeaders"
:before-upload="beforeUpload" :before-upload="beforeUpload"
:class="['upload', drag ? 'no-border' : '']"
:drag="drag"
:headers="uploadHeaders"
:limit="limit"
:multiple="true"
:on-error="uploadError"
:on-exceed="handleExceed" :on-exceed="handleExceed"
:on-success="uploadSuccess" :on-success="uploadSuccess"
:on-error="uploadError" list-type="picture-card"
:drag="drag"
:accept="fileType.join(',')"
> >
<div class="upload-empty"> <div class="upload-empty">
<slot name="empty"> <slot name="empty">
@@ -40,19 +40,21 @@
</div> </div>
<el-image-viewer <el-image-viewer
v-if="imgViewVisible" v-if="imgViewVisible"
@close="imgViewVisible = false"
:url-list="[viewImageUrl]" :url-list="[viewImageUrl]"
@close="imgViewVisible = false"
/> />
</div> </div>
</template> </template>
<script setup lang="ts" name="UploadImgs"> <script lang="ts" setup>
import { PropType } from 'vue' import { PropType } from 'vue'
import type { UploadFile, UploadProps, UploadUserFile } from 'element-plus'
import { ElNotification } from 'element-plus' import { ElNotification } from 'element-plus'
import type { UploadProps, UploadFile, UploadUserFile } from 'element-plus'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { getAccessToken, getTenantId } from '@/utils/auth' import { getAccessToken, getTenantId } from '@/utils/auth'
defineOptions({ name: 'UploadImgs' })
const message = useMessage() // 消息弹窗 const message = useMessage() // 消息弹窗
type FileTypes = type FileTypes =
@@ -80,7 +82,7 @@ const props = defineProps({
fileType: propTypes.array.def(['image/jpeg', 'image/png', 'image/gif']), // 图片类型限制 ==> 非必传(默认为 ["image/jpeg", "image/png", "image/gif"]) fileType: propTypes.array.def(['image/jpeg', 'image/png', 'image/gif']), // 图片类型限制 ==> 非必传(默认为 ["image/jpeg", "image/png", "image/gif"])
height: propTypes.string.def('150px'), // 组件高度 ==> 非必传(默认为 150px) height: propTypes.string.def('150px'), // 组件高度 ==> 非必传(默认为 150px)
width: propTypes.string.def('150px'), // 组件宽度 ==> 非必传(默认为 150px) width: propTypes.string.def('150px'), // 组件宽度 ==> 非必传(默认为 150px)
borderRadius: propTypes.string.def('8px') // 组件边框圆角 ==> 非必传(默认为 8px) borderradius: propTypes.string.def('8px') // 组件边框圆角 ==> 非必传(默认为 8px)
}) })
const uploadHeaders = ref({ const uploadHeaders = ref({
@@ -88,8 +90,19 @@ const uploadHeaders = ref({
'tenant-id': getTenantId() 'tenant-id': getTenantId()
}) })
const fileList = ref<UploadUserFile[]>(props.modelValue) const fileList = ref<UploadUserFile[]>([])
// fix: 改为动态监听赋值解决图片回显问题
watch(
() => props.modelValue,
(data) => {
if (!data) return
fileList.value = data
},
{
deep: true,
immediate: true
}
)
/** /**
* @description 文件上传之前判断 * @description 文件上传之前判断
* @param rawFile 上传的文件 * @param rawFile 上传的文件
@@ -116,9 +129,11 @@ const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
interface UploadEmits { interface UploadEmits {
(e: 'update:modelValue', value: UploadUserFile[]): void (e: 'update:modelValue', value: UploadUserFile[]): void
} }
const emit = defineEmits<UploadEmits>() const emit = defineEmits<UploadEmits>()
const uploadSuccess = (response, uploadFile: UploadFile) => { const uploadSuccess = (response, uploadFile: UploadFile) => {
if (!response) return if (!response) return
// TODO 多图上传组件成功后只是把保存成功后的url替换掉组件选图时的文件路径,所以返回的fileList包含的是一个包含文件信息的对象列表
uploadFile.url = response.data uploadFile.url = response.data
emit('update:modelValue', fileList.value) emit('update:modelValue', fileList.value)
message.success('上传成功') message.success('上传成功')
@@ -159,35 +174,40 @@ const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
} }
</script> </script>
<style scoped lang="scss"> <style lang="scss" scoped>
.is-error { .is-error {
.upload { .upload {
:deep(.el-upload--picture-card), :deep(.el-upload--picture-card),
:deep(.el-upload-dragger) { :deep(.el-upload-dragger) {
border: 1px dashed var(--el-color-danger) !important; border: 1px dashed var(--el-color-danger) !important;
&:hover { &:hover {
border-color: var(--el-color-primary) !important; border-color: var(--el-color-primary) !important;
} }
} }
} }
} }
:deep(.disabled) { :deep(.disabled) {
.el-upload--picture-card, .el-upload--picture-card,
.el-upload-dragger { .el-upload-dragger {
cursor: not-allowed; cursor: not-allowed;
background: var(--el-disabled-bg-color) !important; background: var(--el-disabled-bg-color) !important;
border: 1px dashed var(--el-border-color-darker); border: 1px dashed var(--el-border-color-darker);
&:hover { &:hover {
border-color: var(--el-border-color-darker) !important; border-color: var(--el-border-color-darker) !important;
} }
} }
} }
.upload-box { .upload-box {
.no-border { .no-border {
:deep(.el-upload--picture-card) { :deep(.el-upload--picture-card) {
border: none !important; border: none !important;
} }
} }
:deep(.upload) { :deep(.upload) {
.el-upload-dragger { .el-upload-dragger {
display: flex; display: flex;
@@ -198,27 +218,32 @@ const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
padding: 0; padding: 0;
overflow: hidden; overflow: hidden;
border: 1px dashed var(--el-border-color-darker); border: 1px dashed var(--el-border-color-darker);
border-radius: v-bind(borderRadius); border-radius: v-bind(borderradius);
&:hover { &:hover {
border: 1px dashed var(--el-color-primary); border: 1px dashed var(--el-color-primary);
} }
} }
.el-upload-dragger.is-dragover { .el-upload-dragger.is-dragover {
background-color: var(--el-color-primary-light-9); background-color: var(--el-color-primary-light-9);
border: 2px dashed var(--el-color-primary) !important; border: 2px dashed var(--el-color-primary) !important;
} }
.el-upload-list__item, .el-upload-list__item,
.el-upload--picture-card { .el-upload--picture-card {
width: v-bind(width); width: v-bind(width);
height: v-bind(height); height: v-bind(height);
background-color: transparent; background-color: transparent;
border-radius: v-bind(borderRadius); border-radius: v-bind(borderradius);
} }
.upload-image { .upload-image {
width: 100%; width: 100%;
height: 100%; height: 100%;
object-fit: contain; object-fit: contain;
} }
.upload-handle { .upload-handle {
position: absolute; position: absolute;
top: 0; top: 0;
@@ -233,6 +258,7 @@ const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
background: rgb(0 0 0 / 60%); background: rgb(0 0 0 / 60%);
opacity: 0; opacity: 0;
transition: var(--el-transition-duration-fast); transition: var(--el-transition-duration-fast);
.handle-icon { .handle-icon {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -240,15 +266,18 @@ const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
justify-content: center; justify-content: center;
padding: 0 6%; padding: 0 6%;
color: aliceblue; color: aliceblue;
.el-icon { .el-icon {
margin-bottom: 15%; margin-bottom: 15%;
font-size: 140%; font-size: 140%;
} }
span { span {
font-size: 100%; font-size: 100%;
} }
} }
} }
.el-upload-list__item { .el-upload-list__item {
&:hover { &:hover {
.upload-handle { .upload-handle {
@@ -256,6 +285,7 @@ const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
} }
} }
} }
.upload-empty { .upload-empty {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -263,12 +293,14 @@ const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
font-size: 12px; font-size: 12px;
line-height: 30px; line-height: 30px;
color: var(--el-color-info); color: var(--el-color-info);
.el-icon { .el-icon {
font-size: 28px; font-size: 28px;
color: var(--el-text-color-secondary); color: var(--el-text-color-secondary);
} }
} }
} }
.el-upload__tip { .el-upload__tip {
line-height: 15px; line-height: 15px;
text-align: center; text-align: center;
+41 -53
View File
@@ -31,7 +31,7 @@
</div> </div>
</div> </div>
</template> </template>
<script name="Verify" type="text/babel"> <script type="text/babel">
/** /**
* Verify 验证码组件 * Verify 验证码组件
* @description 分发验证码使用 * @description 分发验证码使用
@@ -146,10 +146,9 @@ export default {
.verifybox { .verifybox {
position: relative; position: relative;
box-sizing: border-box; box-sizing: border-box;
border-radius: 2px;
border: 1px solid #e4e7eb; border: 1px solid #e4e7eb;
background-color: #fff; background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); box-shadow: 0 0 10px rgb(0 0 0 / 30%);
left: 50%; left: 50%;
top: 50%; top: 50%;
border-radius: 5px; border-radius: 5px;
@@ -189,7 +188,8 @@ export default {
z-index: 1001; z-index: 1001;
width: 100%; width: 100%;
height: 100vh; height: 100vh;
background: rgba(0, 0, 0, 0.3); background: rgb(0 0 0 / 30%);
/* display: none; */ /* display: none; */
transition: all 0.5s; transition: all 0.5s;
} }
@@ -197,8 +197,8 @@ export default {
.verify-tips { .verify-tips {
text-indent: 10px; text-indent: 10px;
position: absolute; position: absolute;
left: 0px; left: 0;
bottom: 0px; bottom: 0;
width: 100%; width: 100%;
height: 30px; height: 30px;
line-height: 30px; line-height: 30px;
@@ -206,12 +206,12 @@ export default {
} }
.suc-bg { .suc-bg {
background-color: rgba(92, 184, 92, 0.5); background-color: rgb(92 184 92 / 50%);
filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7f5CB85C, endcolorstr=#7f5CB85C); filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7f5CB85C, endcolorstr=#7f5CB85C);
} }
.err-bg { .err-bg {
background-color: rgba(217, 83, 79, 0.5); background-color: rgb(217 83 79 / 50%);
filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7fD9534F, endcolorstr=#7fD9534F); filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7fD9534F, endcolorstr=#7fD9534F);
} }
@@ -226,7 +226,8 @@ export default {
} }
/* ---------------------------- */ /* ---------------------------- */
/*常规验证码*/
/* 常规验证码 */
.verify-code { .verify-code {
font-size: 20px; font-size: 20px;
text-align: center; text-align: center;
@@ -270,19 +271,17 @@ export default {
width: 200px; width: 200px;
height: 30px; height: 30px;
background-color: #337ab7; background-color: #337ab7;
color: #ffffff; color: #fff;
border: none; border: none;
margin-top: 10px; margin-top: 10px;
border-radius: 8px; border-radius: 8px;
} }
/*滑动验证码*/ /* 滑动验证码 */
.verify-bar-area { .verify-bar-area {
position: relative; position: relative;
background: #ffffff; background: #fff;
text-align: center; text-align: center;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box; box-sizing: content-box;
border: 1px solid #ddd; border: 1px solid #ddd;
border-radius: 8px; border-radius: 8px;
@@ -290,20 +289,18 @@ export default {
.verify-bar-area .verify-move-block { .verify-bar-area .verify-move-block {
position: absolute; position: absolute;
top: 0px; top: 0;
left: 0; left: 0;
background: #fff; background: #fff;
cursor: pointer; cursor: pointer;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box; box-sizing: content-box;
box-shadow: 0 0 2px #888888; box-shadow: 0 0 2px #888;
border-radius: 8px; border-radius: 8px;
} }
.verify-bar-area .verify-move-block:hover { .verify-bar-area .verify-move-block:hover {
background-color: #337ab7; background-color: #337ab7;
color: #ffffff; color: #fff;
} }
.verify-bar-area .verify-left-bar { .verify-bar-area .verify-left-bar {
@@ -312,8 +309,6 @@ export default {
left: -1px; left: -1px;
background: #f0fff0; background: #f0fff0;
cursor: pointer; cursor: pointer;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box; box-sizing: content-box;
border: 1px solid #ddd; border: 1px solid #ddd;
border-radius: 8px; border-radius: 8px;
@@ -321,8 +316,6 @@ export default {
.verify-img-panel { .verify-img-panel {
margin: 0; margin: 0;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box; box-sizing: content-box;
border-top: 1px solid #ddd; border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd; border-bottom: 1px solid #ddd;
@@ -358,6 +351,7 @@ export default {
position: absolute; position: absolute;
text-align: center; text-align: center;
z-index: 3; z-index: 3;
/* border: 1px solid #fff; */ /* border: 1px solid #fff; */
} }
@@ -369,83 +363,77 @@ export default {
z-index: 3; z-index: 3;
} }
/*字体图标的css*/ /* 字体图标的css */
/*@font-face {font-family: "iconfont";*/
/*src: url('../fonts/iconfont.eot?t=1508229193188'); !* IE9*!*/ /* @font-face {font-family: "iconfont"; */
/*src: url('../fonts/iconfont.eot?t=1508229193188#iefix') format('embedded-opentype'), !* IE6-IE8 *!*/
/*url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'),*/ /* src: url('../fonts/iconfont.eot?t=1508229193188'); !* IE9*! */
/*url('../fonts/iconfont.ttf?t=1508229193188') format('truetype'), !* chrome, firefox, opera, Safari, Android, iOS 4.2+*!*/
/*url('../fonts/iconfont.svg?t=1508229193188#iconfont') format('svg'); !* iOS 4.1- *!*/ /* src: url('../fonts/iconfont.eot?t=1508229193188#iefix') format('embedded-opentype'), !* IE6-IE8 *! */
/*}*/
/* url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'), */
/* url('../fonts/iconfont.ttf?t=1508229193188') format('truetype'), !* chrome, firefox, opera, Safari, Android, iOS 4.2+*! */
/* url('../fonts/iconfont.svg?t=1508229193188#iconfont') format('svg'); !* iOS 4.1- *! */
/* } */
.iconfont { .iconfont {
font-family: 'iconfont' !important; font-family: iconfont !important;
font-size: 16px; font-size: 16px;
font-style: normal; font-style: normal;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.icon-check:before { .icon-check::before {
content: ' '; content: ' ';
display: block; display: block;
width: 16px; width: 16px;
height: 16px; height: 16px;
position: absolute; position: absolute;
margin: auto; margin: auto;
left: 0; inset: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999; z-index: 9999;
background-image: url('data:image/png;base64,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 truncated background-image: url('data:image/png;base64,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 truncated
background-size: contain; background-size: contain;
} }
.icon-close:before { .icon-close::before {
content: ' '; content: ' ';
display: block; display: block;
width: 16px; width: 16px;
height: 16px; height: 16px;
position: absolute; position: absolute;
margin: auto; margin: auto;
left: 0; inset: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999; z-index: 9999;
background-image: url('data:image/png;base64,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 truncated background-image: url('data:image/png;base64,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 truncated
background-size: contain; background-size: contain;
} }
.icon-right:before { .icon-right::before {
content: ' '; content: ' ';
display: block; display: block;
width: 16px; width: 16px;
height: 16px; height: 16px;
position: absolute; position: absolute;
margin: auto; margin: auto;
left: 0; inset: 0;
right: 0;
top: 0;
bottom: 0;
background-size: cover;
z-index: 9999; z-index: 9999;
background-image: url('data:image/png;base64,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 truncated background-image: url('data:image/png;base64,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 truncated
background-size: contain; background-size: contain;
} }
.icon-refresh:before { .icon-refresh::before {
content: ' '; content: ' ';
display: block; display: block;
width: 16px; width: 16px;
height: 16px; height: 16px;
position: absolute; position: absolute;
margin: auto; margin: auto;
left: 0; inset: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999; z-index: 9999;
background-image: url('data:image/png;base64,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 truncated background-image: url('data:image/png;base64,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 truncated
background-size: contain; background-size: contain;
@@ -57,7 +57,7 @@
</div> </div>
</div> </div>
</template> </template>
<script name="VerifyPoints" setup type="text/babel"> <script setup type="text/babel">
/** /**
* VerifyPoints * VerifyPoints
* @description 点选 * @description 点选
@@ -71,7 +71,7 @@
</div> </div>
</div> </div>
</template> </template>
<script name="VerifySlide" setup type="text/babel"> <script setup type="text/babel">
/** /**
* VerifySlide * VerifySlide
* @description 滑块 * @description 滑块
+3 -1
View File
@@ -1,7 +1,9 @@
<script lang="ts" name="XButton" setup> <script lang="ts" setup>
import { PropType } from 'vue' import { PropType } from 'vue'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
defineOptions({ name: 'XButton' })
const props = defineProps({ const props = defineProps({
modelValue: propTypes.bool.def(false), modelValue: propTypes.bool.def(false),
loading: propTypes.bool.def(false), loading: propTypes.bool.def(false),
+3 -1
View File
@@ -1,7 +1,9 @@
<script lang="ts" name="XTextButton" setup> <script lang="ts" setup>
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { PropType } from 'vue' import { PropType } from 'vue'
defineOptions({ name: 'XTextButton' })
const props = defineProps({ const props = defineProps({
modelValue: propTypes.bool.def(false), modelValue: propTypes.bool.def(false),
loading: propTypes.bool.def(false), loading: propTypes.bool.def(false),
@@ -206,7 +206,7 @@
</div> </div>
</template> </template>
<script setup lang="ts" name="MyProcessDesigner"> <script lang="ts" setup>
// import 'bpmn-js/dist/assets/diagram-js.css' // 左边工具栏以及编辑节点的样式 // import 'bpmn-js/dist/assets/diagram-js.css' // 左边工具栏以及编辑节点的样式
// import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css' // import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'
// import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css' // import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css'
@@ -244,6 +244,9 @@ import { XmlNode, XmlNodeType, parseXmlString } from 'steady-xml'
// const eventName = reactive({ // const eventName = reactive({
// name: '' // name: ''
// }) // })
defineOptions({ name: 'MyProcessDesigner' })
const bpmnCanvas = ref() const bpmnCanvas = ref()
const refFile = ref() const refFile = ref()
const emit = defineEmits([ const emit = defineEmits([
@@ -6,10 +6,14 @@
</div> </div>
</template> </template>
<script setup lang="ts" name="MyProcessViewer"> <script lang="ts" setup>
import BpmnViewer from 'bpmn-js/lib/Viewer' import BpmnViewer from 'bpmn-js/lib/Viewer'
import DefaultEmptyXML from './plugins/defaultEmpty' import DefaultEmptyXML from './plugins/defaultEmpty'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { formatDate } from '@/utils/formatTime'
defineOptions({ name: 'MyProcessViewer' })
const props = defineProps({ const props = defineProps({
value: { value: {
// BPMN XML 字符串 // BPMN XML 字符串
@@ -403,6 +407,7 @@ watch(
stroke-dasharray: 4px !important; stroke-dasharray: 4px !important;
fill-opacity: 0.2 !important; fill-opacity: 0.2 !important;
} }
.highlight-todo.djs-shape .djs-visual > :nth-child(1) { .highlight-todo.djs-shape .djs-visual > :nth-child(1) {
fill: #1890ff !important; fill: #1890ff !important;
stroke: #1890ff !important; stroke: #1890ff !important;
@@ -414,8 +419,9 @@ watch(
stroke: #1890ff !important; stroke: #1890ff !important;
stroke-dasharray: 4px !important; stroke-dasharray: 4px !important;
fill-opacity: 0.2 !important; fill-opacity: 0.2 !important;
marker-end: url(#sequenceflow-end-_E7DFDF-_E7DFDF-803g1kf6zwzmcig1y2ulm5egr); marker-end: url('#sequenceflow-end-_E7DFDF-_E7DFDF-803g1kf6zwzmcig1y2ulm5egr');
} }
:deep(.highlight-todo.djs-shape .djs-visual > :nth-child(1)) { :deep(.highlight-todo.djs-shape .djs-visual > :nth-child(1)) {
fill: #1890ff !important; fill: #1890ff !important;
stroke: #1890ff !important; stroke: #1890ff !important;
@@ -429,14 +435,17 @@ watch(
stroke: green !important; stroke: green !important;
fill-opacity: 0.2 !important; fill-opacity: 0.2 !important;
} }
.highlight.djs-shape .djs-visual > :nth-child(2) { .highlight.djs-shape .djs-visual > :nth-child(2) {
fill: green !important; fill: green !important;
} }
.highlight.djs-shape .djs-visual > path { .highlight.djs-shape .djs-visual > path {
fill: green !important; fill: green !important;
fill-opacity: 0.2 !important; fill-opacity: 0.2 !important;
stroke: green !important; stroke: green !important;
} }
.highlight.djs-connection > .djs-visual > path { .highlight.djs-connection > .djs-visual > path {
stroke: green !important; stroke: green !important;
} }
@@ -450,14 +459,17 @@ watch(
stroke: green !important; stroke: green !important;
fill-opacity: 0.2 !important; fill-opacity: 0.2 !important;
} }
:deep(.highlight.djs-shape .djs-visual > :nth-child(2)) { :deep(.highlight.djs-shape .djs-visual > :nth-child(2)) {
fill: green !important; fill: green !important;
} }
:deep(.highlight.djs-shape .djs-visual > path) { :deep(.highlight.djs-shape .djs-visual > path) {
fill: green !important; fill: green !important;
fill-opacity: 0.2 !important; fill-opacity: 0.2 !important;
stroke: green !important; stroke: green !important;
} }
:deep(.highlight.djs-connection > .djs-visual > path) { :deep(.highlight.djs-connection > .djs-visual > path) {
stroke: green !important; stroke: green !important;
} }
@@ -468,14 +480,17 @@ watch(
stroke: red !important; stroke: red !important;
fill-opacity: 0.2 !important; fill-opacity: 0.2 !important;
} }
.highlight-reject.djs-shape .djs-visual > :nth-child(2) { .highlight-reject.djs-shape .djs-visual > :nth-child(2) {
fill: red !important; fill: red !important;
} }
.highlight-reject.djs-shape .djs-visual > path { .highlight-reject.djs-shape .djs-visual > path {
fill: red !important; fill: red !important;
fill-opacity: 0.2 !important; fill-opacity: 0.2 !important;
stroke: red !important; stroke: red !important;
} }
.highlight-reject.djs-connection > .djs-visual > path { .highlight-reject.djs-connection > .djs-visual > path {
stroke: red !important; stroke: red !important;
} }
@@ -489,14 +504,17 @@ watch(
stroke: red !important; stroke: red !important;
fill-opacity: 0.2 !important; fill-opacity: 0.2 !important;
} }
:deep(.highlight-reject.djs-shape .djs-visual > :nth-child(2)) { :deep(.highlight-reject.djs-shape .djs-visual > :nth-child(2)) {
fill: red !important; fill: red !important;
} }
:deep(.highlight-reject.djs-shape .djs-visual > path) { :deep(.highlight-reject.djs-shape .djs-visual > path) {
fill: red !important; fill: red !important;
fill-opacity: 0.2 !important; fill-opacity: 0.2 !important;
stroke: red !important; stroke: red !important;
} }
:deep(.highlight-reject.djs-connection > .djs-visual > path) { :deep(.highlight-reject.djs-connection > .djs-visual > path) {
stroke: red !important; stroke: red !important;
} }
@@ -507,14 +525,17 @@ watch(
stroke: grey !important; stroke: grey !important;
fill-opacity: 0.2 !important; fill-opacity: 0.2 !important;
} }
.highlight-cancel.djs-shape .djs-visual > :nth-child(2) { .highlight-cancel.djs-shape .djs-visual > :nth-child(2) {
fill: grey !important; fill: grey !important;
} }
.highlight-cancel.djs-shape .djs-visual > path { .highlight-cancel.djs-shape .djs-visual > path {
fill: grey !important; fill: grey !important;
fill-opacity: 0.2 !important; fill-opacity: 0.2 !important;
stroke: grey !important; stroke: grey !important;
} }
.highlight-cancel.djs-connection > .djs-visual > path { .highlight-cancel.djs-connection > .djs-visual > path {
stroke: grey !important; stroke: grey !important;
} }
@@ -528,14 +549,17 @@ watch(
stroke: grey !important; stroke: grey !important;
fill-opacity: 0.2 !important; fill-opacity: 0.2 !important;
} }
:deep(.highlight-cancel.djs-shape .djs-visual > :nth-child(2)) { :deep(.highlight-cancel.djs-shape .djs-visual > :nth-child(2)) {
fill: grey !important; fill: grey !important;
} }
:deep(.highlight-cancel.djs-shape .djs-visual > path) { :deep(.highlight-cancel.djs-shape .djs-visual > path) {
fill: grey !important; fill: grey !important;
fill-opacity: 0.2 !important; fill-opacity: 0.2 !important;
stroke: grey !important; stroke: grey !important;
} }
:deep(.highlight-cancel.djs-connection > .djs-visual > path) { :deep(.highlight-cancel.djs-connection > .djs-visual > path) {
stroke: grey !important; stroke: grey !important;
} }
@@ -543,7 +567,7 @@ watch(
.element-overlays { .element-overlays {
box-sizing: border-box; box-sizing: border-box;
padding: 8px; padding: 8px;
background: rgba(0, 0, 0, 0.6); background: rgb(0 0 0 / 60%);
border-radius: 4px; border-radius: 4px;
color: #fafafa; color: #fafafa;
width: 200px; width: 200px;
@@ -5,9 +5,11 @@
</div> </div>
</template> </template>
<script setup lang="ts" name="MyProcessPalette"> <script lang="ts" setup>
import { assign } from 'min-dash' import { assign } from 'min-dash'
defineOptions({ name: 'MyProcessPalette' })
const bpmnInstances = () => (window as any).bpmnInstances const bpmnInstances = () => (window as any).bpmnInstances
const addTask = (event, options: any = {}) => { const addTask = (event, options: any = {}) => {
const ElementFactory = bpmnInstances().elementFactory const ElementFactory = bpmnInstances().elementFactory
@@ -30,12 +32,13 @@ const addTask = (event, options: any = {}) => {
<style scoped lang="scss"> <style scoped lang="scss">
.my-process-palette { .my-process-palette {
box-sizing: border-box; box-sizing: border-box;
padding: 80px 20px 20px 20px; padding: 80px 20px 20px;
.test-button { .test-button {
box-sizing: border-box; box-sizing: border-box;
padding: 8px 16px; padding: 8px 16px;
border-radius: 4px; border-radius: 4px;
border: 1px solid rgba(24, 144, 255, 0.8); border: 1px solid rgb(24 144 255 / 80%);
cursor: pointer; cursor: pointer;
} }
} }
@@ -62,7 +62,7 @@
</el-collapse> </el-collapse>
</div> </div>
</template> </template>
<script setup lang="ts" name="MyPropertiesPanel"> <script lang="ts" setup>
import ElementBaseInfo from './base/ElementBaseInfo.vue' import ElementBaseInfo from './base/ElementBaseInfo.vue'
import ElementOtherConfig from './other/ElementOtherConfig.vue' import ElementOtherConfig from './other/ElementOtherConfig.vue'
import ElementTask from './task/ElementTask.vue' import ElementTask from './task/ElementTask.vue'
@@ -73,6 +73,9 @@ import ElementListeners from './listeners/ElementListeners.vue'
import ElementProperties from './properties/ElementProperties.vue' import ElementProperties from './properties/ElementProperties.vue'
// import ElementForm from './form/ElementForm.vue' // import ElementForm from './form/ElementForm.vue'
import UserTaskListeners from './listeners/UserTaskListeners.vue' import UserTaskListeners from './listeners/UserTaskListeners.vue'
defineOptions({ name: 'MyPropertiesPanel' })
/** /**
* 侧边栏 * 侧边栏
* @Author MiyueFE * @Author MiyueFE
@@ -106,22 +109,22 @@ const elementBusinessObject = ref<any>({}) // 元素 businessObject 镜像,提
const conditionFormVisible = ref(false) // 流转条件设置 const conditionFormVisible = ref(false) // 流转条件设置
const formVisible = ref(false) // 表单配置 const formVisible = ref(false) // 表单配置
const bpmnElement = ref() const bpmnElement = ref()
const timer = ref()
provide('prefix', props.prefix) provide('prefix', props.prefix)
provide('width', props.width) provide('width', props.width)
const bpmnInstances = () => (window as any)?.bpmnInstances const bpmnInstances = () => (window as any)?.bpmnInstances
const initModels = () => {
// console.log(props, 'props') // 监听 props.bpmnModeler 然后 initModels
// console.log(props.bpmnModeler, 'sakdjjaskdsajdkasdjkadsjk') const unwatchBpmn = watch(
// 初始化 modeler 以及其他 moddle () => props.bpmnModeler,
// nextTick(() => { () => {
if (!props.bpmnModeler) {
// 避免加载时 流程图 并未加载完成 // 避免加载时 流程图 并未加载完成
timer.value = setTimeout(() => initModels(), 10) if (!props.bpmnModeler) {
return console.log('缺少props.bpmnModeler')
} return
if (timer.value) { }
clearTimeout(timer.value)
console.log('props.bpmnModeler 有值了!!!')
const w = window as any const w = window as any
w.bpmnInstances = { w.bpmnInstances = {
modeler: props.bpmnModeler, modeler: props.bpmnModeler,
@@ -134,12 +137,16 @@ const initModels = () => {
replace: props.bpmnModeler.get('replace'), replace: props.bpmnModeler.get('replace'),
selection: props.bpmnModeler.get('selection') selection: props.bpmnModeler.get('selection')
} }
}
console.log(bpmnInstances(), 'window.bpmnInstances') console.log(bpmnInstances(), 'window.bpmnInstances')
getActiveElement() getActiveElement()
// }) unwatchBpmn()
} },
{
immediate: true
}
)
const getActiveElement = () => { const getActiveElement = () => {
// 初始第一个选中元素 bpmn:Process // 初始第一个选中元素 bpmn:Process
initFormOnChanged(null) initFormOnChanged(null)
@@ -187,11 +194,7 @@ const initFormOnChanged = (element) => {
) )
formVisible.value = elementType.value === 'UserTask' || elementType.value === 'StartEvent' formVisible.value = elementType.value === 'UserTask' || elementType.value === 'StartEvent'
} }
onMounted(() => {
setTimeout(() => {
initModels()
}, 100)
})
onBeforeUnmount(() => { onBeforeUnmount(() => {
const w = window as any const w = window as any
w.bpmnInstances = null w.bpmnInstances = null
@@ -7,8 +7,9 @@
href="https://doc.iocoder.cn/bpm/#_3-%E6%B5%81%E7%A8%8B%E5%9B%BE%E7%A4%BA%E4%BE%8B" href="https://doc.iocoder.cn/bpm/#_3-%E6%B5%81%E7%A8%8B%E5%9B%BE%E7%A4%BA%E4%BE%8B"
type="danger" type="danger"
target="_blank" target="_blank"
>如何实现实现会签、或签?</el-link
> >
如何实现实现会签、或签?
</el-link>
<el-form-item label="流程标识" prop="id"> <el-form-item label="流程标识" prop="id">
<el-input <el-input
v-model="needProps.id" v-model="needProps.id"
@@ -37,7 +38,9 @@
</el-form> </el-form>
</div> </div>
</template> </template>
<script setup lang="ts" name="ElementBaseInfo"> <script lang="ts" setup>
defineOptions({ name: 'ElementBaseInfo' })
const props = defineProps({ const props = defineProps({
businessObject: { businessObject: {
type: Object, type: Object,
@@ -62,7 +62,9 @@
</div> </div>
</template> </template>
<script setup lang="ts" name="FlowCondition"> <script lang="ts" setup>
defineOptions({ name: 'FlowCondition' })
const props = defineProps({ const props = defineProps({
businessObject: Object, businessObject: Object,
type: String type: String
@@ -222,7 +222,9 @@
</div> </div>
</template> </template>
<script setup lang="ts" name="ElementForm"> <script lang="ts" setup>
defineOptions({ name: 'ElementForm' })
const props = defineProps({ const props = defineProps({
id: String, id: String,
type: String type: String
@@ -241,10 +241,13 @@
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script setup lang="ts" name="ElementListeners"> <script lang="ts" setup>
import { ElMessageBox } from 'element-plus' import { ElMessageBox } from 'element-plus'
import { createListenerObject, updateElementExtensions } from '../../utils' import { createListenerObject, updateElementExtensions } from '../../utils'
import { initListenerType, initListenerForm, listenerType, fieldType } from './utilSelf' import { initListenerType, initListenerForm, listenerType, fieldType } from './utilSelf'
defineOptions({ name: 'ElementListeners' })
const props = defineProps({ const props = defineProps({
id: String, id: String,
type: String type: String
@@ -287,10 +287,13 @@
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script setup lang="ts" name="UserTaskListeners"> <script lang="ts" setup>
import { ElMessageBox } from 'element-plus' import { ElMessageBox } from 'element-plus'
import { createListenerObject, updateElementExtensions } from '../../utils' import { createListenerObject, updateElementExtensions } from '../../utils'
import { initListenerForm, initListenerType, eventType, listenerType, fieldType } from './utilSelf' import { initListenerForm, initListenerType, eventType, listenerType, fieldType } from './utilSelf'
defineOptions({ name: 'UserTaskListeners' })
const props = defineProps({ const props = defineProps({
id: String, id: String,
type: String type: String
@@ -66,7 +66,9 @@
</div> </div>
</template> </template>
<script setup lang="ts" name="ElementMultiInstance"> <script lang="ts" setup>
defineOptions({ name: 'ElementMultiInstance' })
const props = defineProps({ const props = defineProps({
businessObject: Object, businessObject: Object,
type: String type: String
@@ -16,7 +16,8 @@
</div> </div>
</template> </template>
<script setup lang="ts" name="ElementOtherConfig"> <script lang="ts" setup>
defineOptions({ name: 'ElementOtherConfig' })
const props = defineProps({ const props = defineProps({
id: String id: String
}) })
@@ -6,17 +6,18 @@
<el-table-column label="属性值" prop="value" min-width="100px" show-overflow-tooltip /> <el-table-column label="属性值" prop="value" min-width="100px" show-overflow-tooltip />
<el-table-column label="操作" width="110px"> <el-table-column label="操作" width="110px">
<template #default="scope"> <template #default="scope">
<el-button link @click="openAttributesForm(scope.row, scope.$index)" size="small" <el-button link @click="openAttributesForm(scope.row, scope.$index)" size="small">
>编辑</el-button 编辑
> </el-button>
<el-divider direction="vertical" /> <el-divider direction="vertical" />
<el-button <el-button
link link
size="small" size="small"
style="color: #ff4d4f" style="color: #ff4d4f"
@click="removeAttributes(scope.row, scope.$index)" @click="removeAttributes(scope.row, scope.$index)"
>移除</el-button
> >
移除
</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -52,8 +53,9 @@
</div> </div>
</template> </template>
<script setup lang="ts" name="ElementProperties"> <script lang="ts" setup>
import { ElMessageBox } from 'element-plus' import { ElMessageBox } from 'element-plus'
defineOptions({ name: 'ElementProperties' })
const props = defineProps({ const props = defineProps({
id: String, id: String,
type: String type: String
@@ -1,7 +1,7 @@
<template> <template>
<div class="panel-tab__content"> <div class="panel-tab__content">
<div class="panel-tab__content--title"> <div class="panel-tab__content--title">
<span><Icon icon="ep:menu" style="margin-right: 8px; color: #555555" />消息列表</span> <span><Icon icon="ep:menu" style="margin-right: 8px; color: #555" />消息列表</span>
<XButton type="primary" title="创建新消息" preIcon="ep:plus" @click="openModel('message')" /> <XButton type="primary" title="创建新消息" preIcon="ep:plus" @click="openModel('message')" />
</div> </div>
<el-table :data="messageList" border> <el-table :data="messageList" border>
@@ -11,9 +11,9 @@
</el-table> </el-table>
<div <div
class="panel-tab__content--title" class="panel-tab__content--title"
style="padding-top: 8px; margin-top: 8px; border-top: 1px solid #eeeeee" style="padding-top: 8px; margin-top: 8px; border-top: 1px solid #eee"
> >
<span><Icon icon="ep:menu" style="margin-right: 8px; color: #555555" />信号列表</span> <span><Icon icon="ep:menu" style="margin-right: 8px; color: #555" />信号列表</span>
<XButton type="primary" title="创建新信号" preIcon="ep:plus" @click="openModel('signal')" /> <XButton type="primary" title="创建新信号" preIcon="ep:plus" @click="openModel('signal')" />
</div> </div>
<el-table :data="signalList" border> <el-table :data="signalList" border>
@@ -45,7 +45,9 @@
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script setup lang="ts" name="SignalAndMassage"> <script lang="ts" setup>
defineOptions({ name: 'SignalAndMassage' })
const message = useMessage() const message = useMessage()
const signalList = ref<any[]>([]) const signalList = ref<any[]>([])
const messageList = ref<any[]>([]) const messageList = ref<any[]>([])
@@ -20,11 +20,13 @@
</div> </div>
</template> </template>
<script setup lang="ts" name="ElementTaskConfig"> <script lang="ts" setup>
import UserTask from './task-components/UserTask.vue' import UserTask from './task-components/UserTask.vue'
import ScriptTask from './task-components/ScriptTask.vue' import ScriptTask from './task-components/ScriptTask.vue'
import ReceiveTask from './task-components/ReceiveTask.vue' import ReceiveTask from './task-components/ReceiveTask.vue'
defineOptions({ name: 'ElementTaskConfig' })
const props = defineProps({ const props = defineProps({
id: String, id: String,
type: String type: String
@@ -48,7 +48,8 @@
</div> </div>
</template> </template>
<script setup lang="ts" name="ReceiveTask"> <script lang="ts" setup>
defineOptions({ name: 'ReceiveTask' })
const props = defineProps({ const props = defineProps({
id: String, id: String,
type: String type: String
@@ -44,7 +44,8 @@
</div> </div>
</template> </template>
<script setup lang="ts" name="ScriptTask"> <script lang="ts" setup>
defineOptions({ name: 'ScriptTask' })
const props = defineProps({ const props = defineProps({
id: String, id: String,
type: String type: String
@@ -37,7 +37,8 @@
</div> </div>
</template> </template>
<script setup lang="ts" name="UserTask"> <script lang="ts" setup>
defineOptions({ name: 'UserTask' })
const props = defineProps({ const props = defineProps({
id: String, id: String,
type: String type: String
+5 -2
View File
@@ -1,7 +1,7 @@
import { reactive } from 'vue' import { reactive } from 'vue'
import { AxiosPromise } from 'axios' import { AxiosPromise } from 'axios'
import { findIndex } from '@/utils' import { findIndex } from '@/utils'
import { eachTree, treeMap, filter } from '@/utils/tree' import { eachTree, filter, treeMap } from '@/utils/tree'
import { getBoolDictOptions, getDictOptions, getIntDictOptions } from '@/utils/dict' import { getBoolDictOptions, getDictOptions, getIntDictOptions } from '@/utils/dict'
import { FormSchema } from '@/types/form' import { FormSchema } from '@/types/form'
@@ -36,8 +36,11 @@ type CrudSearchParams = {
type CrudTableParams = { type CrudTableParams = {
// 是否显示表头 // 是否显示表头
show?: boolean show?: boolean
// 列宽配置
width?: number | string
// 列是否固定在左侧或者右侧
fixed?: 'left' | 'right'
} & Omit<FormSchema, 'field'> } & Omit<FormSchema, 'field'>
type CrudFormParams = { type CrudFormParams = {
// 是否显示表单项 // 是否显示表单项
show?: boolean show?: boolean
+1 -3
View File
@@ -136,9 +136,7 @@ export const useTable = <T = any>(config?: UseTableConfig<T>) => {
}) })
if (res) { if (res) {
tableObject.tableList = (res as unknown as ResponseType).list tableObject.tableList = (res as unknown as ResponseType).list
if ((res as unknown as ResponseType).total) { tableObject.total = (res as unknown as ResponseType).total ?? 0
tableObject.total = (res as unknown as ResponseType).total as unknown as number
}
} }
}, },
setProps: async (props: TableProps = {}) => { setProps: async (props: TableProps = {}) => {
+3 -1
View File
@@ -1,8 +1,10 @@
<script lang="ts" name="AppView" setup> <script lang="ts" setup>
import { useTagsViewStore } from '@/store/modules/tagsView' import { useTagsViewStore } from '@/store/modules/tagsView'
import { useAppStore } from '@/store/modules/app' import { useAppStore } from '@/store/modules/app'
import { Footer } from '@/layout/components/Footer' import { Footer } from '@/layout/components/Footer'
defineOptions({ name: 'AppView' })
const appStore = useAppStore() const appStore = useAppStore()
const layout = computed(() => appStore.getLayout) const layout = computed(() => appStore.getLayout)
@@ -1,8 +1,10 @@
<script lang="ts" name="Collapse" setup> <script lang="ts" setup>
import { useAppStore } from '@/store/modules/app' import { useAppStore } from '@/store/modules/app'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
defineOptions({ name: 'Collapse' })
const { getPrefixCls } = useDesign() const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('collapse') const prefixCls = getPrefixCls('collapse')
@@ -1,4 +1,4 @@
<script lang="ts" name="ContextMenu" setup> <script lang="ts" setup>
import { PropType } from 'vue' import { PropType } from 'vue'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
@@ -6,6 +6,8 @@ import type { RouteLocationNormalizedLoaded } from 'vue-router'
import { contextMenuSchema } from '@/types/contextMenu' import { contextMenuSchema } from '@/types/contextMenu'
import type { ElDropdown } from 'element-plus' import type { ElDropdown } from 'element-plus'
defineOptions({ name: 'ContextMenu' })
const { getPrefixCls } = useDesign() const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('context-menu') const prefixCls = getPrefixCls('context-menu')
+4 -1
View File
@@ -1,7 +1,10 @@
<script lang="ts" name="Footer" setup> <script lang="ts" setup>
import { useAppStore } from '@/store/modules/app' import { useAppStore } from '@/store/modules/app'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
// eslint-disable-next-line vue/no-reserved-component-names
defineOptions({ name: 'Footer' })
const { getPrefixCls } = useDesign() const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('footer') const prefixCls = getPrefixCls('footer')
@@ -1,9 +1,11 @@
<script lang="ts" name="LocaleDropdown" setup> <script lang="ts" setup>
import { useLocaleStore } from '@/store/modules/locale' import { useLocaleStore } from '@/store/modules/locale'
import { useLocale } from '@/hooks/web/useLocale' import { useLocale } from '@/hooks/web/useLocale'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
defineOptions({ name: 'LocaleDropdown' })
const { getPrefixCls } = useDesign() const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('locale-dropdown') const prefixCls = getPrefixCls('locale-dropdown')
+3 -1
View File
@@ -1,8 +1,10 @@
<script lang="ts" name="Logo" setup> <script lang="ts" setup>
import { computed, onMounted, ref, unref, watch } from 'vue' import { computed, onMounted, ref, unref, watch } from 'vue'
import { useAppStore } from '@/store/modules/app' import { useAppStore } from '@/store/modules/app'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
defineOptions({ name: 'Logo' })
const { getPrefixCls } = useDesign() const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('logo') const prefixCls = getPrefixCls('logo')
+1
View File
@@ -13,6 +13,7 @@ const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('menu') const prefixCls = getPrefixCls('menu')
export default defineComponent({ export default defineComponent({
// eslint-disable-next-line vue/no-reserved-component-names
name: 'Menu', name: 'Menu',
props: { props: {
menuSelect: { menuSelect: {
@@ -1,7 +1,9 @@
<script lang="ts" name="Message" setup> <script lang="ts" setup>
import { formatDate } from '@/utils/formatTime' import { formatDate } from '@/utils/formatTime'
import * as NotifyMessageApi from '@/api/system/notify/message' import * as NotifyMessageApi from '@/api/system/notify/message'
defineOptions({ name: 'Message' })
const { push } = useRouter() const { push } = useRouter()
const activeName = ref('notice') const activeName = ref('notice')
const unreadCount = ref(0) // 未读消息数量 const unreadCount = ref(0) // 未读消息数量
@@ -1,9 +1,11 @@
<script lang="ts" name="ScreenFull" setup> <script lang="ts" setup>
import { Icon } from '@/components/Icon' import { Icon } from '@/components/Icon'
import { useFullscreen } from '@vueuse/core' import { useFullscreen } from '@vueuse/core'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
defineOptions({ name: 'ScreenFull' })
const { getPrefixCls } = useDesign() const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('screenfull') const prefixCls = getPrefixCls('screenfull')
@@ -1,4 +1,4 @@
<script lang="ts" name="Setting" setup> <script lang="ts" setup>
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { useClipboard, useCssVar } from '@vueuse/core' import { useClipboard, useCssVar } from '@vueuse/core'
@@ -13,6 +13,8 @@ import ColorRadioPicker from './components/ColorRadioPicker.vue'
import InterfaceDisplay from './components/InterfaceDisplay.vue' import InterfaceDisplay from './components/InterfaceDisplay.vue'
import LayoutRadioPicker from './components/LayoutRadioPicker.vue' import LayoutRadioPicker from './components/LayoutRadioPicker.vue'
defineOptions({ name: 'Setting' })
const { t } = useI18n() const { t } = useI18n()
const appStore = useAppStore() const appStore = useAppStore()
@@ -1,8 +1,10 @@
<script lang="ts" name="ColorRadioPicker" setup> <script lang="ts" setup>
import { PropType } from 'vue' import { PropType } from 'vue'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
defineOptions({ name: 'ColorRadioPicker' })
const { getPrefixCls } = useDesign() const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('color-radio-picker') const prefixCls = getPrefixCls('color-radio-picker')
@@ -1,10 +1,12 @@
<script lang="ts" name="InterfaceDisplay" setup> <script lang="ts" setup>
import { setCssVar } from '@/utils' import { setCssVar } from '@/utils'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
import { useWatermark } from '@/hooks/web/useWatermark' import { useWatermark } from '@/hooks/web/useWatermark'
import { useAppStore } from '@/store/modules/app' import { useAppStore } from '@/store/modules/app'
defineOptions({ name: 'InterfaceDisplay' })
const { t } = useI18n() const { t } = useI18n()
const { getPrefixCls } = useDesign() const { getPrefixCls } = useDesign()
const { setWatermark } = useWatermark() const { setWatermark } = useWatermark()
Loaded 100 of 372 files, more files were not shown because too many files have changed in this diff. Show more