Compare commits

..

69 Commits
v2.11.4 ... v2

Author SHA1 Message Date
Tang
038936ff7d fix(table): Fixed table tree structure bug (#4543) 2024-09-29 10:50:10 +08:00
li-yi-hong
960f1d3c0b fix: 修复table setting 上下不居中 (#4410) 2024-09-15 21:36:36 +08:00
lijian3828940
f67b5d8569 table控件settingCache在非开发模式下为true,优化用户体验 (#4310) 2024-09-03 21:26:16 +08:00
YanQi
f99cc9b9fe fix: modify the default image type to avoid cropping images that become too large. (#4307)
Co-authored-by: YanQi <yanqirj@gmail.com>
2024-09-03 21:26:01 +08:00
lijian3828940
0cf2271667 fix:修复showAdvancedButton为true时,FormSchema中ifshow是与model有关的函数时候,查询按钮位置不重新计算的问题。 (#4304) 2024-09-03 13:02:49 +08:00
alucardxh
6d2de002ef Support array parameter parsing (#4300) 2024-09-02 09:55:11 +08:00
张阿文
617e594d8d refactor(form): 使用空值合并运算符 (??) 和 isDef 优化宽度判断逻辑,处理 labelWidth 可能为 0 的情况 (#4086) 2024-08-08 20:50:32 +08:00
coderPeng3yang
4aac1c388c 删除了多余的菜单数据的步骤,减少性能开销,优化初始化速度。 (#4012)
* types(logic): 减少冗沉,用了泛型

* perf(router): 删除了多余的菜单数据的步骤,减少性能开销,优化初始化速度。

删除了每次刷新页面都会获取静态菜单数据的操作,改为在角色权限控制时才进行数据获取。

此更改优化了应用的初始化速度,减少了不必要的性能开销,并且确保获取静态菜单数据时不会污染路由数据。

这样可以确保其他地方更清晰地跟踪路由数据

---------

Co-authored-by: zach.zqy <bianzhixiaoyuan@163.com>
2024-08-06 18:36:18 +08:00
No name
7b6531a309 fix: The projectSettings default dark mode is not taking effect (#4052)
The projectSettings default dark mode is not taking effect. In the getDarkMode function, setting.menuSetting.theme should be present must be higher priority than darkMode.
2024-08-06 10:58:26 +08:00
1455668754
65651fc25c feat: 1.ApiSelect增加远程搜索功能 2.ApiSelect设定懒加载时允许控制空搜索时不查询 3.增加下拉远程搜索Json版本demo (#3992)
* feat: 1.ApiSelect增加远程搜索功能 2.ApiSelect设定懒加载时允许控制空搜索时不查询

* feat: 增加下拉远程搜索Json版本demo
2024-08-02 08:24:21 +08:00
vince
4fcbdd3925 Merge pull request #3991 from vbenjs/update-upgrade-prompt
chore: update UpgradePrompt
2024-08-01 09:55:25 +08:00
Li Kui
db2a27060c chore: update UpgradePrompt 2024-08-01 07:50:30 +08:00
vince
d9bfe96dad Merge pull request #3986 from 1455668754/main
fix: Echarts初始宽度监听修复
2024-08-01 05:11:35 +08:00
vince
77a0ad450d Merge pull request #3987 from mrmsl/main
chore(multipleTab): Make the code more readable
2024-08-01 05:10:56 +08:00
vince
c37ed8f7e9 Merge pull request #3988 from snapea/fix/mult-upload
fix(upload): 修复上传组件删除无效bug
2024-08-01 05:10:24 +08:00
vince
1698be7ce4 chore: update upgrade prompt 2024-08-01 05:07:53 +08:00
vince
ea5c66b6eb feat: add upgrade prompt 2024-07-31 22:15:01 +08:00
wen zhenjin
371c972cc1 fix(upload): 修复上传组件删除无效bug 2024-07-31 11:50:40 +08:00
mrmsl
2880174be2 fix(multipleTab): 已经打开的动态路由数判断bug 2024-07-31 10:20:51 +08:00
vince
b0c0b916fd fix: Wrong color value 2024-07-31 00:26:08 +08:00
雪忆
f314826230 Revert "feat: ApiSelect增加远程搜索功能"
This reverts commit 56c5dce99f.
2024-07-29 15:18:30 +08:00
雪忆
56c5dce99f feat: ApiSelect增加远程搜索功能 2024-07-29 15:14:07 +08:00
雪忆
95abe06107 fix: Echarts初始宽度监听修复 2024-07-29 15:11:06 +08:00
雪忆
ecfe66a019 Merge remote-tracking branch 'origin/main' 2024-07-29 15:10:40 +08:00
苗大
25699c0b60 feat(Preview): 优化实例创建更新逻辑, 防止重复创建dom (#3979)
* perf(Preview): 优化实例创建更新逻辑, 防止重复创建dom

* perf: 逻辑优化
2024-07-26 14:30:14 +08:00
Sny
5b7b6b1780 chore(component): 优化EditableCell组件handleSubmit方法报错时增加warn日志显示 (#3981)
closed #3869
2024-07-26 14:28:20 +08:00
coderPeng3yang
57ff038d82 chore: types(logic) 减少冗沉,用了泛型 (#3977)
Co-authored-by: zach.zqy <bianzhixiaoyuan@163.com>
2024-07-25 10:08:20 +08:00
clddup
baf406e7e2 chore: 格式化代码 (#3972) 2024-07-19 16:47:21 +08:00
苗大
1745f480fd fix: typo opend -> opened (#3968) 2024-07-17 13:56:09 +08:00
fourteendp
cec5c11289 fix(VxeTable): 修复VxeTable自定义组件重复注册导致控制台警告 (#3944) 2024-07-04 14:12:52 +08:00
Allure-eve
dd1b16acdc fix(BasicTable): ColumnSettings.vue columnOptions typeof lost (#3941) 2024-07-04 08:50:58 +08:00
fourteendp
64a4992a84 fix(VxeTable): 更新vxe-table以及相关依赖,修改废弃API至最新 (#3939) 2024-07-04 08:49:47 +08:00
jinmao88
cae5538aba fix(VxeTable): update vxeTable ,fix imports and support theme change 2024-06-24 16:33:55 +08:00
1455668754
e7868e7193 fix: vxe-table index.css已废弃,切换至all (#3926)
fix: vxe-table index.css已废弃,切换至all
2024-06-24 16:06:25 +08:00
No name
71c4edad63 chore: improve build file naming convention and caching (#3908)
* fix: improve build file naming convention

* remove js to the entryFileName path

* replace dot to hyphen
2024-06-14 15:26:49 +08:00
Electrolux
65fba1c329 perf(UploadPreviewModal): delete invalid assign (#3915) 2024-06-13 18:24:11 +08:00
Li Kui
8d3981f599 fix: axios retry losing headers (#3902) 2024-06-07 11:42:48 +08:00
Electrolux
cca7f59fac fix(BasicForm->Upload): setValue and defaultValue uncertain && rule about first render (#3900)
* chore: upload component defaulttype should be array

* chore: upload component setFieldsValue  should be array

* chore(upload): split event between change and  update:value

* update

* update
2024-06-06 15:27:15 +08:00
苗大
1a5692060b perf: 未登录重定向路径存储改为完整路径 (#3897) 2024-06-06 11:31:50 +08:00
1455668754
4974de2553 chore: typo destroy word 2024-06-04 16:23:02 +08:00
No name
f83002441d fix(dataSource): BasicTable Component with dataSource is not working (hot fix) (#3888) 2024-06-04 16:22:09 +08:00
雪忆
e84c4051f3 fix: destroy方法命名修正 2024-06-03 17:33:50 +08:00
Fifteen
af39afa24b perf(demo->screenshot): optimize the screenshot code && add print and download (#3885) 2024-06-03 08:56:55 +08:00
invalid w
2dcd733e16 chore: release 2.11.5 2024-05-31 09:57:10 +08:00
xachary
d5fed8a47c perf(menu->search): highlight match chars when search menu (#3880)
* fix: state mutations in computed getters should be avoided

* fix: type about getDataSourceRef

* perf(menu search): highlight match chars when search menu
2024-05-31 09:55:27 +08:00
xachary
a6086f4cc8 chore(build): keep same hash for the same files (#3878)
* fix: state mutations in computed getters should be avoided

* fix: type about getDataSourceRef

* chore(build): keep same hash for the same files
2024-05-31 09:54:41 +08:00
Electrolux
d9cdf3f034 chore(upload): use uid && fix handleDelete (#3872)
* chore(upload): 重构组件,添加key作为标识

* fix(upload): 显式传入handleDelete

* update case
2024-05-31 09:54:05 +08:00
Electrolux
0bc01d8528 feat(form): add valueFormat for schema (#3873) 2024-05-31 09:53:50 +08:00
Jun
5d36b1a560 fix: 修复表单重置后,页面变化了,但是由于异步问题导致表单内部的状态没有及时同步 (#3882) 2024-05-29 21:56:56 +08:00
No name
c89417f523 fix(loading): useLoading is not working as expected (#3877)
* fix(loading): useLoading is not working as expected

* chore: remove comment

---------

Co-authored-by: likui628 <90845831+likui628@users.noreply.github.com>
2024-05-28 09:14:55 +08:00
Electrolux
dcba0ca837 perf(form->util): duplicate judge (#3865) 2024-05-23 21:59:44 +08:00
Arlo
e69dd1e223 feat: add devtools plugin instead of inspector plugin (#3856) 2024-05-23 08:25:43 +08:00
xachary
fee808198e fix(useDataSource): state mutations in computed getters should be avoided (#3859)
* fix: state mutations in computed getters should be avoided

* fix: type about getDataSourceRef
2024-05-23 08:20:41 +08:00
zhang
cfdb09fe5b style: format code style (#3857)
* first commit

* style: format code style

* style: format code
2024-05-22 22:40:56 +08:00
Electrolux
821238ea04 update case (#3858) 2024-05-22 22:40:23 +08:00
wangjinchuan108
bcd98ee067 fix(Loading): 处理v-loading指令和useLoading的内存泄露 (#3861)
Co-authored-by: jinchuanwang <1085296443@qq.com>
2024-05-22 22:39:51 +08:00
No name
144cdd4680 fix(Application): search menu now correctly lowercases input keys (#3842) 2024-05-14 14:07:57 +08:00
Kyun Wong
1fee161786 fix: 路由参数存在非英文字符的情况下 会生成一个新的tab 而非返回原有tab (#3832) 2024-05-14 10:52:44 +08:00
Electrolux
265627fcc8 feat(BasicForm): add prefix slot for schema (#3840) 2024-05-13 18:29:42 +08:00
李吉磊(Leo)
223562eab5 chore(docs): update git url (#3839) 2024-05-13 10:54:32 +08:00
zhang
22052f10f9 fix(BasicForm): when value is 0 or false resetFields is not work (#3828)
* fix(BasicForm): when value is 0 or false resetFields is not work

* fix(BasicForm): when value is 0 or false resetFields is not work
2024-05-11 06:56:36 +08:00
zzy-jonay
478802b426 fix(BasicForm): 修复FormSchema中使用ifShow隐藏字段时,默认表单查询重置按钮位置偏移量计算问题 (#3830) 2024-05-10 17:51:50 +08:00
tors
5a2d74249e feat(Demo): add ScreenShot page demo (#3826) 2024-05-10 17:30:52 +08:00
Electrolux
0ee721183b feat(codeEditor): add type and config && add use case (#3829)
* chore(codeEditor): add type and config && add use case

* type(codeEditor): perf the config

* fix annotate

* fix annotate
2024-05-10 16:37:22 +08:00
zhang
b66a0def98 fix(Breadcrumb): if hideBreadcrumb is true and hidden (#3821) 2024-05-09 09:16:20 +08:00
tors
679a23332f chore: Rename the default export name (#3820) 2024-05-09 09:15:58 +08:00
Electrolux
7538c57db7 fix(BasicForm): setFieldsValue not work in form when use date comp (#3819)
* fix(BasicForm): setFieldsValue not work in form when use date comp

* fix(BasicForm): add lost time component
2024-05-09 09:12:36 +08:00
Electrolux
88e77dbf99 perf(BasicForm): fix invaild defaultValue && split-setdefault-setvalue (#3815) 2024-05-08 14:05:54 +08:00
Electrolux
4348d21da8 fix(imgUpload): disabled not effect in the form (#3809) 2024-05-06 14:57:26 +08:00
105 changed files with 1809 additions and 1079 deletions

View File

@@ -5,4 +5,4 @@
PATH="/usr/local/bin:$PATH"
npx --no-install commitlint --edit "$1"
# npx --no-install commitlint --edit "$1"

View File

@@ -7,4 +7,4 @@
PATH="/usr/local/bin:$PATH"
# Format and submit code according to lintstagedrc.js configuration
pnpm exec lint-staged
# pnpm exec lint-staged

View File

@@ -1,3 +1,33 @@
## [2.11.5](https://github.com/vbenjs/vue-vben-admin/compare/v2.11.4...v2.11.5) (2024-05-31)
### Bug Fixes
- 路由参数存在非英文字符的情况下 会生成一个新的tab 而非返回原有tab ([#3832](https://github.com/vbenjs/vue-vben-admin/issues/3832)) ([1fee161](https://github.com/vbenjs/vue-vben-admin/commit/1fee161786fee79a06fb3b308374db098abd461a))
- 修复表单重置后,页面变化了,但是由于异步问题导致表单内部的状态没有及时同步 ([#3882](https://github.com/vbenjs/vue-vben-admin/issues/3882)) ([5d36b1a](https://github.com/vbenjs/vue-vben-admin/commit/5d36b1a5604f72921bf09c16a78e5e287a1ba9d0))
- **Application:** search menu now correctly lowercases input keys ([#3842](https://github.com/vbenjs/vue-vben-admin/issues/3842)) ([144cdd4](https://github.com/vbenjs/vue-vben-admin/commit/144cdd468092f9314abf766ffc2eccc66c00f08a))
- **BasicForm:** 修复FormSchema中使用ifShow隐藏字段时默认表单查询重置按钮位置偏移量计算问题 ([#3830](https://github.com/vbenjs/vue-vben-admin/issues/3830)) ([478802b](https://github.com/vbenjs/vue-vben-admin/commit/478802b42625f74e8e8f817dea343b0692e3d024))
- **BasicForm:** setFieldsValue not work in form when use date comp ([#3819](https://github.com/vbenjs/vue-vben-admin/issues/3819)) ([7538c57](https://github.com/vbenjs/vue-vben-admin/commit/7538c57db755f221d201e3fdb5052ecf1f42fd9a))
- **BasicForm:** when value is 0 or false resetFields is not work ([#3828](https://github.com/vbenjs/vue-vben-admin/issues/3828)) ([22052f1](https://github.com/vbenjs/vue-vben-admin/commit/22052f10f9264008dcd25f6efdd53d679585407a))
- **Breadcrumb:** if hideBreadcrumb is true and hidden ([#3821](https://github.com/vbenjs/vue-vben-admin/issues/3821)) ([b66a0de](https://github.com/vbenjs/vue-vben-admin/commit/b66a0def98018fc1504573692a9b7a83b5c2d483))
- **imgUpload:** disabled not effect in the form ([#3809](https://github.com/vbenjs/vue-vben-admin/issues/3809)) ([4348d21](https://github.com/vbenjs/vue-vben-admin/commit/4348d21da80a1e54c94fb9528617b29090701080))
- **Loading:** 处理v-loading指令和useLoading的内存泄露 ([#3861](https://github.com/vbenjs/vue-vben-admin/issues/3861)) ([bcd98ee](https://github.com/vbenjs/vue-vben-admin/commit/bcd98ee0672047aafebdd504ef0ecc630b5068da))
- **loading:** useLoading is not working as expected ([#3877](https://github.com/vbenjs/vue-vben-admin/issues/3877)) ([c89417f](https://github.com/vbenjs/vue-vben-admin/commit/c89417f523bf4c7e2329d943796c3dd92c066d3a))
- **useDataSource:** state mutations in computed getters should be avoided ([#3859](https://github.com/vbenjs/vue-vben-admin/issues/3859)) ([fee8081](https://github.com/vbenjs/vue-vben-admin/commit/fee808198e5c2038424a5f5b1da41b11d16d1508))
### Features
- add devtools plugin instead of inspector plugin ([#3856](https://github.com/vbenjs/vue-vben-admin/issues/3856)) ([e69dd1e](https://github.com/vbenjs/vue-vben-admin/commit/e69dd1e223a2e817805739f11823092992d14ae1))
- **BasicForm:** add prefix slot for schema ([#3840](https://github.com/vbenjs/vue-vben-admin/issues/3840)) ([265627f](https://github.com/vbenjs/vue-vben-admin/commit/265627fcc8a197861aea2f04641f457548180177))
- **codeEditor:** add type and config && add use case ([#3829](https://github.com/vbenjs/vue-vben-admin/issues/3829)) ([0ee7211](https://github.com/vbenjs/vue-vben-admin/commit/0ee721183bf52c4d1239a7966cc76f2150b43b13))
- **Demo:** add ScreenShot page demo ([#3826](https://github.com/vbenjs/vue-vben-admin/issues/3826)) ([5a2d742](https://github.com/vbenjs/vue-vben-admin/commit/5a2d74249e9e9a9631f3f43e2249b7ccc13f6da4))
- **form:** add valueFormat for schema ([#3873](https://github.com/vbenjs/vue-vben-admin/issues/3873)) ([0bc01d8](https://github.com/vbenjs/vue-vben-admin/commit/0bc01d8528fc11904628974799ab44180e3e3314))
### Performance Improvements
- **BasicForm:** fix invaild defaultValue && split-setdefault-setvalue ([#3815](https://github.com/vbenjs/vue-vben-admin/issues/3815)) ([88e77db](https://github.com/vbenjs/vue-vben-admin/commit/88e77dbf994f594bc31189b896deab4be18351b8))
- **form->util:** duplicate judge ([#3865](https://github.com/vbenjs/vue-vben-admin/issues/3865)) ([dcba0ca](https://github.com/vbenjs/vue-vben-admin/commit/dcba0ca837a0f72beaa09ff394fa9b6ff465dec1))
- **menu->search:** highlight match chars when search menu ([#3880](https://github.com/vbenjs/vue-vben-admin/issues/3880)) ([d5fed8a](https://github.com/vbenjs/vue-vben-admin/commit/d5fed8a47c031f6f228ca41ed29c0f9aaf05f623))
## [2.11.4](https://github.com/vbenjs/vue-vben-admin/compare/v2.11.3...v2.11.4) (2024-05-06)
### Bug Fixes

View File

@@ -62,7 +62,7 @@ Open the project in Gitpod (free online dev environment for GitHub) and start co
- Get the project code
```bash
git clone https://github.com/anncwb/vue-vben-admin.git
git clone https://github.com/vbenjs/vue-vben-admin.git
```
- Install dependencies

View File

@@ -62,7 +62,7 @@ Vue Vben Admin 是一个免费开源的中后台模版。使用了最新的`vue3
- 获取项目代码
```bash
git clone https://github.com/anncwb/vue-vben-admin.git
git clone https://github.com/vbenjs/vue-vben-admin.git
```
- 安装依赖

View File

@@ -36,7 +36,7 @@ function defineApplicationConfig(defineOptions: DefineOptions = {}) {
});
const pathResolve = (pathname: string) => resolve(root, '.', pathname);
const timestamp = new Date().getTime();
const applicationConfig: UserConfig = {
base: VITE_PUBLIC_PATH,
resolve: {
@@ -64,7 +64,7 @@ function defineApplicationConfig(defineOptions: DefineOptions = {}) {
rollupOptions: {
output: {
// 入口文件名
entryFileNames: `assets/entry/[name]-[hash]-${timestamp}.js`,
entryFileNames: 'assets/entry/[name]-[hash].js',
manualChunks: {
vue: ['vue', 'pinia', 'vue-router'],
antd: ['ant-design-vue', '@ant-design/icons-vue'],

View File

@@ -2,6 +2,7 @@ import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import { type PluginOption } from 'vite';
import purgeIcons from 'vite-plugin-purge-icons';
import DevTools from 'vite-plugin-vue-devtools';
import { createAppConfigPlugin } from './appConfig';
import { configCompressPlugin } from './compress';
@@ -24,6 +25,8 @@ async function createPlugins({ isBuild, root, enableMock, compress, enableAnalyz
const appConfigPlugin = await createAppConfigPlugin({ root, isBuild });
vitePlugins.push(appConfigPlugin);
vitePlugins.push(DevTools());
// vite-plugin-html
vitePlugins.push(configHtmlPlugin({ isBuild }));

View File

@@ -1,6 +1,6 @@
{
"name": "vben-admin",
"version": "2.11.4",
"version": "2.11.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": {
"url": "https://github.com/vbenjs/vue-vben-admin/issues"
@@ -85,6 +85,7 @@
"dayjs": "^1.11.10",
"echarts": "^5.5.0",
"exceljs": "^4.4.0",
"html2canvas": "^1.4.1",
"lodash-es": "^4.17.21",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
@@ -106,9 +107,10 @@
"vue-router": "^4.3.2",
"vue-types": "^5.1.1",
"vuedraggable": "^4.1.0",
"vxe-table": "^4.6.3",
"vxe-table-plugin-export-xlsx": "^4.0.1",
"xe-utils": "^3.5.25",
"vxe-pc-ui": "^4.0.44",
"vxe-table": "^4.7.40",
"vxe-table-plugin-export-xlsx": "^4.0.4",
"xe-utils": "^3.5.28",
"xlsx": "^0.18.5"
},
"devDependencies": {
@@ -146,7 +148,7 @@
"unbuild": "^2.0.0",
"vite": "^5.2.10",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-vue-inspector": "^5.0.1",
"vite-plugin-vue-devtools": "^7.2.0",
"vue-tsc": "^2.0.14"
},
"packageManager": "pnpm@9.0.4",

356
pnpm-lock.yaml generated
View File

@@ -56,6 +56,9 @@ importers:
exceljs:
specifier: ^4.4.0
version: 4.4.0
html2canvas:
specifier: ^1.4.1
version: 1.4.1
lodash-es:
specifier: ^4.17.21
version: 4.17.21
@@ -119,15 +122,18 @@ importers:
vuedraggable:
specifier: ^4.1.0
version: 4.1.0(vue@3.4.25(typescript@5.4.5))
vxe-pc-ui:
specifier: ^4.0.44
version: 4.0.44
vxe-table:
specifier: ^4.6.3
version: 4.6.3(vue@3.4.25(typescript@5.4.5))
specifier: ^4.7.40
version: 4.7.40
vxe-table-plugin-export-xlsx:
specifier: ^4.0.1
version: 4.0.1(vxe-table@4.6.3(vue@3.4.25(typescript@5.4.5)))
specifier: ^4.0.4
version: 4.0.4(vxe-table@4.7.40)
xe-utils:
specifier: ^3.5.25
version: 3.5.25
specifier: ^3.5.28
version: 3.5.28
xlsx:
specifier: ^0.18.5
version: 0.18.5
@@ -234,9 +240,9 @@ importers:
vite-plugin-mock:
specifier: ^2.9.6
version: 2.9.8(mockjs@1.1.0)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3))
vite-plugin-vue-inspector:
specifier: ^5.0.1
version: 5.0.1(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3))
vite-plugin-vue-devtools:
specifier: ^7.2.0
version: 7.2.0(rollup@3.29.4)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3))(vue@3.4.25(typescript@5.4.5))
vue-tsc:
specifier: ^2.0.14
version: 2.0.14(typescript@5.4.5)
@@ -1931,21 +1937,9 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
'@vue/compiler-core@3.4.23':
resolution: {integrity: sha512-HAFmuVEwNqNdmk+w4VCQ2pkLk1Vw4XYiiyxEp3z/xvl14aLTUBw2OfVH3vBcx+FtGsynQLkkhK410Nah1N2yyQ==}
'@vue/compiler-core@3.4.24':
resolution: {integrity: sha512-vbW/tgbwJYj62N/Ww99x0zhFTkZDTcGh3uwJEuadZ/nF9/xuFMC4693P9r+3sxGXISABpDKvffY5ApH9pmdd1A==}
'@vue/compiler-core@3.4.25':
resolution: {integrity: sha512-Y2pLLopaElgWnMNolgG8w3C5nNUVev80L7hdQ5iIKPtMJvhVpG0zhnBG/g3UajJmZdvW0fktyZTotEHD1Srhbg==}
'@vue/compiler-dom@3.4.23':
resolution: {integrity: sha512-t0b9WSTnCRrzsBGrDd1LNR5HGzYTr7LX3z6nNBG+KGvZLqrT0mY6NsMzOqlVMBKKXKVuusbbB5aOOFgTY+senw==}
'@vue/compiler-dom@3.4.24':
resolution: {integrity: sha512-4XgABML/4cNndVsQndG6BbGN7+EoisDwi3oXNovqL/4jdNhwvP8/rfRMTb6FxkxIxUUtg6AI1/qZvwfSjxJiWA==}
'@vue/compiler-dom@3.4.25':
resolution: {integrity: sha512-Ugz5DusW57+HjllAugLci19NsDK+VyjGvmbB2TXaTcSlQxwL++2PETHx/+Qv6qFwNLzSt7HKepPe4DcTE3pBWg==}
@@ -1958,6 +1952,17 @@ packages:
'@vue/devtools-api@6.6.1':
resolution: {integrity: sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA==}
'@vue/devtools-core@7.2.0':
resolution: {integrity: sha512-cHSeu70rTtubt2DYia+VDGNTC1m84Xyuk5eNTjmOpMLECaJnWnzCv6kR84EZp7rG+MVZalJG+4ecX2GaTbU3cQ==}
'@vue/devtools-kit@7.2.0':
resolution: {integrity: sha512-Kx+U0QiQg/g714euYKfnCdhTcOycSlH1oyTE57D0sAmisdsRCNLfXcnnIwcFY2jdCpuz9DNbuE0VWQuYF5zAZQ==}
peerDependencies:
vue: ^3.0.0
'@vue/devtools-shared@7.2.0':
resolution: {integrity: sha512-gVr3IjKjU7axNvclRgICgy1gq/TDnF1hhBAEox+l5mMXZiTIFVIm1zpcIPssc0HxMDgzy+lXqOVsY4DGyZ+ZeA==}
'@vue/language-core@1.8.27':
resolution: {integrity: sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==}
peerDependencies:
@@ -1988,12 +1993,6 @@ packages:
peerDependencies:
vue: 3.4.25
'@vue/shared@3.4.23':
resolution: {integrity: sha512-wBQ0gvf+SMwsCQOyusNw/GoXPV47WGd1xB5A1Pgzy0sQ3Bi5r5xm3n+92y3gCnB3MWqnRDdvfkRGxhKtbBRNgg==}
'@vue/shared@3.4.24':
resolution: {integrity: sha512-BW4tajrJBM9AGAknnyEw5tO2xTmnqgup0VTnDAMcxYmqOX0RG0b9aSUGAbEKolD91tdwpA6oCwbltoJoNzpItw==}
'@vue/shared@3.4.25':
resolution: {integrity: sha512-k0yappJ77g2+KNrIaF0FFnzwLvUBLUYr8VOwz+/6vLsmItFp51AcxLL7Ey3iPd7BIRyWPOcqUjMnm7OkahXllA==}
@@ -2009,6 +2008,9 @@ packages:
'@vueuse/shared@10.9.0':
resolution: {integrity: sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==}
'@vxe-ui/core@1.0.12':
resolution: {integrity: sha512-s79mQw6uYSbTVGBWbxrisHwJV1b770vZMT9XpY3khcFQhXNo25+PS3FLrNCSsBBJR0ZkBLOXDER/ft9DIqgFTw==}
'@zxcvbn-ts/core@3.0.4':
resolution: {integrity: sha512-aQeiT0F09FuJaAqNrxynlAwZ2mW/1MdXakKWNmGM1Qp/VaY6CnB/GfnMS2T8gB2231Esp1/maCWd8vTG4OuShw==}
@@ -2296,6 +2298,10 @@ packages:
balanced-match@2.0.0:
resolution: {integrity: sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==}
base64-arraybuffer@1.0.2:
resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==}
engines: {node: '>= 0.6.0'}
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
@@ -2387,6 +2393,10 @@ packages:
resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
engines: {node: '>=6'}
bundle-name@4.1.0:
resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
engines: {node: '>=18'}
bundle-require@4.0.2:
resolution: {integrity: sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -2805,6 +2815,9 @@ packages:
resolution: {integrity: sha512-c+N0v6wbKVxTu5gOBBFkr9BEdBWaqqjQeiJ8QvSRIJOf+UxlJh930m8e6/WNeODIK0mYLFkoONrnj16i2EcvfQ==}
engines: {node: '>=12 || >=16'}
css-line-break@2.1.0:
resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==}
css-property-sort-order-smacss@2.2.0:
resolution: {integrity: sha512-nXutswsivIEBOrPo/OZw2KQjFPLvtg68aovJf6Kqrm3L6FmTvvFPaeDrk83hh0+pRJGuP3PeKJwMS0E6DFipdQ==}
@@ -2968,6 +2981,14 @@ packages:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
default-browser-id@5.0.0:
resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==}
engines: {node: '>=18'}
default-browser@5.2.1:
resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==}
engines: {node: '>=18'}
define-data-property@1.1.4:
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
engines: {node: '>= 0.4'}
@@ -2976,6 +2997,10 @@ packages:
resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==}
engines: {node: '>=8'}
define-lazy-prop@3.0.0:
resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
engines: {node: '>=12'}
define-properties@1.2.1:
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
engines: {node: '>= 0.4'}
@@ -3077,8 +3102,8 @@ packages:
dom-serializer@2.0.0:
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
dom-zindex@1.0.2:
resolution: {integrity: sha512-QceDZxPlvzhpg6e8szxNiKPUt5Y9SfFTe3nZy8og3JoPQPlAlzBzHa/lhDkhgeG3cjbKyQcuoic+wymF0o0d1Q==}
dom-zindex@1.0.4:
resolution: {integrity: sha512-PNk7u71TJ1C9Lwjjp5nNuQcVWuECFMmr9kZAwi2UbgWUM7jXdTCe4O4x5bhLUa07jpcZUVA5Du3ho7/FXzS9Ng==}
domelementtype@1.3.1:
resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==}
@@ -3209,6 +3234,9 @@ packages:
error-ex@1.3.2:
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
error-stack-parser-es@0.1.4:
resolution: {integrity: sha512-l0uy0kAoo6toCgVOYaAayqtPa2a1L15efxUMEnQebKwLQX2X0OpS6wMMQdc4juJXmxd9i40DuaUHq+mjIya9TQ==}
es-abstract@1.23.3:
resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==}
engines: {node: '>= 0.4'}
@@ -3951,6 +3979,10 @@ packages:
resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==}
engines: {node: '>=8'}
html2canvas@1.4.1:
resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==}
engines: {node: '>=8.0.0'}
htmlparser2@3.10.1:
resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==}
@@ -4140,6 +4172,11 @@ packages:
engines: {node: '>=8'}
hasBin: true
is-docker@3.0.0:
resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
hasBin: true
is-extendable@0.1.1:
resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==}
engines: {node: '>=0.10.0'}
@@ -4176,6 +4213,11 @@ packages:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
is-inside-container@1.0.0:
resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==}
engines: {node: '>=14.16'}
hasBin: true
is-module@1.0.0:
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
@@ -4278,6 +4320,10 @@ packages:
resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
engines: {node: '>=8'}
is-wsl@3.1.0:
resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==}
engines: {node: '>=16'}
isarray@0.0.1:
resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==}
@@ -4828,10 +4874,6 @@ packages:
magic-string@0.30.10:
resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
magic-string@0.30.9:
resolution: {integrity: sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==}
engines: {node: '>=12'}
make-dir@2.1.0:
resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
engines: {node: '>=6'}
@@ -4947,6 +4989,9 @@ packages:
resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==}
engines: {node: '>=16 || 14 >=14.17'}
mitt@3.0.1:
resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
mixin-deep@1.3.2:
resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==}
engines: {node: '>=0.10.0'}
@@ -5185,6 +5230,10 @@ packages:
only@0.0.2:
resolution: {integrity: sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==}
open@10.1.0:
resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==}
engines: {node: '>=18'}
open@8.4.2:
resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==}
engines: {node: '>=12'}
@@ -5914,6 +5963,10 @@ packages:
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
run-applescript@7.0.0:
resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==}
engines: {node: '>=18'}
run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
@@ -6144,6 +6197,10 @@ packages:
spdx-license-ids@3.0.17:
resolution: {integrity: sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==}
speakingurl@14.0.1:
resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==}
engines: {node: '>=0.10.0'}
split-string@3.1.0:
resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==}
engines: {node: '>=0.10.0'}
@@ -6445,6 +6502,9 @@ packages:
resolution: {integrity: sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==}
engines: {node: '>=8'}
text-segmentation@1.0.3:
resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==}
text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
@@ -6797,6 +6857,9 @@ packages:
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
engines: {node: '>= 0.4.0'}
utrie@1.0.2:
resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==}
uuid@3.4.0:
resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==}
deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
@@ -6827,6 +6890,11 @@ packages:
vditor@3.10.4:
resolution: {integrity: sha512-NWaMom0buUvRjOCaK/jKeJEVfZNmfTgblK4+pxBoeTdiCYn5yWokcGYMh9GzHIvt5gy6FiQFc1VQvytIwyeIwA==}
vite-hot-client@0.2.3:
resolution: {integrity: sha512-rOGAV7rUlUHX89fP2p2v0A2WWvV3QMX2UYq0fRqsWSvFvev4atHWqjwGoKaZT1VTKyLGk533ecu3eyd0o59CAg==}
peerDependencies:
vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0
vite-plugin-compression@0.5.1:
resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==}
peerDependencies:
@@ -6847,6 +6915,16 @@ packages:
peerDependencies:
vite: '>=2.0.0'
vite-plugin-inspect@0.8.4:
resolution: {integrity: sha512-G0N3rjfw+AiiwnGw50KlObIHYWfulVwaCBUBLh2xTW9G1eM9ocE5olXkEYUbwyTmX+azM8duubi+9w5awdCz+g==}
engines: {node: '>=14'}
peerDependencies:
'@nuxt/kit': '*'
vite: ^3.1.0 || ^4.0.0 || ^5.0.0-0
peerDependenciesMeta:
'@nuxt/kit':
optional: true
vite-plugin-mock@2.9.8:
resolution: {integrity: sha512-YTQM5Sn7t+/DNOwTkr+W26QGTCk1PrDkhGHslTJ90lIPJhJtDTwuSkEYMAuLP9TcVQ/qExTFx/x/GE3kxJ05sw==}
engines: {node: '>=12.0.0'}
@@ -6865,8 +6943,14 @@ packages:
peerDependencies:
vite: '>=2.0.0'
vite-plugin-vue-inspector@5.0.1:
resolution: {integrity: sha512-R93P8iFa6BPODhc/aOtO04A8FFMMyFIfm8ZVSmN+8vU1TgwsHya734APGpX4fVHSPX2aVwYyiezXBUYQ0Opsqw==}
vite-plugin-vue-devtools@7.2.0:
resolution: {integrity: sha512-bFWwx/YF9M+aXTjDo0/6DrC7+WCzLg7wAmFoQA3Gd7cv5WV4u65hHSZN8bq0zhgHqtYQZdWnp0L2z6JNCwcIGg==}
engines: {node: '>=v14.21.3'}
peerDependencies:
vite: ^3.1.0 || ^4.0.0-0 || ^5.0.0-0
vite-plugin-vue-inspector@5.1.0:
resolution: {integrity: sha512-yIw9dvBz9nQW7DPfbJtUVW6JTnt67hqTPRnTwT2CZWMqDvISyQHRjgKl32nlMh1DRH+92533Sv6t59pWMLUCWA==}
peerDependencies:
vite: ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0
@@ -6982,15 +7066,16 @@ packages:
peerDependencies:
vue: ^3.0.1
vxe-table-plugin-export-xlsx@4.0.1:
resolution: {integrity: sha512-puUOUfptu5ciEiFqTlVni3twLICSbkl87uXOsjZzrEyXJHJS9dYu7ZTD7/DRMqyuWyU3Idg7AekfcdcslP4Y/A==}
vxe-pc-ui@4.0.44:
resolution: {integrity: sha512-wiauFMmSvEkVKa/AsKGb5CMi91Ojts+Ydcn+iespgl3xMBD01BR/CGzeCI478P3XAFBsiN4gWlgxHmGP5TR8UA==}
vxe-table-plugin-export-xlsx@4.0.4:
resolution: {integrity: sha512-Og2ZcIWTV7msT1ddPT/spxJaP1T8wxs3Uuu1LO/3HL5Ugt9tShEY3FJ7YGic3j1Nk6ZZT+VsU+afgT5EzpcUJw==}
peerDependencies:
vxe-table: ^4.5.0
vxe-table@4.6.3:
resolution: {integrity: sha512-71FOi0lFQbvs1dUIZPTDCLaSJkRjLHlBuNzWIR9RofBe4EvhX4OowrhaCCsCXXKCCGSlJRp6+/O2c71lEZY9PQ==}
peerDependencies:
vue: ^3.2.28
vxe-table@4.7.40:
resolution: {integrity: sha512-y9VC3oLJgusxFj3xZ28G4gU+YClBuDIV8oM75Dx3doYJ7vanXZnSf70XJ+W5xEKflamUmjGre66XZ2b4XuqtMw==}
w3c-hr-time@1.0.2:
resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==}
@@ -7128,8 +7213,8 @@ packages:
utf-8-validate:
optional: true
xe-utils@3.5.25:
resolution: {integrity: sha512-d/ty5eo4hXtho/3195XAvqereIoSYJ+XfC52f3ZEPxTaCeyLFivDZTyX6gTdsR65ISH1Irvn85H0bSL60dUhSQ==}
xe-utils@3.5.28:
resolution: {integrity: sha512-oeLLJ0b54QdOSSgYQ9TiKW/xAGrc9r0weCA/5UfyGdm3n3js4cNOuuf9Tml7UwgBQpl4uWMbMwUZKLh2yqPF3A==}
xlsx@0.18.5:
resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==}
@@ -9020,22 +9105,6 @@ snapshots:
'@babel/parser': 7.24.4
'@vue/compiler-sfc': 3.4.25
'@vue/compiler-core@3.4.23':
dependencies:
'@babel/parser': 7.24.4
'@vue/shared': 3.4.23
entities: 4.5.0
estree-walker: 2.0.2
source-map-js: 1.2.0
'@vue/compiler-core@3.4.24':
dependencies:
'@babel/parser': 7.24.4
'@vue/shared': 3.4.24
entities: 4.5.0
estree-walker: 2.0.2
source-map-js: 1.2.0
'@vue/compiler-core@3.4.25':
dependencies:
'@babel/parser': 7.24.4
@@ -9044,16 +9113,6 @@ snapshots:
estree-walker: 2.0.2
source-map-js: 1.2.0
'@vue/compiler-dom@3.4.23':
dependencies:
'@vue/compiler-core': 3.4.23
'@vue/shared': 3.4.23
'@vue/compiler-dom@3.4.24':
dependencies:
'@vue/compiler-core': 3.4.24
'@vue/shared': 3.4.24
'@vue/compiler-dom@3.4.25':
dependencies:
'@vue/compiler-core': 3.4.25
@@ -9078,11 +9137,36 @@ snapshots:
'@vue/devtools-api@6.6.1': {}
'@vue/devtools-core@7.2.0(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3))(vue@3.4.25(typescript@5.4.5))':
dependencies:
'@vue/devtools-kit': 7.2.0(vue@3.4.25(typescript@5.4.5))
'@vue/devtools-shared': 7.2.0
mitt: 3.0.1
nanoid: 3.3.7
pathe: 1.1.2
vite-hot-client: 0.2.3(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3))
transitivePeerDependencies:
- vite
- vue
'@vue/devtools-kit@7.2.0(vue@3.4.25(typescript@5.4.5))':
dependencies:
'@vue/devtools-shared': 7.2.0
hookable: 5.5.3
mitt: 3.0.1
perfect-debounce: 1.0.0
speakingurl: 14.0.1
vue: 3.4.25(typescript@5.4.5)
'@vue/devtools-shared@7.2.0':
dependencies:
rfdc: 1.3.1
'@vue/language-core@1.8.27(typescript@5.4.5)':
dependencies:
'@volar/language-core': 1.11.1
'@volar/source-map': 1.11.1
'@vue/compiler-dom': 3.4.24
'@vue/compiler-dom': 3.4.25
'@vue/shared': 3.4.25
computeds: 0.0.1
minimatch: 9.0.4
@@ -9095,7 +9179,7 @@ snapshots:
'@vue/language-core@2.0.14(typescript@5.4.5)':
dependencies:
'@volar/language-core': 2.2.0-alpha.10
'@vue/compiler-dom': 3.4.24
'@vue/compiler-dom': 3.4.25
'@vue/shared': 3.4.25
computeds: 0.0.1
minimatch: 9.0.4
@@ -9125,10 +9209,6 @@ snapshots:
'@vue/shared': 3.4.25
vue: 3.4.25(typescript@5.4.5)
'@vue/shared@3.4.23': {}
'@vue/shared@3.4.24': {}
'@vue/shared@3.4.25': {}
'@vue/test-utils@2.4.5':
@@ -9155,6 +9235,11 @@ snapshots:
- '@vue/composition-api'
- vue
'@vxe-ui/core@1.0.12':
dependencies:
dom-zindex: 1.0.4
xe-utils: 3.5.28
'@zxcvbn-ts/core@3.0.4':
dependencies:
fastest-levenshtein: 1.0.16
@@ -9507,6 +9592,8 @@ snapshots:
balanced-match@2.0.0: {}
base64-arraybuffer@1.0.2: {}
base64-js@1.5.1: {}
base@0.11.2:
@@ -9604,6 +9691,10 @@ snapshots:
builtin-modules@3.3.0: {}
bundle-name@4.1.0:
dependencies:
run-applescript: 7.0.0
bundle-require@4.0.2(esbuild@0.19.12):
dependencies:
esbuild: 0.19.12
@@ -10031,6 +10122,10 @@ snapshots:
css-functions-list@3.2.2: {}
css-line-break@2.1.0:
dependencies:
utrie: 1.0.2
css-property-sort-order-smacss@2.2.0: {}
css-select@4.3.0:
@@ -10198,6 +10293,13 @@ snapshots:
deepmerge@4.3.1: {}
default-browser-id@5.0.0: {}
default-browser@5.2.1:
dependencies:
bundle-name: 4.1.0
default-browser-id: 5.0.0
define-data-property@1.1.4:
dependencies:
es-define-property: 1.0.0
@@ -10206,6 +10308,8 @@ snapshots:
define-lazy-prop@2.0.0: {}
define-lazy-prop@3.0.0: {}
define-properties@1.2.1:
dependencies:
define-data-property: 1.1.4
@@ -10297,7 +10401,7 @@ snapshots:
domhandler: 5.0.3
entities: 4.5.0
dom-zindex@1.0.2: {}
dom-zindex@1.0.4: {}
domelementtype@1.3.1: {}
@@ -10420,6 +10524,8 @@ snapshots:
dependencies:
is-arrayish: 0.2.1
error-stack-parser-es@0.1.4: {}
es-abstract@1.23.3:
dependencies:
array-buffer-byte-length: 1.0.1
@@ -11313,6 +11419,11 @@ snapshots:
html-tags@3.3.1: {}
html2canvas@1.4.1:
dependencies:
css-line-break: 2.1.0
text-segmentation: 1.0.3
htmlparser2@3.10.1:
dependencies:
domelementtype: 1.3.1
@@ -11515,6 +11626,8 @@ snapshots:
is-docker@2.2.1: {}
is-docker@3.0.0: {}
is-extendable@0.1.1: {}
is-extendable@1.0.1:
@@ -11541,6 +11654,10 @@ snapshots:
dependencies:
is-extglob: 2.1.1
is-inside-container@1.0.0:
dependencies:
is-docker: 3.0.0
is-module@1.0.0: {}
is-negative-zero@2.0.3: {}
@@ -11620,6 +11737,10 @@ snapshots:
dependencies:
is-docker: 2.2.1
is-wsl@3.1.0:
dependencies:
is-inside-container: 1.0.0
isarray@0.0.1: {}
isarray@1.0.0: {}
@@ -12452,10 +12573,6 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.4.15
magic-string@0.30.9:
dependencies:
'@jridgewell/sourcemap-codec': 1.4.15
make-dir@2.1.0:
dependencies:
pify: 4.0.1
@@ -12562,6 +12679,8 @@ snapshots:
minipass@7.0.4: {}
mitt@3.0.1: {}
mixin-deep@1.3.2:
dependencies:
for-in: 1.0.2
@@ -12818,6 +12937,13 @@ snapshots:
only@0.0.2: {}
open@10.1.0:
dependencies:
default-browser: 5.2.1
define-lazy-prop: 3.0.0
is-inside-container: 1.0.0
is-wsl: 3.1.0
open@8.4.2:
dependencies:
define-lazy-prop: 2.0.0
@@ -13584,6 +13710,8 @@ snapshots:
'@rollup/rollup-win32-x64-msvc': 4.14.3
fsevents: 2.3.3
run-applescript@7.0.0: {}
run-parallel@1.2.0:
dependencies:
queue-microtask: 1.2.3
@@ -13829,6 +13957,8 @@ snapshots:
spdx-license-ids@3.0.17: {}
speakingurl@14.0.1: {}
split-string@3.1.0:
dependencies:
extend-shallow: 3.0.2
@@ -14192,6 +14322,10 @@ snapshots:
text-extensions@2.4.0: {}
text-segmentation@1.0.3:
dependencies:
utrie: 1.0.2
text-table@0.2.0: {}
thenify-all@1.6.0:
@@ -14469,7 +14603,7 @@ snapshots:
globby: 13.2.2
hookable: 5.5.3
jiti: 1.21.0
magic-string: 0.30.9
magic-string: 0.30.10
mkdist: 1.4.0(sass@1.75.0)(typescript@5.4.5)
mlly: 1.6.1
pathe: 1.1.2
@@ -14623,6 +14757,10 @@ snapshots:
utils-merge@1.0.1: {}
utrie@1.0.2:
dependencies:
base64-arraybuffer: 1.0.2
uuid@3.4.0: {}
uuid@8.3.2: {}
@@ -14648,6 +14786,10 @@ snapshots:
dependencies:
diff-match-patch: 1.0.5
vite-hot-client@0.2.3(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3)):
dependencies:
vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3)
vite-plugin-compression@0.5.1(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3)):
dependencies:
chalk: 4.1.2
@@ -14690,6 +14832,22 @@ snapshots:
pathe: 0.2.0
vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3)
vite-plugin-inspect@0.8.4(rollup@3.29.4)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3)):
dependencies:
'@antfu/utils': 0.7.7
'@rollup/pluginutils': 5.1.0(rollup@3.29.4)
debug: 4.3.4
error-stack-parser-es: 0.1.4
fs-extra: 11.2.0
open: 10.1.0
perfect-debounce: 1.0.0
picocolors: 1.0.0
sirv: 2.0.4
vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3)
transitivePeerDependencies:
- rollup
- supports-color
vite-plugin-mock@2.9.8(mockjs@1.1.0)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3)):
dependencies:
'@types/mockjs': 1.0.10
@@ -14729,7 +14887,23 @@ snapshots:
transitivePeerDependencies:
- supports-color
vite-plugin-vue-inspector@5.0.1(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3)):
vite-plugin-vue-devtools@7.2.0(rollup@3.29.4)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3))(vue@3.4.25(typescript@5.4.5)):
dependencies:
'@vue/devtools-core': 7.2.0(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3))(vue@3.4.25(typescript@5.4.5))
'@vue/devtools-kit': 7.2.0(vue@3.4.25(typescript@5.4.5))
'@vue/devtools-shared': 7.2.0
execa: 8.0.1
sirv: 2.0.4
vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3)
vite-plugin-inspect: 0.8.4(rollup@3.29.4)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3))
vite-plugin-vue-inspector: 5.1.0(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3))
transitivePeerDependencies:
- '@nuxt/kit'
- rollup
- supports-color
- vue
vite-plugin-vue-inspector@5.1.0(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3)):
dependencies:
'@babel/core': 7.24.4
'@babel/plugin-proposal-decorators': 7.24.1(@babel/core@7.24.4)
@@ -14737,7 +14911,7 @@ snapshots:
'@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.4)
'@babel/plugin-transform-typescript': 7.24.4(@babel/core@7.24.4)
'@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.24.4)
'@vue/compiler-dom': 3.4.23
'@vue/compiler-dom': 3.4.25
kolorist: 1.8.0
magic-string: 0.30.10
vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.30.3)
@@ -14843,15 +15017,17 @@ snapshots:
sortablejs: 1.14.0
vue: 3.4.25(typescript@5.4.5)
vxe-table-plugin-export-xlsx@4.0.1(vxe-table@4.6.3(vue@3.4.25(typescript@5.4.5))):
vxe-pc-ui@4.0.44:
dependencies:
vxe-table: 4.6.3(vue@3.4.25(typescript@5.4.5))
'@vxe-ui/core': 1.0.12
vxe-table@4.6.3(vue@3.4.25(typescript@5.4.5)):
vxe-table-plugin-export-xlsx@4.0.4(vxe-table@4.7.40):
dependencies:
dom-zindex: 1.0.2
vue: 3.4.25(typescript@5.4.5)
xe-utils: 3.5.25
vxe-table: 4.7.40
vxe-table@4.7.40:
dependencies:
vxe-pc-ui: 4.0.44
w3c-hr-time@1.0.2:
dependencies:
@@ -14976,7 +15152,7 @@ snapshots:
ws@8.16.0: {}
xe-utils@3.5.25: {}
xe-utils@3.5.28: {}
xlsx@0.18.5:
dependencies:

View File

@@ -43,7 +43,14 @@
<Icon :icon="item.icon || 'mdi:form-select'" :size="20" />
</div>
<div :class="`${prefixCls}-list__item-text`">
{{ item.name }}
<!-- 搜索结果包含的字符着色 -->
<span
v-for="(each, i) in item.chars"
:key="i"
:class="{ highlight: each.highlight }"
>
{{ each.char }}
</span>
</div>
<div :class="`${prefixCls}-list__item-enter`">
<Icon icon="ant-design:enter-outlined" :size="20" />
@@ -254,6 +261,13 @@
&-text {
flex: 1;
// 搜索结果包含的字符着色
& > span {
&.highlight {
color: lighten(@primary-color, 20%);
}
}
}
&-enter {

View File

@@ -13,6 +13,8 @@ export interface SearchResult {
name: string;
path: string;
icon?: string;
// 搜索结果包含的字符着色
chars: { char: string; highlight: boolean }[];
}
// Translate special characters
@@ -49,7 +51,7 @@ export function useMenuSearch(refs: Ref<HTMLElement[]>, scrollWrap: Ref, emit: A
function search(e: ChangeEvent) {
e?.stopPropagation();
const key = e.target.value;
keyword.value = key.trim();
keyword.value = key.trim().toLowerCase();
if (!key) {
searchResult.value = [];
return;
@@ -68,11 +70,85 @@ export function useMenuSearch(refs: Ref<HTMLElement[]>, scrollWrap: Ref, emit: A
const { name, path, icon, children, hideMenu, meta } = item;
if (
!hideMenu &&
reg.test(name?.toLowerCase()) &&
reg.test(name?.toLowerCase() ?? '') &&
(!children?.length || meta?.hideChildrenInMenu)
) {
const chars: { char: string; highlight: boolean }[] = [];
// 显示字符串
const label = (parent?.name ? `${parent.name} > ${name}` : name) ?? '';
const labelChars = label.split('');
let labelPointer = 0;
const keywordChars = keyword.value.split('');
const keywordLength = keywordChars.length;
let keywordPointer = 0;
// 用于查找完整关键词的匹配
let includePointer = 0;
// 优先查找完整关键词的匹配
if (label.toLowerCase().includes(keyword.value.toLowerCase())) {
while (includePointer < labelChars.length) {
if (
label.toLowerCase().slice(includePointer, includePointer + keywordLength) ===
keyword.value.toLowerCase()
) {
chars.push(
...label
.substring(labelPointer, includePointer)
.split('')
.map((v) => ({
char: v,
highlight: false,
})),
);
chars.push(
...label
.slice(includePointer, includePointer + keywordLength)
.split('')
.map((v) => ({
char: v,
highlight: true,
})),
);
includePointer += keywordLength;
labelPointer = includePointer;
} else {
includePointer++;
}
}
}
// 查找满足关键词顺序的匹配
while (labelPointer < labelChars.length) {
keywordPointer = 0;
while (keywordPointer < keywordChars.length) {
if (keywordChars[keywordPointer] !== void 0 && labelChars[labelPointer] !== void 0) {
if (
keywordChars[keywordPointer].toLowerCase() ===
labelChars[labelPointer].toLowerCase()
) {
chars.push({
char: labelChars[labelPointer],
highlight: true,
});
keywordPointer++;
} else {
chars.push({
char: labelChars[labelPointer],
highlight: false,
});
}
} else {
keywordPointer++;
}
labelPointer++;
}
}
ret.push({
name: parent?.name ? `${parent.name} > ${name}` : name,
name: label,
chars,
path,
icon,
});
@@ -81,7 +157,36 @@ export function useMenuSearch(refs: Ref<HTMLElement[]>, scrollWrap: Ref, emit: A
ret.push(...handlerSearchResult(children, reg, item));
}
});
return ret;
// 排序
return ret.sort((a, b) => {
if (
a.name.toLowerCase().includes(keyword.value.toLowerCase()) &&
b.name.toLowerCase().includes(keyword.value.toLowerCase())
) {
// 两者都存在完整关键词的匹配
// 匹配数量
const ca =
a.name.toLowerCase().match(new RegExp(keyword.value.toLowerCase(), 'g'))?.length ?? 0;
const cb =
b.name.toLowerCase().match(new RegExp(keyword.value.toLowerCase(), 'g'))?.length ?? 0;
// 匹配数量越多的优先显示,数量相同的按字符串排序
return ca === cb ? a.name.toLowerCase().localeCompare(b.name.toLowerCase()) : cb - ca;
} else {
if (a.name.toLowerCase().includes(keyword.value.toLowerCase())) {
// 完整关键词的匹配优先
return -1;
} else if (b.name.toLowerCase().includes(keyword.value.toLowerCase())) {
// 完整关键词的匹配优先
return 1;
} else {
// 按字符串排序
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
}
}
});
}
// Activate when the mouse moves to a certain line

View File

@@ -6,6 +6,7 @@
:mode="mode"
:readonly="readonly"
:bordered="bordered"
:config="config"
/>
</div>
</template>
@@ -14,6 +15,7 @@
import CodeMirrorEditor from './codemirror/CodeMirror.vue';
import { isString } from '@/utils/is';
import { MODE } from './typing';
import type { EditorConfiguration } from 'codemirror';
const props = defineProps({
value: { type: [Object, String] as PropType<Record<string, any> | string> },
@@ -28,6 +30,7 @@
readonly: { type: Boolean },
autoFormat: { type: Boolean, default: true },
bordered: { type: Boolean, default: false },
config: { type: Object as PropType<EditorConfiguration>, default: () => {} },
});
const emit = defineEmits(['change', 'update:value', 'format-error']);

View File

@@ -22,15 +22,22 @@
import { useDebounceFn } from '@vueuse/core';
import { useAppStore } from '@/store/modules/app';
import CodeMirror from 'codemirror';
import { MODE } from './../typing';
import type { EditorConfiguration } from 'codemirror';
import { MODE, parserDynamicImport } from './../typing';
// css
import './codemirror.css';
import 'codemirror/lib/codemirror.css';
import 'codemirror/theme/idea.css';
import 'codemirror/theme/material-palenight.css';
// modes
import 'codemirror/mode/javascript/javascript';
import 'codemirror/mode/css/css';
import 'codemirror/mode/htmlmixed/htmlmixed';
// 代码段折叠功能
import 'codemirror/addon/fold/foldgutter.css';
import 'codemirror/addon/fold/foldcode.js';
import 'codemirror/addon/fold/foldgutter';
import 'codemirror/addon/fold/brace-fold';
import 'codemirror/addon/fold/comment-fold';
import 'codemirror/addon/fold/markdown-fold';
import 'codemirror/addon/fold/xml-fold';
import 'codemirror/addon/fold/indent-fold';
const props = defineProps({
mode: {
@@ -44,6 +51,7 @@
value: { type: String, default: '' },
readonly: { type: Boolean, default: false },
bordered: { type: Boolean, default: false },
config: { type: Object as PropType<EditorConfiguration>, default: () => {} },
});
const emit = defineEmits(['change']);
@@ -66,7 +74,8 @@
{ flush: 'post' },
);
watchEffect(() => {
watchEffect(async () => {
await parserDynamicImport(props.mode)();
editor?.setOption('mode', props.mode);
});
@@ -96,7 +105,7 @@
autoCloseBrackets: true,
autoCloseTags: true,
foldGutter: true,
gutters: ['CodeMirror-linenumbers'],
gutters: ['CodeMirror-lint-markers', 'CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
};
editor = CodeMirror(el.value!, {
@@ -108,6 +117,7 @@
lineWrapping: true,
lineNumbers: true,
...addonOptions,
...props.config,
});
editor?.setValue(props.value);
setTheme();

View File

@@ -1,529 +0,0 @@
/* BASICS */
.CodeMirror {
--base: #545281;
--comment: hsl(210deg 25% 60%);
--keyword: #af4ab1;
--variable: #0055d1;
--function: #c25205;
--string: #2ba46d;
--number: #c25205;
--tags: #d00;
--qualifier: #ff6032;
--important: var(--string);
position: relative;
height: auto;
height: 100%;
overflow: hidden;
font-family: var(--font-code);
background: white;
direction: ltr;
}
/* PADDING */
.CodeMirror-lines {
min-height: 1px; /* prevents collapsing before first draw */
padding: 4px 0; /* Vertical padding around content */
cursor: text;
}
.CodeMirror-scrollbar-filler,
.CodeMirror-gutter-filler {
background-color: white; /* The little square between H and V scrollbars */
}
/* GUTTER */
.CodeMirror-gutters {
position: absolute;
top: 0;
left: 0;
z-index: 3;
min-height: 100%;
white-space: nowrap;
background-color: transparent;
border-right: 1px solid #ddd;
}
.CodeMirror-linenumber {
min-width: 20px;
padding: 0 3px 0 5px;
color: var(--comment);
text-align: right;
white-space: nowrap;
opacity: 0.6;
}
.CodeMirror-guttermarker {
color: black;
}
.CodeMirror-guttermarker-subtle {
color: #999;
}
/* FOLD GUTTER */
.CodeMirror-foldmarker {
font-family: arial;
line-height: 0.3;
color: #414141;
text-shadow:
#f96 1px 1px 2px,
#f96 -1px -1px 2px,
#f96 1px -1px 2px,
#f96 -1px 1px 2px;
cursor: pointer;
}
.CodeMirror-foldgutter {
width: 0.7em;
}
.CodeMirror-foldgutter-open,
.CodeMirror-foldgutter-folded {
cursor: pointer;
}
.CodeMirror-foldgutter-open::after,
.CodeMirror-foldgutter-folded::after {
position: relative;
top: -0.1em;
display: inline-block;
font-size: 0.8em;
content: '>';
opacity: 0.8;
transform: rotate(90deg);
transition: transform 0.2s;
}
.CodeMirror-foldgutter-folded::after {
transform: none;
}
/* CURSOR */
.CodeMirror-cursor {
position: absolute;
width: 0;
pointer-events: none;
border-right: none;
border-left: 1px solid black;
}
/* Shown when moving in bi-directional text */
.CodeMirror div.CodeMirror-secondarycursor {
border-left: 1px solid silver;
}
.cm-fat-cursor .CodeMirror-cursor {
width: auto;
background: #7e7;
border: 0 !important;
}
.cm-fat-cursor div.CodeMirror-cursors {
z-index: 1;
}
.cm-fat-cursor-mark {
background-color: rgb(20 255 20 / 50%);
animation: blink 1.06s steps(1) infinite;
}
.cm-animate-fat-cursor {
width: auto;
background-color: #7e7;
border: 0;
animation: blink 1.06s steps(1) infinite;
}
@keyframes blink {
50% {
background-color: transparent;
}
}
@keyframes blink {
50% {
background-color: transparent;
}
}
@keyframes blink {
50% {
background-color: transparent;
}
}
.cm-tab {
display: inline-block;
text-decoration: inherit;
}
.CodeMirror-rulers {
position: absolute;
top: -50px;
right: 0;
bottom: -20px;
left: 0;
overflow: hidden;
}
.CodeMirror-ruler {
position: absolute;
top: 0;
bottom: 0;
border-left: 1px solid #ccc;
}
/* DEFAULT THEME */
.cm-s-default.CodeMirror {
background-color: transparent;
}
.cm-s-default .cm-header {
color: blue;
}
.cm-s-default .cm-quote {
color: #090;
}
.cm-negative {
color: #d44;
}
.cm-positive {
color: #292;
}
.cm-header,
.cm-strong {
font-weight: bold;
}
.cm-em {
font-style: italic;
}
.cm-link {
text-decoration: underline;
}
.cm-strikethrough {
text-decoration: line-through;
}
.cm-s-default .cm-atom,
.cm-s-default .cm-def,
.cm-s-default .cm-property,
.cm-s-default .cm-variable-2,
.cm-s-default .cm-variable-3,
.cm-s-default .cm-punctuation {
color: var(--base);
}
.cm-s-default .cm-hr,
.cm-s-default .cm-comment {
color: var(--comment);
}
.cm-s-default .cm-attribute,
.cm-s-default .cm-keyword {
color: var(--keyword);
}
.cm-s-default .cm-variable {
color: var(--variable);
}
.cm-s-default .cm-bracket,
.cm-s-default .cm-tag {
color: var(--tags);
}
.cm-s-default .cm-number {
color: var(--number);
}
.cm-s-default .cm-string,
.cm-s-default .cm-string-2 {
color: var(--string);
}
.cm-s-default .cm-type {
color: #085;
}
.cm-s-default .cm-meta {
color: #555;
}
.cm-s-default .cm-qualifier {
color: var(--qualifier);
}
.cm-s-default .cm-builtin {
color: #7539ff;
}
.cm-s-default .cm-link {
color: var(--flash);
}
.cm-s-default .cm-error {
color: #ff008c;
}
.cm-invalidchar {
color: #ff008c;
}
.CodeMirror-composing {
border-bottom: 2px solid;
}
/* Default styles for common addons */
div.CodeMirror span.CodeMirror-matchingbracket {
color: #0b0;
}
div.CodeMirror span.CodeMirror-nonmatchingbracket {
color: #a22;
}
.CodeMirror-matchingtag {
background: rgb(255 150 0 / 30%);
}
.CodeMirror-activeline-background {
background: #e8f2ff;
}
/* STOP */
/* The rest of this file contains styles related to the mechanics of
the editor. You probably shouldn't touch them. */
.CodeMirror-scroll {
position: relative;
height: 100%;
padding-bottom: 30px;
margin-right: -30px;
/* 30px is the magic margin used to hide the element's real scrollbars */
/* See overflow: hidden in .CodeMirror */
margin-bottom: -30px;
overflow: scroll !important; /* Things will break if this is overridden */
outline: none; /* Prevent dragging from highlighting the element */
}
.CodeMirror-sizer {
position: relative;
margin-bottom: 20px !important;
border-right: 30px solid transparent;
}
/* The fake, visible scrollbars. Used to force redraw during scrolling
before actual scrolling happens, thus preventing shaking and
flickering artifacts. */
.CodeMirror-vscrollbar,
.CodeMirror-hscrollbar,
.CodeMirror-scrollbar-filler,
.CodeMirror-gutter-filler {
position: absolute;
z-index: 6;
display: none;
}
.CodeMirror-vscrollbar {
top: 0;
right: 0;
overflow-x: hidden;
overflow-y: scroll;
}
.CodeMirror-hscrollbar {
bottom: 0;
left: 0;
overflow-x: scroll;
overflow-y: hidden;
}
.CodeMirror-scrollbar-filler {
right: 0;
bottom: 0;
}
.CodeMirror-gutter-filler {
bottom: 0;
left: 0;
}
.CodeMirror-gutter {
display: inline-block;
height: 100%;
margin-bottom: -30px;
white-space: normal;
vertical-align: top;
}
.CodeMirror-gutter-wrapper {
position: absolute;
z-index: 4;
background: none !important;
border: none !important;
}
.CodeMirror-gutter-background {
position: absolute;
top: 0;
bottom: 0;
z-index: 4;
}
.CodeMirror-gutter-elt {
position: absolute;
z-index: 4;
cursor: default;
}
.CodeMirror-gutter-wrapper ::selection {
background-color: transparent;
}
.CodeMirrorwrapper ::selection {
background-color: transparent;
}
.CodeMirror pre {
position: relative;
z-index: 2;
padding: 0 4px; /* Horizontal padding of content */
margin: 0;
overflow: visible;
font-family: inherit;
font-size: inherit;
line-height: inherit;
color: inherit;
word-wrap: normal;
white-space: pre;
background: transparent;
border-width: 0;
/* Reset some styles that the rest of the page might have set */
border-radius: 0;
-webkit-tap-highlight-color: transparent;
font-variant-ligatures: contextual;
}
.CodeMirror-wrap pre {
word-break: normal;
word-wrap: break-word;
white-space: pre-wrap;
}
.CodeMirror-linebackground {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 0;
}
.CodeMirror-linewidget {
position: relative;
z-index: 2;
padding: 0.1px; /* Force widget margins to stay inside of the container */
}
.CodeMirror-rtl pre {
direction: rtl;
}
.CodeMirror-code {
outline: none;
}
/* Force content-box sizing for the elements where we expect it */
.CodeMirror-scroll,
.CodeMirror-sizer,
.CodeMirror-gutter,
.CodeMirror-gutters,
.CodeMirror-linenumber {
box-sizing: content-box;
}
.CodeMirror-measure {
position: absolute;
width: 100%;
height: 0;
overflow: hidden;
visibility: hidden;
}
.CodeMirror-measure pre {
position: static;
}
div.CodeMirror-cursors {
position: relative;
z-index: 3;
visibility: hidden;
}
div.CodeMirror-dragcursors {
visibility: visible;
}
.CodeMirror-focused div.CodeMirror-cursors {
visibility: visible;
}
.CodeMirror-selected {
background: #d9d9d9;
}
.CodeMirror-focused .CodeMirror-selected {
background: #d7d4f0;
}
.CodeMirror-crosshair {
cursor: crosshair;
}
.CodeMirror-line::selection,
.CodeMirror-line > span::selection,
.CodeMirror-line > span > span::selection {
background: #d7d4f0;
}
.cm-searching {
background-color: #ffa;
background-color: rgb(255 255 0 / 40%);
}
/* Used to force a border model for a node */
.cm-force-border {
padding-right: 0.1px;
}
@media print {
/* Hide the cursor when printing */
.CodeMirror div.CodeMirror-cursors {
visibility: hidden;
}
}
/* See issue #2901 */
.cm-tab-wrap-hack::after {
content: '';
}
/* Help users use markselection to safely style text background */
span.CodeMirror-selectedtext {
background: none;
}

View File

@@ -1,5 +1,247 @@
export enum MODE {
JSON = 'application/json',
HTML = 'htmlmixed',
JS = 'javascript',
APL = 'apl',
ASCIIARMOR = 'asciiarmor',
ASTERISK = 'asterisk',
BRAINFUCK = 'brainfuck',
CLIKE = 'clike',
CLOJURE = 'clojure',
CMAKE = 'cmake',
COBOL = 'cobol',
COFFEESCRIPT = 'coffeescript',
COMMONLISP = 'commonlisp',
CRYSTAL = 'crystal',
CSS = 'css',
CYPHER = 'cypher',
D = 'd',
DART = 'dart',
DIFF = 'diff',
DJANGO = 'django',
DOCKERFILE = 'dockerfile',
DTD = 'dtd',
DYLAN = 'dylan',
EBNF = 'ebnf',
ECL = 'ecl',
EIFFEL = 'eiffel',
ELM = 'elm',
ERLANG = 'erlang',
FACTOR = 'factor',
FCL = 'fcl',
FORTH = 'forth',
FORTRAN = 'fortran',
GAS = 'gas',
GFM = 'gfm',
GHERKIN = 'gherkin',
GO = 'go',
GROOVY = 'groovy',
HAML = 'haml',
HANDLEBARS = 'handlebars',
HASKELL = 'haskell',
HAXE = 'haxe',
HTMLEMBEDDED = 'htmlembedded',
HTMLMIXED = 'htmlmixed',
HTTP = 'http',
IDL = 'idl',
JAVASCRIPT = 'javascript',
JINJA2 = 'jinja2',
JSX = 'jsx',
JULIA = 'julia',
LIVESCRIPT = 'livescript',
LUA = 'lua',
MARKDOWN = 'markdown',
MATHEMATICA = 'mathematica',
MBOX = 'mbox',
MIRC = 'mirc',
MLLIKE = 'mllike',
MODELICA = 'modelica',
MSCGEN = 'mscgen',
MUMPS = 'mumps',
NGINX = 'nginx',
NSIS = 'nsis',
NTRIPLES = 'ntriples',
OCTAVE = 'octave',
OZ = 'oz',
PASCAL = 'pascal',
PEGJS = 'pegjs',
PERL = 'perl',
PHP = 'php',
PIG = 'pig',
POWERSHELL = 'powershell',
PROPERTIES = 'properties',
PROTOBUF = 'protobuf',
PUG = 'pug',
PUPPET = 'puppet',
PYTHON = 'python',
Q = 'q',
R = 'r',
RPM = 'rpm',
RST = 'rst',
RUBY = 'ruby',
RUST = 'rust',
SAS = 'sas',
SASS = 'sass',
SCHEME = 'scheme',
SHELL = 'shell',
SIEVE = 'sieve',
SLIM = 'slim',
SMALLTALK = 'smalltalk',
SMARTY = 'smarty',
SOLR = 'solr',
SOY = 'soy',
SPARQL = 'sparql',
SPREADSHEET = 'spreadsheet',
SQL = 'sql',
STEX = 'stex',
STYLUS = 'stylus',
SWIFT = 'swift',
TCL = 'tcl',
TEXTILE = 'textile',
TIDDLYWIKI = 'tiddlywiki',
TIKI = 'tiki',
TOML = 'toml',
TORNADO = 'tornado',
TROFF = 'troff',
TTCN = 'ttcn',
TURTLE = 'turtle',
TWIG = 'twig',
VB = 'vb',
VBSCRIPT = 'vbscript',
VELOCITY = 'velocity',
VERILOG = 'verilog',
VHDL = 'vhdl',
VUE = 'vue',
WAST = 'wast',
WEBIDL = 'webidl',
XML = 'xml',
XQUERY = 'xquery',
YACAS = 'yacas',
YAML = 'yaml',
Z80 = 'z80',
}
/**
* @description: DynamicImport codemirror
*/
export function parserDynamicImport(str: MODE): () => Promise<any> {
const dynamicArray = {
// adapt before demo
'application/json': async () => await import('codemirror/mode/javascript/javascript'),
apl: async () => await import('codemirror/mode/apl/apl'),
asciiarmor: async () => await import('codemirror/mode/asciiarmor/asciiarmor'),
asterisk: async () => await import('codemirror/mode/asterisk/asterisk'),
brainfuck: async () => await import('codemirror/mode/brainfuck/brainfuck'),
clike: async () => await import('codemirror/mode/clike/clike'),
clojure: async () => await import('codemirror/mode/clojure/clojure'),
cmake: async () => await import('codemirror/mode/cmake/cmake'),
cobol: async () => await import('codemirror/mode/cobol/cobol'),
coffeescript: async () => await import('codemirror/mode/coffeescript/coffeescript'),
commonlisp: async () => await import('codemirror/mode/commonlisp/commonlisp'),
crystal: async () => await import('codemirror/mode/crystal/crystal'),
css: async () => await import('codemirror/mode/css/css'),
cypher: async () => await import('codemirror/mode/cypher/cypher'),
d: async () => await import('codemirror/mode/d/d'),
dart: async () => await import('codemirror/mode/dart/dart'),
diff: async () => await import('codemirror/mode/diff/diff'),
django: async () => await import('codemirror/mode/django/django'),
dockerfile: async () => await import('codemirror/mode/dockerfile/dockerfile'),
dtd: async () => await import('codemirror/mode/dtd/dtd'),
dylan: async () => await import('codemirror/mode/dylan/dylan'),
ebnf: async () => await import('codemirror/mode/ebnf/ebnf'),
ecl: async () => await import('codemirror/mode/ecl/ecl'),
eiffel: async () => await import('codemirror/mode/eiffel/eiffel'),
elm: async () => await import('codemirror/mode/elm/elm'),
erlang: async () => await import('codemirror/mode/erlang/erlang'),
factor: async () => await import('codemirror/mode/factor/factor'),
fcl: async () => await import('codemirror/mode/fcl/fcl'),
forth: async () => await import('codemirror/mode/forth/forth'),
fortran: async () => await import('codemirror/mode/fortran/fortran'),
gas: async () => await import('codemirror/mode/gas/gas'),
gfm: async () => await import('codemirror/mode/gfm/gfm'),
gherkin: async () => await import('codemirror/mode/gherkin/gherkin'),
go: async () => await import('codemirror/mode/go/go'),
groovy: async () => await import('codemirror/mode/groovy/groovy'),
haml: async () => await import('codemirror/mode/haml/haml'),
handlebars: async () => await import('codemirror/mode/handlebars/handlebars'),
haskell: async () => await import('codemirror/mode/haskell/haskell'),
haxe: async () => await import('codemirror/mode/haxe/haxe'),
htmlembedded: async () => await import('codemirror/mode/htmlembedded/htmlembedded'),
htmlmixed: async () => await import('codemirror/mode/htmlmixed/htmlmixed'),
http: async () => await import('codemirror/mode/http/http'),
idl: async () => await import('codemirror/mode/idl/idl'),
javascript: async () => await import('codemirror/mode/javascript/javascript'),
jinja2: async () => await import('codemirror/mode/jinja2/jinja2'),
jsx: async () => await import('codemirror/mode/jsx/jsx'),
julia: async () => await import('codemirror/mode/julia/julia'),
livescript: async () => await import('codemirror/mode/livescript/livescript'),
lua: async () => await import('codemirror/mode/lua/lua'),
markdown: async () => await import('codemirror/mode/markdown/markdown'),
mathematica: async () => await import('codemirror/mode/mathematica/mathematica'),
mbox: async () => await import('codemirror/mode/mbox/mbox'),
mirc: async () => await import('codemirror/mode/mirc/mirc'),
mllike: async () => await import('codemirror/mode/mllike/mllike'),
modelica: async () => await import('codemirror/mode/modelica/modelica'),
mscgen: async () => await import('codemirror/mode/mscgen/mscgen'),
mumps: async () => await import('codemirror/mode/mumps/mumps'),
nginx: async () => await import('codemirror/mode/nginx/nginx'),
nsis: async () => await import('codemirror/mode/nsis/nsis'),
ntriples: async () => await import('codemirror/mode/ntriples/ntriples'),
octave: async () => await import('codemirror/mode/octave/octave'),
oz: async () => await import('codemirror/mode/oz/oz'),
pascal: async () => await import('codemirror/mode/pascal/pascal'),
pegjs: async () => await import('codemirror/mode/pegjs/pegjs'),
perl: async () => await import('codemirror/mode/perl/perl'),
php: async () => await import('codemirror/mode/php/php'),
pig: async () => await import('codemirror/mode/pig/pig'),
powershell: async () => await import('codemirror/mode/powershell/powershell'),
properties: async () => await import('codemirror/mode/properties/properties'),
protobuf: async () => await import('codemirror/mode/protobuf/protobuf'),
pug: async () => await import('codemirror/mode/pug/pug'),
puppet: async () => await import('codemirror/mode/puppet/puppet'),
python: async () => await import('codemirror/mode/python/python'),
q: async () => await import('codemirror/mode/q/q'),
r: async () => await import('codemirror/mode/r/r'),
rpm: async () => await import('codemirror/mode/rpm/rpm'),
rst: async () => await import('codemirror/mode/rst/rst'),
ruby: async () => await import('codemirror/mode/ruby/ruby'),
rust: async () => await import('codemirror/mode/rust/rust'),
sas: async () => await import('codemirror/mode/sas/sas'),
sass: async () => await import('codemirror/mode/sass/sass'),
scheme: async () => await import('codemirror/mode/scheme/scheme'),
shell: async () => await import('codemirror/mode/shell/shell'),
sieve: async () => await import('codemirror/mode/sieve/sieve'),
slim: async () => await import('codemirror/mode/slim/slim'),
smalltalk: async () => await import('codemirror/mode/smalltalk/smalltalk'),
smarty: async () => await import('codemirror/mode/smarty/smarty'),
solr: async () => await import('codemirror/mode/solr/solr'),
soy: async () => await import('codemirror/mode/soy/soy'),
sparql: async () => await import('codemirror/mode/sparql/sparql'),
spreadsheet: async () => await import('codemirror/mode/spreadsheet/spreadsheet'),
sql: async () => await import('codemirror/mode/sql/sql'),
stex: async () => await import('codemirror/mode/stex/stex'),
stylus: async () => await import('codemirror/mode/stylus/stylus'),
swift: async () => await import('codemirror/mode/swift/swift'),
tcl: async () => await import('codemirror/mode/tcl/tcl'),
textile: async () => await import('codemirror/mode/textile/textile'),
tiddlywiki: async () => await import('codemirror/mode/tiddlywiki/tiddlywiki'),
tiki: async () => await import('codemirror/mode/tiki/tiki'),
toml: async () => await import('codemirror/mode/toml/toml'),
tornado: async () => await import('codemirror/mode/tornado/tornado'),
troff: async () => await import('codemirror/mode/troff/troff'),
ttcn: async () => await import('codemirror/mode/ttcn/ttcn'),
turtle: async () => await import('codemirror/mode/turtle/turtle'),
twig: async () => await import('codemirror/mode/twig/twig'),
vb: async () => await import('codemirror/mode/vb/vb'),
vbscript: async () => await import('codemirror/mode/vbscript/vbscript'),
velocity: async () => await import('codemirror/mode/velocity/velocity'),
verilog: async () => await import('codemirror/mode/verilog/verilog'),
vhdl: async () => await import('codemirror/mode/vhdl/vhdl'),
vue: async () => await import('codemirror/mode/vue/vue'),
wast: async () => await import('codemirror/mode/wast/wast'),
webidl: async () => await import('codemirror/mode/webidl/webidl'),
xml: async () => await import('codemirror/mode/xml/xml'),
xquery: async () => await import('codemirror/mode/xquery/xquery'),
yacas: async () => await import('codemirror/mode/yacas/yacas'),
yaml: async () => await import('codemirror/mode/yaml/yaml'),
z80: async () => await import('codemirror/mode/z80/z80'),
};
return dynamicArray[str];
}

View File

@@ -151,7 +151,7 @@
fileReader.onerror = () => {
emit('cropendError');
};
}, 'image/png');
}, 'image/jpeg');
}
// Get a circular picture canvas

View File

@@ -54,7 +54,7 @@
import { useFormValues } from './hooks/useFormValues';
import useAdvanced from './hooks/useAdvanced';
import { useFormEvents } from './hooks/useFormEvents';
import { itemIsUploadComponent, useFormEvents } from './hooks/useFormEvents';
import { createFormContext } from './hooks/useFormContext';
import { useAutoFocus } from './hooks/useAutoFocus';
import { useModalContext } from '@/components/Modal';
@@ -64,6 +64,7 @@
import { useDesign } from '@/hooks/web/useDesign';
import { cloneDeep } from 'lodash-es';
import { TableActionType } from '@/components/Table';
import { isArray, isFunction } from '@/utils/is';
defineOptions({ name: 'BasicForm' });
@@ -123,14 +124,28 @@
const getBindValue = computed(() => ({ ...attrs, ...props, ...unref(getProps) }) as AntFormProps);
const getSchema = computed((): FormSchema[] => {
const schemas: FormSchema[] = cloneDeep(unref(schemaRef) || (unref(getProps).schemas as any));
const schemas: (FormSchema & { ifshow2?: boolean })[] = cloneDeep(
unref(schemaRef) || (unref(getProps).schemas as any),
);
for (const schema of schemas) {
const {
defaultValue,
component,
componentProps = {},
isHandleDateDefaultValue = true,
field,
isHandleDefaultValue = true,
valueFormat,
ifShow,
} = schema;
//fix:修复showAdvancedButton为true时FormSchema中ifshow是与model有关的函数时候查询按钮位置不重新计算的问题。
if (unref(getProps).showAdvancedButton) {
schema.ifshow2 = isFunction(ifShow)
? ifShow({ schema, values: formModel, model: formModel, field })
: ifShow;
}
// handle date type
if (
isHandleDateDefaultValue &&
@@ -161,6 +176,24 @@
schema.defaultValue = def;
}
}
// handle upload type
if (defaultValue && itemIsUploadComponent(schema?.component)) {
if (isArray(defaultValue)) {
schema.defaultValue = defaultValue;
} else if (typeof defaultValue == 'string') {
schema.defaultValue = [defaultValue];
}
}
// handle schema.valueFormat
if (isHandleDefaultValue && defaultValue && component && isFunction(valueFormat)) {
schema.defaultValue = valueFormat({
value: defaultValue,
schema,
model: formModel,
field,
});
}
}
if (unref(getProps).showAdvancedButton) {
return schemas.filter(
@@ -207,6 +240,7 @@
removeSchemaByField,
resetFields,
scrollToField,
resetDefaultField,
} = useFormEvents({
emit,
getProps,
@@ -305,6 +339,7 @@
validate,
submit: handleSubmit,
scrollToField: scrollToField,
resetDefaultField,
};
const getFormActionBindProps = computed(
@@ -337,11 +372,20 @@
// margin-bottom: 20px;
// }
&.suffix-item {
&.suffix-item,
&.prefix-item {
.ant-form-item-children {
display: flex;
}
.prefix {
display: inline-flex;
align-items: center;
margin-top: 1px;
padding-right: 6px;
line-height: 1;
}
.suffix {
display: inline-flex;
align-items: center;

View File

@@ -3,6 +3,7 @@
@dropdown-visible-change="handleFetch"
v-bind="$attrs"
@change="handleChange"
@search="debounceSearchFn"
:options="getOptions"
v-model:value="state"
>
@@ -20,26 +21,41 @@
</template>
</Select>
</template>
<script lang="ts" setup>
import { PropType, ref, computed, unref, watch } from 'vue';
import { computed, PropType, ref, unref, watch } from 'vue';
import { Select } from 'ant-design-vue';
import type { SelectValue } from 'ant-design-vue/es/select';
import { isFunction } from '@/utils/is';
import { isEmpty, isFunction } from '@/utils/is';
import { useRuleFormItem } from '@/hooks/component/useFormItem';
import { get, omit, isEqual } from 'lodash-es';
import { assignIn, get, isEqual, omit } from 'lodash-es';
import { LoadingOutlined } from '@ant-design/icons-vue';
import { useI18n } from '@/hooks/web/useI18n';
import { propTypes } from '@/utils/propTypes';
import { useDebounceFn } from '@vueuse/core';
type OptionsItem = { label?: string; value?: string; disabled?: boolean; [name: string]: any };
type ApiSearchOption = {
// 展示搜索
show?: boolean;
// 待搜索字段名
searchName?: string;
// 是否允许空搜索
emptySearch?: boolean;
// 搜索前置方法
beforeFetch?: (value?: string) => Promise<string>;
// 拦截方法
interceptFetch?: (value?: string) => Promise<boolean>;
};
defineOptions({ name: 'ApiSelect', inheritAttrs: false });
const props = defineProps({
value: { type: [Array, Object, String, Number] as PropType<SelectValue> },
numberToString: propTypes.bool,
api: {
type: Function as PropType<(arg?: any) => Promise<OptionsItem[] | Recordable<any>>>,
type: Function as PropType<(arg?: any) => Promise<OptionsItem[] | Recordable>>,
default: null,
},
// api params
@@ -54,6 +70,10 @@
type: Array<OptionsItem>,
default: [],
},
apiSearch: {
type: Object as PropType<ApiSearchOption>,
default: () => null,
},
beforeFetch: {
type: Function as PropType<Fn>,
default: null,
@@ -72,6 +92,7 @@
// 首次是否加载过了
const isFirstLoaded = ref(false);
const emitData = ref<OptionsItem[]>([]);
const searchParams = ref<any>({});
const { t } = useI18n();
// Embedded in the form, just use the hook binding to perform form verification
@@ -110,16 +131,29 @@
{ deep: true, immediate: props.immediate },
);
watch(
() => searchParams.value,
(value, oldValue) => {
if (isEmpty(value) || isEqual(value, oldValue)) return;
(async () => {
await fetch();
searchParams.value = {};
})();
},
{ deep: true, immediate: props.immediate },
);
async function fetch() {
let { api, beforeFetch, afterFetch, params, resultField } = props;
if (!api || !isFunction(api) || loading.value) return;
optionsRef.value = [];
try {
loading.value = true;
let apiParams = assignIn({}, params, searchParams.value);
if (beforeFetch && isFunction(beforeFetch)) {
params = (await beforeFetch(params)) || params;
apiParams = (await beforeFetch(apiParams)) || apiParams;
}
let res = await api(params);
let res = await api(apiParams);
if (afterFetch && isFunction(afterFetch)) {
res = (await afterFetch(res)) || res;
}
@@ -147,11 +181,43 @@
if (props.alwaysLoad) {
await fetch();
} else if (!props.immediate && !unref(isFirstLoaded)) {
await fetch();
// 动态搜索查询时,允许控制初始不加载数据
if (!(!!props.apiSearch && !!props.apiSearch.show && !props.apiSearch.emptySearch)) {
await fetch();
} else {
optionsRef.value = [];
emitChange();
}
}
}
}
let debounceSearchFn = useDebounceFn(handleSearch, 500);
async function handleSearch(value: any) {
if (!props.apiSearch) {
return;
}
const { show, searchName, beforeFetch, interceptFetch } = props.apiSearch;
if (!show || !searchName) {
return;
}
value = value || undefined;
if (beforeFetch && isFunction(beforeFetch)) {
value = (await beforeFetch(value)) || value;
}
if (interceptFetch && isFunction(interceptFetch)) {
if (!(await interceptFetch(value))) {
return;
}
}
searchParams.value = {
[searchName]: value,
};
}
function emitChange() {
emit('options-change', unref(getOptions));
}

View File

@@ -277,6 +277,7 @@
field,
changeEvent = 'change',
valueField,
valueFormat,
} = props.schema;
const isCheck = component && ['Switch', 'Checkbox'].includes(component);
@@ -288,7 +289,10 @@
const [e] = args;
const target = e ? e.target : null;
const value = target ? (isCheck ? target.checked : target.value) : e;
let value = target ? (isCheck ? target.checked : target.value) : e;
if (isFunction(valueFormat)) {
value = valueFormat({ ...unref(getValues), value });
}
props.setFormModel(field, value, props.schema);
if (propsData[eventKey]) {
@@ -367,7 +371,7 @@
}
function renderItem() {
const { itemProps, slot, render, field, suffix, component } = props.schema;
const { itemProps, slot, render, field, suffix, component, prefix } = props.schema;
const { labelCol, wrapperCol } = unref(itemLabelWidthProp);
const { colon } = props.formProps;
const opts = { disabled: unref(getDisable), readonly: unref(getReadonly) };
@@ -383,7 +387,10 @@
labelCol={labelCol}
wrapperCol={wrapperCol}
name={field}
class={{ 'suffix-item': !!suffix }}
class={{
'suffix-item': !!suffix,
'prefix-item': !!prefix,
}}
>
<BasicTitle {...unref(getComponentsProps)}>{renderLabelHelpMessage()}</BasicTitle>
</Form.Item>
@@ -400,6 +407,8 @@
const showSuffix = !!suffix;
const getSuffix = isFunction(suffix) ? suffix(unref(getValues)) : suffix;
const showPrefix = !!prefix;
const getPrefix = isFunction(prefix) ? prefix(unref(getValues)) : prefix;
// TODO 自定义组件验证会出现问题因此这里框架默认将自定义组件设置手动触发验证如果其他组件还有此问题请手动设置autoLink=false
if (component && NO_AUTO_LINK_COMPONENTS.includes(component)) {
props.schema &&
@@ -413,7 +422,10 @@
<Form.Item
name={field}
colon={colon}
class={{ 'suffix-item': showSuffix }}
class={{
'suffix-item': showSuffix,
'prefix-item': showPrefix,
}}
{...(itemProps as Recordable<any>)}
label={renderLabelHelpMessage()}
rules={handleRules()}
@@ -421,6 +433,7 @@
wrapperCol={wrapperCol}
>
<div style="display:flex">
{showPrefix && <span class="prefix">{getPrefix}</span>}
<div style="flex:1;">{getContent()}</div>
{showSuffix && <span class="suffix">{getSuffix}</span>}
</div>

View File

@@ -31,8 +31,13 @@ export function createPlaceholderMessage(component: ComponentType) {
const DATE_TYPE = ['DatePicker', 'MonthPicker', 'WeekPicker', 'TimePicker'];
/**
* 上传组件
*/
export const uploadItemType: ComponentType[] = ['Upload', 'ImageUpload'];
function genType() {
return [...DATE_TYPE, 'RangePicker'];
return [...DATE_TYPE, 'RangePicker', 'TimeRangePicker'];
}
export function setComponentRuleType(
@@ -45,7 +50,7 @@ export function setComponentRuleType(
}
if (['DatePicker', 'MonthPicker', 'WeekPicker', 'TimePicker'].includes(component)) {
rule.type = valueFormat ? 'string' : 'object';
} else if (['RangePicker', 'Upload', 'CheckboxGroup', 'TimePicker'].includes(component)) {
} else if (['RangePicker', 'CheckboxGroup'].includes(component)) {
rule.type = 'array';
} else if (['InputNumber'].includes(component)) {
rule.type = 'number';

View File

@@ -1,6 +1,15 @@
import type { ColEx } from '../types';
import type { AdvanceState } from '../types/hooks';
import { ComputedRef, getCurrentInstance, Ref, shallowReactive, computed, unref, watch } from 'vue';
import {
ComputedRef,
getCurrentInstance,
Ref,
shallowReactive,
computed,
unref,
watch,
nextTick,
} from 'vue';
import type { FormProps, FormSchemaInner as FormSchema } from '../types/form';
import { isBoolean, isFunction, isNumber, isObject } from '@/utils/is';
import { useBreakpoint } from '@/hooks/event/useBreakpoint';
@@ -49,14 +58,17 @@ export default function ({
return 0;
});
const debounceUpdateAdvanced = useDebounceFn(updateAdvanced, 30);
// const debounceUpdateAdvanced = useDebounceFn(updateAdvanced, 30);
watch(
[() => unref(getSchema), () => advanceState.isAdvanced, () => unref(realWidthRef)],
() => {
const { showAdvancedButton } = unref(getProps);
if (showAdvancedButton) {
debounceUpdateAdvanced();
// debounceUpdateAdvanced();
nextTick(() => {
updateAdvanced();
});
}
},
{ immediate: true },
@@ -120,24 +132,18 @@ export default function ({
const { baseColProps = {} } = unref(getProps);
for (const schema of unref(getSchema)) {
const { show, colProps } = schema;
const { show, ifShow, colProps } = schema;
const renderCallbackParams = {
schema: schema,
model: formModel,
field: schema.field,
values: { ...unref(defaultValueRef), ...formModel },
};
let isShow = true;
if (isBoolean(show)) {
isShow = show;
}
if (isFunction(show)) {
isShow = show({
schema: schema,
model: formModel,
field: schema.field,
values: {
...unref(defaultValueRef),
...formModel,
},
});
}
isShow && isBoolean(ifShow) && (isShow = ifShow);
isShow && isFunction(ifShow) && (isShow = ifShow(renderCallbackParams));
isShow && isBoolean(show) && (isShow = show);
isShow && isFunction(show) && (isShow = show(renderCallbackParams));
if (isShow && (colProps || baseColProps)) {
const { itemColSum: sum, isAdvanced } = getAdvanced(

View File

@@ -78,9 +78,13 @@ export function useForm(props?: Props): UseFormReturnType {
form.clearValidate(name);
},
resetFields: async () => {
getForm().then(async (form) => {
await form.resetFields();
resetFields: () => {
// 修复表单重置后,页面变化了,但是由于异步问题导致表单内部的状态没有及时同步
return new Promise((resolve) => {
getForm().then(async (form) => {
await form.resetFields();
resolve();
});
});
},
@@ -121,6 +125,9 @@ export function useForm(props?: Props): UseFormReturnType {
const form = await getForm();
return form.validateFields(nameList);
},
resetDefaultField: async (nameList?: NamePath[]) => {
unref(formRef)?.resetDefaultField(nameList);
},
};
return [register, methods];

View File

@@ -2,12 +2,18 @@ import type { ComputedRef, Ref } from 'vue';
import type { FormProps, FormSchemaInner as FormSchema, FormActionType } from '../types/form';
import type { NamePath } from 'ant-design-vue/lib/form/interface';
import { unref, toRaw, nextTick } from 'vue';
import { isArray, isFunction, isObject, isString, isDef, isNil } from '@/utils/is';
import { isArray, isFunction, isObject, isString, isNil } from '@/utils/is';
import { deepMerge } from '@/utils';
import { dateItemType, defaultValueComponents, isIncludeSimpleComponents } from '../helper';
import {
dateItemType,
defaultValueComponents,
isIncludeSimpleComponents,
uploadItemType,
} from '../helper';
import { dateUtil } from '@/utils/dateUtil';
import { cloneDeep, has, uniqBy, get } from 'lodash-es';
import { cloneDeep, has, uniqBy, get, set } from 'lodash-es';
import { error } from '@/utils/log';
import { ComponentProps } from '../types';
interface UseFormActionContext {
emit: EmitType;
@@ -19,7 +25,29 @@ interface UseFormActionContext {
schemaRef: Ref<FormSchema[]>;
handleFormValues: Fn;
}
/**
* @description: Is it upload
*/
export function itemIsUploadComponent(key: keyof ComponentProps) {
return uploadItemType.includes(key);
}
function tryConstructArray(field: string, values: Recordable = {}): any[] | undefined {
const pattern = /^\[(.+)\]$/;
if (pattern.test(field)) {
const match = field.match(pattern);
if (match && match[1]) {
const keys = match[1].split(',');
if (!keys.length) {
return undefined;
}
const result = [];
keys.forEach((k, index) => {
set(result, index, values[k.trim()]);
});
return result.filter(Boolean).length ? result : undefined;
}
}
}
export function useFormEvents({
emit,
getProps,
@@ -83,37 +111,79 @@ export function useFormEvents({
});
}
const constructValue = get(value, key);
let constructValue;
const setDateFieldValue = (v) => {
return v ? (_props?.valueFormat ? v : dateUtil(v)) : null;
};
// 0| '' is allow
if (hasKey || !!constructValue) {
const fieldValue = constructValue || value;
// time type
if (itemIsDateType(key)) {
// Adapt date component
if (itemIsDateComponent(schema?.component)) {
constructValue = tryConstructArray(key, values);
if (constructValue) {
const fieldValue = constructValue || value;
if (Array.isArray(fieldValue)) {
const arr: any[] = [];
for (const ele of fieldValue) {
arr.push(setDateFieldValue(ele));
}
unref(formModel)[key] = arr;
validKeys.push(key);
} else {
unref(formModel)[key] = setDateFieldValue(fieldValue);
validKeys.push(key);
}
} else {
unref(formModel)[key] = fieldValue;
}
}
// Adapt upload component
if (itemIsUploadComponent(schema?.component)) {
constructValue = get(value, key);
const fieldValue = constructValue || value;
if (fieldValue) {
if (isArray(fieldValue)) {
unref(formModel)[key] = fieldValue;
} else if (typeof fieldValue == 'string') {
unref(formModel)[key] = [fieldValue];
}
}
validKeys.push(key);
return;
}
// Adapt common component
if (hasKey) {
constructValue = get(value, key);
const fieldValue = constructValue || value;
unref(formModel)[key] = fieldValue;
if (_props?.onChange) {
_props?.onChange(fieldValue);
}
validKeys.push(key);
} else {
// key not exist
if (isDef(get(defaultValueRef.value, key))) {
unref(formModel)[key] = cloneDeep(unref(get(defaultValueRef.value, key)));
}
// refer:https://github.com/vbenjs/vue-vben-admin/issues/3795
}
});
validateFields(validKeys).catch((_) => {});
}
/**
* @description: Set form default value
*/
function resetDefaultField(nameList?: NamePath[]) {
if (!Array.isArray(nameList)) {
return;
}
if (Array.isArray(nameList) && nameList.length === 0) {
return;
}
const validKeys: string[] = [];
const keys = Object.keys(unref(formModel));
if (!keys) {
return;
}
nameList.forEach((key: any) => {
if (keys.includes(key)) {
validKeys.push(key);
unref(formModel)[key] = cloneDeep(unref(get(defaultValueRef.value, key)));
}
});
validateFields(validKeys).catch((_) => {});
@@ -128,9 +198,9 @@ export function useFormEvents({
return;
}
let fieldList: string[] = isString(fields) ? [fields] : fields;
let fieldList = (isString(fields) ? [fields] : fields) as string[];
if (isString(fields)) {
fieldList = [fields];
fieldList = [fields as string];
}
for (const field of fieldList) {
_removeSchemaByField(field, schemaList);
@@ -273,10 +343,8 @@ export function useFormEvents({
/**
* @description: Is it time
*/
function itemIsDateType(key: string) {
return unref(getSchema).some((item) => {
return item.field === key && item.component ? dateItemType.includes(item.component) : false;
});
function itemIsDateComponent(key: string) {
return dateItemType.includes(key);
}
async function validateFields(nameList?: NamePath[] | undefined) {
@@ -359,6 +427,7 @@ export function useFormEvents({
resetFields,
setFieldsValue,
scrollToField,
resetDefaultField,
};
}
@@ -370,7 +439,7 @@ function getDefaultValue(
let defaultValue = cloneDeep(defaultValueRef.value[key]);
const isInput = checkIsInput(schema);
if (isInput) {
return defaultValue || undefined;
return !isNil(defaultValue) ? defaultValue : undefined;
}
if (!defaultValue && schema && checkIsRangeSlider(schema)) {
defaultValue = [0, 0];

View File

@@ -135,7 +135,7 @@ export function useFormValues({
const schemas = unref(getSchema);
const obj: Recordable = {};
schemas.forEach((item) => {
const { defaultValue, defaultValueObj } = item;
const { defaultValue, defaultValueObj, componentProps = {} } = item;
const fieldKeys = Object.keys(defaultValueObj || {});
if (fieldKeys.length) {
fieldKeys.forEach((field) => {
@@ -152,6 +152,12 @@ export function useFormValues({
formModel[item.field] = defaultValue;
}
}
if (!isNil(componentProps?.defaultValue)) {
obj[item.field] = componentProps?.defaultValue;
if (formModel[item.field] === undefined) {
formModel[item.field] = componentProps?.defaultValue;
}
}
});
defaultValueRef.value = cloneDeep(obj);
}

View File

@@ -1,7 +1,7 @@
import type { Ref } from 'vue';
import { computed, unref } from 'vue';
import type { FormProps, FormSchemaInner as FormSchema } from '../types/form';
import { isNumber } from '@/utils/is';
import { isDef, isNumber } from '@/utils/is';
export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref<FormProps>) {
return computed(() => {
@@ -23,11 +23,11 @@ export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref<
};
return { labelCol, wrapperCol };
}
let width = labelWidth || globalLabelWidth;
let width = labelWidth ?? globalLabelWidth;
const col = { ...globalLabelCol, ...labelCol };
const wrapCol = { ...globWrapperCol, ...wrapperCol };
if (width) {
if (isDef(width)) {
width = isNumber(width) ? `${width}px` : width;
}

View File

@@ -41,6 +41,7 @@ export interface FormActionType {
validateFields: (nameList?: NamePath[]) => Promise<any>;
validate: <T = Recordable>(nameList?: NamePath[] | false) => Promise<T>;
scrollToField: (name: NamePath, options?: ScrollOptions) => Promise<void>;
resetDefaultField: (name?: NamePath[]) => void;
}
export type RegisterFn = (formInstance: FormActionType) => void;
@@ -166,8 +167,16 @@ interface BaseFormSchema<T extends ComponentType = any> {
// Required
required?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean);
suffix?: string | number | ((values: RenderCallbackParams) => string | number);
suffix?:
| string
| number
| VNode
| ((renderCallbackParams: RenderCallbackParams) => string | VNode | number);
prefix?:
| string
| number
| VNode
| ((renderCallbackParams: RenderCallbackParams) => string | VNode | number);
// Validation rules
rules?: Rule[];
// Check whether the information is added to the label
@@ -188,6 +197,9 @@ interface BaseFormSchema<T extends ComponentType = any> {
// 是否自动处理与时间相关组件的默认值
isHandleDateDefaultValue?: boolean;
// 是否使用valueFormat自动处理默认值
isHandleDefaultValue?: boolean;
isAdvanced?: boolean;
// Matching details components
@@ -223,6 +235,8 @@ interface BaseFormSchema<T extends ComponentType = any> {
dynamicReadonly?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean);
dynamicRules?: (renderCallbackParams: RenderCallbackParams) => Rule[];
valueFormat?: (arg: Partial<RenderCallbackParams> & { value: any }) => any;
}
export interface ComponentFormSchema<T extends ComponentType = any> extends BaseFormSchema<T> {
// render component

View File

@@ -54,7 +54,7 @@
justify-content: center;
width: 100%;
height: 100%;
background-color: rgb(240 242 245 / 40%);
background-color: #f0f2f566;
&.absolute {
position: absolute;

View File

@@ -1,4 +1,4 @@
import { VNode, defineComponent, createVNode, render, reactive, h } from 'vue';
import { createVNode, defineComponent, h, reactive, render, VNode } from 'vue';
import type { LoadingProps } from './typing';
import Loading from './Loading.vue';
@@ -19,13 +19,13 @@ export function createLoading(props?: Partial<LoadingProps>, target?: HTMLElemen
vm = createVNode(LoadingWrap);
let container: Nullable<HTMLElement> = null;
if (wait) {
// TODO fix https://github.com/anncwb/vue-vben-admin/issues/438
setTimeout(() => {
render(vm, document.createElement('div'));
render(vm, (container = document.createElement('div')));
}, 0);
} else {
render(vm, document.createElement('div'));
render(vm, (container = document.createElement('div')));
}
function close() {
@@ -41,6 +41,11 @@ export function createLoading(props?: Partial<LoadingProps>, target?: HTMLElemen
target.appendChild(vm.el as HTMLElement);
}
function destroy() {
container && render(null, container);
container = vm = null;
}
if (target) {
open(target);
}
@@ -48,6 +53,7 @@ export function createLoading(props?: Partial<LoadingProps>, target?: HTMLElemen
vm,
close,
open,
destroy,
setTip: (tip: string) => {
data.tip = tip;
},

View File

@@ -1,7 +1,8 @@
import type { Ref } from 'vue';
import { unref } from 'vue';
import { tryOnUnmounted } from '@vueuse/core';
import { createLoading } from './createLoading';
import type { LoadingProps } from './typing';
import type { Ref } from 'vue';
export interface UseLoadingOptions {
target?: any;
@@ -45,5 +46,9 @@ export function useLoading(
instance.setTip(tip);
};
tryOnUnmounted(() => {
instance.destroy();
});
return [open, close, setTip];
}

View File

@@ -1,7 +1,7 @@
import type { Options, Props } from './typing';
import ImgPreview from './Functional.vue';
import { isClient } from '@/utils/is';
import { createVNode, render } from 'vue';
import ImgPreview from './Functional.vue';
import type { Options, Props } from './typing';
let instance: ReturnType<typeof createVNode> | null = null;
export function createImgPreview(options: Options) {
@@ -10,8 +10,13 @@ export function createImgPreview(options: Options) {
const container = document.createElement('div');
Object.assign(propsData, { show: true, index: 0, scaleStep: 100 }, options);
instance = createVNode(ImgPreview, propsData);
render(instance, container);
document.body.appendChild(container);
if (instance?.component) {
// 存在实例时更新props
Object.assign(instance.component.props, propsData);
} else {
instance = createVNode(ImgPreview, propsData);
render(instance, container);
document.body.appendChild(container);
}
return instance.component?.exposed;
}

View File

@@ -153,11 +153,11 @@
height: 0;
transition: 0.3s background-color;
border-radius: inherit;
background-color: rgb(144 147 153 / 30%);
background-color: #9093994d;
cursor: pointer;
&:hover {
background-color: rgb(144 147 153 / 50%);
background-color: #90939980;
}
}

View File

@@ -17,11 +17,11 @@
</template>
<script lang="ts" setup>
import { PropType, ref, computed, unref, getCurrentInstance, watch, useSlots } from 'vue';
import { useDesign } from '@/hooks/web/useDesign';
import { propTypes } from '@/utils/propTypes';
import { useMenuItem } from './useMenu';
import { Tooltip } from 'ant-design-vue';
import { computed, getCurrentInstance, PropType, ref, unref, useSlots, watch } from 'vue';
import { useMenuItem } from './useMenu';
import { useSimpleRootMenuContext } from './useSimpleMenuContext';
defineOptions({ name: 'MenuItem' });
@@ -76,7 +76,7 @@
const { uidList } = getParentList();
rootMenuEmitter.emit('on-update-opened', {
opend: false,
opened: false,
parent: instance?.parent,
uidList: uidList,
});

View File

@@ -57,27 +57,27 @@
</template>
<script lang="ts" setup>
import { type TimeoutHandle, type Recordable } from '@vben/types';
import type { CSSProperties, PropType } from 'vue';
import type { SubMenuProvider } from './types';
import {
computed,
unref,
getCurrentInstance,
reactive,
provide,
onBeforeMount,
inject,
} from 'vue';
import { useDesign } from '@/hooks/web/useDesign';
import { propTypes } from '@/utils/propTypes';
import { useMenuItem } from './useMenu';
import { useSimpleRootMenuContext } from './useSimpleMenuContext';
import { CollapseTransition } from '@/components/Transition';
import Icon from '@/components/Icon/Icon.vue';
import { Popover } from 'ant-design-vue';
import { CollapseTransition } from '@/components/Transition';
import { useDesign } from '@/hooks/web/useDesign';
import { isBoolean, isObject } from '@/utils/is';
import { mitt } from '@/utils/mitt';
import { propTypes } from '@/utils/propTypes';
import { type Recordable, type TimeoutHandle } from '@vben/types';
import { Popover } from 'ant-design-vue';
import type { CSSProperties, PropType } from 'vue';
import {
computed,
getCurrentInstance,
inject,
onBeforeMount,
provide,
reactive,
unref,
} from 'vue';
import type { SubMenuProvider } from './types';
import { useMenuItem } from './useMenu';
import { useSimpleRootMenuContext } from './useSimpleMenuContext';
defineOptions({ name: 'SubMenu' });
@@ -184,7 +184,7 @@
if (unref(getAccordion)) {
const { uidList } = getParentList();
rootMenuEmitter.emit('on-update-opened', {
opend: false,
opened: false,
parent: instance?.parent,
uidList: uidList,
});
@@ -267,9 +267,9 @@
return;
}
if (isObject(data) && rootProps.accordion) {
const { opend, parent, uidList } = data as Recordable<any>;
const { opened, parent, uidList } = data as Recordable<any>;
if (parent === instance?.parent) {
state.opened = opend;
state.opened = opened;
} else if (!uidList.includes(instance?.uid)) {
state.opened = false;
}

View File

@@ -1,12 +1,12 @@
import type { InjectionKey, Ref, ComponentInternalInstance } from 'vue';
import type { Emitter } from '@/utils/mitt';
import { createContext, useContext } from '@/hooks/core/useContext';
import type { Emitter } from '@/utils/mitt';
import type { ComponentInternalInstance, InjectionKey, Ref } from 'vue';
export type MenuEmitterEvents = {
'on-update-opened':
| (string | number)[]
| {
opend: boolean;
opened: boolean;
parent?: ComponentInternalInstance | null;
uidList: number[];
};

View File

@@ -17,6 +17,7 @@
import { treeToList } from '@/utils/helper/treeHelper';
import { Spin } from 'ant-design-vue';
import { parseRowKey } from '../../helper';
import { warn } from '@/utils/log';
export default defineComponent({
name: 'EditableCell',
@@ -282,6 +283,7 @@
});
} catch (e) {
result = false;
warn(e);
} finally {
spinning.value = false;
}

View File

@@ -540,13 +540,13 @@
label:
typeof col.title === 'string'
? col.title
: col.customTitle === 'string'
: typeof col.customTitle === 'string'
? col.customTitle
: '',
value:
typeof col.dataIndex === 'string'
? col.dataIndex
: col.title === 'string'
: typeof col.title === 'string'
? col.title
: '',
column: {

View File

@@ -39,7 +39,7 @@
redo: true,
size: true,
setting: true,
settingCache: false,
settingCache: !import.meta.env.DEV,
fullScreen: false,
...props.setting,
};
@@ -55,6 +55,8 @@
</script>
<style lang="less">
.table-settings {
display: flex;
& > * {
margin-right: 12px;
}

View File

@@ -114,32 +114,41 @@ export function useDataSource(
return unref(getAutoCreateKey) ? ROW_KEY : rowKey;
});
const getDataSourceRef = computed(() => {
const dataSource = unref(dataSourceRef);
if (!dataSource || dataSource.length === 0) {
return unref(dataSourceRef);
}
if (unref(getAutoCreateKey)) {
const firstItem = dataSource[0];
const lastItem = dataSource[dataSource.length - 1];
const getDataSourceRef: Ref<Recordable<any>[]> = ref([]);
if (firstItem && lastItem) {
if (!firstItem[ROW_KEY] || !lastItem[ROW_KEY]) {
const data = cloneDeep(unref(dataSourceRef));
data.forEach((item) => {
if (!item[ROW_KEY]) {
item[ROW_KEY] = buildUUID();
}
if (item.children && item.children.length) {
setTableKey(item.children);
}
});
dataSourceRef.value = data;
watch(
() => dataSourceRef.value,
() => {
const dataSource = unref(dataSourceRef);
if (!dataSource || dataSource.length === 0) {
getDataSourceRef.value = unref(dataSourceRef);
}
if (unref(getAutoCreateKey)) {
const firstItem = dataSource[0];
const lastItem = dataSource[dataSource.length - 1];
if (firstItem && lastItem) {
if (!firstItem[ROW_KEY] || !lastItem[ROW_KEY]) {
const data = cloneDeep(unref(dataSourceRef));
data.forEach((item) => {
if (!item[ROW_KEY]) {
item[ROW_KEY] = buildUUID();
}
if (item.children && item.children.length) {
setTableKey(item.children);
}
});
dataSourceRef.value = data;
}
}
}
}
return unref(dataSourceRef);
});
getDataSourceRef.value = unref(dataSourceRef);
},
{
deep: true,
immediate: true,
},
);
async function updateTableData(index: number, key: Key, value: any) {
const record = dataSourceRef.value[index];
@@ -351,7 +360,7 @@ export function useDataSource(
});
return {
getDataSourceRef,
getDataSourceRef: computed(() => getDataSourceRef.value),
getDataSource,
getRawDataSource,
searchInfoRef,

View File

@@ -33,7 +33,7 @@ export function useRowSelection(
// 点击 checkbox/radiobox 触发
// 取出【当前页】所有 keyValues
const currentPageKeys = tableData.value.map((o) => parseRowKeyValue(unref(getRowKey), o));
const currentPageKeys = getCcurrentPageKeys();
// 从【所有分页】已选的 keyValues且属于【当前页】的部分
for (const selectedKey of selectedRowKeysRef.value.filter((k) =>
@@ -110,6 +110,18 @@ export function useRowSelection(
const { rowKey } = unref(propsRef);
return unref(getAutoCreateKey) ? ROW_KEY : rowKey;
});
function getCcurrentPageKeys() {
const { childrenColumnName = 'children' } = unref(propsRef);
const keys: Key[] = [];
const extractKeys = (record: Recordable) => {
keys.push(parseRowKeyValue(unref(getRowKey), record));
if (record[childrenColumnName]?.length) {
record[childrenColumnName].forEach(extractKeys);
}
};
tableData.value.forEach(extractKeys);
return keys;
}
function setSelectedRowKeys(keyValues?: Key[]) {
selectedRowKeysRef.value = keyValues || [];

View File

@@ -54,9 +54,11 @@
import { uploadContainerProps } from './props';
import { omit } from 'lodash-es';
import { useI18n } from '@/hooks/web/useI18n';
import { isArray } from '@/utils/is';
import { isArray, isObject, isString } from '@/utils/is';
import UploadModal from './components/UploadModal.vue';
import UploadPreviewModal from './components/UploadPreviewModal.vue';
import { BaseFileItem } from './types/typing';
import { buildUUID } from '@/utils/uuid';
defineOptions({ name: 'BasicUpload' });
@@ -72,7 +74,7 @@
// 预览modal
const [registerPreviewModal, { openModal: openPreviewModal }] = useModal();
const fileList = ref<string[]>([]);
const fileList = ref<BaseFileItem[] | any[]>([]);
const showPreview = computed(() => {
const { emptyHidePreview } = props;
@@ -85,26 +87,72 @@
return omit(value, 'onChange');
});
const isFirstRender = ref<boolean>(true);
function getValue(valueKey = 'url') {
const list = (fileList.value || []).map((item: any) => {
return item[valueKey];
});
return list;
}
function genFileListByUrls(urls: string[]) {
const list = urls.map((e) => {
return {
uid: buildUUID(),
url: e,
};
});
return list;
}
watch(
() => props.value,
(value = []) => {
fileList.value = isArray(value) ? value : [];
(v = []) => {
let values: string[] = [];
if (v) {
if (isArray(v)) {
values = v;
} else if (typeof v == 'string') {
values.push(v);
}
fileList.value = values.map((item) => {
if (item && isString(item)) {
return {
uid: buildUUID(),
url: item,
};
} else if (item && isObject(item)) {
return item;
} else {
return;
}
}) as any;
}
emit('update:value', values);
if (!isFirstRender.value) {
emit('change', values);
isFirstRender.value = false;
}
},
{
immediate: true,
deep: true,
},
{ immediate: true },
);
// 上传modal保存操作
function handleChange(urls: string[]) {
fileList.value = [...unref(fileList), ...(urls || [])];
emit('update:value', fileList.value);
emit('change', fileList.value);
function handleChange(urls: string[], valueKey: string) {
fileList.value = [...unref(fileList), ...(genFileListByUrls(urls) || [])];
const values = getValue(valueKey);
emit('update:value', values);
emit('change', values);
}
// 预览modal保存操作
function handlePreviewChange(urls: string[]) {
fileList.value = [...(urls || [])];
emit('update:value', fileList.value);
emit('change', fileList.value);
function handlePreviewChange(fileItems: string[], valueKey: string) {
fileList.value = [...(fileItems || [])];
const values = getValue(valueKey);
emit('update:value', values);
emit('change', values);
}
function handleDelete(record: Recordable<any>) {

View File

@@ -9,6 +9,7 @@
:maxCount="maxNumber"
:before-upload="beforeUpload"
:custom-request="customRequest"
:disabled="disabled"
@preview="handlePreview"
@remove="handleRemove"
>
@@ -62,6 +63,7 @@
const fileList = ref<UploadProps['fileList']>([]);
const isLtMsg = ref<boolean>(true);
const isActMsg = ref<boolean>(true);
const isFirstRender = ref<boolean>(true);
watch(
() => props.value,
@@ -93,7 +95,10 @@
}) as UploadProps['fileList'];
}
emit('update:value', value);
emit('change', value);
if (!isFirstRender.value) {
emit('change', value);
isFirstRender.value = false;
}
},
{
immediate: true,

View File

@@ -57,7 +57,7 @@
import { useMessage } from '@/hooks/web/useMessage';
// types
import { FileItem, UploadResultStatus } from '../types/typing';
import { basicProps } from '../props';
import { handleFnKey, basicProps } from '../props';
import { createTableColumns, createActionColumn } from './data';
// utils
import { checkImgType, getBase64WithFile } from '../helper';
@@ -71,7 +71,7 @@
const props = defineProps({
...basicProps,
previewFileList: {
type: Array as PropType<string[]>,
type: Array as PropType<string[] | any[]>,
default: () => [],
},
});
@@ -161,13 +161,13 @@
}
// 删除
function handleRemove(record: FileItem) {
const index = fileListRef.value.findIndex((item) => item.uuid === record.uuid);
index !== -1 && fileListRef.value.splice(index, 1);
isUploadingRef.value = fileListRef.value.some(
(item) => item.status === UploadResultStatus.UPLOADING,
);
emit('delete', record);
function handleRemove(obj: Record<handleFnKey, any>) {
let { record = {}, uidKey = 'uid' } = obj;
const index = fileListRef.value.findIndex((item) => item[uidKey] === record[uidKey]);
if (index !== -1) {
const removed = fileListRef.value.splice(index, 1);
emit('delete', removed[0][uidKey]);
}
}
async function uploadApiByItem(item: FileItem) {

View File

@@ -14,14 +14,15 @@
import { watch, ref } from 'vue';
import FileList from './FileList.vue';
import { BasicModal, useModalInner } from '@/components/Modal';
import { previewProps } from '../props';
import { FileBasicColumn, PreviewFileItem } from '../types/typing';
import { handleFnKey, previewProps } from '../props';
import { BaseFileItem, FileBasicColumn, PreviewFileItem } from '../types/typing';
import { downloadByUrl } from '@/utils/file/download';
import { createPreviewColumns, createPreviewActionColumn } from './data';
import { useI18n } from '@/hooks/web/useI18n';
import { isArray, isFunction } from '@/utils/is';
import { BasicColumn } from '@/components/Table';
import { useMessage } from '@/hooks/web/useMessage';
import { buildUUID } from '@/utils/uuid';
const { createMessage } = useMessage();
@@ -35,7 +36,7 @@
const [register] = useModalInner();
const { t } = useI18n();
const fileListRef = ref<PreviewFileItem[] | Array<any>>([]);
const fileListRef = ref<BaseFileItem[] | Array<any>>([]);
watch(
() => props.previewColumns,
() => {
@@ -64,14 +65,15 @@
fileListRef.value = value
.filter((item) => !!item)
.map((item) => {
if (typeof item != 'string') {
console.error('return value should be string');
if (typeof item != 'object') {
console.error('return value should be object');
return;
}
return {
url: item,
type: item.split('.').pop() || '',
name: item.split('/').pop() || '',
uid: item?.uid,
url: item?.url,
type: item?.url?.split('.').pop() || '',
name: item?.url?.split('/').pop() || '',
};
});
},
@@ -79,28 +81,25 @@
);
// 删除
function handleRemove(record: PreviewFileItem | Record<string, any>, urlKey = 'url') {
const index = fileListRef.value.findIndex((item) => item[urlKey] === record[urlKey]);
function handleRemove(obj: Record<handleFnKey, any>) {
let { record = {}, valueKey = 'url', uidKey = 'uid' } = obj;
const index = fileListRef.value.findIndex((item) => item[uidKey] === record[uidKey]);
if (index !== -1) {
const removed = fileListRef.value.splice(index, 1);
emit('delete', removed[0][urlKey]);
emit(
'list-change',
fileListRef.value.map((item) => item[urlKey]),
);
emit('delete', removed[0][uidKey]);
emit('list-change', fileListRef.value, valueKey);
}
}
// 添加
function handleAdd(record: PreviewFileItem | Record<string, any>, urlKey = 'url') {
function handleAdd(obj: Record<handleFnKey, any>) {
let { record = {}, valueKey = 'url', uidKey = 'uid' } = obj;
const { maxNumber } = props;
if (fileListRef.value.length + fileListRef.value.length > maxNumber) {
return createMessage.warning(t('component.upload.maxNumber', [maxNumber]));
}
record[uidKey] = record[uidKey] ?? buildUUID();
fileListRef.value = [...fileListRef.value, record];
emit(
'list-change',
fileListRef.value.map((item) => item[urlKey]),
);
emit('list-change', fileListRef.value, valueKey);
}
// 下载
function handleDownload(record: PreviewFileItem) {

View File

@@ -5,6 +5,7 @@ import { Progress, Tag } from 'ant-design-vue';
import TableAction from '@/components/Table/src/components/TableAction.vue';
import ThumbUrl from './ThumbUrl.vue';
import { useI18n } from '@/hooks/web/useI18n';
import { previewColumnsFnType } from '../props';
const { t } = useI18n();
@@ -81,7 +82,11 @@ export function createActionColumn(handleRemove: Function): FileBasicColumn {
{
label: t('component.upload.del'),
color: 'error',
onClick: handleRemove.bind(null, record),
onClick: handleRemove.bind(null, {
record,
uidKey: 'uid',
valueKey: 'url',
}),
},
];
return <TableAction actions={actions} outside={true} />;
@@ -112,7 +117,7 @@ export function createPreviewActionColumn({
handleRemove,
handleDownload,
}: {
handleRemove: Fn;
handleRemove: previewColumnsFnType['handleRemove'];
handleDownload: Fn;
}): BasicColumn {
return {
@@ -125,7 +130,11 @@ export function createPreviewActionColumn({
{
label: t('component.upload.del'),
color: 'error',
onClick: handleRemove.bind(null, record),
onClick: handleRemove.bind(null, {
record,
uidKey: 'uid',
valueKey: 'url',
}),
},
{
label: t('component.upload.download'),

View File

@@ -1,5 +1,5 @@
import type { PropType } from 'vue';
import { FileBasicColumn } from './types/typing';
import { BaseFileItem, FileBasicColumn } from './types/typing';
import type { Options } from 'sortablejs';
@@ -14,9 +14,10 @@ type SortableOptions = Merge<
// ...可扩展
}
>;
type previewColumnsFnType = {
handleRemove: (record: Record<string, any>, key: string) => any;
handleAdd: (record: Record<string, any>, key: string) => any;
export type handleFnKey = 'record' | 'valueKey' | 'uidKey';
export type previewColumnsFnType = {
handleRemove: (record: Record<handleFnKey, any>) => any;
handleAdd: (record: Record<handleFnKey, any>) => any;
};
export const previewType = {
previewColumns: {
@@ -26,7 +27,7 @@ export const previewType = {
required: false,
},
beforePreviewData: {
type: Function as PropType<(arg: string[]) => Recordable<any>>,
type: Function as PropType<(arg: BaseFileItem[] | any) => Recordable<any>>,
default: null,
required: false,
},
@@ -112,7 +113,7 @@ export const uploadContainerProps = {
export const previewProps = {
value: {
type: Array as PropType<string[]>,
type: Array as PropType<BaseFileItem[] | any[]>,
default: () => [],
},
maxNumber: {

View File

@@ -20,6 +20,11 @@ export interface FileItem {
uuid: string;
}
export interface BaseFileItem {
uid: string | number;
url: string;
name?: string;
}
export interface PreviewFileItem {
url: string;
name: string;

View File

@@ -1,6 +1,6 @@
import { withInstall } from '@/utils';
import vxeBasicTable from './src/VxeBasicTable';
import { VXETable } from 'vxe-table';
import { VxeUI } from 'vxe-table';
import VXETablePluginAntd from './src/components';
import VXETablePluginExportXLSX from 'vxe-table-plugin-export-xlsx';
import ExcelJS from 'exceljs';
@@ -10,4 +10,4 @@ export const VxeBasicTable = withInstall(vxeBasicTable);
export * from 'vxe-table';
export * from './src/types';
VXETable.use(VXETablePluginAntd).use(VXETablePluginExportXLSX, { ExcelJS });
VxeUI.use(VXETablePluginAntd).use(VXETablePluginExportXLSX, { ExcelJS });

View File

@@ -1,22 +1,25 @@
import { defineComponent, computed, ref } from 'vue';
import { defineComponent, computed, ref, watch } from 'vue';
import { BasicTableProps } from './types';
import { basicProps } from './props';
import { ignorePropKeys } from './const';
import { basicEmits } from './emits';
import XEUtils from 'xe-utils';
import type {
import {
VxeGridInstance,
VxeGridEventProps,
GridMethods,
TableMethods,
TableEditMethods,
TableValidatorMethods,
VxeUI,
VxeGlobalThemeName,
VxeGrid,
} from 'vxe-table';
import { Grid as VxeGrid } from 'vxe-table';
import { extendSlots } from '@/utils/helper/tsxHelper';
import { gridComponentMethodKeys } from './methods';
import { omit } from 'lodash-es';
import { useRootSetting } from '@/hooks/setting/useRootSetting';
export default defineComponent({
name: 'VxeBasicTable',
@@ -25,7 +28,14 @@ export default defineComponent({
setup(props, { emit, attrs }) {
const tableElRef = ref<VxeGridInstance>();
const emitEvents: VxeGridEventProps = {};
const { getDarkMode } = useRootSetting();
watch(
() => getDarkMode.value,
() => {
VxeUI.setTheme(getDarkMode.value as VxeGlobalThemeName);
},
{ immediate: true },
);
const extendTableMethods = (methodKeys) => {
const funcs: any = {};
methodKeys.forEach((name) => {

View File

@@ -1,20 +1,21 @@
import XEUtils from 'xe-utils';
import { createDefaultRender, createEditRender, createFormItemRender } from './common';
import { VxeGlobalRendererOptions } from 'vxe-table';
export default {
renderDefault: createDefaultRender({}, (_, params) => {
renderTableDefault: createDefaultRender({}, (_, params) => {
return {
params: XEUtils.get(params, 'row'),
};
}),
renderEdit: createEditRender({}, (_, params) => {
renderTableEdit: createEditRender({}, (_, params) => {
return {
params: XEUtils.get(params, 'row'),
};
}),
renderItemContent: createFormItemRender({}, (_, params) => {
renderFormItemContent: createFormItemRender({}, (_, params) => {
return {
params: XEUtils.get(params, 'row'),
};
}),
};
} as VxeGlobalRendererOptions;

View File

@@ -1,20 +1,21 @@
import XEUtils from 'xe-utils';
import { createDefaultRender, createEditRender, createFormItemRender } from './common';
import { VxeGlobalRendererOptions } from 'vxe-table';
export default {
renderDefault: createDefaultRender({}, (_, params) => {
renderTableDefault: createDefaultRender({}, (_, params) => {
return {
params: XEUtils.get(params, 'row'),
};
}),
renderEdit: createEditRender({}, (_, params) => {
renderTableEdit: createEditRender({}, (_, params) => {
return {
params: XEUtils.get(params, 'row'),
};
}),
renderItemContent: createFormItemRender({}, (_, params) => {
renderFormItemContent: createFormItemRender({}, (_, params) => {
return {
params: XEUtils.get(params, 'row'),
};
}),
};
} as VxeGlobalRendererOptions;

View File

@@ -1,3 +1,4 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import {
createEditRender,
createDefaultRender,
@@ -7,10 +8,10 @@ import {
} from './common';
export default {
autofocus: 'input.ant-input',
renderDefault: createDefaultRender(),
renderEdit: createEditRender(),
renderFilter: createFilterRender(),
defaultFilterMethod: createDefaultFilterRender(),
renderItemContent: createFormItemRender(),
};
tableAutoFocus: 'input.ant-input',
renderTableDefault: createDefaultRender(),
renderTableEdit: createEditRender(),
renderTableFilter: createFilterRender(),
tableFilterDefaultMethod: createDefaultFilterRender(),
renderFormItemContent: createFormItemRender(),
} as VxeGlobalRendererOptions;

View File

@@ -1,8 +1,9 @@
import { h } from 'vue';
import {
FormItemContentRenderParams,
FormItemRenderOptions,
VxeFormItemPropTypes,
VxeGlobalRendererHandles,
VxeGlobalRendererOptions,
} from 'vxe-table';
import XEUtils from 'xe-utils';
import { cellText, createEvents, createProps, getComponent } from './common';
@@ -11,8 +12,8 @@ const COMPONENT_NAME = 'AButton';
export function createEditRender() {
return function (
renderOpts: VxeGlobalRendererHandles.RenderEditOptions,
params: VxeGlobalRendererHandles.RenderEditParams,
renderOpts: VxeGlobalRendererHandles.RenderTableEditOptions,
params: VxeGlobalRendererHandles.RenderTableEditParams,
) {
const { attrs } = renderOpts;
const Component = getComponent(COMPONENT_NAME);
@@ -29,8 +30,8 @@ export function createEditRender() {
export function createDefaultRender() {
return function (
renderOpts: VxeGlobalRendererHandles.RenderEditOptions,
params: VxeGlobalRendererHandles.RenderEditParams,
renderOpts: VxeGlobalRendererHandles.RenderTableEditOptions,
params: VxeGlobalRendererHandles.RenderTableEditParams,
) {
const { attrs } = renderOpts;
const Component = getComponent(COMPONENT_NAME);
@@ -50,7 +51,10 @@ export function createDefaultRender() {
}
export function createFormItemRender() {
return function (renderOpts: FormItemRenderOptions, params: FormItemContentRenderParams) {
return function (
renderOpts: VxeFormItemPropTypes.ItemRender,
params: FormItemContentRenderParams,
) {
const { attrs, content } = renderOpts;
const { property, $form, data } = params;
const props = createProps(renderOpts, null);
@@ -113,8 +117,8 @@ function createToolbarButtonRender() {
}
export default {
renderEdit: createEditRender(),
renderDefault: createDefaultRender(),
renderItemContent: createFormItemRender(),
renderTableEdit: createEditRender(),
renderTableDefault: createDefaultRender(),
renderFormItemContent: createFormItemRender(),
renderToolbarButton: createToolbarButtonRender(),
};
} as VxeGlobalRendererOptions;

View File

@@ -1,20 +1,21 @@
import {
FormItemContentRenderParams,
FormItemRenderOptions,
VxeFormItemPropTypes,
VxeGlobalRendererHandles,
VxeGlobalRendererOptions,
} from 'vxe-table';
import { createDefaultRender, createEditRender, createFormItemRender } from './AButton';
function createEditButtonRender() {
return function (
renderOpts: VxeGlobalRendererHandles.RenderEditOptions,
params: VxeGlobalRendererHandles.RenderEditParams,
renderOpts: VxeGlobalRendererHandles.RenderTableEditOptions,
params: VxeGlobalRendererHandles.RenderTableEditParams,
) {
const buttonEditRender = createEditRender();
const { children } = renderOpts;
if (children) {
return children.map(
(childRenderOpts: VxeGlobalRendererHandles.RenderEditOptions) =>
(childRenderOpts: VxeGlobalRendererHandles.RenderTableEditOptions) =>
buttonEditRender(childRenderOpts, params)[0],
);
}
@@ -25,7 +26,7 @@ function createEditButtonRender() {
function createDefaultButtonRender() {
return function (
renderOpts: VxeGlobalRendererHandles.RenderDefaultOptions,
params: VxeGlobalRendererHandles.RenderDefaultParams,
params: VxeGlobalRendererHandles.RenderTableDefaultParams,
) {
const buttonDefaultRender = createDefaultRender();
const { children } = renderOpts;
@@ -40,12 +41,16 @@ function createDefaultButtonRender() {
}
function createButtonItemRender() {
return function (renderOpts: FormItemRenderOptions, params: FormItemContentRenderParams) {
return function (
renderOpts: VxeFormItemPropTypes.ItemRender,
params: FormItemContentRenderParams,
) {
const buttonItemRender = createFormItemRender();
const { children } = renderOpts;
if (children) {
return children.map(
(childRenderOpts: FormItemRenderOptions) => buttonItemRender(childRenderOpts, params)[0],
(childRenderOpts: VxeFormItemPropTypes.ItemRender) =>
buttonItemRender(childRenderOpts, params)[0],
);
}
return [];
@@ -53,7 +58,7 @@ function createButtonItemRender() {
}
export default {
renderEdit: createEditButtonRender(),
renderDefault: createDefaultButtonRender(),
renderItemContent: createButtonItemRender(),
};
renderTableEdit: createEditButtonRender(),
renderTableDefault: createDefaultButtonRender(),
renderFormItemContent: createButtonItemRender(),
} as VxeGlobalRendererOptions;

View File

@@ -1,4 +1,4 @@
import { VxeGlobalRendererHandles } from 'vxe-table';
import { VxeGlobalRendererHandles, VxeGlobalRendererOptions } from 'vxe-table';
import XEUtils from 'xe-utils';
import {
createEditRender,
@@ -21,7 +21,7 @@ function matchCascaderData(index: number, list: any[], values: any[], labels: an
function getCascaderCellValue(
renderOpts: VxeGlobalRendererHandles.RenderOptions,
params: VxeGlobalRendererHandles.RenderCellParams,
params: VxeGlobalRendererHandles.RenderTableCellParams,
) {
const { props = {} } = renderOpts;
const { row, column } = params;
@@ -35,8 +35,8 @@ function getCascaderCellValue(
}
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getCascaderCellValue),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getCascaderCellValue),
};
renderTableEdit: createEditRender(),
renderTableCell: createCellRender(getCascaderCellValue),
renderFormItemContent: createFormItemRender(),
tableExportMethod: createExportMethod(getCascaderCellValue),
} as VxeGlobalRendererOptions;

View File

@@ -1,5 +1,6 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import { createFormItemRender } from './common';
export default {
renderItemContent: createFormItemRender(),
};
renderFormItemContent: createFormItemRender(),
} as VxeGlobalRendererOptions;

View File

@@ -1,4 +1,4 @@
import { VxeGlobalRendererHandles } from 'vxe-table';
import { VxeGlobalRendererHandles, VxeGlobalRendererOptions } from 'vxe-table';
import XEUtils from 'xe-utils';
import {
createCellRender,
@@ -9,7 +9,9 @@ import {
export function getDatePickerCellValue(
renderOpts: VxeGlobalRendererHandles.RenderOptions,
params: VxeGlobalRendererHandles.RenderCellParams | VxeGlobalRendererHandles.ExportMethodParams,
params:
| VxeGlobalRendererHandles.RenderTableCellParams
| VxeGlobalRendererHandles.ExportMethodParams,
defaultFormat: string,
) {
const { props = {} } = renderOpts;
@@ -22,12 +24,12 @@ export function getDatePickerCellValue(
}
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getDatePickerCellValue, () => {
renderTableEdit: createEditRender(),
renderTableCell: createCellRender(getDatePickerCellValue, () => {
return ['YYYY-MM-DD'];
}),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getDatePickerCellValue, () => {
renderFormItemContent: createFormItemRender(),
tableExportMethod: createExportMethod(getDatePickerCellValue, () => {
return ['YYYY-MM-DD'];
}),
};
} as VxeGlobalRendererOptions;

View File

@@ -1,9 +1,9 @@
import { h } from 'vue';
import { VxeGlobalRendererHandles } from 'vxe-table';
import { VxeGlobalRendererHandles, VxeGlobalRendererOptions } from 'vxe-table';
import { getComponent } from './common';
function createEmptyRender() {
return function (renderOpts: VxeGlobalRendererHandles.RenderEmptyOptions) {
return function (renderOpts: VxeGlobalRendererHandles.RenderTableEmptyOptions) {
const { name, attrs, props } = renderOpts;
const Component = getComponent(name);
@@ -23,5 +23,5 @@ function createEmptyRender() {
}
export default {
renderEmpty: createEmptyRender(),
};
renderTableEmptyView: createEmptyRender(),
} as VxeGlobalRendererOptions;

View File

@@ -1,3 +1,4 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import {
createEditRender,
createDefaultRender,
@@ -7,10 +8,10 @@ import {
} from './common';
export default {
autofocus: 'input.ant-input',
renderDefault: createDefaultRender(),
renderEdit: createEditRender(),
renderFilter: createFilterRender(),
defaultFilterMethod: createDefaultFilterRender(),
renderItemContent: createFormItemRender(),
};
tableAutoFocus: 'input.ant-input',
renderTableDefault: createDefaultRender(),
renderTableEdit: createEditRender(),
renderTableFilter: createFilterRender(),
tableFilterDefaultMethod: createDefaultFilterRender(),
renderFormItemContent: createFormItemRender(),
} as VxeGlobalRendererOptions;

View File

@@ -1,3 +1,4 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import {
createEditRender,
createFilterRender,
@@ -7,10 +8,10 @@ import {
} from './common';
export default {
autofocus: 'input.ant-input-number-input',
renderDefault: createDefaultRender(),
renderEdit: createEditRender(),
renderFilter: createFilterRender(),
defaultFilterMethod: createDefaultFilterRender(),
renderItemContent: createFormItemRender(),
};
tableAutoFocus: 'input.ant-input-number-input',
renderTableDefault: createDefaultRender(),
renderTableEdit: createEditRender(),
renderTableFilter: createFilterRender(),
tableFilterDefaultMethod: createDefaultFilterRender(),
renderFormItemContent: createFormItemRender(),
} as VxeGlobalRendererOptions;

View File

@@ -1,3 +1,4 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import {
createEditRender,
createDefaultRender,
@@ -8,10 +9,10 @@ import {
} from './common';
export default {
renderDefault: createDefaultRender(),
renderEdit: createEditRender(),
renderFilter: createFilterRender(),
defaultFilterMethod: createDefaultFilterRender(),
renderItemContent: createFormItemRender(),
renderTableDefault: createDefaultRender(),
renderTableEdit: createEditRender(),
renderTableFilter: createFilterRender(),
tableFilterDefaultMethod: createDefaultFilterRender(),
renderFormItemContent: createFormItemRender(),
renderToolbarTool: createToolbarToolRender(),
};
} as VxeGlobalRendererOptions;

View File

@@ -1,3 +1,4 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import { getDatePickerCellValue } from './ADatePicker';
import {
createCellRender,
@@ -7,12 +8,12 @@ import {
} from './common';
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getDatePickerCellValue, () => {
renderTableEdit: createEditRender(),
renderTableCell: createCellRender(getDatePickerCellValue, () => {
return ['YYYY-MM'];
}),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getDatePickerCellValue, () => {
renderFormItemContent: createFormItemRender(),
tableExportMethod: createExportMethod(getDatePickerCellValue, () => {
return ['YYYY-MM'];
}),
};
} as VxeGlobalRendererOptions;

View File

@@ -1,5 +1,6 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import { createFormItemRender } from './common';
export default {
renderItemContent: createFormItemRender(),
};
renderFormItemContent: createFormItemRender(),
} as VxeGlobalRendererOptions;

View File

@@ -1,4 +1,4 @@
import { VxeColumnPropTypes, VxeGlobalRendererHandles } from 'vxe-table';
import { VxeColumnPropTypes, VxeGlobalRendererHandles, VxeGlobalRendererOptions } from 'vxe-table';
import XEUtils from 'xe-utils';
import {
createCellRender,
@@ -9,7 +9,9 @@ import {
function getRangePickerCellValue(
renderOpts: VxeColumnPropTypes.EditRender,
params: VxeGlobalRendererHandles.RenderCellParams | VxeGlobalRendererHandles.ExportMethodParams,
params:
| VxeGlobalRendererHandles.RenderTableCellParams
| VxeGlobalRendererHandles.ExportMethodParams,
) {
const { props = {} } = renderOpts;
const { row, column } = params;
@@ -23,8 +25,8 @@ function getRangePickerCellValue(
}
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getRangePickerCellValue),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getRangePickerCellValue),
};
renderTableEdit: createEditRender(),
renderTableCell: createCellRender(getRangePickerCellValue),
renderFormItemContent: createFormItemRender(),
tableExportMethod: createExportMethod(getRangePickerCellValue),
} as VxeGlobalRendererOptions;

View File

@@ -1,3 +1,4 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import {
createEditRender,
createDefaultRender,
@@ -7,9 +8,9 @@ import {
} from './common';
export default {
renderDefault: createDefaultRender(),
renderEdit: createEditRender(),
renderFilter: createFilterRender(),
defaultFilterMethod: createDefaultFilterRender(),
renderItemContent: createFormItemRender(),
};
renderTableDefault: createDefaultRender(),
renderTableEdit: createEditRender(),
renderTableFilter: createFilterRender(),
tableFilterDefaultMethod: createDefaultFilterRender(),
renderFormItemContent: createFormItemRender(),
} as VxeGlobalRendererOptions;

View File

@@ -1,5 +1,5 @@
import { ComponentOptions, h, resolveComponent } from 'vue';
import { VxeColumnPropTypes, VxeGlobalRendererHandles } from 'vxe-table';
import { VxeColumnPropTypes, VxeGlobalRendererHandles, VxeGlobalRendererOptions } from 'vxe-table';
import XEUtils from 'xe-utils';
import {
cellText,
@@ -32,7 +32,7 @@ function renderOptions(options: any[], optionProps: VxeGlobalRendererHandles.Ren
function createEditRender() {
return function (
renderOpts: VxeColumnPropTypes.EditRender,
params: VxeGlobalRendererHandles.RenderEditParams,
params: VxeGlobalRendererHandles.RenderTableEditParams,
) {
const { options = [], optionGroups, optionProps = {}, optionGroupProps = {} } = renderOpts;
const { row, column, $table } = params;
@@ -100,8 +100,8 @@ function createEditRender() {
}
function getSelectCellValue(
renderOpts: VxeGlobalRendererHandles.RenderCellOptions,
params: VxeGlobalRendererHandles.RenderCellParams,
renderOpts: VxeGlobalRendererHandles.RenderTableCellOptions,
params: VxeGlobalRendererHandles.RenderTableCellParams,
) {
const {
options = [],
@@ -144,7 +144,7 @@ function getSelectCellValue(
function createFilterRender() {
return function (
renderOpts: VxeColumnPropTypes.FilterRender,
params: VxeGlobalRendererHandles.RenderFilterParams,
params: VxeGlobalRendererHandles.RenderTableFilterParams,
) {
const { options = [], optionGroups, optionProps = {}, optionGroupProps = {} } = renderOpts;
const groupOptions = optionGroupProps.options || 'options';
@@ -249,10 +249,10 @@ function createFilterRender() {
}
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getSelectCellValue),
renderFilter: createFilterRender(),
defaultFilterMethod(params) {
renderTableEdit: createEditRender(),
renderTableCell: createCellRender(getSelectCellValue),
renderTableFilter: createFilterRender(),
tableFilterDefaultMethod(params) {
const { option, row, column } = params;
const { data } = option;
const { field, filterRender: renderOpts } = column;
@@ -266,6 +266,6 @@ export default {
}
return cellValue == data;
},
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getSelectCellValue),
};
renderFormItemContent: createFormItemRender(),
tableExportMethod: createExportMethod(getSelectCellValue),
} as VxeGlobalRendererOptions;

View File

@@ -9,11 +9,12 @@ import {
createFormItemRender,
getComponent,
} from './common';
import { VxeGlobalRendererOptions } from 'vxe-table';
export default {
renderDefault: createDefaultRender(),
renderEdit: createEditRender(),
renderFilter(renderOpts, params) {
renderTableDefault: createDefaultRender(),
renderTableEdit: createEditRender(),
renderTableFilter(renderOpts, params) {
const { column } = params;
const { name, attrs } = renderOpts;
const Component = getComponent(name);
@@ -48,6 +49,6 @@ export default {
),
];
},
defaultFilterMethod: createDefaultFilterRender(),
renderItemContent: createFormItemRender(),
};
tableFilterDefaultMethod: createDefaultFilterRender(),
renderFormItemContent: createFormItemRender(),
} as VxeGlobalRendererOptions;

View File

@@ -1,3 +1,4 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import { getDatePickerCellValue } from './ADatePicker';
import {
createEditRender,
@@ -7,12 +8,12 @@ import {
} from './common';
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getDatePickerCellValue, () => {
renderTableEdit: createEditRender(),
renderTableCell: createCellRender(getDatePickerCellValue, () => {
return ['HH:mm:ss'];
}),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getDatePickerCellValue, () => {
renderFormItemContent: createFormItemRender(),
tableExportMethod: createExportMethod(getDatePickerCellValue, () => {
return ['HH:mm:ss'];
}),
};
} as VxeGlobalRendererOptions;

View File

@@ -1,4 +1,4 @@
import { VxeGlobalRendererHandles } from 'vxe-table';
import { VxeGlobalRendererHandles, VxeGlobalRendererOptions } from 'vxe-table';
import XEUtils from 'xe-utils';
import {
createEditRender,
@@ -10,7 +10,9 @@ import {
function getTreeSelectCellValue(
renderOpts: VxeGlobalRendererHandles.RenderOptions,
params: VxeGlobalRendererHandles.RenderCellParams | VxeGlobalRendererHandles.ExportMethodParams,
params:
| VxeGlobalRendererHandles.RenderTableCellParams
| VxeGlobalRendererHandles.ExportMethodParams,
) {
const { props = {} } = renderOpts;
const { treeData, treeCheckable } = props;
@@ -28,8 +30,8 @@ function getTreeSelectCellValue(
}
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getTreeSelectCellValue),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getTreeSelectCellValue),
};
renderTableEdit: createEditRender(),
renderTableCell: createCellRender(getTreeSelectCellValue),
renderFormItemContent: createFormItemRender(),
tableExportMethod: createExportMethod(getTreeSelectCellValue),
} as VxeGlobalRendererOptions;

View File

@@ -1,3 +1,4 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import { getDatePickerCellValue } from './ADatePicker';
import {
createEditRender,
@@ -7,12 +8,12 @@ import {
} from './common';
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getDatePickerCellValue, () => {
renderTableEdit: createEditRender(),
renderTableCell: createCellRender(getDatePickerCellValue, () => {
return ['YYYY-WW周'];
}),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getDatePickerCellValue, () => {
renderFormItemContent: createFormItemRender(),
tableExportMethod: createExportMethod(getDatePickerCellValue, () => {
return ['YYYY-WW周'];
}),
};
} as VxeGlobalRendererOptions;

View File

@@ -1,3 +1,4 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import { getDatePickerCellValue } from './ADatePicker';
import {
createEditRender,
@@ -7,12 +8,12 @@ import {
} from './common';
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getDatePickerCellValue, () => {
renderTableEdit: createEditRender(),
renderTableCell: createCellRender(getDatePickerCellValue, () => {
return ['YYYY'];
}),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getDatePickerCellValue, () => {
renderFormItemContent: createFormItemRender(),
tableExportMethod: createExportMethod(getDatePickerCellValue, () => {
return ['YYYY'];
}),
};
} as VxeGlobalRendererOptions;

View File

@@ -1,7 +1,7 @@
import { ComponentOptions, h } from 'vue';
import {
FormItemContentRenderParams,
FormItemRenderOptions,
VxeFormItemPropTypes,
VxeGlobalRendererHandles,
} from 'vxe-table';
import XEUtils from 'xe-utils';
@@ -160,12 +160,12 @@ export function createDefaultRender(
defaultProps?: { [key: string]: any },
callBack?: (
renderOpts: VxeGlobalRendererHandles.RenderDefaultOptions,
params: VxeGlobalRendererHandles.RenderDefaultParams,
params: VxeGlobalRendererHandles.RenderTableDefaultParams,
) => Record<string, any>,
) {
return function (
renderOpts: VxeGlobalRendererHandles.RenderDefaultOptions,
params: VxeGlobalRendererHandles.RenderDefaultParams,
params: VxeGlobalRendererHandles.RenderTableDefaultParams,
) {
const { row, column, $table } = params;
const { name, attrs } = renderOpts;
@@ -195,13 +195,13 @@ export function createDefaultRender(
export function createEditRender(
defaultProps?: { [key: string]: any },
callBack?: (
renderOpts: VxeGlobalRendererHandles.RenderEditOptions,
params: VxeGlobalRendererHandles.RenderEditParams,
renderOpts: VxeGlobalRendererHandles.RenderTableEditOptions,
params: VxeGlobalRendererHandles.RenderTableEditParams,
) => Record<string, any>,
) {
return function (
renderOpts: VxeGlobalRendererHandles.RenderEditOptions,
params: VxeGlobalRendererHandles.RenderEditParams,
renderOpts: VxeGlobalRendererHandles.RenderTableEditOptions,
params: VxeGlobalRendererHandles.RenderTableEditParams,
) {
const { row, column, $table } = params;
const { name, attrs } = renderOpts;
@@ -232,12 +232,12 @@ export function createFilterRender(
defaultProps?: { [key: string]: any },
callBack?: (
renderOpts: VxeGlobalRendererHandles.RenderFilterOptions,
params: VxeGlobalRendererHandles.RenderFilterParams,
params: VxeGlobalRendererHandles.RenderTableFilterParams,
) => Record<string, any>,
) {
return function (
renderOpts: VxeGlobalRendererHandles.RenderFilterOptions,
params: VxeGlobalRendererHandles.RenderFilterParams,
params: VxeGlobalRendererHandles.RenderTableFilterParams,
) {
const { column } = params;
const { name, attrs } = renderOpts;
@@ -287,7 +287,7 @@ export function createFilterRender(
*/
export function createDefaultFilterRender() {
return function (params: VxeGlobalRendererHandles.FilterMethodParams) {
return function (params: VxeGlobalRendererHandles.TableFilterMethodParams) {
const { option, row, column } = params;
const { data } = option;
const cellValue = XEUtils.get(row, column.field as string);
@@ -301,11 +301,14 @@ export function createDefaultFilterRender() {
export function createFormItemRender(
defaultProps?: { [key: string]: any },
callBack?: (
renderOpts: FormItemRenderOptions,
renderOpts: VxeFormItemPropTypes.ItemRender,
params: FormItemContentRenderParams,
) => Record<string, any>,
) {
return function (renderOpts: FormItemRenderOptions, params: FormItemContentRenderParams) {
return function (
renderOpts: VxeFormItemPropTypes.ItemRender,
params: FormItemContentRenderParams,
) {
const args = (callBack && callBack(renderOpts, params)) ?? {};
const { data, property, $form } = params;
const { name } = renderOpts;
@@ -344,13 +347,13 @@ export function createFormItemRender(
export function createCellRender(
getSelectCellValue: Function,
callBack?: (
renderOpts: VxeGlobalRendererHandles.RenderCellOptions,
params: VxeGlobalRendererHandles.RenderCellParams,
renderOpts: VxeGlobalRendererHandles.RenderTableCellOptions,
params: VxeGlobalRendererHandles.RenderTableCellParams,
) => Array<any>,
) {
return function (
renderOpts: VxeGlobalRendererHandles.RenderCellOptions,
params: VxeGlobalRendererHandles.RenderCellParams,
renderOpts: VxeGlobalRendererHandles.RenderTableCellOptions,
params: VxeGlobalRendererHandles.RenderTableCellParams,
) {
const args = (callBack && callBack(renderOpts, params)) ?? [];
const cellLabel = getSelectCellValue && getSelectCellValue(renderOpts, params, ...args);

View File

@@ -1,4 +1,4 @@
import { VXETableCore, VxeGlobalInterceptorHandles } from 'vxe-table';
import { VxeUIExport, VxeGlobalInterceptorHandles } from 'vxe-table';
import AAutoComplete from './AAutoComplete';
import AInput from './AInput';
import AInputNumber from './AInputNumber';
@@ -50,7 +50,7 @@ function getEventTargetNode(evnt: any, container: HTMLElement, className: string
function handleClearEvent(
params:
| VxeGlobalInterceptorHandles.InterceptorClearFilterParams
| VxeGlobalInterceptorHandles.InterceptorClearActivedParams
| VxeGlobalInterceptorHandles.InterceptorClearEditParams
| VxeGlobalInterceptorHandles.InterceptorClearAreasParams,
) {
const { $event } = params;
@@ -73,10 +73,10 @@ function handleClearEvent(
* 基于 vxe-table 表格的适配插件,用于兼容 ant-design-vue 组件库
*/
export const VXETablePluginAntd = {
install(vxetablecore: VXETableCore) {
install(vxetablecore: VxeUIExport) {
const { interceptor, renderer } = vxetablecore;
renderer.mixin({
const customRenderComponents = {
AAutoComplete,
AInput,
AInputNumber,
@@ -99,16 +99,21 @@ export const VXETablePluginAntd = {
AEmpty,
AInputSearch,
AYearPicker,
};
Object.keys(customRenderComponents).forEach((name) => {
if (renderer.get(name)) return;
renderer.add(name, customRenderComponents[name]);
});
interceptor.add('event.clearFilter', handleClearEvent);
interceptor.add('event.clearActived', handleClearEvent);
interceptor.add('event.clearEdit', handleClearEvent);
interceptor.add('event.clearAreas', handleClearEvent);
},
};
if (typeof window !== 'undefined' && window.VXETable && window.VXETable.use) {
window.VXETable.use(VXETablePluginAntd);
if (typeof window !== 'undefined' && window.VxeUI && window.VxeUI.use) {
window.VxeUI.use(VXETablePluginAntd);
}
export default VXETablePluginAntd;

View File

@@ -2,4 +2,5 @@
@import './variable';
@import './toolbar';
@import './component';
@import 'vxe-table/styles/index';
@import 'vxe-table/styles/all';
@import 'vxe-pc-ui/styles/all';

View File

@@ -1,4 +1,4 @@
import { VXETable } from '..';
import { VxeUI } from '..';
import componentSetting from '@/settings/componentSetting';
VXETable.setup(componentSetting.vxeTable);
VxeUI.setConfig(componentSetting.vxeTable);

View File

@@ -2,7 +2,8 @@ import type { App } from 'vue';
import { Button } from './Button';
import { Input, Layout } from 'ant-design-vue';
import VXETable from 'vxe-table';
import VXEUI from 'vxe-pc-ui';
export function registerGlobComp(app: App) {
app.use(Input).use(Button).use(Layout).use(VXETable);
app.use(Input).use(Button).use(Layout).use(VXETable).use(VXEUI);
}

View File

@@ -17,15 +17,15 @@
// }
::-webkit-scrollbar-track {
background-color: rgb(0 0 0 / 5%);
background-color: #0000000d;
}
::-webkit-scrollbar-thumb {
// background-color: rgba(144, 147, 153, 0.3);
border-radius: 2px;
// background: rgba(0, 0, 0, 0.6);
background-color: rgb(144 147 153 / 30%);
box-shadow: inset 0 0 6px rgb(0 0 0 / 20%);
background-color: #9093994d;
box-shadow: inset 0 0 6px #00000033;
}
::-webkit-scrollbar-thumb:hover {

View File

@@ -1,5 +1,5 @@
import { createLoading } from '@/components/Loading';
import type { Directive, App } from 'vue';
import type { App, Directive } from 'vue';
const loadingDirective: Directive = {
mounted(el, binding) {
@@ -28,7 +28,7 @@ const loadingDirective: Directive = {
}
},
unmounted(el) {
el?.instance?.close();
el?.instance?.destroy();
},
};

View File

@@ -1,8 +1,8 @@
import type { EChartsOption } from 'echarts';
import type { Ref } from 'vue';
import { computed, nextTick, ref, unref, watch } from 'vue';
import { useTimeoutFn } from '@vben/hooks';
import { tryOnUnmounted, useDebounceFn } from '@vueuse/core';
import { unref, nextTick, watch, computed, ref } from 'vue';
import { useEventListener } from '@/hooks/event/useEventListener';
import { useBreakpoint } from '@/hooks/event/useBreakpoint';
import echarts from '@/utils/lib/echarts';
@@ -49,6 +49,10 @@ export function useECharts(
listener: resizeFn,
});
removeResizeFn = removeEvent;
const resizeObserver = new ResizeObserver(resizeFn);
resizeObserver.observe(el);
const { widthRef, screenEnum } = useBreakpoint();
if (unref(widthRef) <= screenEnum.MD || el.offsetHeight === 0) {
useTimeoutFn(() => {
@@ -64,7 +68,7 @@ export function useECharts(
useTimeoutFn(() => {
setOptions(unref(getOptions));
resolve(null);
}, 30);
}, 50);
}
nextTick(() => {
useTimeoutFn(() => {

View File

@@ -91,7 +91,7 @@
const breadcrumbList = filterItem(matched);
if (currentRoute.value.meta?.currentActiveMenu) {
if (currentRoute.value.meta?.currentActiveMenu && !currentRoute.value.meta?.hideBreadcrumb) {
breadcrumbList.push({
...currentRoute.value,
name: currentRoute.value.meta?.title || currentRoute.value.name,
@@ -131,7 +131,6 @@
}
function handleClick(route) {
console.log(route);
const { children, redirect, meta } = route;
if (children?.length && !redirect) {

View File

@@ -0,0 +1,33 @@
<script setup lang="ts">
import { h } from 'vue';
import { Modal } from 'ant-design-vue';
import { useI18n } from '@/hooks/web/useI18n';
const { t } = useI18n();
const localKey = 'vben-v5.0.0-upgrade-prompt';
if (!localStorage.getItem(localKey)) {
Modal.confirm({
title: t('layout.header.upgrade-prompt.title'),
content: h('div', {}, [h('p', t('layout.header.upgrade-prompt.content'))]),
onOk() {
handleClick();
},
okText: t('layout.header.upgrade-prompt.ok-text'),
cancelText: t('common.closeText'),
});
}
localStorage.setItem(localKey, String(Date.now()));
function handleClick() {
window.open('https://www.vben.pro', '_blank');
}
</script>
<template>
<div>
<a-button type="primary" @click="handleClick">{{
t('layout.header.upgrade-prompt.ok-text')
}}</a-button>
</div>
</template>

View File

@@ -33,6 +33,8 @@
<!-- action -->
<div :class="`${prefixCls}-action`">
<UpgradePrompt class="mr-2" />
<AppSearch v-if="getShowSearch" :class="`${prefixCls}-action__item `" />
<ErrorAction v-if="getUseErrorHandle" :class="`${prefixCls}-action__item error-action`" />
@@ -70,6 +72,7 @@
import { createAsyncComponent } from '@/utils/factory/createAsyncComponent';
import { propTypes } from '@/utils/propTypes';
import UpgradePrompt from './components/UpgradePrompt.vue';
import LayoutMenu from '../menu/index.vue';
import LayoutTrigger from '../trigger/index.vue';
import { ErrorAction, FullScreen, LayoutBreadcrumb, Notify, UserDropDown } from './components';

View File

@@ -15,7 +15,12 @@
"lockScreenPassword": "Lock screen password",
"lockScreen": "Lock screen",
"lockScreenBtn": "Locking",
"home": "Home"
"home": "Home",
"upgrade-prompt": {
"title": "New version released",
"content": "Vben Admin v5.0.0 preview version has been released",
"ok-text": "Go to new version"
}
},
"multipleTab": {
"reload": "Refresh current",

View File

@@ -37,7 +37,7 @@
},
"editor": {
"editor": "Editor",
"jsonEditor": "Json editor",
"codeEditor": "Code editor",
"markdown": "Markdown editor",
"tinymce": "Rich text",
"tinymceBasic": "Basic",
@@ -53,6 +53,7 @@
"feat": {
"feat": "Page Function",
"icon": "Icon",
"screenShot": "Screen Shot",
"tabs": "Tabs",
"tabDetail": "Tab Detail",
"sessionTimeout": "Session Timeout",

View File

@@ -15,7 +15,12 @@
"lockScreenPassword": "锁屏密码",
"lockScreen": "锁定屏幕",
"lockScreenBtn": "锁定",
"home": "首页"
"home": "首页",
"upgrade-prompt": {
"title": "新版本发布",
"content": "Vben Admin v5.0.0 预览版本已发布",
"ok-text": "前往体验新版"
}
},
"multipleTab": {
"reload": "重新加载",

View File

@@ -37,7 +37,7 @@
},
"editor": {
"editor": "编辑器",
"jsonEditor": "Json编辑器",
"codeEditor": "代码编辑器",
"markdown": "markdown编辑器",
"tinymce": "富文本",
"tinymceBasic": "基础使用",
@@ -53,6 +53,7 @@
"feat": {
"feat": "功能",
"icon": "图标",
"screenShot": "截图",
"sessionTimeout": "登录过期",
"tabs": "标签页操作",
"tabDetail": "标签详情页",

View File

@@ -24,7 +24,7 @@ import { Persistent } from '@/utils/cache/persistent';
export function initAppConfigStore() {
const localeStore = useLocaleStore();
const appStore = useAppStore();
let projCfg: ProjectConfig = Persistent.getLocal(PROJ_CFG_KEY) as ProjectConfig;
let projCfg = Persistent.getLocal<ProjectConfig>(PROJ_CFG_KEY);
projCfg = deepMerge(projectSetting, projCfg || {});
const darkMode = appStore.getDarkMode;
const {

View File

@@ -61,10 +61,10 @@ export function createPermissionGuard(router: Router) {
path: LOGIN_PATH,
replace: true,
};
if (to.path) {
if (to.fullPath) {
redirectData.query = {
...redirectData.query,
redirect: to.path,
redirect: to.fullPath,
};
}
next(redirectData);

View File

@@ -1,5 +1,5 @@
import { AppRouteModule } from '@/router/types';
import type { MenuModule, Menu, AppRouteRecordRaw } from '@/router/types';
import type { Menu, AppRouteRecordRaw } from '@/router/types';
import { findPath, treeMap } from '@/utils/helper/treeHelper';
import { cloneDeep } from 'lodash-es';
import { isHttpUrl } from '@/utils/is';
@@ -30,13 +30,12 @@ function joinParentPath(menus: Menu[], parentPath = '') {
}
}
}
// Parsing the menu module
export function transformMenuModule(menuModule: MenuModule): Menu {
const menuList = [menuModule];
joinParentPath(menuList);
return menuList[0];
// 菜单路径处理
export function transformMenuModules(routeModList: Menu[]) {
const cloneMenuModules = cloneDeep(routeModList);
// 路径处理
joinParentPath(cloneMenuModules);
return cloneMenuModules;
}
// 将路由转换成菜单

View File

@@ -3,7 +3,7 @@ import type { RouteRecordNormalized } from 'vue-router';
import { useAppStoreWithOut } from '@/store/modules/app';
import { usePermissionStore } from '@/store/modules/permission';
import { transformMenuModule, getAllParentPath } from '@/router/helper/menuHelper';
import { getAllParentPath } from '@/router/helper/menuHelper';
import { filter } from '@/utils/helper/treeHelper';
import { isHttpUrl } from '@/utils/is';
import { router } from '@/router';
@@ -12,7 +12,7 @@ import { pathToRegexp } from 'path-to-regexp';
const modules = import.meta.glob('../routes/modules/**/*.ts', { eager: true });
const menuModules: MenuModule[] = [];
export const menuModules: MenuModule[] = [];
Object.keys(modules).forEach((key) => {
const mod = (modules as Recordable)[key].default || {};
@@ -40,17 +40,6 @@ const isRoleMode = () => {
return getPermissionMode() === PermissionModeEnum.ROLE;
};
const staticMenus: Menu[] = [];
(() => {
menuModules.sort((a, b) => {
return (a.orderNo || 0) - (b.orderNo || 0);
});
for (const menu of menuModules) {
staticMenus.push(transformMenuModule(menu));
}
})();
async function getAsyncMenus() {
const permissionStore = usePermissionStore();
//递归过滤所有隐藏的菜单
@@ -69,7 +58,7 @@ async function getAsyncMenus() {
if (isRouteMappingMode()) {
return menuFilter(permissionStore.getFrontMenuList);
}
return staticMenus;
return permissionStore.getStaticMenuList;
}
export const getMenus = async (): Promise<Menu[]> => {

View File

@@ -345,12 +345,30 @@ const comp: AppRouteModule = {
},
children: [
{
path: 'json',
component: () => import('@/views/demo/editor/json/index.vue'),
name: 'JsonEditorDemo',
path: 'code',
component: () => import('@/views/demo/editor/code/index.vue'),
name: 'codeEditorDemo',
meta: {
title: t('routes.demo.editor.jsonEditor'),
title: t('routes.demo.editor.codeEditor'),
},
children: [
{
path: 'code',
name: 'codeBasicDemo',
component: () => import('@/views/demo/editor/code/index.vue'),
meta: {
title: t('routes.demo.editor.tinymceBasic'),
},
},
{
path: 'editor',
name: 'codeEditorBasicDemo',
component: () => import('@/views/demo/editor/code/Editor.vue'),
meta: {
title: t('routes.demo.editor.tinymceForm'),
},
},
],
},
{
path: 'markdown',

View File

@@ -23,6 +23,14 @@ const feat: AppRouteModule = {
title: t('routes.demo.feat.icon'),
},
},
{
path: 'screenshot',
name: 'Screenshot',
component: () => import('@/views/demo/feat/screenshot/index.vue'),
meta: {
title: t('routes.demo.feat.screenShot'),
},
},
{
path: 'ws',
name: 'WebSocket',

View File

@@ -3,7 +3,7 @@ import type { AppRouteModule } from '@/router/types';
import { LAYOUT } from '@/router/constant';
import { t } from '@/hooks/web/useI18n';
const charts: AppRouteModule = {
const flow: AppRouteModule = {
path: '/flow',
name: 'FlowDemo',
component: LAYOUT,
@@ -25,4 +25,4 @@ const charts: AppRouteModule = {
],
};
export default charts;
export default flow;

View File

@@ -3,7 +3,7 @@ import type { AppRouteModule } from '@/router/types';
import { getParentLayout, LAYOUT } from '@/router/constant';
import { t } from '@/hooks/web/useI18n';
const permission: AppRouteModule = {
const level: AppRouteModule = {
path: '/level',
name: 'Level',
component: LAYOUT,
@@ -65,4 +65,4 @@ const permission: AppRouteModule = {
],
};
export default permission;
export default level;

View File

@@ -16,6 +16,7 @@ import { Persistent } from '@/utils/cache/persistent';
import { darkMode } from '@/settings/designSetting';
import { resetRouter } from '@/router';
import { deepMerge } from '@/utils';
import setting from '@/settings/projectSetting';
interface AppState {
darkMode?: ThemeEnum;
@@ -40,7 +41,12 @@ export const useAppStore = defineStore({
return state.pageLoading;
},
getDarkMode(state): 'light' | 'dark' | string {
return state.darkMode || localStorage.getItem(APP_DARK_MODE_KEY) || darkMode;
return (
state.darkMode ||
localStorage.getItem(APP_DARK_MODE_KEY) ||
setting.menuSetting.theme ||
darkMode
);
},
getBeforeMiniInfo(state): BeforeMiniState {

View File

@@ -134,7 +134,9 @@ export const useMultipleTabStore = defineStore({
// Existing pages, do not add tabs repeatedly
const tabHasExits = this.tabList.some((tab, index) => {
updateIndex = index;
return (tab.fullPath || tab.path) === (fullPath || path);
return (
decodeURIComponent(tab.fullPath || tab.path) === decodeURIComponent(fullPath || path)
);
});
// If the tab already exists, perform the update operation
@@ -158,7 +160,7 @@ export const useMultipleTabStore = defineStore({
const realPath = meta?.realPath ?? '';
// 获取到已经打开的动态路由数, 判断是否大于某一个值
if (
this.tabList.filter((e) => e.meta?.realPath ?? '' === realPath).length >= dynamicLevel
this.tabList.filter((e) => (e.meta?.realPath ?? '') === realPath).length >= dynamicLevel
) {
// 关闭第一个
const index = this.tabList.findIndex((item) => item.meta.realPath === realPath);

View File

@@ -7,13 +7,14 @@ import { useUserStore } from './user';
import { useAppStoreWithOut } from './app';
import { toRaw } from 'vue';
import { transformObjToRoute, flatMultiLevelRoutes } from '@/router/helper/routeHelper';
import { transformRouteToMenu } from '@/router/helper/menuHelper';
import { transformRouteToMenu, transformMenuModules } from '@/router/helper/menuHelper';
import projectSetting from '@/settings/projectSetting';
import { PermissionModeEnum } from '@/enums/appEnum';
import { asyncRoutes } from '@/router/routes';
import { menuModules } from '@/router/menus';
import { ERROR_LOG_ROUTE, PAGE_NOT_FOUND_ROUTE } from '@/router/routes/basic';
import { filter } from '@/utils/helper/treeHelper';
@@ -39,6 +40,7 @@ interface PermissionState {
backMenuList: Menu[];
// 菜单列表
frontMenuList: Menu[];
staticMenuList: Menu[];
}
export const usePermissionStore = defineStore({
@@ -58,6 +60,7 @@ export const usePermissionStore = defineStore({
// menu List
// 菜单列表
frontMenuList: [],
staticMenuList: [],
}),
getters: {
getPermCodeList(state): string[] | number[] {
@@ -69,6 +72,9 @@ export const usePermissionStore = defineStore({
getFrontMenuList(state): Menu[] {
return state.frontMenuList;
},
getStaticMenuList(state): Menu[] {
return state.staticMenuList;
},
getLastBuildMenuTime(state): number {
return state.lastBuildMenuTime;
},
@@ -90,6 +96,10 @@ export const usePermissionStore = defineStore({
this.frontMenuList = list;
},
setStaticMenuList(list: Menu[]) {
this.staticMenuList = list;
},
setLastBuildMenuTime() {
this.lastBuildMenuTime = new Date().getTime();
},
@@ -171,6 +181,12 @@ export const usePermissionStore = defineStore({
switch (permissionMode) {
// 角色权限
case PermissionModeEnum.ROLE:
const staticMenuList = transformMenuModules(menuModules);
staticMenuList.sort((a, b) => {
return (a.orderNo || 0) - (b.orderNo || 0);
});
// 设置菜单列表
this.setStaticMenuList(staticMenuList);
// 对非一级路由进行过滤
routes = filter(asyncRoutes, routeFilter);
// 对一级路由根据角色权限过滤

View File

@@ -16,8 +16,6 @@ export class AxiosRetry {
return Promise.reject(error);
}
config.__retryCount += 1;
//请求返回后config的header不正确造成重试请求失败,删除返回headers采用默认headers
delete config.headers;
return this.delay(waitTime).then(() => axiosInstance(config));
}

View File

@@ -20,14 +20,19 @@ export function getPopupContainer(node?: HTMLElement): HTMLElement {
* @param obj
* @returns {string}
* eg:
* let obj = {a: '3', b: '4'}
* let obj = {a: '3', b: '4', c: ['1','2']}
* setObjToUrlParams('www.baidu.com', obj)
* ==>www.baidu.com?a=3&b=4
* ==>www.baidu.com?a=3&b=4&c=1,2
*/
export function setObjToUrlParams(baseUrl: string, obj: any): string {
let parameters = '';
for (const key in obj) {
parameters += key + '=' + encodeURIComponent(obj[key]) + '&';
const value = obj[key];
if (Array.isArray(value)) {
parameters += `${key}=${encodeURIComponent(value.join(','))}&`;
} else {
parameters += `${key}=${encodeURIComponent(value)}&`;
}
}
parameters = parameters.replace(/&$/, '');
return /\?$/.test(baseUrl) ? baseUrl + parameters : baseUrl.replace(/\/?$/, '?') + parameters;

View File

@@ -106,10 +106,14 @@
type: 'primary',
style: 'margin:4px',
onclick: () => {
handleAdd(
{ url6: 'https://vebn.oss-cn-beijing.aliyuncs.com/vben/logo.png' },
'url6',
);
handleAdd({
record: {
id6: new Date().getTime(),
url6: 'https://vebn.oss-cn-beijing.aliyuncs.com/vben/logo.png',
},
uidKey: 'id6',
valueKey: 'url6',
});
},
},
() => '点我新增',
@@ -119,7 +123,11 @@
{
danger: true,
onclick: () => {
handleRemove({ url6: record.url6 }, 'url6');
handleRemove({
record: { url6: record.url6 },
uidKey: 'url6',
valueKey: 'url6',
});
},
},
() => '点我删除',
@@ -133,14 +141,15 @@
let data = arg
.filter((item) => !!item)
.map((item) => {
if (typeof item !== 'string') {
console.error('return value should be string');
if (typeof item !== 'object') {
console.error('return value should be object');
return;
}
return {
url6: item,
type6: item.split('.').pop() || '',
name6: item.split('/').pop() || '',
uid: item?.uid,
url6: item?.url,
type6: item?.url?.split('.').pop() || '',
name6: item?.url?.split('/').pop() || '',
};
});
return data;

View File

@@ -0,0 +1,85 @@
<template>
<PageWrapper title="代码编辑器组件嵌入Form示例">
<CollapseContainer title="代码编辑器组件">
<BasicForm
:labelWidth="100"
:schemas="schemas"
:actionColOptions="{ span: 24 }"
:baseColProps="{ span: 24 }"
@submit="handleSubmit"
/>
</CollapseContainer>
</PageWrapper>
</template>
<script lang="ts" setup>
import { h } from 'vue';
import { BasicForm, FormSchema } from '@/components/Form';
import { CollapseContainer } from '@/components/Container';
import { useMessage } from '@/hooks/web/useMessage';
import { PageWrapper } from '@/components/Page';
import { CodeEditor, MODE } from '@/components/CodeEditor';
const schemas: FormSchema[] = [
{
field: 'title',
component: 'Input',
label: 'title',
defaultValue: '标题',
rules: [{ required: true }],
},
{
field: 'JSON',
component: 'Input',
label: 'JSON',
defaultValue: `{
"name":"BeJson",
"url":"http://www.xxx.com",
"page":88,
"isNonProfit":true,"
address:{
"street":"科技园路.",
"city":"江苏苏州",
"country":"中国"
},
}`,
rules: [{ required: true, trigger: 'blur' }],
render: ({ model, field }) => {
return h(CodeEditor, {
value: model[field],
mode: MODE.JSON,
onChange: (value: string) => {
model[field] = value;
},
config: {
tabSize: 10,
},
});
},
},
{
field: 'PYTHON',
component: 'Input',
label: 'PYTHON',
defaultValue: `def functionname( parameters ):
"函数_文档字符串"
function_suite
return [expression]`,
rules: [{ required: true, trigger: 'blur' }],
render: ({ model, field }) => {
return h(CodeEditor, {
value: model[field],
mode: MODE.PYTHON,
onChange: (value: string) => {
model[field] = value;
},
});
},
},
];
const { createMessage } = useMessage();
function handleSubmit(values: any) {
console.log('click search,values:', values);
createMessage.success('click search,values:' + JSON.stringify(values));
}
</script>

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