Compare commits

...

106 Commits

Author SHA1 Message Date
vben
2aa5e5da76 chore: release 2.7.2 2021-09-14 00:05:45 +08:00
vben
44b21bfc6c chore: update deps 2021-09-14 00:03:34 +08:00
vben
2820d5a627 fix: improve type introduction, fix #1196 2021-09-13 23:46:31 +08:00
无木
9640484895 fix: fixed token clear error
修复将token设置为undefined时可能失败的问题
2021-09-13 19:04:02 +08:00
无木
f87b0f2f5e fix(api-select): fixed value prop define
修复ApiSelect的value属性定义问题

fixed: #1175
2021-09-11 22:52:52 +08:00
无木
656ee4e5c9 fix(upload): accept not work as expected
修复basicUpload的accept属性未按预期工作的问题
2021-09-11 21:47:04 +08:00
无木
7593ef6a4f fix(table-action): divider not work as expected
修复tableAction中的divider未按预期工作
2021-09-11 20:26:27 +08:00
无木
b3307fe283 fix: warning in logout action
修复退出登录相关代码中的警告
2021-09-11 11:08:34 +08:00
无木
73dc492b2a feat(markdown-viewer): add new component
新增MarkdownViewer组件用于显示Markdown格式的富文本

close: #1181
2021-09-10 11:24:53 +08:00
无木
0bb9c035f7 fix(markdown): value not worked on init
修复Markdown组件的value属性初始值不起作用的问题
2021-09-10 11:22:40 +08:00
Francis Zuo
9e9ea3f43d fix: 修复弹窗全屏按钮异常关闭的问题(#1177) (#1182) 2021-09-09 22:59:53 +08:00
vben
996f2f3c22 chore: update deps 2021-09-09 22:59:10 +08:00
vben
b90a9557a3 chore: update deps 2021-09-09 22:58:29 +08:00
love-life
7df9b51344 fix: 修改axios 中 urlPrefix 字段不生效问题 (#1170)
* fix(样式污染): 会污染其他带有srcollbar的组件样式

* fix(axios): urlPrefix 字段传递不生问题效
2021-09-09 09:41:34 +08:00
handsomeFu
c753d945e0 fix: 修复 apiSelect 绑定值 attrs 的问题 (#1172)
* chore(permission): fix func name typo

* fix(apiSelect): fix `v-bind` value  `attrs` to `$attrs`
2021-09-09 09:40:53 +08:00
无木
83c1683bfd feat(demo): add JsonPreview demo
添加JsonPreview组件的使用演示

close: #1146
2021-09-06 20:36:19 +08:00
无木
044e2e4e86 fix(table): rowClassName not worked with striped
修复rowClassName属性无法和striped同时生效的问题

fixed: #1167
2021-09-06 20:13:13 +08:00
frezs
59a9087728 feat(table): 添加和支持动态删除和插入数据 (#1152) 2021-09-06 09:14:12 +08:00
Lan
3b6b4f7303 perf(tree): 优化Tree搜索功能,添加搜索高亮功能,优化样式表现 (#1153)
1. 修复expandOnSearch与checkOnSearch功能
2. 添加selectOnSearch功能
3. 添加搜索高亮title功能
4. 优化TreeHeader的样式表现: searchInput自动扩充
2021-09-06 09:13:53 +08:00
songweionline
5fa730c49a fix(table): Solve the bug of setting ifshow to false in table column (#1166)
表格列设置ifshow为false,表格的列设置里依然会渲染该列的checkBox,实际应该不渲染。如果需要隐藏应该是设置defaultHidden。
2021-09-06 09:13:35 +08:00
vben
6cadcf087d chore: update deps 2021-09-05 18:11:59 +08:00
江麻妞
95aca2ab8d fix (modal): 修复对话框 hook 不设置 loaded问题 (#1143)
fix (modal):  修复对话框 hook 不设置 loaded问题
2021-08-30 09:05:15 +08:00
Lan
e00578c40a feat(tree): 1. 添加自定义数据过滤判断方法 2. 添加搜索完成自动展开结果选项 3. 添加搜索完成自动选中结果选项 4. 树节点数据变化时强制搜索(同步searchData避免展示错误) (#1132) 2021-08-30 09:04:59 +08:00
Lan
6717fe654e fix: Improve content height calculation (#1136)
* feat(useContentHeight): 为useContentHeight 添加 向上递归 移除差值 的功能。

* feat(useContentHeight): 为useContentHeight 添加 向上递归 移除差值 的功能。 pagewrapper添加 upwardSpace以支持向上递归功能。
2021-08-30 09:04:32 +08:00
无木
ee7c31db44 feat(table): add onValid for editRow
为table的可编辑行添加校验方法
2021-08-27 22:23:39 +08:00
无木
a36825a6d4 fix: add loss action for userStore 2021-08-27 11:24:36 +08:00
无木
628e820684 fix(card-list): fixed build error
修复CardList组件造成的build错误
2021-08-27 08:55:38 +08:00
JinMao
0f5ddbf1ec feat: add CardList component 2021-08-27 05:51:58 +08:00
无木
1ddfc31c3c fix: getUserinfo is compatible with empty roles data
修复getUserinfo接口数据未携带roles字段时登录失败的问题
2021-08-26 21:20:26 +08:00
无木
d27633fb31 fix: fixed build warning for style of intro.js
修复intro.js的样式文件造成的build警告

fixed: #1130
2021-08-26 20:50:25 +08:00
江麻妞
30fa4cfa2a fix(table): 修复表格背景颜色再深色模式下会被穿透问题 (#1133) 2021-08-26 20:01:25 +08:00
love-life
6e7f6f82ed fix(modal): avoid style pollution to the whole world (#1128) 2021-08-26 20:01:05 +08:00
vben
466d4edcd0 perf: optimize css volume 2021-08-25 23:04:15 +08:00
vben
0b0a7ceef9 Revert "Revert "feat: support setup name""
This reverts commit 99daecdb60.
2021-08-25 22:57:00 +08:00
vben
99daecdb60 Revert "feat: support setup name"
This reverts commit d8362f084f.
2021-08-25 22:44:56 +08:00
vben
c8017b1365 fix(markdown): the hierarchy of markDown components after full screen 2021-08-25 22:42:39 +08:00
vben
d8362f084f feat: support setup name 2021-08-25 22:39:28 +08:00
无木
9f6822991c fix: name of vite mode support more characters
修复vite模式名称不支持下划线的问题

fixed: #1115
2021-08-24 22:54:31 +08:00
vben
56a966cfbf chore: format code 2021-08-24 22:41:48 +08:00
vben
2884e863ce perf: not waiting for router.isReady 2021-08-24 22:32:43 +08:00
无木
1235978ab2 fix: useRedo called duplicate may cause exception
修复useRedo的不当调用可能导致异常的问题

fixed: #1121
2021-08-24 21:01:28 +08:00
vben
9dd9fcd334 chore: adjust the windicss reference 2021-08-24 00:29:22 +08:00
无木
a426b9027e fix(table): fix table footer style
修复表尾合计行可能与主体部分的列没有对齐的问题

fixed: #1112
2021-08-23 16:36:26 +08:00
vben
455d109f71 chore: update deps 2021-08-22 12:22:56 +08:00
vben
6e85795737 chore: update vite-plugin-html 2021-08-21 00:13:43 +08:00
vben
d1f59b493d chore: update deps 2021-08-20 21:46:51 +08:00
无木
edc3096565 fix(table): editable icon not show with empty cell
修复可编辑单元格当内容为空时不会显示编辑图标的问题

fixed: #1103
2021-08-20 17:07:42 +08:00
无木
3a5d1a5757 fix: refresh failed while token invalid
修复当token失效时,刷新页面可能出现异常的问题

fixed: #1101
2021-08-20 16:55:42 +08:00
无木
2c867b3d63 feat(table): add beforeEditSubmit for editable cell
单元格编辑功能新增提交回调
2021-08-19 23:57:42 +08:00
无木
fb43fad555 fix(tinymce): fixed tinymce destory method
修复tinymce销毁方法可能出现异常的问题
2021-08-19 19:51:55 +08:00
无木
8e01377481 fix(tinymce): fixed inline mode
修复Tinymce的inline模式在一些场景下会出现异常的问题

fixed: #1092
2021-08-18 22:55:36 +08:00
无木
e7c96363a1 fix(code-editor): fixed formatting error
修复JSON编辑器在格式化无效JSON文本时会抛出异常的问题
2021-08-18 20:52:34 +08:00
无木
93812f734e fix(echarts): theme setting supported
修复useECharts的theme参数不起作用的问题

fixed: #1095
2021-08-18 20:05:40 +08:00
vben
e15b4f14db fix: fix all types of errors, compatible with volar plugin 2021-08-17 23:04:29 +08:00
无木
a5ff59237f feat(form): component Divider support helpMessage
Divider表单组件支持helpMessage配置
2021-08-17 22:59:36 +08:00
vben
65735926d4 chore: update deps 2021-08-17 22:15:27 +08:00
无木
47a448b8ae feat(form): add Divider for schema component type
新增Divider用于较长表单的区域分割
2021-08-17 17:50:54 +08:00
无木
5138e447e7 fix: slots worked in basicTable and basicModal
修复basicTable和basicModal的插槽传递异常的问题
2021-08-17 17:09:48 +08:00
matevip
837a365885 docs: Readme增加后台整合示例 (#1087) 2021-08-17 15:07:22 +08:00
vben
43658e2fb3 chore: release 2.7.1 2021-08-16 23:44:29 +08:00
vben
8fa6015b1a chore: change to setup syntax 2021-08-16 23:43:09 +08:00
handsomeFu
91cbe0a03b chore(permission): fix func name typo (#1082) 2021-08-16 23:15:19 +08:00
CXM
72634ffe6e fix: add axios error info from response (#1083)
* fix(type): fix ant-design-vue  ->

* fix: add axios error info from response
2021-08-16 23:14:40 +08:00
无木
c420174c1d style: fix basicButton style 2021-08-16 20:18:53 +08:00
无木
b7487675ce chore: downgrade vue-json-pretty to 1.8.1 2021-08-16 13:33:20 +08:00
无木
1b577922e7 fix: fixed basicButton primary style
修正BasicButton primary类型的样式
2021-08-16 09:12:48 +08:00
无木
3ba8a67647 fix: fixed basicButton ghost style
修正BasicButton幽灵状态的样式
2021-08-16 08:47:45 +08:00
无木
beb4ae92c1 fix: fixed basicButton style
修正BasicButton的样式
2021-08-16 07:35:47 +08:00
无木
cc46935a82 feat: always refresh userinfo when page reload
每次刷新整个页面时都从接口更新用户信息
2021-08-16 06:04:12 +08:00
无木
53e79a2d94 fix(table): fix injection not found warning
修复injection警告
2021-08-16 05:52:04 +08:00
vben
8ff5c03d53 ci: remove cache 2021-08-15 23:05:00 +08:00
vben
c69996d073 chore: use node16 2021-08-15 22:49:03 +08:00
RemMai
b07003e184 添加v-model:value双向绑定的支持 (#1073)
无需在Change事件中修改绑定的Value。
仅需在属性中设置 v-model:value,选择图标后,value值自动修改。
2021-08-15 22:37:21 +08:00
vben
45a8eb974a refactor(dashboard): change to setup syntax 2021-08-15 22:36:46 +08:00
无木
2dd3d85448 fix: fixed useRedo may loss route params
修复useRedo会丢失当前路由的params数据问题

fixed: #1079
2021-08-15 16:45:13 +08:00
无木
da12da9d8c perf(table): fixed code style
修复一些代码检查警告,并且为table的canResize属性添加不兼容场景警告

close: #1070
2021-08-15 08:54:42 +08:00
无木
30c5fc63c8 fix(demo): fix form style in modal
修复演示页面中Modal内的Form样式问题

closed: #1076
2021-08-14 23:21:05 +08:00
无木
7971896383 fix(table): size not worked in editComponentProps
修复无法设置basicTable编辑组件的size属性的问题

fixed: #1074
2021-08-14 22:31:25 +08:00
无木
a8b18c2697 style: fix selected background color of tr
修复表格选中行的背景颜色与固定列的冲突

fixed: #1069
2021-08-14 21:12:30 +08:00
无木
5ae894a5c7 style: restore default border-color
恢复antd默认的基础边框色
2021-08-14 20:53:52 +08:00
无木
bcfa338227 feat: add updatePath for useTabs
添加更新标签path的方法

close: #1068
2021-08-13 15:13:35 +08:00
无木
b1f31762e3 fix: slots working in components
修复vue新版本改动导致组件传递slots可能出现错误的问题
2021-08-13 15:06:06 +08:00
无木
93f9a19aa1 feat(form): add alwaysShowLines prop
允许设置Form折叠时始终保持显示状态的行数

close: #1051
2021-08-13 11:51:23 +08:00
无木
61d853e6a5 style(types): fix some type statement 2021-08-13 11:13:29 +08:00
无木
1f55c4180f fix(i18n): add i18n translate data
添加部分缺失的翻译文案
2021-08-13 11:11:35 +08:00
无木
4b6025cb9a fix(table): getSelectRows support multi-page
getSelectRows支持跨页选择

close: #914
2021-08-13 08:50:28 +08:00
vben
2f6d133b96 refactor(application): change to setup syntax 2021-08-13 07:29:33 +08:00
vben
9035fd191e fix(types): fix some type errors 2021-08-13 00:12:51 +08:00
vben
bb89c5059c refactor(sys): change to setup syntax 2021-08-12 23:54:12 +08:00
CXM
66feb779a8 fix: fix build handler & misc (#1060)
* fix(type): fix ant-design-vue  ->

* fix: fix build handler & misc
2021-08-12 23:23:44 +08:00
vben
948219c576 chore: update deps 2021-08-12 23:19:28 +08:00
无木
60577d6720 feat(tree): add searchable function
添加搜索功能相关属性和方法

close: #1057
2021-08-11 17:59:07 +08:00
无木
953bfc6f1a fix(modal): helpMessage doesn't work
修复`helpMessage`属性不起作用的问题
2021-08-10 23:02:59 +08:00
无木
2052eb5a65 fix(table): wrong bg-color in fullscreen mode
修复浅色主题下的table在全屏状态时背景颜色不正确的问题
2021-08-10 22:34:41 +08:00
无木
019555be0c fix(table): selection-change not triggered in unchecking
修复selection-change事件在取消勾选时未能正确触发的问题

fixed: #1053
2021-08-10 14:36:29 +08:00
无木
33a335a3f5 fix(table): 0 is not shown in editable cell
修复可编辑单元格中未能正确显示零值的问题

fixed: #1039
2021-08-09 21:49:11 +08:00
vben
9d2231b1cd chore: update deps 2021-08-08 23:05:44 +08:00
CXM
6d5388aaf1 fix(type): fix ant-design-vue -> (#1043) 2021-08-08 10:16:37 +08:00
spking11
b2d49cbbf8 fix(locales): fix that vscode extension i18n-Ally detect zh-CN as zh (#1044) 2021-08-08 10:16:19 +08:00
Leo Caan (陈栋)
1bb5156923 fix(route): the whitelist should include basicRoutes (#1048)
* fix(table): recursive updateTableDataRecord

无刷新更新表格数据时,支持递归查找,用于树状数据时。同时新增 findTableDataRecord 函数,用于支持无刷新新增数据到树状表格中

* fix(router): whitelist include basicRoutes

白名单应包含不在菜单上出现的静态路由,否则在动态切换菜单 resetRouter 时会丢失这些,如在usePermission.resume中

* fix: get basicRoutes whitelist bad code
2021-08-08 10:15:34 +08:00
Vben
62f8468775 chore: add windi.config.ts 2021-08-04 23:26:08 +08:00
Vben
8e5740e715 chore: update deps 2021-08-04 23:21:43 +08:00
JasonYHZ
f3cf162af1 feat(table): add getRawDataSource() function (#1029) 2021-08-04 08:59:21 +08:00
无木
381943078f fix(cropper): cropper not destroy in time
图片剪裁组件未能及时销毁资源

fixed: #1027
2021-08-03 21:17:38 +08:00
无木
26f251e1ed fix(qrcode): qrcode not displayed properly
fixed: #1026
2021-08-03 20:55:40 +08:00
无木
1214b7c32c fix(table): cellFormat support Map
close: #1031
2021-08-03 20:37:02 +08:00
280 changed files with 4757 additions and 3617 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',
{

View File

@@ -68,10 +68,10 @@ jobs:
sed -i "s#VITE_BUILD_COMPRESS\s*=.*#VITE_BUILD_COMPRESS = 'gzip'#g" ./.env.production
cat ./.env.production
- name: use Node.js 14
- name: use Node.js 16
uses: actions/setup-node@v2.1.2
with:
node-version: '14.x'
node-version: '16.x'
- name: Get yarn cache
id: yarn-cache

View File

@@ -21,10 +21,10 @@ jobs:
sed -i "s#VITE_DROP_CONSOLE\s*=.*#VITE_DROP_CONSOLE = true#g" ./.env.production
cat ./.env.production
- name: use Node.js 15
- name: use Node.js 16
uses: actions/setup-node@v2.1.2
with:
node-version: '15.x'
node-version: '16.x'
- name: Get yarn cache
id: yarn-cache

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,55 @@
## 2.7.2(2021-09-14)
### ✨ Features
- **BasicForm** New `Divider` in the form component for dividing the area of longer forms
- **BasicTable**
- Cell editor adds submit callback, which will decide whether to submit data to the form based on the result returned by the callback function
- Add check method for row editing, allowing only check but not submit value, so asynchronously save data successfully before submit to table
- Fix the problem that the `rowClassName` property cannot be used at the same time as `striped`.
- New component **MarkdownViewer** for displaying rich text in Markdown format
### 🐛 Bug Fixes
- **CodeEditor** Fix JSON editor throwing exception when formatting invalid JSON text
- **Tinymce** fixes an issue where inline mode throws an exception in some scenarios
- **BasicTable**
- Repair the problem that the editing icon is not displayed when the content of editable cell is empty
- Repair the problem that the total row at the end of the table sometimes fails to align with the columns in the main part of the table.
- **MarkDown** Repair the problem that the value of initial value property does not work.
- **BasicUpload** Repair the problem that `accept` property does not support `MIME` and suffix name starting with dot.
- **ApiSelect** Fix the problem of type definition of `value` property.
- **Other**
- Repair the problem that some wrapper components give error when using slots.
- Repair the problem that `theme` parameter of `useECharts` does not work.
- Repair the problem that when `Token` is invalid, pressing F5 to refresh the page may cause abnormal page loading.
- Repair the problem that the improper call of `useRedo` may lead to `path` redirection abnormality.
- Repair the problem that `vite` custom mode name does not support underscore.
## 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,144 @@
## [2.7.2](https://github.com/anncwb/vue-vben-admin/compare/v2.7.1...v2.7.2) (2021-09-13)
### Bug Fixes
- fixed token clear error ([9640484](https://github.com/anncwb/vue-vben-admin/commit/96404848955f84d57b88dd240ab3a57b7017103c))
- improve type introduction, fix [#1196](https://github.com/anncwb/vue-vben-admin/issues/1196) ([2820d5a](https://github.com/anncwb/vue-vben-admin/commit/2820d5a627260bb8eddfcd25df1cd7d1196932e8))
- **api-select:** fixed `value` prop define ([f87b0f2](https://github.com/anncwb/vue-vben-admin/commit/f87b0f2f5efe4e9977c4cc0742dbcaefbad2ca02)), closes [#1175](https://github.com/anncwb/vue-vben-admin/issues/1175)
- **card-list:** fixed build error ([628e820](https://github.com/anncwb/vue-vben-admin/commit/628e820684ce5d81f130548505efe83e8d516131))
- **code-editor:** fixed formatting error ([e7c9636](https://github.com/anncwb/vue-vben-admin/commit/e7c96363a1963b7733a9ee498403eb6a062160e6))
- **echarts:** theme setting supported ([93812f7](https://github.com/anncwb/vue-vben-admin/commit/93812f734ec85529aa27fc3100a2eaef8c7a6df5)), closes [#1095](https://github.com/anncwb/vue-vben-admin/issues/1095)
- **markdown:** the hierarchy of markDown components after full screen ([c8017b1](https://github.com/anncwb/vue-vben-admin/commit/c8017b1365ea49f95a26148a539f8c30d8a8631f))
- **markdown:** `value` not worked on init ([0bb9c03](https://github.com/anncwb/vue-vben-admin/commit/0bb9c035f77588c58d36b3fd45d89b9730cd70d7))
- **modal:** avoid style pollution to the whole world ([#1128](https://github.com/anncwb/vue-vben-admin/issues/1128)) ([6e7f6f8](https://github.com/anncwb/vue-vben-admin/commit/6e7f6f82ed2819e02e2b3114884e665d0762d7e9))
- **table:** `rowClassName` not worked with `striped` ([044e2e4](https://github.com/anncwb/vue-vben-admin/commit/044e2e4e866dd5b120daab03c47aba1ca1f9140a)), closes [#1167](https://github.com/anncwb/vue-vben-admin/issues/1167)
- **table:** 修复表格背景颜色再深色模式下会被穿透问题 ([#1133](https://github.com/anncwb/vue-vben-admin/issues/1133)) ([30fa4cf](https://github.com/anncwb/vue-vben-admin/commit/30fa4cfa2ab6229efc67224fd082e32da0a95d49))
- **table:** editable icon not show with empty cell ([edc3096](https://github.com/anncwb/vue-vben-admin/commit/edc30965653831b4572c5d5e067f556f4757ce75)), closes [#1103](https://github.com/anncwb/vue-vben-admin/issues/1103)
- **table:** fix table footer style ([a426b90](https://github.com/anncwb/vue-vben-admin/commit/a426b9027ef524f9033d510d0c74cd17b2ad5bcf)), closes [#1112](https://github.com/anncwb/vue-vben-admin/issues/1112)
- **table:** Solve the bug of setting ifshow to false in table column ([#1166](https://github.com/anncwb/vue-vben-admin/issues/1166)) ([5fa730c](https://github.com/anncwb/vue-vben-admin/commit/5fa730c49ae46fa448d49d597dc7b2b6a019b268))
- **table-action:** `divider` not work as expected ([7593ef6](https://github.com/anncwb/vue-vben-admin/commit/7593ef6a4f081ed800658b70316ab2f1e3ee631d))
- **tinymce:** fixed `inline` mode ([8e01377](https://github.com/anncwb/vue-vben-admin/commit/8e01377481a34cda221de6bbb01fc7d5b2824c82)), closes [#1092](https://github.com/anncwb/vue-vben-admin/issues/1092)
- **upload:** `accept` not work as expected ([656ee4e](https://github.com/anncwb/vue-vben-admin/commit/656ee4e5c9b363b6ab59aa071915414e5ee95de4))
- `getUserinfo` is compatible with empty roles data ([1ddfc31](https://github.com/anncwb/vue-vben-admin/commit/1ddfc31c3c4c792c5f741f6d0f0754ffc9a6613c))
- `slots` worked in `basicTable` and `basicModal` ([5138e44](https://github.com/anncwb/vue-vben-admin/commit/5138e447e74ef01309457d22f44129c8b1b2f815))
- `useRedo` called duplicate may cause exception ([1235978](https://github.com/anncwb/vue-vben-admin/commit/1235978ab23740dfb11e3de7ac26a7d10a4899dc)), closes [#1121](https://github.com/anncwb/vue-vben-admin/issues/1121)
- 修复 `apiSelect` 绑定值 `attrs` 的问题 ([#1172](https://github.com/anncwb/vue-vben-admin/issues/1172)) ([c753d94](https://github.com/anncwb/vue-vben-admin/commit/c753d945e08f72cab5bc8a585601cab6a0523fca))
- 修复弹窗全屏按钮异常关闭的问题([#1177](https://github.com/anncwb/vue-vben-admin/issues/1177)) ([#1182](https://github.com/anncwb/vue-vben-admin/issues/1182)) ([9e9ea3f](https://github.com/anncwb/vue-vben-admin/commit/9e9ea3f43d8c4b88649c1998bf89186b5f7ee6a2))
- 修改 axios 中 urlPrefix 字段不生效问题 ([#1170](https://github.com/anncwb/vue-vben-admin/issues/1170)) ([7df9b51](https://github.com/anncwb/vue-vben-admin/commit/7df9b513447d8deab2fd8e86fa23c807adb6d440))
- add loss action for userStore ([a36825a](https://github.com/anncwb/vue-vben-admin/commit/a36825a6d423aae9aaf1936ce55947ba8c2104b0))
- fix all types of errors, compatible with volar plugin ([e15b4f1](https://github.com/anncwb/vue-vben-admin/commit/e15b4f14db51812effd55670b3d2da7b082e00a7))
- fixed build warning for style of `intro.js` ([d27633f](https://github.com/anncwb/vue-vben-admin/commit/d27633fb31824e92cbeb24f8d626d8e33ce7179e)), closes [#1130](https://github.com/anncwb/vue-vben-admin/issues/1130)
- Improve content height calculation ([#1136](https://github.com/anncwb/vue-vben-admin/issues/1136)) ([6717fe6](https://github.com/anncwb/vue-vben-admin/commit/6717fe654e88e6a939a16c523832870388ec1886))
- name of vite `mode` support more characters ([9f68229](https://github.com/anncwb/vue-vben-admin/commit/9f6822991c4b2da78e0a5d0c7d6e0288f0d9d1cb)), closes [#1115](https://github.com/anncwb/vue-vben-admin/issues/1115)
- refresh failed while token invalid ([3a5d1a5](https://github.com/anncwb/vue-vben-admin/commit/3a5d1a5757c0a2be17e6dd370cbb023ddbb30d5e)), closes [#1101](https://github.com/anncwb/vue-vben-admin/issues/1101)
- warning in logout action ([b3307fe](https://github.com/anncwb/vue-vben-admin/commit/b3307fe2836fb6f9806d602d5bdb7e540c49f1b0))
- **tinymce:** fixed `tinymce` destory method ([fb43fad](https://github.com/anncwb/vue-vben-admin/commit/fb43fad555b093af23194bdb3670bc1347c0010f))
### Features
- **demo:** add `JsonPreview` demo ([83c1683](https://github.com/anncwb/vue-vben-admin/commit/83c1683bfdcf4ea33de771895b46e41f276969e8)), closes [#1146](https://github.com/anncwb/vue-vben-admin/issues/1146)
- **form:** add `Divider` for schema component type ([47a448b](https://github.com/anncwb/vue-vben-admin/commit/47a448b8aea572e54dac97dc4f9fb6c1c005685a))
- **form:** component `Divider` support `helpMessage` ([a5ff592](https://github.com/anncwb/vue-vben-admin/commit/a5ff59237f2eb6ea4c1770acc594c75bf1f6e95f))
- **markdown-viewer:** add new component ([73dc492](https://github.com/anncwb/vue-vben-admin/commit/73dc492b2a49793d945ccdae7f5c429c874f298c)), closes [#1181](https://github.com/anncwb/vue-vben-admin/issues/1181)
- **table:** 添加和支持动态删除和插入数据 ([#1152](https://github.com/anncwb/vue-vben-admin/issues/1152)) ([59a9087](https://github.com/anncwb/vue-vben-admin/commit/59a90877287a289f746eec97d12c2d3a1d5476b0))
- **table:** add `beforeEditSubmit` for editable cell ([2c867b3](https://github.com/anncwb/vue-vben-admin/commit/2c867b3d636d57cdc526a4ca600af7d747b7d833))
- **table:** add `onValid` for editRow ([ee7c31d](https://github.com/anncwb/vue-vben-admin/commit/ee7c31db44fd8f99f0d26da368e1d82b5630f309))
- **tree:** 1. 添加自定义数据过滤判断方法 2. 添加搜索完成自动展开结果选项 3. 添加搜索完成自动选中结果选项 4. 树节点数据变化时强制搜索(同步 searchData 避免展示错误) ([#1132](https://github.com/anncwb/vue-vben-admin/issues/1132)) ([e00578c](https://github.com/anncwb/vue-vben-admin/commit/e00578c40a585a4a35f235c0228aebaf62cea1ba))
- add CardList component ([0f5ddbf](https://github.com/anncwb/vue-vben-admin/commit/0f5ddbf1ec777fc238a94bd037d37ea787316757))
### Performance Improvements
- **tree:** 优化 Tree 搜索功能,添加搜索高亮功能,优化样式表现 ([#1153](https://github.com/anncwb/vue-vben-admin/issues/1153)) ([3b6b4f7](https://github.com/anncwb/vue-vben-admin/commit/3b6b4f73033e8757fd3a032f0910dfcc30dee151))
- not waiting for router.isReady ([2884e86](https://github.com/anncwb/vue-vben-admin/commit/2884e863ce826cd92cd782f40cdee31588bc6d32))
- optimize css volume ([466d4ed](https://github.com/anncwb/vue-vben-admin/commit/466d4edcd02fc91e2b4cdbbc3c501bfd2fde7a3d))
## [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,3 +1,55 @@
## 2.7.2(2021-09-14)
### ✨ Features
- **BasicForm** 表单组件新增`Divider`,用于较长表单的区域分割
- **BasicTable**
- 单元格编辑新增提交回调,将根据回调函数返回的结果来决定是否将数据提交到表格
- 行编辑添加校验方法,允许只校验而不提交值,以便异步保存数据成功后才提交倒表格
- 修复`rowClassName`属性无法和`striped`同时使用的问题
- 新增组件 **MarkdownViewer** 用于显示 Markdown 格式的富文本
### 🐛 Bug Fixes
- **CodeEditor** 修复 JSON 编辑器在格式化无效 JSON 文本时会抛出异常的问题
- **Tinymce** 修复 inline 模式在一些场景下会出现异常的问题
- **BasicTable**
- 修复可编辑单元格的内容为空时,不会显示编辑图标的问题
- 修复表尾合计行与表格主体部分的列有时候未能对齐的问题
- **MarkDown** 修复初始 value 属性的值不起作用的问题
- **BasicUpload** 修复`accept`属性不支持`MIME`及点开头的后缀名的问题
- **ApiSelect** 修复`value`属性的类型定义问题
- **其它**
- 修复部分封装组件在使用插槽时报错的问题
- 修复`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`类型数据的问题
- 修复可编辑单元格未能正确显示`0`值的问题
- 修复 selection-change 事件在取消勾选时未能正确触发的问题
- 修复浅色主题下的全屏状态背景颜色不正确的问题
- 修复`getSelectRows`不支持远程数据跨页选择时获取完整数据的问题
- 修复在`editComponentProps`中为编辑组件提供的`size`属性无效的问题
- **Qrcode** 修复二维码组件在创建时未能及时绘制的问题
- **BasicModal** 修复`helpMessage`属性不起作用的问题
- **BasicButton** 修复按钮样式表现与 antd 官方不一致的问题
- **其它** 修复`useRedo`(重新加载当前路由)会丢失路由`params`数据的问题
## 2.7.0(2021-08-03)
## (破坏性更新) Breaking changes

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,11 +1,10 @@
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 vueSetupExtend from 'vite-plugin-vue-setup-extend';
import { configHtmlPlugin } from './html';
import { configPwaConfig } from './pwa';
import { configMockPlugin } from './mock';
@@ -31,6 +30,8 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
vue(),
// have to
vueJsx(),
// support name
vueSetupExtend(),
];
// vite-plugin-windicss
@@ -70,7 +71,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}`;
},
@@ -61,7 +66,7 @@ export function configThemePlugin(isBuild: boolean): Plugin[] {
'border-color-base': '#303030',
// 'border-color-split': '#30363d',
'item-active-bg': '#111b26',
'app-content-background': 'rgb(255 255 255 / 4%)',
'app-content-background': '#1e1e1e',
'tree-node-selected-bg': '#11263c',
'alert-success-border-color': '#274916',

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.2",
"author": {
"name": "vben",
"email": "anncwb@126.com",
@@ -34,62 +34,64 @@
"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.16",
"@logicflow/extension": "^0.6.16",
"@vueuse/core": "^6.3.3",
"@zxcvbn-ts/core": "^1.0.0-beta.0",
"ant-design-vue": "2.2.2",
"axios": "^0.21.1",
"codemirror": "^5.62.2",
"ant-design-vue": "2.2.7",
"axios": "^0.21.4",
"codemirror": "^5.62.3",
"cropperjs": "^1.5.12",
"crypto-js": "^4.1.1",
"echarts": "^5.1.2",
"intro.js": "^4.1.0",
"echarts": "^5.2.0",
"intro.js": "^4.2.2",
"lodash-es": "^4.17.21",
"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.9",
"print-js": "^1.6.0",
"qrcode": "^1.4.4",
"resize-observer-polyfill": "^1.5.1",
"showdown": "^1.9.1",
"sortablejs": "^1.14.0",
"tinymce": "^5.8.2",
"tinymce": "^5.9.2",
"vditor": "^3.8.6",
"vue": "3.1.5",
"vue": "3.2.11",
"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-json-pretty": "^2.0.4",
"vue-router": "^4.0.11",
"vue-types": "^4.1.0",
"xlsx": "^0.17.1"
},
"devDependencies": {
"@commitlint/cli": "^13.1.0",
"@commitlint/config-conventional": "^13.1.0",
"@iconify/json": "^1.1.382",
"@iconify/json": "^1.1.401",
"@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/inquirer": "^8.1.1",
"@types/intro.js": "^3.0.2",
"@types/jest": "^26.0.24",
"@types/lodash-es": "^4.17.4",
"@types/jest": "^27.0.1",
"@types/lodash-es": "^4.17.5",
"@types/mockjs": "^1.0.4",
"@types/node": "^16.4.10",
"@types/node": "^16.9.1",
"@types/nprogress": "^0.2.0",
"@types/qrcode": "^1.4.1",
"@types/qs": "^6.9.7",
"@types/showdown": "^1.9.4",
"@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",
"@vitejs/plugin-vue-jsx": "^1.1.7",
"@vue/compiler-sfc": "3.1.5",
"@vue/test-utils": "^2.0.0-rc.12",
"autoprefixer": "^10.3.1",
"@typescript-eslint/eslint-plugin": "^4.31.0",
"@typescript-eslint/parser": "^4.31.0",
"@vitejs/plugin-legacy": "^1.5.3",
"@vitejs/plugin-vue": "^1.6.2",
"@vitejs/plugin-vue-jsx": "^1.1.8",
"@vue/compiler-sfc": "3.2.11",
"@vue/test-utils": "^2.0.0-rc.14",
"autoprefixer": "^10.3.4",
"commitizen": "^4.2.4",
"conventional-changelog-cli": "^2.1.1",
"cross-env": "^7.0.3",
@@ -98,20 +100,20 @@
"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": "^4.0.0",
"eslint-plugin-vue": "^7.17.0",
"esno": "^0.9.1",
"fs-extra": "^10.0.0",
"http-server": "^0.12.3",
"husky": "^7.0.1",
"http-server": "^13.0.1",
"husky": "^7.0.2",
"inquirer": "^8.1.2",
"is-ci": "^3.0.0",
"jest": "^27.0.6",
"jest": "^27.2.0",
"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",
"prettier": "^2.4.0",
"pretty-quick": "^3.1.1",
"rimraf": "^3.0.2",
"rollup-plugin-visualizer": "5.5.2",
@@ -119,27 +121,28 @@
"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",
"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",
"ts-jest": "^27.0.5",
"ts-node": "^10.2.1",
"typescript": "4.4.3",
"vite": "2.5.7",
"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.2",
"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",
"vue-eslint-parser": "^7.10.0",
"vue-tsc": "^0.2.2"
"vite-plugin-vue-setup-extend": "^0.1.0",
"vite-plugin-windicss": "^1.4.2",
"vue-eslint-parser": "^7.11.0",
"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,8 +7,7 @@ module.exports = {
singleQuote: true,
quoteProps: 'as-needed',
bracketSpacing: true,
trailingComma: 'es5',
jsxBracketSameLine: false,
trailingComma: 'all',
jsxSingleQuote: false,
arrowParens: 'always',
insertPragma: false,
@@ -16,5 +15,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

@@ -21,7 +21,7 @@ export function loginApi(params: LoginParams, mode: ErrorMessageMode = 'modal')
},
{
errorMessageMode: mode,
}
},
);
}
@@ -29,7 +29,7 @@ export function loginApi(params: LoginParams, mode: ErrorMessageMode = 'modal')
* @description: getUserInfo
*/
export function getUserInfo() {
return defHttp.get<GetUserInfoModel>({ url: Api.GetUserInfo });
return defHttp.get<GetUserInfoModel>({ url: Api.GetUserInfo }, { errorMessageMode: 'none' });
}
export function getPermCode() {

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

@@ -0,0 +1,4 @@
import { withInstall } from '/@/utils';
import cardList from './src/CardList.vue';
export const CardList = withInstall(cardList);

View File

@@ -0,0 +1,178 @@
<template>
<div class="p-2">
<div class="bg-white mb-2 p-4">
<BasicForm @register="registerForm" />
</div>
{{ sliderProp.width }}
<div class="bg-white p-2">
<List
:grid="{ gutter: 5, xs: 1, sm: 2, md: 4, lg: 4, xl: 6, xxl: grid }"
:data-source="data"
:pagination="paginationProp"
>
<template #header>
<div class="flex justify-end space-x-2"
><slot name="header"></slot>
<Tooltip>
<template #title>
<div class="w-50">每行显示数量</div
><Slider
id="slider"
v-bind="sliderProp"
v-model:value="grid"
@change="sliderChange"
/></template>
<Button><TableOutlined /></Button>
</Tooltip>
<Tooltip @click="fetch">
<template #title>刷新</template>
<Button><RedoOutlined /></Button>
</Tooltip>
</div>
</template>
<template #renderItem="{ item }">
<ListItem>
<Card>
<template #title></template>
<template #cover>
<div :class="height">
<Image :src="item.imgs[0]" />
</div>
</template>
<template class="ant-card-actions" #actions>
<!-- <SettingOutlined key="setting" />-->
<EditOutlined key="edit" />
<Dropdown
:trigger="['hover']"
:dropMenuList="[
{
text: '删除',
event: '1',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, item.id),
},
},
]"
popconfirm
>
<EllipsisOutlined key="ellipsis" />
</Dropdown>
</template>
<CardMeta>
<template #title>
<TypographyText :content="item.name" :ellipsis="{ tooltip: item.address }" />
</template>
<template #avatar>
<Avatar :src="item.avatar" />
</template>
<template #description>{{ item.time }}</template>
</CardMeta>
</Card>
</ListItem>
</template>
</List>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted, ref } from 'vue';
import {
EditOutlined,
EllipsisOutlined,
RedoOutlined,
TableOutlined,
} from '@ant-design/icons-vue';
import { List, Card, Image, Typography, Tooltip, Slider, Avatar } from 'ant-design-vue';
import { Dropdown } from '/@/components/Dropdown';
import { BasicForm, useForm } from '/@/components/Form';
import { propTypes } from '/@/utils/propTypes';
import { Button } from '/@/components/Button';
import { isFunction } from '/@/utils/is';
import { useSlider, grid } from './data';
const ListItem = List.Item;
const CardMeta = Card.Meta;
const TypographyText = Typography.Text;
// 获取slider属性
const sliderProp = computed(() => useSlider(4));
// 组件接收参数
const props = defineProps({
// 请求API的参数
params: propTypes.object.def({}),
//api
api: propTypes.func,
});
//暴露内部方法
const emit = defineEmits(['getMethod', 'delete']);
//数据
const data = ref([]);
// 切换每行个数
// cover图片自适应高度
//修改pageSize并重新请求数据
const height = computed(() => {
return `h-${120 - grid.value * 6}`;
});
//表单
const [registerForm, { validate }] = useForm({
schemas: [{ field: 'type', component: 'Input', label: '类型' }],
labelWidth: 80,
baseColProps: { span: 6 },
actionColOptions: { span: 24 },
autoSubmitOnEnter: true,
submitFunc: handleSubmit,
});
//表单提交
async function handleSubmit() {
const data = await validate();
await fetch(data);
}
function sliderChange(n) {
pageSize.value = n * 4;
fetch();
}
// 自动请求并暴露内部方法
onMounted(() => {
fetch();
emit('getMethod', fetch);
});
async function fetch(p = {}) {
const { api, params } = props;
if (api && isFunction(api)) {
const res = await api({ ...params, page: page.value, pageSize: pageSize.value, ...p });
data.value = res.items;
total.value = res.total;
}
}
//分页相关
const page = ref(1);
const pageSize = ref(36);
const total = ref(0);
const paginationProp = ref({
showSizeChanger: false,
showQuickJumper: true,
pageSize,
current: page,
total,
showTotal: (total) => `${total}`,
onChange: pageChange,
onShowSizeChange: pageSizeChange,
});
function pageChange(p, pz) {
page.value = p;
pageSize.value = pz;
fetch();
}
function pageSizeChange(current, size) {
pageSize.value = size;
fetch();
}
async function handleDelete(id) {
emit('delete', id);
}
</script>

View File

@@ -0,0 +1,25 @@
import { ref } from 'vue';
//每行个数
export const grid = ref(12);
// slider属性
export const useSlider = (min = 6, max = 12) => {
// 每行显示个数滑动条
const getMarks = () => {
const l = {};
for (let i = min; i < max + 1; i++) {
l[i] = {
style: {
color: '#fff',
},
label: i,
};
}
return l;
};
return {
min,
max,
marks: getMarks(),
step: 1,
};
};

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';
const MODE = {
<script lang="ts">
export 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

@@ -12,7 +12,7 @@
</template>
<script lang="ts">
import type { CSSProperties } from 'vue';
import { defineComponent, onMounted, ref, unref, computed } from 'vue';
import { defineComponent, onMounted, ref, unref, computed, onUnmounted } from 'vue';
import Cropper from 'cropperjs';
import 'cropperjs/dist/cropper.css';
import { useDesign } from '/@/hooks/web/useDesign';
@@ -93,6 +93,10 @@
onMounted(init);
onUnmounted(() => {
cropper.value?.destroy();
});
async function init() {
const imgEl = unref(imgElRef);
if (!imgEl) {

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

@@ -1,13 +1,13 @@
<template>
<Select
@dropdownVisibleChange="handleFetch"
v-bind="attrs"
v-bind="$attrs"
@change="handleChange"
:options="getOptions"
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 />
@@ -41,12 +41,7 @@
},
inheritAttrs: false,
props: {
value: propTypes.oneOfType([
propTypes.object,
propTypes.number,
propTypes.string,
propTypes.array,
]),
value: [Array, Object, String, Number],
numberToString: propTypes.bool,
api: {
type: Function as PropType<(arg?: Recordable) => Promise<OptionsItem[]>>,
@@ -100,7 +95,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

@@ -1,5 +1,7 @@
import { withInstall } from '/@/utils';
import markDown from './src/Markdown.vue';
import markDownViewer from './src/MarkdownViewer.vue';
export const MarkDown = withInstall(markDown);
export const MarkdownViewer = withInstall(markDownViewer);
export * from './src/typing';

View File

@@ -2,6 +2,7 @@
<div ref="wrapRef"></div>
</template>
<script lang="ts">
import type { Ref } from 'vue';
import {
defineComponent,
ref,
@@ -30,14 +31,14 @@
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();
const { getLocale } = useLocale();
const { getDarkMode } = useRootSetting();
const valueRef = ref('');
const valueRef = ref(props.value || '');
watch(
[() => getDarkMode.value, () => initedRef.value],
@@ -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' => {
@@ -89,6 +90,9 @@
theme: getDarkMode.value === 'dark' ? 'dark' : 'classic',
lang: unref(getCurrentLang),
mode: 'sv',
fullscreen: {
index: 520,
},
preview: {
actions: [],
},

View File

@@ -0,0 +1,22 @@
<template>
<div v-html="getHtmlData" :class="$props.class" class="markdown-viewer"></div>
</template>
<script lang="ts" setup>
import { computed } from 'vue';
import showdown from 'showdown';
const converter = new showdown.Converter();
converter.setOption('tables', true);
const props = defineProps({
value: { type: String },
class: { type: String },
});
const getHtmlData = computed(() => converter.makeHtml(props.value || ''));
</script>
<style scoped>
.markdown-viewer {
width: 100%;
}
</style>

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[] }) {
@@ -126,9 +126,6 @@
emit('menuClick', key);
isClickGo.value = true;
// const parentPath = await getCurrentParentPath(key);
// menuState.openKeys = [parentPath];
menuState.selectedKeys = [key];
}
@@ -150,8 +147,6 @@
}
return {
prefixCls,
getIsHorizontal,
handleMenuClick,
getInlineCollapseOptions,
getMenuClass,

View File

@@ -1,13 +1,11 @@
<template>
<MenuItem :key="item.path">
<!-- <MenuItem :class="getLevelClass"> -->
<MenuItemContent v-bind="$props" :item="item" />
</MenuItem>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { Menu } from 'ant-design-vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { itemProps } from '../props';
import MenuItemContent from './MenuItemContent.vue';
@@ -15,20 +13,8 @@
name: 'BasicMenuItem',
components: { MenuItem: Menu.Item, MenuItemContent },
props: itemProps,
setup() // props
{
const { prefixCls } = useDesign('basic-menu-item');
// const getLevelClass = computed(() => {
// const { level, theme } = props;
// const levelCls = [`${prefixCls}__level${level}`, theme];
// return levelCls;
// });
return {
prefixCls,
// getLevelClass,
};
setup() {
return {};
},
});
</script>

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

@@ -1,5 +1,5 @@
<template>
<Modal v-bind="getBindValue" @cancel="handleCancel">
<Modal v-bind="getBindValue">
<template #closeIcon v-if="!$slots.closeIcon">
<ModalClose
:canFullscreen="getProps.canFullscreen"
@@ -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

@@ -48,6 +48,7 @@ export function useModal(): UseModalReturnType {
if (unref(loaded) && isProdMode() && modalMethod === unref(modal)) return;
modal.value = modalMethod;
loaded.value = true;
modalMethod.emitVisible = (visible: boolean, uid: number) => {
visibleData[uid] = visible;
};

View File

@@ -19,7 +19,7 @@
width: 520px;
padding-bottom: 0;
.scrollbar {
.ant-modal-body > .scrollbar {
padding: 14px;
}

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',
@@ -60,6 +61,7 @@
contentFullHeight: propTypes.bool,
contentClass: propTypes.string,
fixedHeight: propTypes.bool,
upwardSpace: propTypes.oneOfType([propTypes.number, propTypes.string]).def(0),
},
setup(props, { slots, attrs }) {
const wrapperRef = ref(null);
@@ -68,15 +70,22 @@
const footerRef = ref(null);
const { prefixCls } = useDesign('page-wrapper');
provide(
PageWrapperFixedHeightKey,
computed(() => props.fixedHeight),
);
const getIsContentFullHeight = computed(() => {
return props.contentFullHeight;
});
const getUpwardSpace = computed(() => props.upwardSpace);
const { redoHeight, setCompensation, contentHeight } = useContentHeight(
getIsContentFullHeight,
wrapperRef,
[headerRef, footerRef],
[contentRef]
[contentRef],
getUpwardSpace,
);
setCompensation({ useLayoutFooter: true, elements: [footerRef] });
@@ -129,7 +138,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

@@ -4,7 +4,7 @@
</div>
</template>
<script lang="ts">
import { defineComponent, watch, PropType, ref, unref } from 'vue';
import { defineComponent, watch, PropType, ref, unref, onMounted } from 'vue';
import { toCanvas, QRCodeRenderersOptions, LogoType } from './qrcodePlus';
import { toDataURL } from 'qrcode';
import { downloadByUrl } from '/@/utils/file/download';
@@ -93,16 +93,18 @@
});
}
onMounted(createQrcode);
// 监听参数变化重新生成二维码
watch(
props,
() => {
createQrcode()
createQrcode();
},
{
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,8 +138,11 @@
handleTableChange: onTableChange,
getDataSourceRef,
getDataSource,
getRawDataSource,
setTableData,
updateTableDataRecord,
deleteTableDataRecord,
insertTableDataRecord,
findTableDataRecord,
fetch,
getRowKey,
@@ -145,7 +159,7 @@
getFieldsValue: formActions.getFieldsValue,
clearSelectedRowKeys,
},
emit
emit,
);
function handleTableChange(...args) {
@@ -170,7 +184,7 @@
tableElRef,
getColumnsRef,
getRowSelectionRef,
getDataSourceRef
getDataSourceRef,
);
const { customRow } = useCustomRow(getProps, {
@@ -199,7 +213,7 @@
getProps,
getScrollRef,
tableElRef,
getDataSourceRef
getDataSourceRef,
);
const { getFormProps, replaceFormSlotKey, getFormSlotKeys, handleSearchInfoChange } =
@@ -267,12 +281,15 @@
setPagination,
setTableData,
updateTableDataRecord,
deleteTableDataRecord,
insertTableDataRecord,
findTableDataRecord,
redoHeight,
setSelectedRowKeys,
setColumns,
setLoading,
getDataSource,
getRawDataSource,
setProps,
getRowSelection,
getPaginationRef: getPagination,
@@ -307,7 +324,7 @@
wrapRef,
tableAction,
redoHeight,
getFormProps,
getFormProps: getFormProps as any,
replaceFormSlotKey,
getFormSlotKeys,
getWrapperClass,
@@ -321,6 +338,13 @@
@prefix-cls: ~'@{namespace}-basic-table';
[data-theme='dark'] {
.ant-table-tbody > tr:hover.ant-table-row-selected > td,
.ant-table-tbody > tr.ant-table-row-selected td {
background-color: #262626;
}
}
.@{prefix-cls} {
max-width: 100%;
@@ -378,9 +402,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 +424,7 @@
.ant-table-body {
overflow-x: hidden !important;
overflow-y: scroll !important;
// overflow-y: scroll !important;
}
td {

View File

@@ -14,11 +14,7 @@
<Divider
type="vertical"
class="action-divider"
v-if="
divider &&
index < getActions.length - (dropDownActions ? 0 : 1) &&
getDropdownList.length > 0
"
v-if="divider && index < getActions.length - 1"
/>
</template>
<Dropdown
@@ -95,7 +91,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 +103,7 @@
});
});
const getDropdownList = computed(() => {
const getDropdownList = computed((): any[] => {
return (toRaw(props.dropDownActions) || [])
.filter((action) => {
return hasPermission(action.auth) && isIfShow(action);
@@ -133,7 +129,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,
}
},
);
};

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