Merge remote-tracking branch 'vben/main' into Gf-Vben-Admin

# Conflicts:
#	.github/workflows/deploy.yml
#	.github/workflows/ftp-schedule.yml
#	src/views/sys/login/LoginForm.vue
This commit is contained in:
JinMao 2021-08-25 08:54:16 +08:00
commit c188d8398d
257 changed files with 3236 additions and 3035 deletions

View File

@ -25,6 +25,7 @@ module.exports = defineConfig({
'plugin:jest/recommended',
],
rules: {
'vue/script-setup-uses-vars': 'error',
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off',
@ -61,7 +62,6 @@ module.exports = defineConfig({
'vue/singleline-html-element-content-newline': 'off',
'vue/attribute-hyphenation': 'off',
'vue/require-default-prop': 'off',
'vue/script-setup-uses-vars': 'off',
'vue/html-self-closing': [
'error',
{

2
.vscode/launch.json vendored
View File

@ -8,6 +8,6 @@
"url": "http://localhost:3100",
"webRoot": "${workspaceFolder}/src",
"sourceMaps": true
},
}
]
}

View File

@ -117,6 +117,7 @@
"i18n-ally.pathMatcher": "{locale}/{namespaces}.{ext}",
"i18n-ally.enabledParsers": ["ts"],
"i18n-ally.sourceLanguage": "en",
"i18n-ally.displayLanguage": "zh-CN",
"i18n-ally.enabledFrameworks": ["vue", "react"],
"cSpell.words": [
"vben",

View File

@ -1,3 +1,27 @@
## 2.7.1(2021-08-16)
- Upgrade vue 3.2, if the operation fails, delete node_modules and reinstall it
### ✨ Features
- **BasicTree** Add search function related properties and methods
- **BasicForm** added `alwaysShowLines` to set the number of lines kept displayed when folding
### 🐛 Bug Fixes
- **Cropper** Fix the problem of failure to destroy in time
- **BasicTable**
- Fix the problem that `CellFormat` cannot use `Map` type data
- Fixed an issue where the editable cell failed to display the `0` value correctly
- Fixed the issue that selection-change event failed to trigger correctly when unchecked
- Fix the problem that the background color of the full screen state under the light theme is incorrect
- Fix the problem of obtaining complete data when `getSelectRows` does not support remote data cross-page selection
- Fix the issue that the `size` property provided for editing components in `editComponentProps` is invalid
- **Qrcode** Fixed the problem that the QR code component could not be drawn in time when it was created
- **BasicModal** Fix the problem that the `helpMessage` property does not work
- **BasicButton** Fix the problem that the button style performance is inconsistent with the official antd
- **Others** Fix the problem that `useRedo` (reload the current route) will lose route `params` data
## 2.7.0(2021-08-03)
## (Breaking changes) Breaking changes

View File

@ -1,3 +1,90 @@
## [2.7.1](https://github.com/anncwb/vue-vben-admin/compare/v2.6.1...v2.7.1) (2021-08-16)
### Bug Fixes
- `slots` working in components ([b1f3176](https://github.com/anncwb/vue-vben-admin/commit/b1f31762e3c86a432a8d559ab957444eaf5525ad))
- add axios error info from response ([#1083](https://github.com/anncwb/vue-vben-admin/issues/1083)) ([72634ff](https://github.com/anncwb/vue-vben-admin/commit/72634ffe6e6649d36ee41f7633c8ee2ab80cf25e))
- auto remove script dom in `useScript` ([a544dd3](https://github.com/anncwb/vue-vben-admin/commit/a544dd3e589329339177dad3d5c1f75dd6e6f0ca))
- fixed `useRedo` may loss route params ([2dd3d85](https://github.com/anncwb/vue-vben-admin/commit/2dd3d8544866231895d23dba63785b683ae0062e)), closes [#1079](https://github.com/anncwb/vue-vben-admin/issues/1079)
- fixed basicButton ghost style ([3ba8a67](https://github.com/anncwb/vue-vben-admin/commit/3ba8a67647d35fb9639a5af66f33d43eff493d15))
- fixed basicButton primary style ([1b57792](https://github.com/anncwb/vue-vben-admin/commit/1b577922e752c02fe7c033c53be37ef81e4e9b8e))
- fixed basicButton style ([beb4ae9](https://github.com/anncwb/vue-vben-admin/commit/beb4ae92c190780bbd3bc6bc7547d52e2ccf8cf1))
- **cropper:** cropper not destroy in time ([3819430](https://github.com/anncwb/vue-vben-admin/commit/381943078fd55123fde3d5555e04f279d7f1c407)), closes [#1027](https://github.com/anncwb/vue-vben-admin/issues/1027)
- **demo:** fix form style in modal ([30c5fc6](https://github.com/anncwb/vue-vben-admin/commit/30c5fc63c8600cfb03f917d79e56c0a7e7ff64e0)), closes [#1076](https://github.com/anncwb/vue-vben-admin/issues/1076)
- **i18n:** add i18n translate data ([1f55c41](https://github.com/anncwb/vue-vben-admin/commit/1f55c4180f9c0cf48e3796a77d6f0bfd46107272))
- **locales:** fix that vscode extension i18n-Ally detect zh-CN as zh ([#1044](https://github.com/anncwb/vue-vben-admin/issues/1044)) ([b2d49cb](https://github.com/anncwb/vue-vben-admin/commit/b2d49cbbf81cb15e75905deb95bdf7ac4af4e599))
- **modal:** `helpMessage` doesn't work ([953bfc6](https://github.com/anncwb/vue-vben-admin/commit/953bfc6f1a559309ea2b1114b8ede911a3751cc7))
- **page-wrapper:** fix `class` not working ([8879ae8](https://github.com/anncwb/vue-vben-admin/commit/8879ae8d773e8dc4c252c4234eefeab9bc135a30))
- **qrcode:** qrcode not displayed properly ([26f251e](https://github.com/anncwb/vue-vben-admin/commit/26f251e1ed5bfd79c8615fb552ca302f917cc588)), closes [#1026](https://github.com/anncwb/vue-vben-admin/issues/1026)
- **route:** the whitelist should include basicRoutes ([#1048](https://github.com/anncwb/vue-vben-admin/issues/1048)) ([1bb5156](https://github.com/anncwb/vue-vben-admin/commit/1bb51569236fd9bcc55dd9f237f51f218956b258))
- **table:** `0` is not shown in editable cell ([33a335a](https://github.com/anncwb/vue-vben-admin/commit/33a335a3f52aead522b3fbee0d558e2e797580ff)), closes [#1039](https://github.com/anncwb/vue-vben-admin/issues/1039)
- **table:** `cellFormat` support `Map` ([1214b7c](https://github.com/anncwb/vue-vben-admin/commit/1214b7c32c425750a4d0202a9b235eb9e45a6f47)), closes [#1031](https://github.com/anncwb/vue-vben-admin/issues/1031)
- **table:** `getSelectRows` support multi-page ([4b6025c](https://github.com/anncwb/vue-vben-admin/commit/4b6025cb9a3ef067680201ec3052bc651e0a0c1b)), closes [#914](https://github.com/anncwb/vue-vben-admin/issues/914)
- **table:** `selection-change` not triggered in unchecking ([019555b](https://github.com/anncwb/vue-vben-admin/commit/019555be0c88edc673cae382023d647e78959b30)), closes [#1053](https://github.com/anncwb/vue-vben-admin/issues/1053)
- **table:** `size` not worked in `editComponentProps` ([7971896](https://github.com/anncwb/vue-vben-admin/commit/7971896383296c155b7ab16b5beb3544f34ee525)), closes [#1074](https://github.com/anncwb/vue-vben-admin/issues/1074)
- **table:** fix `getSelectRows` for treeTable ([f2b8bb4](https://github.com/anncwb/vue-vben-admin/commit/f2b8bb43a0b9172b9ef9ced8e83bf91143a091d9)), closes [#1003](https://github.com/anncwb/vue-vben-admin/issues/1003)
- **table:** fix `injection not found` warning ([53e79a2](https://github.com/anncwb/vue-vben-admin/commit/53e79a2d94df19c0e1aa7399d5ce4c27834e0350))
- **types:** fix some type errors ([9035fd1](https://github.com/anncwb/vue-vben-admin/commit/9035fd191e4e8d954f42b3a4cd1e80ec70b7cbb6))
- The Style of tableTitle slot ([#1023](https://github.com/anncwb/vue-vben-admin/issues/1023)) ([02e7756](https://github.com/anncwb/vue-vben-admin/commit/02e77560624cc4a95a5a20ffd5e0601f1f88c6f4))
- fix build handler & misc ([#1060](https://github.com/anncwb/vue-vben-admin/issues/1060)) ([66feb77](https://github.com/anncwb/vue-vben-admin/commit/66feb779a8645a93760c784c510512118c4c6efa))
- **table:** recursive updateTableDataRecord ([#1024](https://github.com/anncwb/vue-vben-admin/issues/1024)) ([72f953c](https://github.com/anncwb/vue-vben-admin/commit/72f953c8d3413a7f5482793258503017a81cc759))
- **table:** wrong bg-color in fullscreen mode ([2052eb5](https://github.com/anncwb/vue-vben-admin/commit/2052eb5a65be38c44165efecdb15266de4638667))
- **type:** fix ant-design-vue -> ([#1043](https://github.com/anncwb/vue-vben-admin/issues/1043)) ([6d5388a](https://github.com/anncwb/vue-vben-admin/commit/6d5388aaf143ac76bac0b68d56a3ab6b5993e807))
- fix iframe heigth error ([#1012](https://github.com/anncwb/vue-vben-admin/issues/1012)) ([d76cfd7](https://github.com/anncwb/vue-vben-admin/commit/d76cfd7f809ba48880c950a64cb43a5c9c44176c))
- Fix the invalid hot update of BasicButton when changing style outside ([#1016](https://github.com/anncwb/vue-vben-admin/issues/1016)) ([be2d11d](https://github.com/anncwb/vue-vben-admin/commit/be2d11d5d344a508e94abe3534726c80e1f1f271))
- the position of tinymce upload image is wrong ([#1015](https://github.com/anncwb/vue-vben-admin/issues/1015)) ([2fd0fd2](https://github.com/anncwb/vue-vben-admin/commit/2fd0fd281e65d6d2551478c5f19250347dc14062))
- **tree:** fix `checkAll` effects `disabled` node ([ddd1893](https://github.com/anncwb/vue-vben-admin/commit/ddd1893b113e13786037522341abb2e75f8f9d5b))
- style property of actionColOpt is invalid ([#997](https://github.com/anncwb/vue-vben-admin/issues/997)) ([225bd4c](https://github.com/anncwb/vue-vben-admin/commit/225bd4c39de377d93c605f33bfdf3d8fd565f12b))
- typo ([#980](https://github.com/anncwb/vue-vben-admin/issues/980)) ([7e6a89f](https://github.com/anncwb/vue-vben-admin/commit/7e6a89ffeb8c63467908d5807d3d7c4761620ee3))
- **api-tree-select:** auto reload while `params` changed ([c734f68](https://github.com/anncwb/vue-vben-admin/commit/c734f6858daea6d11cd517463b06fcce58744947))
- **dark-theme:** alert color in dark-theme ([9b7ede0](https://github.com/anncwb/vue-vben-admin/commit/9b7ede09b9efe4d5a15ab0cdeadac480a29c0f62))
- **dark-theme:** bgcolor of `selected tree node` in dark theme ([8cf004a](https://github.com/anncwb/vue-vben-admin/commit/8cf004a5f59895e2487c3a350c83000e585b897e)), closes [#949](https://github.com/anncwb/vue-vben-admin/issues/949)
- **dark-theme:** disabled link `button` color ([4281216](https://github.com/anncwb/vue-vben-admin/commit/42812162c46832ce4d3e332bd579c042309115bc))
- **dark-theme:** fixed `TreeSelect` & `DatePicker` theme ([d1e0e8b](https://github.com/anncwb/vue-vben-admin/commit/d1e0e8bcea1c168631222989969e14f7d0d1b6a4)), closes [#955](https://github.com/anncwb/vue-vben-admin/issues/955)
- **dark-theme:** style for checked tree nodes ([662b576](https://github.com/anncwb/vue-vben-admin/commit/662b576ac2088247cb58e295378f228462508a37))
- **demo:** account page form validation ([8702965](https://github.com/anncwb/vue-vben-admin/commit/87029650570e470431fb94d35a273c5d07a73135))
- **demo:** fix roles mock data ([c375e32](https://github.com/anncwb/vue-vben-admin/commit/c375e32305eae5128e09ad1bda39ce0cc6afd790))
- **form:** remove console error for `setFieldsValue` ([8d185bb](https://github.com/anncwb/vue-vben-admin/commit/8d185bb5841c83eb49c78e8342e65067aa6f9b80)), closes [#952](https://github.com/anncwb/vue-vben-admin/issues/952)
- **table:** fix `pagination` props working ([e327893](https://github.com/anncwb/vue-vben-admin/commit/e32789373eb5b1b531572b59692bf552dac365dc))
- expandIcon slot of BasicTable component is invalid ([#975](https://github.com/anncwb/vue-vben-admin/issues/975)) ([98c206d](https://github.com/anncwb/vue-vben-admin/commit/98c206d9c9661a18dde4ec7782cbe1eb6e62ebeb))
- **demo:** menu `error-log` link to 404 page ([341bd63](https://github.com/anncwb/vue-vben-admin/commit/341bd633d8ed38a5a357db8f97166c2eba2895d3))
- **demo:** multi-modal used with dynamic component ([e1c4723](https://github.com/anncwb/vue-vben-admin/commit/e1c47233edf7675aede6d5f023726945a510ddf7))
- **echarts:** fix graphic config cannot be used in echarts options ([#959](https://github.com/anncwb/vue-vben-admin/issues/959)) ([525484e](https://github.com/anncwb/vue-vben-admin/commit/525484e7a409b032d22231f90a92e700ef4290ae))
- **form:** fix `validate` promise catch ([571f281](https://github.com/anncwb/vue-vben-admin/commit/571f28138f782553eb39cda2d632e5ac1aa1e145))
- **img-rotate-drag-verify:** fix `resume` method support ([32d64db](https://github.com/anncwb/vue-vben-admin/commit/32d64dbe816a0afda6ee9e91863199afb3e7b48e)), closes [#946](https://github.com/anncwb/vue-vben-admin/issues/946)
- **login:** fix `auto fill` style in dark-theme ([cebc6a5](https://github.com/anncwb/vue-vben-admin/commit/cebc6a590e1a19af7380a55aed43b23af274df0a))
- **perm-guard:** Fix the problem that the routing query is lost after refreshing the page ([#941](https://github.com/anncwb/vue-vben-admin/issues/941)) ([9c4889f](https://github.com/anncwb/vue-vben-admin/commit/9c4889f0859bc60decf0ef40c383c1946de1d68a))
- **qrcode:** Fix the problem that the QR code cannot be dynamically generated ([#974](https://github.com/anncwb/vue-vben-admin/issues/974)) ([fe4eae3](https://github.com/anncwb/vue-vben-admin/commit/fe4eae37146068f01ba08f033e0c2e8bd03e48b5))
- **style:** fix checkbox-checked css in dark mode ([d3f08e3](https://github.com/anncwb/vue-vben-admin/commit/d3f08e37c5b6e46f33d525e9ef4b4c235d77a192))
- **table:** component shown in `fullscreen` mode ([a07ab6d](https://github.com/anncwb/vue-vben-admin/commit/a07ab6d7aa1060f856649a9bdbec9dfa50b14f26))
- **table:** editable cell display with validation ([202aa42](https://github.com/anncwb/vue-vben-admin/commit/202aa42b8d5a94e84ad386bcf7feab96926c70dd)), closes [#953](https://github.com/anncwb/vue-vben-admin/issues/953)
- **table:** fix `dataPicker` show in `fullscreen` mode ([a5a9b3f](https://github.com/anncwb/vue-vben-admin/commit/a5a9b3fb34c64b6ea9c9ab3d58045f6e5963952b))
- **table:** fix expand style ([14fb21d](https://github.com/anncwb/vue-vben-admin/commit/14fb21d0b7b9ac69c7b3c463de6d709bd5713d14)), closes [#969](https://github.com/anncwb/vue-vben-admin/issues/969)
- **table:** fix tableSettings popup in fullscreen mode ([dce3fb0](https://github.com/anncwb/vue-vben-admin/commit/dce3fb0f20516aaf4817281f5d08109e53a73ecb))
- **table-action:** stopButtonPropagation not working ([9b8f165](https://github.com/anncwb/vue-vben-admin/commit/9b8f165a365758d001e6d86ae7afe4ae3316d485))
- Fix vite profile hot update error reporting ([#968](https://github.com/anncwb/vue-vben-admin/issues/968)) ([956ed2e](https://github.com/anncwb/vue-vben-admin/commit/956ed2e3f770cc9cf822ce80f71b1e7f179792fb))
- **utils:** The date function gets a non-date when the parameter is null ([#954](https://github.com/anncwb/vue-vben-admin/issues/954)) ([350c85a](https://github.com/anncwb/vue-vben-admin/commit/350c85accf5033cc5a21b71bc36d5b7a74eb2573))
- fixed moment locale config ([27207a7](https://github.com/anncwb/vue-vben-admin/commit/27207a78caccb04372e0275c5cee526ec460de0e))
- typo for utils/env ([#1004](https://github.com/anncwb/vue-vben-admin/issues/1004)) ([e8eefd1](https://github.com/anncwb/vue-vben-admin/commit/e8eefd1bca41c181ec6395bf1d087d2018e2b1f1))
- **table:** fix editable cell not support `ellipsis` ([4bb506f](https://github.com/anncwb/vue-vben-admin/commit/4bb506fb1f6ac7d246f8792d29f337ec003ff426)), closes [#944](https://github.com/anncwb/vue-vben-admin/issues/944)
### Features
- add `updatePath` for `useTabs` ([bcfa338](https://github.com/anncwb/vue-vben-admin/commit/bcfa33822736b761757a2673d977f752cb5c4f7c)), closes [#1068](https://github.com/anncwb/vue-vben-admin/issues/1068)
- always refresh userinfo when page reload ([cc46935](https://github.com/anncwb/vue-vben-admin/commit/cc46935a8296dae62ecfc753a956338ba433927e))
- **demo:** add `async-validator` demo ([8b4b767](https://github.com/anncwb/vue-vben-admin/commit/8b4b767f4ca78f7c6f7586d8ba662552c2b7bb51))
- **form:** add `alwaysShowLines` prop ([93f9a19](https://github.com/anncwb/vue-vben-admin/commit/93f9a19aa16a3e9cb95338417c52d9a398e3f70b)), closes [#1051](https://github.com/anncwb/vue-vben-admin/issues/1051)
- **preview:** add more features ([e23bd26](https://github.com/anncwb/vue-vben-admin/commit/e23bd2696da945291a9b652f1af39ad1936f376b))
- **table:** add getRawDataSource() function ([#1029](https://github.com/anncwb/vue-vben-admin/issues/1029)) ([f3cf162](https://github.com/anncwb/vue-vben-admin/commit/f3cf162af1fa5634d4e562fa5239939af6f26093))
- **tree:** add searchable function ([60577d6](https://github.com/anncwb/vue-vben-admin/commit/60577d6720fd3f8d4d1a88b20ab902d6161a0eec)), closes [#1057](https://github.com/anncwb/vue-vben-admin/issues/1057)
- **use-loading:** add `setTip` method ([26d9476](https://github.com/anncwb/vue-vben-admin/commit/26d9476caff41cc355190604af42e0bd2ef0a353))
- Added support for tailwindcss night mode mechanism ([#998](https://github.com/anncwb/vue-vben-admin/issues/998)) ([189bc6f](https://github.com/anncwb/vue-vben-admin/commit/189bc6feb3f2860be8c531dd1ca996f3a2cff018))
### Performance Improvements
- **table:** fixed code style ([da12da9](https://github.com/anncwb/vue-vben-admin/commit/da12da9d8caeba0e7732551cfbad9b0da3baaac4)), closes [#1070](https://github.com/anncwb/vue-vben-admin/issues/1070)
- improve legacy compatibility ([e2664f6](https://github.com/anncwb/vue-vben-admin/commit/e2664f60029f03642f8b1a6afa9b1998705fce37))
# [2.7.0](https://github.com/anncwb/vue-vben-admin/compare/v2.5.9...v2.7.0) (2021-08-03)
### Bug Fixes

View File

@ -1,8 +1,45 @@
### ✨ Features
- **BasicForm** 表单组件新增`Divider`,用于较长表单的区域分割
- **BasicTable** 单元格编辑新增提交回调,将根据回调函数返回的结果来决定是否将数据提交到表格
### 🐛 Bug Fixes
- **CodeEditor** 修复 JSON 编辑器在格式化无效 JSON 文本时会抛出异常的问题
- **Tinymce** 修复 inline 模式在一些场景下会出现异常的问题
- **BasicTable**
- 修复可编辑单元格的内容为空时,不会显示编辑图标的问题
- 修复表尾合计行与表格主体部分的列有时候未能对齐的问题
- **其它**
- 修复部分封装组件在使用插槽时报错的问题
- 修复`useECharts`的`theme`参数不起作用的问题
- 修复`Token`失效时,按 F5 刷新页面可能会出现页面加载异常的问题
- 修复`useRedo`的不当调用可能会导致重定向`path`异常的问题
- 修复`vite`自定义模式名称不支持下划线的问题
## 2.7.1(2021-08-16)
- 升级 vue 3.2,如果运行失败,删除 node_modules 后重装即可
### ✨ Features
- **BasicTree** 添加搜索功能相关属性和方法
- **BasicForm** 新增`alwaysShowLines`用于设置折叠时保留显示的行数
### 🐛 Bug Fixes
- **Cropper** 修复未能及时销毁的问题
- **BasicTable** 修复`CellFormat`无法使用`Map`类型数据的问题
- **BasicTable**
- 修复`CellFormat`无法使用`Map`类型数据的问题
- 修复可编辑单元格未能正确显示`0`值的问题
- 修复 selection-change 事件在取消勾选时未能正确触发的问题
- 修复浅色主题下的全屏状态背景颜色不正确的问题
- 修复`getSelectRows`不支持远程数据跨页选择时获取完整数据的问题
- 修复在`editComponentProps`中为编辑组件提供的`size`属性无效的问题
- **Qrcode** 修复二维码组件在创建时未能及时绘制的问题
- **BasicModal** 修复`helpMessage`属性不起作用的问题
- **BasicButton** 修复按钮样式表现与 antd 官方不一致的问题
- **其它** 修复`useRedo`(重新加载当前路由)会丢失路由`params`数据的问题
## 2.7.0(2021-08-03)

View File

@ -150,6 +150,7 @@ yarn build
## 后台整合示例
- [lamp-cloud](https://github.com/zuihou/lamp-cloud) - 基于 SpringCloud Alibaba 的微服务中后台快速开发平台
- [matecloud](https://github.com/matevip/matecloud) - MateCloud 微服务脚手架,基于 Spring Cloud 2020.0.3、SpringBoot 2.5.3 的全开源平台
## 维护者

View File

@ -28,7 +28,7 @@ export function generateModifyVars(dark = false) {
'success-color': '#55D187', // Success color
'error-color': '#ED6F6F', // False color
'warning-color': '#EFBD47', // Warning color
'border-color-base': '#EEEEEE',
//'border-color-base': '#EEEEEE',
'font-size-base': '14px', // Main font size
'border-radius-base': '2px', // Component/float fillet
'link-color': primary, // Link color

View File

@ -52,19 +52,19 @@ async function generateIcon() {
const { prefix } = data;
const isLocal = useType === 'local';
const icons = Object.keys(data.icons).map(
(item) => `${isLocal ? prefix + ':' : ''}${item}`
(item) => `${isLocal ? prefix + ':' : ''}${item}`,
);
await fs.writeFileSync(
path.join(output, `icons.data.ts`),
`export default ${isLocal ? JSON.stringify(icons) : JSON.stringify({ prefix, icons })}`
`export default ${isLocal ? JSON.stringify(icons) : JSON.stringify({ prefix, icons })}`,
);
prefixSet.push(prefix);
}
}
fs.emptyDir(path.join(process.cwd(), 'node_modules/.vite'));
console.log(
`${chalk.cyan(`[${pkg.name}]`)}` + ' - Icon generated successfully:' + `[${prefixSet}]`
`${chalk.cyan(`[${pkg.name}]`)}` + ' - Icon generated successfully:' + `[${prefixSet}]`,
);
});
}

View File

@ -15,7 +15,7 @@ function createConfig(
configName,
config,
configFileName = GLOB_CONFIG_FILE_NAME,
}: { configName: string; config: any; configFileName?: string } = { configName: '', config: {} }
}: { configName: string; config: any; configFileName?: string } = { configName: '', config: {} },
) {
try {
const windowConf = `window.${configName}`;

View File

@ -11,7 +11,7 @@ export const runBuild = async () => {
// Generate configuration file
if (!argvList.includes('disabled-config')) {
await runBuildConfig();
runBuildConfig();
}
console.log(`${chalk.cyan(`[${pkg.name}]`)}` + ' - build successfully!');

View File

@ -31,7 +31,9 @@ export function wrapperEnv(envConf: Recordable): ViteEnv {
if (envName === 'VITE_PROXY') {
try {
realName = JSON.parse(realName);
} catch (error) {}
} catch (error) {
realName = '';
}
}
ret[envName] = realName;
if (typeof realName === 'string') {
@ -48,7 +50,7 @@ export function wrapperEnv(envConf: Recordable): ViteEnv {
*/
function getConfFiles() {
const script = process.env.npm_lifecycle_script;
const reg = new RegExp('--mode ([a-z]+)');
const reg = new RegExp('--mode ([a-z_\\d]+)');
const result = reg.exec(script as string) as any;
if (result) {
const mode = result[1] as string;

View File

@ -3,12 +3,11 @@
* https://github.com/anncwb/vite-plugin-compression
*/
import type { Plugin } from 'vite';
import compressPlugin from 'vite-plugin-compression';
export function configCompressPlugin(
compress: 'gzip' | 'brotli' | 'none',
deleteOriginFile = false
deleteOriginFile = false,
): Plugin | Plugin[] {
const compressList = compress.split(',');
@ -19,16 +18,17 @@ export function configCompressPlugin(
compressPlugin({
ext: '.gz',
deleteOriginFile,
})
}),
);
}
if (compressList.includes('brotli')) {
plugins.push(
compressPlugin({
ext: '.br',
algorithm: 'brotliCompress',
deleteOriginFile,
})
}),
);
}
return plugins;

View File

@ -3,9 +3,7 @@
* https://github.com/anncwb/vite-plugin-html
*/
import type { Plugin } from 'vite';
import html from 'vite-plugin-html';
import pkg from '../../../package.json';
import { GLOB_CONFIG_FILE_NAME } from '../../constant';
@ -22,7 +20,7 @@ export function configHtmlPlugin(env: ViteEnv, isBuild: boolean) {
minify: isBuild,
inject: {
// Inject data into ejs template
injectData: {
data: {
title: VITE_GLOB_APP_TITLE,
},
// Embed the generated app.config.js file

View File

@ -1,6 +1,5 @@
// Image resource files used to compress the output of the production environment
// https://github.com/anncwb/vite-plugin-imagemin
import viteImagemin from 'vite-plugin-imagemin';
export function configImageminPlugin() {

View File

@ -1,9 +1,7 @@
import type { Plugin } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import legacy from '@vitejs/plugin-legacy';
import purgeIcons from 'vite-plugin-purge-icons';
import windiCSS from 'vite-plugin-windicss';
import { configHtmlPlugin } from './html';
@ -70,7 +68,7 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
// rollup-plugin-gzip
vitePlugins.push(
configCompressPlugin(VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE)
configCompressPlugin(VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE),
);
// vite-plugin-pwa

View File

@ -2,7 +2,6 @@
* Zero-config PWA for Vite
* https://github.com/antfu/vite-plugin-pwa
*/
import { VitePWA } from 'vite-plugin-pwa';
export function configPwaConfig(env: ViteEnv) {

View File

@ -2,11 +2,12 @@
* Introduces component library styles on demand.
* https://github.com/anncwb/vite-plugin-style-import
*/
import styleImport from 'vite-plugin-style-import';
export function configStyleImportPlugin(isBuild: boolean) {
if (!isBuild) return [];
if (!isBuild) {
return [];
}
const styleImportPlugin = styleImport({
libs: [
{

View File

@ -35,6 +35,11 @@ export function configThemePlugin(isBuild: boolean): Plugin[] {
return s;
case '.ant-select-item-option-selected:not(.ant-select-item-option-disabled)':
return s;
default:
if (s.indexOf('.ant-btn') >= -1) {
// 按钮被重新定制过需要过滤掉class防止覆盖
return s;
}
}
return s.startsWith('[data-theme') ? s : `[data-theme] ${s}`;
},

View File

@ -13,7 +13,7 @@ export function resultPageSuccess<T = any>(
page: number,
pageSize: number,
list: T[],
{ message = 'ok' } = {}
{ message = 'ok' } = {},
) {
const pageData = pagination(page, pageSize, list);

View File

@ -52,7 +52,7 @@ export default [
response: ({ body }) => {
const { username, password } = body;
const checkUser = createFakeUserList().find(
(item) => item.username === username && password === item.password
(item) => item.username === username && password === item.password,
);
if (!checkUser) {
return resultError('Incorrect account or password');

View File

@ -1,6 +1,6 @@
{
"name": "vben-admin",
"version": "2.7.0",
"version": "2.7.1",
"author": {
"name": "vben",
"email": "anncwb@126.com",
@ -34,14 +34,14 @@
"gen:icon": "esno ./build/generate/icon/index.ts"
},
"dependencies": {
"@iconify/iconify": "^2.0.3",
"@logicflow/core": "^0.6.6",
"@logicflow/extension": "^0.6.6",
"@vueuse/core": "^5.2.0",
"@iconify/iconify": "^2.0.4",
"@logicflow/core": "^0.6.15",
"@logicflow/extension": "^0.6.15",
"@vueuse/core": "^6.0.0",
"@zxcvbn-ts/core": "^1.0.0-beta.0",
"ant-design-vue": "2.2.2",
"ant-design-vue": "2.2.6",
"axios": "^0.21.1",
"codemirror": "^5.62.2",
"codemirror": "^5.62.3",
"cropperjs": "^1.5.12",
"crypto-js": "^4.1.1",
"echarts": "^5.1.2",
@ -50,46 +50,46 @@
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"path-to-regexp": "^6.2.0",
"pinia": "2.0.0-beta.5",
"pinia": "2.0.0-rc.6",
"print-js": "^1.6.0",
"qrcode": "^1.4.4",
"resize-observer-polyfill": "^1.5.1",
"sortablejs": "^1.14.0",
"tinymce": "^5.8.2",
"vditor": "^3.8.6",
"vue": "3.1.5",
"vue": "3.2.4",
"vue-i18n": "9.1.7",
"vue-json-pretty": "^2.0.2",
"vue-router": "^4.0.10",
"vue-types": "^4.0.1",
"xlsx": "^0.17.0"
"vue-router": "^4.0.11",
"vue-types": "^4.0.3",
"xlsx": "^0.17.1",
"vue-json-pretty": "1.8.1"
},
"devDependencies": {
"@commitlint/cli": "^13.1.0",
"@commitlint/config-conventional": "^13.1.0",
"@iconify/json": "^1.1.382",
"@iconify/json": "^1.1.392",
"@purge-icons/generated": "^0.7.0",
"@types/codemirror": "^5.60.2",
"@types/crypto-js": "^4.0.2",
"@types/fs-extra": "^9.0.12",
"@types/inquirer": "^7.3.3",
"@types/intro.js": "^3.0.2",
"@types/jest": "^26.0.24",
"@types/jest": "^27.0.1",
"@types/lodash-es": "^4.17.4",
"@types/mockjs": "^1.0.4",
"@types/node": "^16.4.10",
"@types/node": "^16.7.1",
"@types/nprogress": "^0.2.0",
"@types/qrcode": "^1.4.1",
"@types/qs": "^6.9.7",
"@types/sortablejs": "^1.10.7",
"@typescript-eslint/eslint-plugin": "^4.29.0",
"@typescript-eslint/parser": "^4.29.0",
"@vitejs/plugin-legacy": "^1.5.0",
"@vitejs/plugin-vue": "^1.3.0",
"@typescript-eslint/eslint-plugin": "^4.29.3",
"@typescript-eslint/parser": "^4.29.3",
"@vitejs/plugin-legacy": "^1.5.1",
"@vitejs/plugin-vue": "^1.4.0",
"@vitejs/plugin-vue-jsx": "^1.1.7",
"@vue/compiler-sfc": "3.1.5",
"@vue/compiler-sfc": "3.2.4",
"@vue/test-utils": "^2.0.0-rc.12",
"autoprefixer": "^10.3.1",
"autoprefixer": "^10.3.2",
"commitizen": "^4.2.4",
"conventional-changelog-cli": "^2.1.1",
"cross-env": "^7.0.3",
@ -98,17 +98,17 @@
"eslint-config-prettier": "^8.3.0",
"eslint-define-config": "^1.0.9",
"eslint-plugin-jest": "^24.4.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-vue": "^7.15.0",
"esno": "^0.8.0",
"eslint-plugin-prettier": "^3.4.1",
"eslint-plugin-vue": "^7.16.0",
"esno": "^0.9.1",
"fs-extra": "^10.0.0",
"http-server": "^0.12.3",
"http-server": "^13.0.1",
"husky": "^7.0.1",
"inquirer": "^8.1.2",
"is-ci": "^3.0.0",
"jest": "^27.0.6",
"less": "^4.1.1",
"lint-staged": "^11.1.1",
"lint-staged": "^11.1.2",
"npm-run-all": "^4.1.5",
"postcss": "^8.3.6",
"prettier": "^2.3.2",
@ -119,27 +119,27 @@
"stylelint-config-prettier": "^8.0.2",
"stylelint-config-standard": "^22.0.0",
"stylelint-order": "^4.1.0",
"ts-jest": "^27.0.4",
"ts-node": "^10.1.0",
"ts-jest": "^27.0.5",
"ts-node": "^10.2.1",
"typescript": "4.3.5",
"vite": "2.4.4",
"vite-plugin-compression": "^0.3.3",
"vite-plugin-html": "^2.0.7",
"vite-plugin-imagemin": "^0.4.3",
"vite-plugin-mock": "^2.9.4",
"vite": "2.5.0",
"vite-plugin-compression": "^0.3.5",
"vite-plugin-html": "^2.1.0",
"vite-plugin-imagemin": "^0.4.5",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-purge-icons": "^0.7.0",
"vite-plugin-pwa": "^0.9.3",
"vite-plugin-style-import": "^1.1.0",
"vite-plugin-svg-icons": "^1.0.3",
"vite-plugin-pwa": "^0.11.0",
"vite-plugin-style-import": "^1.2.1",
"vite-plugin-svg-icons": "^1.0.4",
"vite-plugin-theme": "^0.8.1",
"vite-plugin-windicss": "^1.2.7",
"vite-plugin-windicss": "^1.2.8",
"vue-eslint-parser": "^7.10.0",
"vue-tsc": "^0.2.2"
"vue-tsc": "^0.3.0"
},
"resolutions": {
"//": "Used to install imagemin dependencies, because imagemin may not be installed in China. If it is abroad, you can delete it",
"bin-wrapper": "npm:bin-wrapper-china",
"rollup": "^2.55.1"
"rollup": "^2.56.3"
},
"repository": {
"type": "git",

View File

@ -7,7 +7,7 @@ module.exports = {
singleQuote: true,
quoteProps: 'as-needed',
bracketSpacing: true,
trailingComma: 'es5',
trailingComma: 'all',
jsxBracketSameLine: false,
jsxSingleQuote: false,
arrowParens: 'always',
@ -16,5 +16,4 @@ module.exports = {
proseWrap: 'never',
htmlWhitespaceSensitivity: 'strict',
endOfLine: 'auto',
rangeStart: 0,
};

View File

@ -6,23 +6,15 @@
</ConfigProvider>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
<script lang="ts" setup>
import { ConfigProvider } from 'ant-design-vue';
import { AppProvider } from '/@/components/Application';
import { useTitle } from '/@/hooks/web/useTitle';
import { useLocale } from '/@/locales/useLocale';
export default defineComponent({
name: 'App',
components: { ConfigProvider, AppProvider },
setup() {
useTitle();
// support Multi-language
const { getAntdLocale } = useLocale();
// support Multi-language
const { getAntdLocale } = useLocale();
return { getAntdLocale };
},
});
// Listening to page changes and dynamically changing site titles
useTitle();
</script>

View File

@ -10,13 +10,13 @@ const { uploadUrl = '' } = useGlobSetting();
*/
export function uploadApi(
params: UploadFileParams,
onUploadProgress: (progressEvent: ProgressEvent) => void
onUploadProgress: (progressEvent: ProgressEvent) => void,
) {
return defHttp.uploadFile<UploadApiResult>(
{
url: uploadUrl,
onUploadProgress,
},
params
params,
);
}

View File

@ -22,7 +22,7 @@ export function loginApi(params: LoginParams, mode: ErrorMessageMode = 'modal')
},
{
errorMessageMode: mode,
}
},
);
}

View File

@ -1,12 +1,12 @@
<template>
<div v-if="getShowDarkModeToggle" :class="getClass" @click="toggleDarkMode">
<div :class="`${prefixCls}-inner`"> </div>
<div :class="`${prefixCls}-inner`"></div>
<SvgIcon size="14" name="sun" />
<SvgIcon size="14" name="moon" />
</div>
</template>
<script lang="ts">
import { defineComponent, computed, unref } from 'vue';
<script lang="ts" setup>
import { computed, unref } from 'vue';
import { SvgIcon } from '/@/components/Icon';
import { useDesign } from '/@/hooks/web/useDesign';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
@ -14,39 +14,25 @@
import { updateDarkTheme } from '/@/logics/theme/dark';
import { ThemeEnum } from '/@/enums/appEnum';
export default defineComponent({
name: 'DarkModeToggle',
components: { SvgIcon },
setup() {
const { prefixCls } = useDesign('dark-switch');
const { getDarkMode, setDarkMode, getShowDarkModeToggle } = useRootSetting();
const { prefixCls } = useDesign('dark-switch');
const { getDarkMode, setDarkMode, getShowDarkModeToggle } = useRootSetting();
const isDark = computed(() => getDarkMode.value === ThemeEnum.DARK);
const isDark = computed(() => getDarkMode.value === ThemeEnum.DARK);
const getClass = computed(() => [
prefixCls,
{
[`${prefixCls}--dark`]: unref(isDark),
},
]);
function toggleDarkMode() {
const darkMode = getDarkMode.value === ThemeEnum.DARK ? ThemeEnum.LIGHT : ThemeEnum.DARK;
setDarkMode(darkMode);
updateDarkTheme(darkMode);
updateHeaderBgColor();
updateSidebarBgColor();
}
return {
getClass,
isDark,
prefixCls,
toggleDarkMode,
getShowDarkModeToggle,
};
const getClass = computed(() => [
prefixCls,
{
[`${prefixCls}--dark`]: unref(isDark),
},
});
]);
function toggleDarkMode() {
const darkMode = getDarkMode.value === ThemeEnum.DARK ? ThemeEnum.LIGHT : ThemeEnum.DARK;
setDarkMode(darkMode);
updateDarkTheme(darkMode);
updateHeaderBgColor();
updateSidebarBgColor();
}
</script>
<style lang="less" scoped>
@prefix-cls: ~'@{namespace}-dark-switch';

View File

@ -17,16 +17,16 @@
</span>
</Dropdown>
</template>
<script lang="ts">
<script lang="ts" setup>
import type { LocaleType } from '/#/config';
import type { DropMenu } from '/@/components/Dropdown';
import { defineComponent, ref, watchEffect, unref, computed } from 'vue';
import { ref, watchEffect, unref, computed } from 'vue';
import { Dropdown } from '/@/components/Dropdown';
import { Icon } from '/@/components/Icon';
import { useLocale } from '/@/locales/useLocale';
import { localeList } from '/@/settings/localeSetting';
const props = {
const props = defineProps({
/**
* Whether to display text
*/
@ -35,45 +35,36 @@
* Whether to refresh the interface when changing
*/
reload: { type: Boolean },
};
export default defineComponent({
name: 'AppLocalPicker',
components: { Dropdown, Icon },
props,
setup(props) {
const selectedKeys = ref<string[]>([]);
const { changeLocale, getLocale } = useLocale();
const getLocaleText = computed(() => {
const key = selectedKeys.value[0];
if (!key) {
return '';
}
return localeList.find((item) => item.event === key)?.text;
});
watchEffect(() => {
selectedKeys.value = [unref(getLocale)];
});
async function toggleLocale(lang: LocaleType | string) {
await changeLocale(lang as LocaleType);
selectedKeys.value = [lang as string];
props.reload && location.reload();
}
function handleMenuEvent(menu: DropMenu) {
if (unref(getLocale) === menu.event) {
return;
}
toggleLocale(menu.event as string);
}
return { localeList, handleMenuEvent, selectedKeys, getLocaleText };
},
});
const selectedKeys = ref<string[]>([]);
const { changeLocale, getLocale } = useLocale();
const getLocaleText = computed(() => {
const key = selectedKeys.value[0];
if (!key) {
return '';
}
return localeList.find((item) => item.event === key)?.text;
});
watchEffect(() => {
selectedKeys.value = [unref(getLocale)];
});
async function toggleLocale(lang: LocaleType | string) {
await changeLocale(lang as LocaleType);
selectedKeys.value = [lang as string];
props.reload && location.reload();
}
function handleMenuEvent(menu: DropMenu) {
if (unref(getLocale) === menu.event) {
return;
}
toggleLocale(menu.event as string);
}
</script>
<style lang="less">

View File

@ -10,8 +10,8 @@
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, computed, unref } from 'vue';
<script lang="ts" setup>
import { computed, unref } from 'vue';
import { useGlobSetting } from '/@/hooks/setting';
import { useGo } from '/@/hooks/web/usePage';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
@ -19,11 +19,11 @@
import { PageEnum } from '/@/enums/pageEnum';
import { useUserStore } from '/@/store/modules/user';
const props = {
const props = defineProps({
/**
* The theme of the current parent component
*/
theme: { type: String, validator: (v) => ['light', 'dark'].includes(v) },
theme: { type: String, validator: (v: string) => ['light', 'dark'].includes(v) },
/**
* Whether to show title
*/
@ -32,45 +32,30 @@
* The title is also displayed when the menu is collapsed
*/
alwaysShowTitle: { type: Boolean },
};
export default defineComponent({
name: 'AppLogo',
props: props,
setup(props) {
const { prefixCls } = useDesign('app-logo');
const { getCollapsedShowTitle } = useMenuSetting();
const userStore = useUserStore();
const { title } = useGlobSetting();
const go = useGo();
const getAppLogoClass = computed(() => [
prefixCls,
props.theme,
{ 'collapsed-show-title': unref(getCollapsedShowTitle) },
]);
const getTitleClass = computed(() => [
`${prefixCls}__title`,
{
'xs:opacity-0': !props.alwaysShowTitle,
},
]);
function goHome() {
go(userStore.getUserInfo.homePath || PageEnum.BASE_HOME);
}
return {
getAppLogoClass,
getTitleClass,
getCollapsedShowTitle,
goHome,
title,
prefixCls,
};
},
});
const { prefixCls } = useDesign('app-logo');
const { getCollapsedShowTitle } = useMenuSetting();
const userStore = useUserStore();
const { title } = useGlobSetting();
const go = useGo();
const getAppLogoClass = computed(() => [
prefixCls,
props.theme,
{ 'collapsed-show-title': unref(getCollapsedShowTitle) },
]);
const getTitleClass = computed(() => [
`${prefixCls}__title`,
{
'xs:opacity-0': !props.alwaysShowTitle,
},
]);
function goHome() {
go(userStore.getUserInfo.homePath || PageEnum.BASE_HOME);
}
</script>
<style lang="less" scoped>
@prefix-cls: ~'@{namespace}-app-logo';

View File

@ -10,20 +10,12 @@
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
<script lang="ts" setup>
import AppSearchKeyItem from './AppSearchKeyItem.vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { useI18n } from '/@/hooks/web/useI18n';
export default defineComponent({
name: 'AppSearchFooter',
components: { AppSearchKeyItem },
setup() {
const { prefixCls } = useDesign('app-search-footer');
const { t } = useI18n();
return { prefixCls, t };
},
});
const { prefixCls } = useDesign('app-search-footer');
const { t } = useI18n();
</script>
<style lang="less" scoped>
@prefix-cls: ~'@{namespace}-app-search-footer';

View File

@ -3,11 +3,9 @@
<Icon :icon="icon" />
</span>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
<script lang="ts" setup>
import { Icon } from '/@/components/Icon';
export default defineComponent({
components: { Icon },
props: { icon: String },
defineProps({
icon: String,
});
</script>

View File

@ -56,85 +56,62 @@
</transition>
</Teleport>
</template>
<script lang="ts">
import { defineComponent, computed, unref, ref, watch, nextTick } from 'vue';
<script lang="ts" setup>
import { computed, unref, ref, watch, nextTick } from 'vue';
import { SearchOutlined } from '@ant-design/icons-vue';
import AppSearchFooter from './AppSearchFooter.vue';
import Icon from '/@/components/Icon';
import clickOutside from '/@/directives/clickOutside';
// @ts-ignore
import vClickOutside from '/@/directives/clickOutside';
import { useDesign } from '/@/hooks/web/useDesign';
import { useRefs } from '/@/hooks/core/useRefs';
import { useMenuSearch } from './useMenuSearch';
import { useI18n } from '/@/hooks/web/useI18n';
import { useAppInject } from '/@/hooks/web/useAppInject';
const props = {
const props = defineProps({
visible: { type: Boolean },
};
export default defineComponent({
name: 'AppSearchModal',
components: { Icon, SearchOutlined, AppSearchFooter },
directives: {
clickOutside,
},
props,
emits: ['close'],
setup(props, { emit }) {
const scrollWrap = ref<ElRef>(null);
const inputRef = ref<Nullable<HTMLElement>>(null);
const { t } = useI18n();
const { prefixCls } = useDesign('app-search-modal');
const [refs, setRefs] = useRefs();
const { getIsMobile } = useAppInject();
const { handleSearch, searchResult, keyword, activeIndex, handleEnter, handleMouseenter } =
useMenuSearch(refs, scrollWrap, emit);
const getIsNotData = computed(() => !keyword || unref(searchResult).length === 0);
const getClass = computed(() => {
return [
prefixCls,
{
[`${prefixCls}--mobile`]: unref(getIsMobile),
},
];
});
watch(
() => props.visible,
(visible: boolean) => {
visible &&
nextTick(() => {
unref(inputRef)?.focus();
});
}
);
function handleClose() {
searchResult.value = [];
emit('close');
}
return {
t,
prefixCls,
getClass,
handleSearch,
searchResult,
activeIndex,
getIsNotData,
handleEnter,
setRefs,
scrollWrap,
handleMouseenter,
handleClose,
inputRef,
};
},
});
const emit = defineEmits(['close']);
const scrollWrap = ref(null);
const inputRef = ref<Nullable<HTMLElement>>(null);
const { t } = useI18n();
const { prefixCls } = useDesign('app-search-modal');
const [refs, setRefs] = useRefs();
const { getIsMobile } = useAppInject();
const { handleSearch, searchResult, keyword, activeIndex, handleEnter, handleMouseenter } =
useMenuSearch(refs, scrollWrap, emit);
const getIsNotData = computed(() => !keyword || unref(searchResult).length === 0);
const getClass = computed(() => {
return [
prefixCls,
{
[`${prefixCls}--mobile`]: unref(getIsMobile),
},
];
});
watch(
() => props.visible,
(visible: boolean) => {
visible &&
nextTick(() => {
unref(inputRef)?.focus();
});
},
);
function handleClose() {
searchResult.value = [];
emit('close');
}
</script>
<style lang="less" scoped>
@prefix-cls: ~'@{namespace}-app-search-modal';

View File

@ -7,12 +7,12 @@
<Icon icon="ion:chevron-forward" :style="$attrs.iconStyle" />
</span>
</template>
<script lang="ts">
import { defineComponent, computed } from 'vue';
<script lang="ts" setup>
import { computed } from 'vue';
import { Icon } from '/@/components/Icon';
import { useDesign } from '/@/hooks/web/useDesign';
const props = {
const props = defineProps({
/**
* Arrow expand state
*/
@ -29,31 +29,22 @@
* Cancel padding/margin for inline
*/
inset: { type: Boolean },
};
});
export default defineComponent({
name: 'BasicArrow',
components: { Icon },
props,
setup(props) {
const { prefixCls } = useDesign('basic-arrow');
const { prefixCls } = useDesign('basic-arrow');
// get component class
const getClass = computed(() => {
const { expand, up, down, inset } = props;
return [
prefixCls,
{
[`${prefixCls}--active`]: expand,
up,
inset,
down,
},
];
});
return { getClass };
},
// get component class
const getClass = computed(() => {
const { expand, up, down, inset } = props;
return [
prefixCls,
{
[`${prefixCls}--active`]: expand,
up,
inset,
down,
},
];
});
</script>
<style lang="less" scoped>

View File

@ -47,7 +47,7 @@
const { prefixCls } = useDesign('basic-help');
const getTooltipStyle = computed(
(): CSSProperties => ({ color: props.color, fontSize: props.fontSize })
(): CSSProperties => ({ color: props.color, fontSize: props.fontSize }),
);
const getOverlayStyle = computed((): CSSProperties => ({ maxWidth: props.maxWidth }));

View File

@ -4,13 +4,13 @@
<BasicHelp :class="`${prefixCls}-help`" v-if="helpMessage" :text="helpMessage" />
</span>
</template>
<script lang="ts">
<script lang="ts" setup>
import type { PropType } from 'vue';
import { defineComponent, computed } from 'vue';
import { useSlots, computed } from 'vue';
import BasicHelp from './BasicHelp.vue';
import { useDesign } from '/@/hooks/web/useDesign';
const props = {
const props = defineProps({
/**
* Help text list or string
* @default: ''
@ -29,24 +29,15 @@
* @default: false
*/
normal: { type: Boolean },
};
export default defineComponent({
name: 'BasicTitle',
components: { BasicHelp },
props,
setup(props, { slots }) {
const { prefixCls } = useDesign('basic-title');
const getClass = computed(() => [
prefixCls,
{ [`${prefixCls}-show-span`]: props.span && slots.default },
{ [`${prefixCls}-normal`]: props.normal },
]);
return { prefixCls, getClass };
},
});
const { prefixCls } = useDesign('basic-title');
const slots = useSlots();
const getClass = computed(() => [
prefixCls,
{ [`${prefixCls}-show-span`]: props.span && slots.default },
{ [`${prefixCls}-normal`]: props.normal },
]);
</script>
<style lang="less" scoped>
@prefix-cls: ~'@{namespace}-basic-title';

View File

@ -2,40 +2,39 @@
<Button v-bind="getBindValue" :class="getButtonClass" @click="onClick">
<template #default="data">
<Icon :icon="preIcon" v-if="preIcon" :size="iconSize" />
<slot v-bind="data"></slot>
<slot v-bind="data || {}"></slot>
<Icon :icon="postIcon" v-if="postIcon" :size="iconSize" />
</template>
</Button>
</template>
<script lang="ts">
import { defineComponent, computed, unref } from 'vue';
import { defineComponent } from 'vue';
export default defineComponent({
name: 'AButton',
inheritAttrs: false,
});
</script>
<script lang="ts" setup>
import { computed, unref } from 'vue';
import { Button } from 'ant-design-vue';
import Icon from '/@/components/Icon/src/Icon.vue';
import { buttonProps } from './props';
import { useAttrs } from '/@/hooks/core/useAttrs';
export default defineComponent({
name: 'AButton',
components: { Button, Icon },
inheritAttrs: false,
props: buttonProps,
setup(props) {
// get component class
const attrs = useAttrs({ excludeDefaultKeys: false });
const getButtonClass = computed(() => {
const { color, disabled } = props;
return [
{
[`ant-btn-${color}`]: !!color,
[`is-disabled`]: disabled,
},
];
});
// get inherit binding value
const getBindValue = computed(() => ({ ...unref(attrs), ...props }));
return { getBindValue, getButtonClass };
},
const props = defineProps(buttonProps);
// get component class
const attrs = useAttrs({ excludeDefaultKeys: false });
const getButtonClass = computed(() => {
const { color, disabled } = props;
return [
{
[`ant-btn-${color}`]: !!color,
[`is-disabled`]: disabled,
},
];
});
// get inherit binding value
const getBindValue = computed(() => ({ ...unref(attrs), ...props }));
</script>

View File

@ -20,7 +20,6 @@
export default defineComponent({
name: 'PopButton',
components: { Popconfirm, BasicButton },
inheritAttrs: false,
props,
setup(props, { slots }) {
@ -34,13 +33,13 @@
okText: t('common.okText'),
cancelText: t('common.cancelText'),
},
{ ...props, ...unref(attrs) }
{ ...props, ...unref(attrs) },
);
});
return () => {
const bindValues = omit(unref(getBindValues), 'icon');
const btnBind = omit(bindValues, 'title');
const btnBind = omit(bindValues, 'title') as Recordable;
if (btnBind.disabled) btnBind.color = '';
const Button = h(BasicButton, btnBind, extendSlots(slots));

View File

@ -3,24 +3,17 @@
<slot></slot>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted } from 'vue';
<script lang="ts" setup>
import { ref, onMounted } from 'vue';
import { onClickOutside } from '@vueuse/core';
export default defineComponent({
name: 'ClickOutSide',
emits: ['mounted', 'clickOutside'],
setup(_, { emit }) {
const wrap = ref<ElRef>(null);
const emit = defineEmits(['mounted', 'clickOutside']);
const wrap = ref<ElRef>(null);
onClickOutside(wrap, () => {
emit('clickOutside');
});
onClickOutside(wrap, () => {
emit('clickOutside');
});
onMounted(() => {
emit('mounted');
});
return { wrap };
},
onMounted(() => {
emit('mounted');
});
</script>

View File

@ -8,45 +8,47 @@
/>
</div>
</template>
<script lang="ts">
import { defineComponent, computed } from 'vue';
import CodeMirrorEditor from './codemirror/CodeMirror.vue';
import { isString } from '/@/utils/is';
<script lang="ts">
const MODE = {
JSON: 'application/json',
html: 'htmlmixed',
js: 'javascript',
};
</script>
<script lang="ts" setup>
import { computed } from 'vue';
import CodeMirrorEditor from './codemirror/CodeMirror.vue';
import { isString } from '/@/utils/is';
const props = {
const props = defineProps({
value: { type: [Object, String] as PropType<Record<string, any> | string> },
mode: { type: String, default: MODE.JSON },
readonly: { type: Boolean },
};
export default defineComponent({
name: 'CodeEditor',
components: { CodeMirrorEditor },
props,
emits: ['change', 'update:value'],
setup(props, { emit }) {
const getValue = computed(() => {
const { value, mode } = props;
if (mode !== MODE.JSON) {
return value as string;
}
return isString(value)
? JSON.stringify(JSON.parse(value), null, 2)
: JSON.stringify(value, null, 2);
});
function handleValueChange(v) {
emit('update:value', v);
emit('change', v);
}
return { handleValueChange, getValue };
},
autoFormat: { type: Boolean, default: true },
});
const emit = defineEmits(['change', 'update:value', 'format-error']);
const getValue = computed(() => {
const { value, mode, autoFormat } = props;
if (!autoFormat || mode !== MODE.JSON) {
return value as string;
}
let result = value;
if (isString(value)) {
try {
result = JSON.parse(value);
} catch (e) {
emit('format-error', value);
return value as string;
}
}
return JSON.stringify(result, null, 2);
});
function handleValueChange(v) {
emit('update:value', v);
emit('change', v);
}
</script>

View File

@ -1,18 +1,9 @@
<template>
<div class="relative !h-full w-full overflow-hidden" ref="el"> </div>
<div class="relative !h-full w-full overflow-hidden" ref="el"></div>
</template>
<script lang="ts">
import {
ref,
onMounted,
onUnmounted,
watchEffect,
watch,
defineComponent,
unref,
nextTick,
} from 'vue';
<script lang="ts" setup>
import { ref, onMounted, onUnmounted, watchEffect, watch, unref, nextTick } from 'vue';
import { useDebounceFn } from '@vueuse/core';
import { useAppStore } from '/@/store/modules/app';
import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
@ -26,95 +17,89 @@
import 'codemirror/mode/css/css';
import 'codemirror/mode/htmlmixed/htmlmixed';
const props = {
const props = defineProps({
mode: { type: String, default: 'application/json' },
value: { type: String, default: '' },
readonly: { type: Boolean, default: false },
};
});
export default defineComponent({
props,
emits: ['change'],
setup(props, { emit }) {
const el = ref();
let editor: Nullable<CodeMirror.Editor>;
const emit = defineEmits(['change']);
const debounceRefresh = useDebounceFn(refresh, 100);
const appStore = useAppStore();
const el = ref();
let editor: Nullable<CodeMirror.Editor>;
watch(
() => props.value,
async (value) => {
await nextTick();
const oldValue = editor?.getValue();
if (value !== oldValue) {
editor?.setValue(value ? value : '');
}
},
{ flush: 'post' }
);
const debounceRefresh = useDebounceFn(refresh, 100);
const appStore = useAppStore();
watchEffect(() => {
editor?.setOption('mode', props.mode);
});
watch(
() => appStore.getDarkMode,
async () => {
setTheme();
},
{
immediate: true,
}
);
function setTheme() {
unref(editor)?.setOption(
'theme',
appStore.getDarkMode === 'light' ? 'idea' : 'material-palenight'
);
watch(
() => props.value,
async (value) => {
await nextTick();
const oldValue = editor?.getValue();
if (value !== oldValue) {
editor?.setValue(value ? value : '');
}
function refresh() {
editor?.refresh();
}
async function init() {
const addonOptions = {
autoCloseBrackets: true,
autoCloseTags: true,
foldGutter: true,
gutters: ['CodeMirror-linenumbers'],
};
editor = CodeMirror(el.value!, {
value: '',
mode: props.mode,
readOnly: props.readonly,
tabSize: 2,
theme: 'material-palenight',
lineWrapping: true,
lineNumbers: true,
...addonOptions,
});
editor?.setValue(props.value);
setTheme();
editor?.on('change', () => {
emit('change', editor?.getValue());
});
}
onMounted(async () => {
await nextTick();
init();
useWindowSizeFn(debounceRefresh);
});
onUnmounted(() => {
editor = null;
});
return { el };
},
{ flush: 'post' },
);
watchEffect(() => {
editor?.setOption('mode', props.mode);
});
watch(
() => appStore.getDarkMode,
async () => {
setTheme();
},
{
immediate: true,
},
);
function setTheme() {
unref(editor)?.setOption(
'theme',
appStore.getDarkMode === 'light' ? 'idea' : 'material-palenight',
);
}
function refresh() {
editor?.refresh();
}
async function init() {
const addonOptions = {
autoCloseBrackets: true,
autoCloseTags: true,
foldGutter: true,
gutters: ['CodeMirror-linenumbers'],
};
editor = CodeMirror(el.value!, {
value: '',
mode: props.mode,
readOnly: props.readonly,
tabSize: 2,
theme: 'material-palenight',
lineWrapping: true,
lineNumbers: true,
...addonOptions,
});
editor?.setValue(props.value);
setTheme();
editor?.on('change', () => {
emit('change', editor?.getValue());
});
}
onMounted(async () => {
await nextTick();
init();
useWindowSizeFn(debounceRefresh);
});
onUnmounted(() => {
editor = null;
});
</script>

View File

@ -2,13 +2,11 @@
<vue-json-pretty :path="'res'" :deep="3" :showLength="true" :data="data" />
</template>
<script lang="ts">
<script lang="ts" setup>
import VueJsonPretty from 'vue-json-pretty';
import 'vue-json-pretty/lib/styles.css';
import { defineComponent } from 'vue';
export default defineComponent({
name: 'JsonPreview',
components: { VueJsonPretty },
props: { data: Object },
defineProps({
data: Object,
});
</script>

View File

@ -54,7 +54,7 @@
return;
}
nextTick(() => {
const wrap = unref(scrollbar.wrap);
const wrap = unref(scrollbar.wrap) as any;
if (!wrap) {
return;
}

View File

@ -22,9 +22,9 @@
</div>
</div>
</template>
<script lang="ts">
<script lang="ts" setup>
import type { PropType } from 'vue';
import { defineComponent, ref } from 'vue';
import { ref } from 'vue';
// component
import { Skeleton } from 'ant-design-vue';
import { CollapseTransition } from '/@/components/Transition';
@ -34,7 +34,7 @@
import { useTimeoutFn } from '/@/hooks/core/useTimeout';
import { useDesign } from '/@/hooks/web/useDesign';
const props = {
const props = defineProps({
title: { type: String, default: '' },
loading: { type: Boolean },
/**
@ -57,39 +57,22 @@
* Delayed loading time
*/
lazyTime: { type: Number, default: 0 },
};
export default defineComponent({
name: 'CollapseContainer',
components: {
Skeleton,
CollapseHeader,
CollapseTransition,
},
props,
setup(props) {
const show = ref(true);
const { prefixCls } = useDesign('collapse-container');
/**
* @description: Handling development events
*/
function handleExpand() {
show.value = !show.value;
if (props.triggerWindowResize) {
// 200 milliseconds here is because the expansion has animation,
useTimeoutFn(triggerWindowResize, 200);
}
}
return {
show,
handleExpand,
prefixCls,
};
},
});
const show = ref(true);
const { prefixCls } = useDesign('collapse-container');
/**
* @description: Handling development events
*/
function handleExpand() {
show.value = !show.value;
if (props.triggerWindowResize) {
// 200 milliseconds here is because the expansion has animation,
useTimeoutFn(triggerWindowResize, 200);
}
}
</script>
<style lang="less">
@prefix-cls: ~'@{namespace}-collapse-container';

View File

@ -46,7 +46,7 @@
name: 'ContextMenu',
props,
setup(props) {
const wrapRef = ref<ElRef>(null);
const wrapRef = ref(null);
const showRef = ref(false);
const getStyle = computed((): CSSProperties => {

View File

@ -4,7 +4,7 @@
<CountButton :size="size" :count="count" :value="state" :beforeStartFunc="sendCodeApi" />
</template>
<template #[item]="data" v-for="item in Object.keys($slots).filter((k) => k !== 'addonAfter')">
<slot :name="item" v-bind="data"></slot>
<slot :name="item" v-bind="data || {}"></slot>
</template>
</a-input>
</template>

View File

@ -122,10 +122,12 @@
import { isFunction } from '/@/utils/is';
import { useI18n } from '/@/hooks/web/useI18n';
type apiFunParams = { file: Blob; name: string; filename: string };
const props = {
circled: { type: Boolean, default: true },
uploadApi: {
type: Function as PropType<({ file: Blob, name: string, filename: string }) => Promise<any>>,
type: Function as PropType<(params: apiFunParams) => Promise<any>>,
},
};

View File

@ -77,7 +77,7 @@
const getStyle = computed((): CSSProperties => ({ width: unref(getWidth) }));
const getImageWrapperStyle = computed(
(): CSSProperties => ({ width: unref(getWidth), height: unref(getWidth) })
(): CSSProperties => ({ width: unref(getWidth), height: unref(getWidth) }),
);
watchEffect(() => {
@ -88,7 +88,7 @@
() => sourceValue.value,
(v: string) => {
emit('update:value', v);
}
},
);
function handleUploadSuccess({ source }) {
@ -103,7 +103,7 @@
t,
prefixCls,
register,
openModal,
openModal: openModal as any,
getIconWidth,
sourceValue,
getClass,

View File

@ -14,7 +14,7 @@ export interface DescItem {
// render
render?: (
val: any,
data: Recordable
data: Recordable,
) => VNode | undefined | JSX.Element | Element | string | number;
}

View File

@ -25,7 +25,7 @@
</ScrollContainer>
<DrawerFooter v-bind="getProps" @close="onClose" @ok="handleOk" :height="getFooterHeight">
<template #[item]="data" v-for="item in Object.keys($slots)">
<slot :name="item" v-bind="data"></slot>
<slot :name="item" v-bind="data || {}"></slot>
</template>
</DrawerFooter>
</Drawer>
@ -139,7 +139,7 @@
(newVal, oldVal) => {
if (newVal !== oldVal) visibleRef.value = newVal;
},
{ deep: true }
{ deep: true },
);
watch(
@ -149,7 +149,7 @@
emit('visible-change', visible);
instance && drawerInstance.emitVisible?.(visible, instance.uid);
});
}
},
);
// Cancel event
@ -181,9 +181,9 @@
onClose,
t,
prefixCls,
getMergeProps,
getMergeProps: getMergeProps as any,
getScrollContentStyle,
getProps,
getProps: getProps as any,
getLoading,
getBindValues,
getFooterHeight,

View File

@ -8,6 +8,7 @@
</div>
</template>
<script lang="ts">
import type { Ref } from 'vue';
import type { Definition } from '@logicflow/core';
import { defineComponent, ref, onMounted, unref, nextTick, computed, watch } from 'vue';
import FlowChartToolbar from './FlowChartToolbar.vue';
@ -46,10 +47,10 @@
},
},
setup(props) {
const lfElRef = ref<ElRef>(null);
const graphData = ref<Recordable>({});
const lfElRef = ref(null);
const graphData = ref({});
const lfInstance = ref<Nullable<LogicFlow>>(null);
const lfInstance = ref(null) as Ref<LogicFlow | null>;
const { prefixCls } = useDesign('flow-chart');
const appStore = useAppStore();
@ -78,7 +79,7 @@
() => props.data,
() => {
onRender();
}
},
);
// TODO
@ -93,7 +94,7 @@
() => unref(getFlowOptions),
(options) => {
unref(lfInstance)?.updateEditConfig(options);
}
},
);
// init logicFlow

View File

@ -19,17 +19,17 @@
:setFormModel="setFormModel"
>
<template #[item]="data" v-for="item in Object.keys($slots)">
<slot :name="item" v-bind="data"></slot>
<slot :name="item" v-bind="data || {}"></slot>
</template>
</FormItem>
</template>
<FormAction v-bind="{ ...getProps, ...advanceState }" @toggle-advanced="handleToggleAdvanced">
<FormAction v-bind="getFormActionBindProps" @toggle-advanced="handleToggleAdvanced">
<template
#[item]="data"
v-for="item in ['resetBefore', 'submitBefore', 'advanceBefore', 'advanceAfter']"
>
<slot :name="item" v-bind="data"></slot>
<slot :name="item" v-bind="data || {}"></slot>
</template>
</FormAction>
<slot name="formFooter"></slot>
@ -62,8 +62,6 @@
import { basicProps } from './props';
import { useDesign } from '/@/hooks/web/useDesign';
import type { RowProps } from 'ant-design-vue/lib/grid/Row';
export default defineComponent({
name: 'BasicForm',
components: { FormItem, Form, Row, FormAction },
@ -103,7 +101,7 @@
});
// Get uniform row style and Row configuration for the entire form
const getRow = computed((): RowProps => {
const getRow = computed((): Recordable => {
const { baseRowStyle = {}, rowProps } = unref(getProps);
return {
style: baseRowStyle,
@ -112,7 +110,7 @@
});
const getBindValue = computed(
() => ({ ...attrs, ...props, ...unref(getProps) } as Recordable)
() => ({ ...attrs, ...props, ...unref(getProps) } as Recordable),
);
const getSchema = computed((): FormSchema[] => {
@ -132,7 +130,11 @@
}
}
}
return schemas as FormSchema[];
if (unref(getProps).showAdvancedButton) {
return schemas.filter((schema) => schema.component !== 'Divider') as FormSchema[];
} else {
return schemas as FormSchema[];
}
});
const { handleToggleAdvanced } = useAdvanced({
@ -196,14 +198,14 @@
},
{
immediate: true,
}
},
);
watch(
() => unref(getProps).schemas,
(schemas) => {
resetSchema(schemas ?? []);
}
},
);
watch(
@ -220,7 +222,7 @@
initDefault();
isInitedDefaultRef.value = true;
}
}
},
);
async function setProps(formProps: Partial<FormProps>): Promise<void> {
@ -278,10 +280,12 @@
getProps,
formElRef,
getSchema,
formActionType,
formActionType: formActionType as any,
setFormModel,
prefixCls,
getFormClass,
getFormActionBindProps: computed(
(): Recordable => ({ ...getProps.value, ...advanceState }),
),
...formActionType,
};
},

View File

@ -18,6 +18,7 @@ import {
TreeSelect,
Slider,
Rate,
Divider,
} from 'ant-design-vue';
import RadioButtonGroup from './components/RadioButtonGroup.vue';
@ -61,6 +62,7 @@ componentMap.set('IconPicker', IconPicker);
componentMap.set('InputCountDown', CountdownInput);
componentMap.set('Upload', BasicUpload);
componentMap.set('Divider', Divider);
export function add(compName: ComponentType, component: Component) {
componentMap.set(compName, component);

View File

@ -7,7 +7,7 @@
v-model:value="state"
>
<template #[item]="data" v-for="item in Object.keys($slots)">
<slot :name="item" v-bind="data"></slot>
<slot :name="item" v-bind="data || {}"></slot>
</template>
<template #suffixIcon v-if="loading">
<LoadingOutlined spin />
@ -100,7 +100,7 @@
() => {
!unref(isFirstLoad) && fetch();
},
{ deep: true }
{ deep: true },
);
async function fetch() {

View File

@ -1,7 +1,7 @@
<template>
<a-tree-select v-bind="getAttrs" @change="handleChange">
<template #[item]="data" v-for="item in Object.keys($slots)">
<slot :name="item" v-bind="data"></slot>
<slot :name="item" v-bind="data || {}"></slot>
</template>
<template #suffixIcon v-if="loading">
<LoadingOutlined spin />
@ -46,14 +46,14 @@
() => {
isFirstLoaded.value && fetch();
},
{ deep: true }
{ deep: true },
);
watch(
() => props.immediate,
(v) => {
v && !isFirstLoaded.value && fetch();
}
},
);
onMounted(() => {

View File

@ -105,7 +105,7 @@
{
text: t('common.resetText'),
},
props.resetButtonOptions
props.resetButtonOptions,
);
});
@ -114,7 +114,7 @@
{
text: t('common.queryText'),
},
props.submitButtonOptions
props.submitButtonOptions,
);
});

View File

@ -5,7 +5,7 @@
import type { ValidationRule } from 'ant-design-vue/lib/form/Form';
import type { TableActionType } from '/@/components/Table';
import { defineComponent, computed, unref, toRefs } from 'vue';
import { Form, Col } from 'ant-design-vue';
import { Form, Col, Divider } from 'ant-design-vue';
import { componentMap } from '../componentMap';
import { BasicHelp } from '/@/components/Basic';
import { isBoolean, isFunction, isNull } from '/@/utils/is';
@ -73,11 +73,17 @@
const getComponentsProps = computed(() => {
const { schema, tableAction, formModel, formActionType } = props;
const { componentProps = {} } = schema;
if (!isFunction(componentProps)) {
return componentProps;
let { componentProps = {} } = schema;
if (isFunction(componentProps)) {
componentProps = componentProps({ schema, tableAction, formModel, formActionType }) ?? {};
}
return componentProps({ schema, tableAction, formModel, formActionType }) ?? {};
if (schema.component === 'Divider') {
componentProps = Object.assign({ type: 'horizontal' }, componentProps, {
orientation: 'left',
plain: true,
});
}
return componentProps as Recordable;
});
const getDisable = computed(() => {
@ -177,7 +183,7 @@
}
const requiredRuleIndex: number = rules.findIndex(
(rule) => Reflect.has(rule, 'required') && !Reflect.has(rule, 'validator')
(rule) => Reflect.has(rule, 'required') && !Reflect.has(rule, 'validator'),
);
if (requiredRuleIndex !== -1) {
@ -300,38 +306,46 @@
}
function renderItem() {
const { itemProps, slot, render, field, suffix } = props.schema;
const { itemProps, slot, render, field, suffix, component } = props.schema;
const { labelCol, wrapperCol } = unref(itemLabelWidthProp);
const { colon } = props.formProps;
const getContent = () => {
return slot
? getSlot(slots, slot, unref(getValues))
: render
? render(unref(getValues))
: renderComponent();
};
if (component === 'Divider') {
return (
<Col span={24}>
<Divider {...unref(getComponentsProps)}>{renderLabelHelpMessage()}</Divider>
</Col>
);
} else {
const getContent = () => {
return slot
? getSlot(slots, slot, unref(getValues))
: render
? render(unref(getValues))
: renderComponent();
};
const showSuffix = !!suffix;
const getSuffix = isFunction(suffix) ? suffix(unref(getValues)) : suffix;
const showSuffix = !!suffix;
const getSuffix = isFunction(suffix) ? suffix(unref(getValues)) : suffix;
return (
<Form.Item
name={field}
colon={colon}
class={{ 'suffix-item': showSuffix }}
{...(itemProps as Recordable)}
label={renderLabelHelpMessage()}
rules={handleRules()}
labelCol={labelCol}
wrapperCol={wrapperCol}
>
<div style="display:flex">
<div style="flex:1">{getContent()}</div>
{showSuffix && <span class="suffix">{getSuffix}</span>}
</div>
</Form.Item>
);
return (
<Form.Item
name={field}
colon={colon}
class={{ 'suffix-item': showSuffix }}
{...(itemProps as Recordable)}
label={renderLabelHelpMessage()}
rules={handleRules()}
labelCol={labelCol}
wrapperCol={wrapperCol}
>
<div style="display:flex">
<div style="flex:1">{getContent()}</div>
{showSuffix && <span class="suffix">{getSuffix}</span>}
</div>
</Form.Item>
);
}
}
return () => {

View File

@ -38,7 +38,7 @@ function genType() {
export function setComponentRuleType(
rule: ValidationRule,
component: ComponentType,
valueFormat: string
valueFormat: string,
) {
if (['DatePicker', 'MonthPicker', 'WeekPicker', 'TimePicker'].includes(component)) {
rule.type = valueFormat ? 'string' : 'object';

View File

@ -58,7 +58,7 @@ export default function ({
debounceUpdateAdvanced();
}
},
{ immediate: true }
{ immediate: true },
);
function getAdvanced(itemCol: Partial<ColEx>, itemColSum = 0, isLastAction = false) {
@ -103,7 +103,7 @@ export default function ({
}
return { isAdvanced: advanceState.isAdvanced, itemColSum };
}
if (itemColSum > BASIC_COL_LEN) {
if (itemColSum > BASIC_COL_LEN * (unref(getProps).alwaysShowLines || 1)) {
return { isAdvanced: advanceState.isAdvanced, itemColSum };
} else {
// The first line is always displayed
@ -139,7 +139,7 @@ export default function ({
if (isShow && (colProps || baseColProps)) {
const { itemColSum: sum, isAdvanced } = getAdvanced(
{ ...baseColProps, ...colProps },
itemColSum
itemColSum,
);
itemColSum = sum || 0;

View File

@ -18,7 +18,7 @@ export function useForm(props?: Props): UseFormReturnType {
const form = unref(formRef);
if (!form) {
error(
'The form instance has not been obtained, please make sure that the form has been rendered when performing the form operation!'
'The form instance has not been obtained, please make sure that the form has been rendered when performing the form operation!',
);
}
await nextTick();
@ -44,7 +44,7 @@ export function useForm(props?: Props): UseFormReturnType {
{
immediate: true,
deep: true,
}
},
);
}
@ -96,7 +96,7 @@ export function useForm(props?: Props): UseFormReturnType {
appendSchemaByField: async (
schema: FormSchema,
prefixField: string | undefined,
first: boolean
first: boolean,
) => {
const form = await getForm();
form.appendSchemaByField(schema, prefixField, first);

View File

@ -149,11 +149,13 @@ export function useFormEvents({
updateData = [...data];
}
const hasField = updateData.every((item) => Reflect.has(item, 'field') && item.field);
const hasField = updateData.every(
(item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field),
);
if (!hasField) {
error(
'All children of the form Schema array that need to be updated must contain the `field` field'
'All children of the form Schema array that need to be updated must contain the `field` field',
);
return;
}
@ -169,11 +171,13 @@ export function useFormEvents({
updateData = [...data];
}
const hasField = updateData.every((item) => Reflect.has(item, 'field') && item.field);
const hasField = updateData.every(
(item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field),
);
if (!hasField) {
error(
'All children of the form Schema array that need to be updated must contain the `field` field'
'All children of the form Schema array that need to be updated must contain the `field` field',
);
return;
}

View File

@ -59,6 +59,8 @@ export const basicProps = {
rulesMessageJoinLabel: propTypes.bool.def(true),
// 超过3行自动折叠
autoAdvancedLine: propTypes.number.def(3),
// 不受折叠影响的行数
alwaysShowLines: propTypes.number.def(1),
// 是否显示操作按钮
showActionButtonGroup: propTypes.bool.def(true),

View File

@ -37,7 +37,7 @@ export interface FormActionType {
appendSchemaByField: (
schema: FormSchema,
prefixField: string | undefined,
first?: boolean | undefined
first?: boolean | undefined,
) => Promise<void>;
validateFields: (nameList?: NamePath[]) => Promise<any>;
validate: (nameList?: NamePath[]) => Promise<any>;
@ -97,6 +97,8 @@ export interface FormProps {
autoFocusFirstItem?: boolean;
// Automatically collapse over the specified number of rows
autoAdvancedLine?: number;
// Always show lines
alwaysShowLines?: number;
// Whether to show the operation button
showActionButtonGroup?: boolean;

View File

@ -109,4 +109,5 @@ export type ComponentType =
| 'IconPicker'
| 'Render'
| 'Slider'
| 'Rate';
| 'Rate'
| 'Divider';

View File

@ -63,7 +63,7 @@
</div>
</div>
<template v-else
><div class="p-5"> <Empty /></div>
><div class="p-5"><Empty /></div>
</template>
</template>
@ -121,7 +121,7 @@
copy: propTypes.bool.def(false),
mode: propTypes.oneOf<('svg' | 'iconify')[]>(['svg', 'iconify']).def('iconify'),
},
emits: ['change'],
emits: ['change', 'update:value'],
setup(props, { emit }) {
const isSvgMode = props.mode === 'svg';
const icons = isSvgMode ? getSvgIcons() : getIcons();
@ -139,7 +139,7 @@
const { getPaginationList, getTotal, setCurrentPage } = usePagination(
currentList,
props.pageSize
props.pageSize,
);
watchEffect(() => {
@ -148,7 +148,10 @@
watch(
() => currentSelect.value,
(v) => emit('change', v)
(v) => {
emit('update:value', v);
return emit('change', v);
},
);
function handlePageChange(page: number) {

View File

@ -4,7 +4,7 @@ import type { LoadingProps } from './typing';
import type { Ref } from 'vue';
export interface UseLoadingOptions {
target?: HTMLElement | Ref<ElRef>;
target?: any;
props?: Partial<LoadingProps>;
}
@ -16,7 +16,7 @@ export function useLoading(props: Partial<LoadingProps>): [Fn, Fn, (string) => v
export function useLoading(opt: Partial<UseLoadingOptions>): [Fn, Fn, (string) => void];
export function useLoading(
opt: Partial<LoadingProps> | Partial<UseLoadingOptions>
opt: Partial<LoadingProps> | Partial<UseLoadingOptions>,
): [Fn, Fn, (string) => void] {
let props: Partial<LoadingProps>;
let target: HTMLElement | Ref<ElRef> = document.body;
@ -32,7 +32,7 @@ export function useLoading(
const instance = createLoading(props, undefined, true);
const open = (): void => {
const t = unref(target);
const t = unref(target as Ref<ElRef>);
if (!t) return;
instance.open(t);
};

View File

@ -2,6 +2,7 @@
<div ref="wrapRef"></div>
</template>
<script lang="ts">
import type { Ref } from 'vue';
import {
defineComponent,
ref,
@ -30,7 +31,7 @@
emits: ['change', 'get', 'update:value'],
setup(props, { attrs, emit }) {
const wrapRef = ref<ElRef>(null);
const vditorRef = ref<Nullable<Vditor>>(null);
const vditorRef = ref(null) as Ref<Nullable<Vditor>>;
const initedRef = ref(false);
const modalFn = useModalContext();
@ -51,7 +52,7 @@
{
immediate: true,
flush: 'post',
}
},
);
watch(
@ -61,7 +62,7 @@
instance.getVditor()?.setValue(v);
}
valueRef.value = v;
}
},
);
const getCurrentLang = computed((): 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' => {

View File

@ -56,15 +56,15 @@
const { prefixCls } = useDesign('basic-menu');
const { items, mode, accordion } = toRefs(props);
const { getCollapsed, getIsHorizontal, getTopMenuAlign, getSplit } = useMenuSetting();
const { getCollapsed, getTopMenuAlign, getSplit } = useMenuSetting();
const { currentRoute } = useRouter();
const { handleOpenChange, setOpenKeys, getOpenKeys } = useOpenKeys(
menuState,
items,
mode,
accordion
mode as any,
accordion,
);
const getIsTopMenu = computed(() => {
@ -114,7 +114,7 @@
() => props.items,
() => {
handleMenuChange();
}
},
);
async function handleMenuClick({ key }: { key: string; keyPath: string[] }) {
@ -150,8 +150,6 @@
}
return {
prefixCls,
getIsHorizontal,
handleMenuClick,
getInlineCollapseOptions,
getMenuClass,

View File

@ -4,6 +4,8 @@ import type { PropType } from 'vue';
import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
import { ThemeEnum } from '/@/enums/appEnum';
import { propTypes } from '/@/utils/propTypes';
import type { MenuTheme } from 'ant-design-vue';
import type { MenuMode } from 'ant-design-vue/lib/menu/src/interface';
export const basicProps = {
items: {
type: Array as PropType<Menu[]>,
@ -14,7 +16,7 @@ export const basicProps = {
inlineIndent: propTypes.number.def(20),
// 菜单组件的mode属性
mode: {
type: String as PropType<MenuModeEnum>,
type: String as PropType<MenuMode>,
default: MenuModeEnum.INLINE,
},
@ -22,7 +24,10 @@ export const basicProps = {
type: String as PropType<MenuTypeEnum>,
default: MenuTypeEnum.MIX,
},
theme: propTypes.string.def(ThemeEnum.DARK),
theme: {
type: String as PropType<MenuTheme>,
default: ThemeEnum.DARK,
},
inlineCollapsed: propTypes.bool,
mixSider: propTypes.bool,

View File

@ -14,7 +14,7 @@ export function useOpenKeys(
menuState: MenuState,
menus: Ref<MenuType[]>,
mode: Ref<MenuModeEnum>,
accordion: Ref<boolean>
accordion: Ref<boolean>,
) {
const { getCollapsed, getIsMixSidebar } = useMenuSetting();
@ -37,7 +37,7 @@ export function useOpenKeys(
}
},
16,
!native
!native,
);
}

View File

@ -20,7 +20,7 @@
<template #footer v-if="!$slots.footer">
<ModalFooter v-bind="getBindValue" @ok="handleOk" @cancel="handleCancel">
<template #[item]="data" v-for="item in Object.keys($slots)">
<slot :name="item" v-bind="data"></slot>
<slot :name="item" v-bind="data || {}"></slot>
</template>
</ModalFooter>
</template>
@ -44,7 +44,7 @@
</ModalWrapper>
<template #[item]="data" v-for="item in Object.keys(omit($slots, 'default'))">
<slot :name="item" v-bind="data"></slot>
<slot :name="item" v-bind="data || {}"></slot>
</template>
</Modal>
</template>
@ -104,7 +104,7 @@
}
// Custom title component: get title
const getMergeProps = computed((): ModalProps => {
const getMergeProps = computed((): Recordable => {
return {
...props,
...(unref(propsRef) as any),
@ -118,7 +118,7 @@
});
// modal component does not need title and origin buttons
const getProps = computed((): ModalProps => {
const getProps = computed((): Recordable => {
const opt = {
...unref(getMergeProps),
visible: unref(visibleRef),
@ -140,9 +140,9 @@
wrapClassName: unref(getWrapClassName),
};
if (unref(fullScreenRef)) {
return omit(attr, 'height');
return omit(attr, ['height', 'title']);
}
return attr;
return omit(attr, 'title');
});
const getWrapperHeight = computed(() => {
@ -169,7 +169,7 @@
},
{
immediate: false,
}
},
);
//
@ -212,7 +212,7 @@
extHeightRef.value = height;
}
function handleTitleDbClick(e: ChangeEvent) {
function handleTitleDbClick(e) {
if (!props.canFullscreen) return;
e.stopPropagation();
handleFullScreen(e);

View File

@ -62,7 +62,7 @@
{
attributes: true,
subtree: true,
}
},
);
createModalContext({
@ -89,7 +89,7 @@
} else {
minRealHeightRef.value = realHeightRef.value;
}
}
},
);
onMounted(() => {
@ -125,7 +125,7 @@
const modalDom = bodyDom.parentElement && bodyDom.parentElement.parentElement;
if (!modalDom) return;
const modalRect = getComputedStyle(modalDom).top;
const modalRect = getComputedStyle(modalDom as Element).top;
const modalTop = Number.parseInt(modalRect);
let maxHeight =
window.innerHeight -

View File

@ -5,3 +5,5 @@ import pageWrapper from './src/PageWrapper.vue';
export const PageFooter = withInstall(pageFooter);
export const PageWrapper = withInstall(pageWrapper);
export const PageWrapperFixedHeightKey = 'PageWrapperFixedHeight';

View File

@ -14,7 +14,7 @@
<slot name="headerContent" v-else></slot>
</template>
<template #[item]="data" v-for="item in getHeaderSlots">
<slot :name="item" v-bind="data"></slot>
<slot :name="item" v-bind="data || {}"></slot>
</template>
</PageHeader>
@ -33,7 +33,7 @@
</div>
</template>
<script lang="ts">
import type { CSSProperties, PropType } from 'vue';
import { CSSProperties, PropType, provide } from 'vue';
import { defineComponent, computed, watch, ref, unref } from 'vue';
import PageFooter from './PageFooter.vue';
@ -43,6 +43,7 @@
import { omit } from 'lodash-es';
import { PageHeader } from 'ant-design-vue';
import { useContentHeight } from '/@/hooks/web/useContentHeight';
import { PageWrapperFixedHeightKey } from '..';
export default defineComponent({
name: 'PageWrapper',
@ -68,6 +69,11 @@
const footerRef = ref(null);
const { prefixCls } = useDesign('page-wrapper');
provide(
PageWrapperFixedHeightKey,
computed(() => props.fixedHeight),
);
const getIsContentFullHeight = computed(() => {
return props.contentFullHeight;
});
@ -76,7 +82,7 @@
getIsContentFullHeight,
wrapperRef,
[headerRef, footerRef],
[contentRef]
[contentRef],
);
setCompensation({ useLayoutFooter: true, elements: [footerRef] });
@ -129,7 +135,7 @@
{
flush: 'post',
immediate: true,
}
},
);
return {

View File

@ -1,6 +1,5 @@
<script lang="tsx">
import { defineComponent, ref, unref, computed, reactive, watchEffect } from 'vue';
import { Props } from './typing';
import { CloseOutlined, LeftOutlined, RightOutlined } from '@ant-design/icons-vue';
import resumeSvg from '/@/assets/svg/preview/resume.svg';
import rotateSvg from '/@/assets/svg/preview/p-rotate.svg';
@ -57,7 +56,7 @@
name: 'ImagePreview',
props,
emits: ['img-load', 'img-error'],
setup(props: Props, { expose, emit }) {
setup(props, { expose, emit }) {
interface stateInfo {
scale: number;
rotate: number;
@ -117,8 +116,9 @@
}
const getScaleStep = computed(() => {
if (props.scaleStep > 0 && props.scaleStep < 100) {
return props.scaleStep / 100;
const scaleStep = props?.scaleStep ?? 0;
if (scaleStep ?? (0 > 0 && scaleStep < 100)) {
return scaleStep / 100;
} else {
return imgState.imgScale / 10;
}
@ -164,7 +164,7 @@
img.src = url;
img.onload = (e: Event) => {
if (imgState.currentUrl !== url) {
const ele: HTMLElement[] = e.composedPath();
const ele: any[] = e.composedPath();
if (props.rememberState) {
//
stateMap.set(imgState.currentUrl, {
@ -244,7 +244,7 @@
setRotate: (rotate: number) => {
imgState.imgRotate = rotate;
},
} as PreviewActions);
});
//
function handleChange(direction: 'left' | 'right') {

View File

@ -56,7 +56,7 @@
setup(props) {
const { prefixCls } = useDesign('image-preview');
const getImageList = computed(() => {
const getImageList = computed((): any[] => {
const { imageList } = props;
if (!imageList) {
return [];

View File

@ -103,7 +103,7 @@
},
{
deep: true,
}
},
);
return { wrapRef, download };

View File

@ -7,9 +7,9 @@ export const renderQrCode = ({
canvas,
content,
width = 0,
options: params = {}
options: params = {},
}: RenderQrCodeParams) => {
const options = cloneDeep(params)
const options = cloneDeep(params);
// 容错率,默认对内容少的二维码采用高容错率,内容多的二维码采用低容错率
options.errorCorrectionLevel = options.errorCorrectionLevel || getErrorCorrectionLevel(content);

View File

@ -44,7 +44,7 @@ export default defineComponent({
const clickTrackHandler = (e: any) => {
const offset = Math.abs(
e.target.getBoundingClientRect()[bar.value.direction] - e[bar.value.client]
e.target.getBoundingClientRect()[bar.value.direction] - e[bar.value.client],
);
const thumbHalf = thumb.value[bar.value.offset] / 2;
const thumbPositionPercentage =
@ -104,7 +104,7 @@ export default defineComponent({
move: props.move,
bar: bar.value,
}),
})
}),
);
},
});

View File

@ -75,7 +75,7 @@
items,
accordion,
mixSider,
collapse
collapse,
);
const getBindValues = computed(() => ({ ...attrs, ...props }));
@ -89,7 +89,7 @@
setOpenKeys(currentRoute.value.path);
}
},
{ immediate: true }
{ immediate: true },
);
watch(
@ -100,7 +100,7 @@
}
setOpenKeys(currentRoute.value.path);
},
{ flush: 'post' }
{ flush: 'post' },
);
listenerRouteChange((route) => {

View File

@ -87,7 +87,7 @@
nextTick(() => {
updateOpened();
});
}
},
);
function updateOpened() {
@ -124,7 +124,7 @@
isRemoveAllPopup,
sliceIndex,
level: 0,
props,
props: props as any,
});
onMounted(() => {

View File

@ -98,7 +98,7 @@
active.value = false;
}
},
{ immediate: true }
{ immediate: true },
);
return { getClass, prefixCls, getItemStyle, getCollapse, handleClickItem, showTooptip };

View File

@ -286,7 +286,7 @@
if (props.name && Array.isArray(data)) {
state.opened = (data as (string | number)[]).includes(props.name);
}
}
},
);
rootMenuEmitter.on('on-update-active-name:submenu', (data: number[]) => {

View File

@ -1,9 +1,9 @@
import type { InjectionKey, Ref } from 'vue';
import type { Emitter } from '/@/utils/mitt';
import { createContext, useContext } from '/@/hooks/core/useContext';
import mitt from '/@/utils/mitt';
export interface SimpleRootMenuContextProps {
rootMenuEmitter: typeof mitt;
rootMenuEmitter: Emitter;
activeName: Ref<string | number>;
}

View File

@ -15,7 +15,7 @@ export function useOpenKeys(
menus: Ref<MenuType[]>,
accordion: Ref<boolean>,
mixSider: Ref<boolean>,
collapse: Ref<boolean>
collapse: Ref<boolean>,
) {
const debounceSetOpenKeys = useDebounceFn(setOpenKeys, 50);
async function setOpenKeys(path: string) {
@ -38,7 +38,7 @@ export function useOpenKeys(
menuState.activeSubMenuNames = menuState.openNames;
},
30,
native
native,
);
}

View File

@ -9,7 +9,7 @@
:disabled="disabled"
>
<template #[item]="data" v-for="item in Object.keys($slots)">
<slot :name="item" v-bind="data"></slot>
<slot :name="item" v-bind="data || {}"></slot>
</template>
</InputPassword>
<div :class="`${prefixCls}-bar`">
@ -59,7 +59,7 @@
() => unref(innerValueRef),
(val) => {
emit('change', val);
}
},
);
return {

View File

@ -10,7 +10,7 @@
@advanced-change="redoHeight"
>
<template #[replaceFormSlotKey(item)]="data" v-for="item in getFormSlotKeys">
<slot :name="item" v-bind="data"></slot>
<slot :name="item" v-bind="data || {}"></slot>
</template>
</BasicForm>
@ -22,7 +22,7 @@
@change="handleTableChange"
>
<template #[item]="data" v-for="item in Object.keys($slots)" :key="item">
<slot :name="item" v-bind="data"></slot>
<slot :name="item" v-bind="data || {}"></slot>
</template>
<template #[`header-${column.dataIndex}`] v-for="column in columns" :key="column.dataIndex">
@ -39,9 +39,10 @@
ColumnChangeParam,
} from './types/table';
import { defineComponent, ref, computed, unref, toRaw } from 'vue';
import { defineComponent, ref, computed, unref, toRaw, inject, watchEffect } from 'vue';
import { Table } from 'ant-design-vue';
import { BasicForm, useForm } from '/@/components/Form/index';
import { PageWrapperFixedHeightKey } from '/@/components/Page';
import expandIcon from './components/ExpandIcon';
import HeaderCell from './components/HeaderCell.vue';
import { InnerHandlers } from './types/table';
@ -64,6 +65,7 @@
import { omit } from 'lodash-es';
import { basicProps } from './props';
import { isFunction } from '/@/utils/is';
import { warn } from '/@/utils/log';
export default defineComponent({
components: {
@ -91,10 +93,10 @@
'columns-change',
],
setup(props, { attrs, emit, slots, expose }) {
const tableElRef = ref<ComponentRef>(null);
const tableElRef = ref(null);
const tableData = ref<Recordable[]>([]);
const wrapRef = ref<Nullable<HTMLDivElement>>(null);
const wrapRef = ref(null);
const innerPropsRef = ref<Partial<BasicTableProps>>();
const { prefixCls } = useDesign('basic-table');
@ -104,6 +106,15 @@
return { ...props, ...unref(innerPropsRef) } as BasicTableProps;
});
const isFixedHeightPage = inject(PageWrapperFixedHeightKey, false);
watchEffect(() => {
unref(isFixedHeightPage) &&
props.canResize &&
warn(
"'canResize' of BasicTable may not work in PageWrapper with 'fixedHeight' (especially in hot updates)",
);
});
const { getLoading, setLoading } = useLoading(getProps);
const {
getPaginationInfo,
@ -127,6 +138,7 @@
handleTableChange: onTableChange,
getDataSourceRef,
getDataSource,
getRawDataSource,
setTableData,
updateTableDataRecord,
findTableDataRecord,
@ -145,7 +157,7 @@
getFieldsValue: formActions.getFieldsValue,
clearSelectedRowKeys,
},
emit
emit,
);
function handleTableChange(...args) {
@ -170,7 +182,7 @@
tableElRef,
getColumnsRef,
getRowSelectionRef,
getDataSourceRef
getDataSourceRef,
);
const { customRow } = useCustomRow(getProps, {
@ -199,7 +211,7 @@
getProps,
getScrollRef,
tableElRef,
getDataSourceRef
getDataSourceRef,
);
const { getFormProps, replaceFormSlotKey, getFormSlotKeys, handleSearchInfoChange } =
@ -273,6 +285,7 @@
setColumns,
setLoading,
getDataSource,
getRawDataSource,
setProps,
getRowSelection,
getPaginationRef: getPagination,
@ -307,7 +320,7 @@
wrapRef,
tableAction,
redoHeight,
getFormProps,
getFormProps: getFormProps as any,
replaceFormSlotKey,
getFormSlotKeys,
getWrapperClass,
@ -378,9 +391,9 @@
align-items: center;
}
.ant-table-tbody > tr.ant-table-row-selected td {
background-color: fade(@primary-color, 8%) !important;
}
//.ant-table-tbody > tr.ant-table-row-selected td {
//background-color: fade(@primary-color, 8%) !important;
//}
}
.ant-pagination {
@ -400,7 +413,7 @@
.ant-table-body {
overflow-x: hidden !important;
overflow-y: scroll !important;
// overflow-y: scroll !important;
}
td {

View File

@ -95,7 +95,7 @@
.map((action) => {
const { popConfirm } = action;
return {
getPopupContainer: () => unref(table?.wrapRef.value) ?? document.body,
getPopupContainer: () => unref((table as any)?.wrapRef.value) ?? document.body,
type: 'link',
size: 'small',
...action,
@ -107,7 +107,7 @@
});
});
const getDropdownList = computed(() => {
const getDropdownList = computed((): any[] => {
return (toRaw(props.dropDownActions) || [])
.filter((action) => {
return hasPermission(action.auth) && isIfShow(action);
@ -133,7 +133,7 @@
function getTooltip(data: string | TooltipProps): TooltipProps {
return {
getPopupContainer: () => unref(table?.wrapRef.value) ?? document.body,
getPopupContainer: () => unref((table as any)?.wrapRef.value) ?? document.body,
placement: 'bottom',
...(isString(data) ? { title: data } : data),
};

View File

@ -24,7 +24,7 @@
<template v-for="(img, index) in imgList" :key="img">
<Image
:width="size"
:style="{ 'margin-left': index === 0 ? 0 : margin }"
:style="{ marginLeft: index === 0 ? 0 : margin }"
:src="srcPrefix + img"
/>
</template>

View File

@ -21,7 +21,7 @@ export const CellComponent: FunctionalComponent = (
popoverVisible,
getPopupContainer,
}: ComponentProps,
{ attrs }
{ attrs },
) => {
const Comp = componentMap.get(component) as typeof defineComponent;
@ -39,6 +39,6 @@ export const CellComponent: FunctionalComponent = (
{
default: () => DefaultComp,
content: () => ruleMessage,
}
},
);
};

View File

@ -5,41 +5,41 @@
:class="{ [`${prefixCls}__normal`]: true, 'ellipsis-cell': column.ellipsis }"
@click="handleEdit"
>
<div class="cell-content" :title="column.ellipsis ? getValues || '' : ''">{{
getValues || '&nbsp;'
}}</div>
<div class="cell-content" :title="column.ellipsis ? getValues ?? '' : ''">
{{ getValues ? getValues : '&nbsp;' }}
</div>
<FormOutlined :class="`${prefixCls}__normal-icon`" v-if="!column.editRow" />
</div>
<div v-if="isEdit" :class="`${prefixCls}__wrapper`" v-click-outside="onClickOutside">
<CellComponent
v-bind="getComponentProps"
:component="getComponent"
:style="getWrapperStyle"
:popoverVisible="getRuleVisible"
:rule="getRule"
:ruleMessage="ruleMessage"
:class="getWrapperClass"
size="small"
ref="elRef"
@change="handleChange"
@options-change="handleOptionsChange"
@pressEnter="handleEnter"
/>
<div :class="`${prefixCls}__action`" v-if="!getRowEditable">
<CheckOutlined :class="[`${prefixCls}__icon`, 'mx-2']" @click="handleSubmit" />
<CloseOutlined :class="`${prefixCls}__icon `" @click="handleCancel" />
<a-spin v-if="isEdit" :spinning="spinning">
<div :class="`${prefixCls}__wrapper`" v-click-outside="onClickOutside">
<CellComponent
v-bind="getComponentProps"
:component="getComponent"
:style="getWrapperStyle"
:popoverVisible="getRuleVisible"
:rule="getRule"
:ruleMessage="ruleMessage"
:class="getWrapperClass"
ref="elRef"
@change="handleChange"
@options-change="handleOptionsChange"
@pressEnter="handleEnter"
/>
<div :class="`${prefixCls}__action`" v-if="!getRowEditable">
<CheckOutlined :class="[`${prefixCls}__icon`, 'mx-2']" @click="handleSubmitClick" />
<CloseOutlined :class="`${prefixCls}__icon `" @click="handleCancel" />
</div>
</div>
</div>
</a-spin>
</div>
</template>
<script lang="ts">
import type { CSSProperties, PropType } from 'vue';
import { computed, defineComponent, nextTick, ref, toRaw, unref, watchEffect } from 'vue';
import type { BasicColumn } from '../../types/table';
import type { EditRecordRow } from './index';
import { defineComponent, ref, unref, nextTick, computed, watchEffect, toRaw } from 'vue';
import { FormOutlined, CloseOutlined, CheckOutlined } from '@ant-design/icons-vue';
import { CheckOutlined, CloseOutlined, FormOutlined } from '@ant-design/icons-vue';
import { CellComponent } from './CellComponent';
import { useDesign } from '/@/hooks/web/useDesign';
@ -48,14 +48,15 @@
import clickOutside from '/@/directives/clickOutside';
import { propTypes } from '/@/utils/propTypes';
import { isString, isBoolean, isFunction, isNumber, isArray } from '/@/utils/is';
import { isArray, isBoolean, isFunction, isNumber, isString } from '/@/utils/is';
import { createPlaceholderMessage } from './helper';
import { set, omit } from 'lodash-es';
import { omit, pick, set } from 'lodash-es';
import { treeToList } from '/@/utils/helper/treeHelper';
import { Spin } from 'ant-design-vue';
export default defineComponent({
name: 'EditableCell',
components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent },
components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent, ASpin: Spin },
directives: {
clickOutside,
},
@ -82,6 +83,7 @@
const optionsRef = ref<LabelValueOptions>([]);
const currentValueRef = ref<any>(props.value);
const defaultValueRef = ref<any>(props.value);
const spinning = ref<boolean>(false);
const { prefixCls } = useDesign('editable-cell');
@ -113,6 +115,7 @@
const value = isCheckValue ? (isNumber(val) && isBoolean(val) ? val : !!val) : val;
return {
size: 'small',
getPopupContainer: () => unref(table?.wrapRef.value) ?? document.body,
getCalendarContainer: () => unref(table?.wrapRef.value) ?? document.body,
placeholder: createPlaceholderMessage(unref(getComponent)),
@ -214,8 +217,7 @@
if (isBoolean(editRule) && !currentValue && !isNumber(currentValue)) {
ruleVisible.value = true;
const component = unref(getComponent);
const message = createPlaceholderMessage(component);
ruleMessage.value = message;
ruleMessage.value = createPlaceholderMessage(component);
return false;
}
if (isFunction(editRule)) {
@ -248,6 +250,35 @@
const dataKey = (dataIndex || key) as string;
if (!record.editable) {
const { getBindValues } = table;
const { beforeEditSubmit, columns } = unref(getBindValues);
if (beforeEditSubmit && isFunction(beforeEditSubmit)) {
spinning.value = true;
const keys: string[] = columns
.map((_column) => _column.dataIndex)
.filter((field) => !!field) as string[];
let result: any = true;
try {
result = await beforeEditSubmit({
record: pick(record, keys),
index,
key,
value,
});
} catch (e) {
result = false;
} finally {
spinning.value = false;
}
if (result === false) {
return;
}
}
}
set(record, dataKey, value);
//const record = await table.updateTableData(index, dataKey, value);
needEmit && table.emit?.('edit-end', { record, index, key, value });
@ -261,6 +292,10 @@
handleSubmit();
}
function handleSubmitClick() {
handleSubmit();
}
function handleCancel() {
isEdit.value = false;
currentValueRef.value = defaultValueRef.value;
@ -365,7 +400,8 @@
getRowEditable,
getValues,
handleEnter,
// getSize,
handleSubmitClick,
spinning,
};
},
});

View File

@ -282,7 +282,7 @@
nextTick(() => {
const columnListEl = unref(columnListRef);
if (!columnListEl) return;
const el = columnListEl.$el;
const el = columnListEl.$el as any;
if (!el) return;
// Drag and drop sort
const { initSortable } = useSortable(el, {
@ -351,7 +351,7 @@
const visible =
columns.findIndex(
(c: BasicColumn | string) =>
c === col.value || (typeof c !== 'string' && c.dataIndex === col.value)
c === col.value || (typeof c !== 'string' && c.dataIndex === col.value),
) !== -1;
return { dataIndex: col.value, fixed: col.fixed, visible };
});

View File

@ -40,7 +40,7 @@ function handleChildren(children: BasicColumn[] | undefined, ellipsis: boolean)
function handleIndexColumn(
propsRef: ComputedRef<BasicTableProps>,
getPaginationRef: ComputedRef<boolean | PaginationProps>,
columns: BasicColumn[]
columns: BasicColumn[],
) {
const { t } = useI18n();
@ -102,7 +102,7 @@ function handleActionColumn(propsRef: ComputedRef<BasicTableProps>, columns: Bas
export function useColumns(
propsRef: ComputedRef<BasicTableProps>,
getPaginationRef: ComputedRef<boolean | PaginationProps>
getPaginationRef: ComputedRef<boolean | PaginationProps>,
) {
const columnsRef = ref(unref(propsRef).columns) as unknown as Ref<BasicColumn[]>;
let cacheColumns = unref(propsRef).columns;
@ -122,7 +122,7 @@ export function useColumns(
handleItem(
item,
Reflect.has(item, 'ellipsis') ? !!item.ellipsis : !!ellipsis && !customRender && !slots
Reflect.has(item, 'ellipsis') ? !!item.ellipsis : !!ellipsis && !customRender && !slots,
);
});
return columns;
@ -179,7 +179,7 @@ export function useColumns(
(columns) => {
columnsRef.value = columns;
cacheColumns = columns?.filter((item) => !item.flag) ?? [];
}
},
);
function setCacheColumnsByField(dataIndex: string | undefined, value: Partial<BasicColumn>) {
@ -288,7 +288,7 @@ function sortFixedColumn(columns: BasicColumn[]) {
defColumns.push(column);
}
return [...fixedLeftColumns, ...defColumns, ...fixedRightColumns].filter(
(item) => !item.defaultHidden
(item) => !item.defaultHidden,
);
}

View File

@ -15,7 +15,7 @@ interface Options {
function getKey(
record: Recordable,
rowKey: string | ((record: Record<string, any>) => string) | undefined,
autoCreateKey?: boolean
autoCreateKey?: boolean,
) {
if (!rowKey || autoCreateKey) {
return record[ROW_KEY];
@ -31,7 +31,7 @@ function getKey(
export function useCustomRow(
propsRef: ComputedRef<BasicTableProps>,
{ setSelectedRowKeys, getSelectRowKeys, getAutoCreateKey, clearSelectedRowKeys, emit }: Options
{ setSelectedRowKeys, getSelectRowKeys, getAutoCreateKey, clearSelectedRowKeys, emit }: Options,
) {
const customRow = (record: Recordable, index: number) => {
return {

View File

@ -40,13 +40,14 @@ export function useDataSource(
clearSelectedRowKeys,
tableData,
}: ActionType,
emit: EmitType
emit: EmitType,
) {
const searchState = reactive<SearchState>({
sortInfo: {},
filterInfo: {},
});
const dataSourceRef = ref<Recordable[]>([]);
const rawDataSourceRef = ref<Recordable>({});
watchEffect(() => {
tableData.value = unref(dataSourceRef);
@ -60,13 +61,13 @@ export function useDataSource(
},
{
immediate: true,
}
},
);
function handleTableChange(
pagination: PaginationProps,
filters: Partial<Recordable<string[]>>,
sorter: SorterResult
sorter: SorterResult,
) {
const { clearSelectOnPageChange, sortFn, filterFn } = unref(propsRef);
if (clearSelectOnPageChange) {
@ -147,7 +148,7 @@ export function useDataSource(
function updateTableDataRecord(
rowKey: string | number,
record: Recordable
record: Recordable,
): Recordable | undefined {
const row = findTableDataRecord(rowKey);
@ -205,7 +206,7 @@ export function useDataSource(
const { pageField, sizeField, listField, totalField } = Object.assign(
{},
FETCH_SETTING,
fetchSetting
fetchSetting,
);
let pageParams: Recordable = {};
@ -235,6 +236,7 @@ export function useDataSource(
}
const res = await api(params);
rawDataSourceRef.value = res;
const isArrayResult = Array.isArray(res);
@ -287,6 +289,10 @@ export function useDataSource(
return getDataSourceRef.value as T[];
}
function getRawDataSource<T = Recordable>() {
return rawDataSourceRef.value as T;
}
async function reload(opt?: FetchParams) {
await fetch(opt);
}
@ -300,6 +306,7 @@ export function useDataSource(
return {
getDataSourceRef,
getDataSource,
getRawDataSource,
getRowKey,
setTableData,
getAutoCreateKey,

View File

@ -8,7 +8,7 @@ export function useLoading(props: ComputedRef<BasicTableProps>) {
() => unref(props).loading,
(loading) => {
loadingRef.value = loading;
}
},
);
const getLoading = computed(() => unref(loadingRef));

View File

@ -8,7 +8,7 @@ import { findNodeAll } from '/@/utils/helper/treeHelper';
export function useRowSelection(
propsRef: ComputedRef<BasicTableProps>,
tableData: Ref<Recordable[]>,
emit: EmitType
emit: EmitType,
) {
const selectedRowKeysRef = ref<string[]>([]);
const selectedRowRef = ref<Recordable[]>([]);
@ -35,7 +35,7 @@ export function useRowSelection(
() => unref(propsRef).rowSelection?.selectedRowKeys,
(v: string[]) => {
setSelectedRowKeys(v);
}
},
);
watch(
@ -52,7 +52,8 @@ export function useRowSelection(
rows: getSelectRows(),
});
});
}
},
{ deep: true },
);
const getAutoCreateKey = computed(() => {
@ -66,13 +67,19 @@ export function useRowSelection(
function setSelectedRowKeys(rowKeys: string[]) {
selectedRowKeysRef.value = rowKeys;
selectedRowRef.value = findNodeAll(
toRaw(unref(tableData)),
const allSelectedRows = findNodeAll(
toRaw(unref(tableData)).concat(toRaw(unref(selectedRowRef))),
(item) => rowKeys.includes(item[unref(getRowKey) as string]),
{
children: propsRef.value.childrenColumnName ?? 'children',
}
},
);
const trueSelectedRows: any[] = [];
rowKeys.forEach((key: string) => {
const found = allSelectedRows.find((item) => item[unref(getRowKey) as string] === key);
found && trueSelectedRows.push(found);
});
selectedRowRef.value = trueSelectedRows;
}
function setSelectedRows(rows: Recordable[]) {

View File

@ -18,7 +18,7 @@ export function useTable(tableProps?: Props): [
(instance: TableActionType, formInstance: UseTableMethod) => void,
TableActionType & {
getForm: () => FormActionType;
}
},
] {
const tableRef = ref<Nullable<TableActionType>>(null);
const loadedRef = ref<Nullable<boolean>>(false);
@ -50,7 +50,7 @@ export function useTable(tableProps?: Props): [
{
immediate: true,
deep: true,
}
},
);
}
@ -58,7 +58,7 @@ export function useTable(tableProps?: Props): [
const table = unref(tableRef);
if (!table) {
error(
'The table instance has not been obtained yet, please make sure the table is presented when performing the table operation!'
'The table instance has not been obtained yet, please make sure the table is presented when performing the table operation!',
);
}
return table as TableActionType;
@ -82,6 +82,9 @@ export function useTable(tableProps?: Props): [
getDataSource: () => {
return getTableInstance().getDataSource();
},
getRawDataSource: () => {
return getTableInstance().getRawDataSource();
},
getColumns: ({ ignoreIndex = false }: { ignoreIndex?: boolean } = {}) => {
const columns = getTableInstance().getColumns({ ignoreIndex }) || [];
return toRaw(columns);

View File

@ -6,7 +6,7 @@ import { ROW_KEY } from '../const';
export function useTableExpand(
propsRef: ComputedRef<BasicTableProps>,
tableData: Ref<Recordable[]>,
emit: EmitType
emit: EmitType,
) {
const expandedRowKeys = ref<string[]>([]);

View File

@ -12,7 +12,7 @@ export function useTableFooter(
scrollToFirstRowOnChange: boolean;
}>,
tableElRef: Ref<ComponentRef>,
getDataSourceRef: ComputedRef<Recordable>
getDataSourceRef: ComputedRef<Recordable>,
) {
const getIsEmptyData = computed(() => {
return (unref(getDataSourceRef) || []).length === 0;
@ -43,7 +43,7 @@ export function useTableFooter(
name: 'scroll',
listener: () => {
const footerBodyDom = tableEl.$el.querySelector(
'.ant-table-footer .ant-table-body'
'.ant-table-footer .ant-table-body',
) as HTMLDivElement;
if (!footerBodyDom || !bodyDom) return;
footerBodyDom.scrollLeft = bodyDom.scrollLeft;

View File

@ -8,7 +8,7 @@ export function useTableForm(
propsRef: ComputedRef<BasicTableProps>,
slots: Slots,
fetch: (opt?: FetchParams | undefined) => Promise<void>,
getLoading: ComputedRef<boolean | undefined>
getLoading: ComputedRef<boolean | undefined>,
) {
const getFormProps = computed((): Partial<FormProps> => {
const { formConfig } = unref(propsRef);
@ -21,9 +21,11 @@ export function useTableForm(
};
});
const getFormSlotKeys = computed(() => {
const getFormSlotKeys: ComputedRef<string[]> = computed(() => {
const keys = Object.keys(slots);
return keys.map((item) => (item.startsWith('form-') ? item : null)).filter(Boolean);
return keys
.map((item) => (item.startsWith('form-') ? item : null))
.filter((item) => !!item) as string[];
});
function replaceFormSlotKey(key: string) {

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