Compare commits

...

59 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
211 changed files with 2726 additions and 1423 deletions

2
.vscode/launch.json vendored
View File

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

View File

@@ -1,3 +1,31 @@
## 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

View File

@@ -1,3 +1,57 @@
## [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

View File

@@ -1,3 +1,31 @@
## 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 后重装即可

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

@@ -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

@@ -50,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

@@ -66,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.1",
"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.9",
"@logicflow/extension": "^0.6.9",
"@vueuse/core": "^5.3.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.6",
"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-rc.4",
"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.2.2",
"vue": "3.2.11",
"vue-i18n": "9.1.7",
"vue-json-pretty": "^1.8.1",
"vue-json-pretty": "^2.0.4",
"vue-router": "^4.0.11",
"vue-types": "^4.0.3",
"xlsx": "^0.17.0"
"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.386",
"@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": "^27.0.1",
"@types/lodash-es": "^4.17.4",
"@types/lodash-es": "^4.17.5",
"@types/mockjs": "^1.0.4",
"@types/node": "^16.6.1",
"@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.1",
"@typescript-eslint/parser": "^4.29.1",
"@vitejs/plugin-legacy": "^1.5.1",
"@vitejs/plugin-vue": "^1.4.0",
"@vitejs/plugin-vue-jsx": "^1.1.7",
"@vue/compiler-sfc": "3.2.2",
"@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.16.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": "^13.0.0",
"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.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.2.0",
"typescript": "4.3.5",
"vite": "2.5.0",
"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.10.0",
"vite-plugin-style-import": "^1.1.1",
"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.3"
"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.56.2"
"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

@@ -15,5 +15,6 @@
// support Multi-language
const { getAntdLocale } = useLocale();
// 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,6 +1,6 @@
<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>

View File

@@ -62,6 +62,7 @@
import { SearchOutlined } from '@ant-design/icons-vue';
import AppSearchFooter from './AppSearchFooter.vue';
import Icon from '/@/components/Icon';
// @ts-ignore
import vClickOutside from '/@/directives/clickOutside';
import { useDesign } from '/@/hooks/web/useDesign';
import { useRefs } from '/@/hooks/core/useRefs';
@@ -104,7 +105,7 @@
nextTick(() => {
unref(inputRef)?.focus();
});
}
},
);
function handleClose() {

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

@@ -9,10 +9,11 @@
</template>
<script lang="ts">
export default {
import { defineComponent } from 'vue';
export default defineComponent({
name: 'AButton',
inheritAttrs: false,
};
});
</script>
<script lang="ts" setup>
import { computed, unref } from 'vue';

View File

@@ -33,7 +33,7 @@
okText: t('common.okText'),
cancelText: t('common.cancelText'),
},
{ ...props, ...unref(attrs) }
{ ...props, ...unref(attrs) },
);
});

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

@@ -10,7 +10,7 @@
</template>
<script lang="ts">
const MODE = {
export const MODE = {
JSON: 'application/json',
html: 'htmlmixed',
js: 'javascript',
@@ -25,18 +25,26 @@
value: { type: [Object, String] as PropType<Record<string, any> | string> },
mode: { type: String, default: MODE.JSON },
readonly: { type: Boolean },
autoFormat: { type: Boolean, default: true },
});
const emit = defineEmits(['change', 'update:value']);
const emit = defineEmits(['change', 'update:value', 'format-error']);
const getValue = computed(() => {
const { value, mode } = props;
if (mode !== MODE.JSON) {
const { value, mode, autoFormat } = props;
if (!autoFormat || mode !== MODE.JSON) {
return value as string;
}
return isString(value)
? JSON.stringify(JSON.parse(value), null, 2)
: JSON.stringify(value, null, 2);
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) {

View File

@@ -1,5 +1,5 @@
<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" setup>
@@ -40,7 +40,7 @@
editor?.setValue(value ? value : '');
}
},
{ flush: 'post' }
{ flush: 'post' },
);
watchEffect(() => {
@@ -54,13 +54,13 @@
},
{
immediate: true,
}
},
);
function setTheme() {
unref(editor)?.setOption(
'theme',
appStore.getDarkMode === 'light' ? 'idea' : 'material-palenight'
appStore.getDarkMode === 'light' ? 'idea' : 'material-palenight',
);
}

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

@@ -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

@@ -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

@@ -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

@@ -79,7 +79,7 @@
() => props.data,
() => {
onRender();
}
},
);
// TODO
@@ -94,7 +94,7 @@
() => unref(getFlowOptions),
(options) => {
unref(lfInstance)?.updateEditConfig(options);
}
},
);
// init logicFlow

View File

@@ -24,12 +24,12 @@
</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,7 +1,7 @@
<template>
<Select
@dropdownVisibleChange="handleFetch"
v-bind="attrs"
v-bind="$attrs"
@change="handleChange"
:options="getOptions"
v-model:value="state"
@@ -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

@@ -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) {
@@ -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

@@ -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>;

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>
@@ -139,7 +139,7 @@
const { getPaginationList, getTotal, setCurrentPage } = usePagination(
currentList,
props.pageSize
props.pageSize,
);
watchEffect(() => {
@@ -151,7 +151,7 @@
(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;

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"
@@ -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),
@@ -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

@@ -61,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);
@@ -71,18 +72,20 @@
provide(
PageWrapperFixedHeightKey,
computed(() => props.fixedHeight)
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] });
@@ -135,7 +138,7 @@
{
flush: 'post',
immediate: true,
}
},
);
return {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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>
@@ -111,7 +111,7 @@
unref(isFixedHeightPage) &&
props.canResize &&
warn(
"'canResize' of BasicTable may not work in PageWrapper with 'fixedHeight' (especially in hot updates)"
"'canResize' of BasicTable may not work in PageWrapper with 'fixedHeight' (especially in hot updates)",
);
});
@@ -141,6 +141,8 @@
getRawDataSource,
setTableData,
updateTableDataRecord,
deleteTableDataRecord,
insertTableDataRecord,
findTableDataRecord,
fetch,
getRowKey,
@@ -157,7 +159,7 @@
getFieldsValue: formActions.getFieldsValue,
clearSelectedRowKeys,
},
emit
emit,
);
function handleTableChange(...args) {
@@ -182,7 +184,7 @@
tableElRef,
getColumnsRef,
getRowSelectionRef,
getDataSourceRef
getDataSourceRef,
);
const { customRow } = useCustomRow(getProps, {
@@ -211,7 +213,7 @@
getProps,
getScrollRef,
tableElRef,
getDataSourceRef
getDataSourceRef,
);
const { getFormProps, replaceFormSlotKey, getFormSlotKeys, handleSearchInfoChange } =
@@ -279,6 +281,8 @@
setPagination,
setTableData,
updateTableDataRecord,
deleteTableDataRecord,
insertTableDataRecord,
findTableDataRecord,
redoHeight,
setSelectedRowKeys,
@@ -320,7 +324,7 @@
wrapRef,
tableAction,
redoHeight,
getFormProps,
getFormProps: getFormProps as any,
replaceFormSlotKey,
getFormSlotKeys,
getWrapperClass,
@@ -334,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%;
@@ -413,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,
}
},
);
};

View File

@@ -5,31 +5,33 @@
:class="{ [`${prefixCls}__normal`]: true, 'ellipsis-cell': column.ellipsis }"
@click="handleEdit"
>
<div class="cell-content" :title="column.ellipsis ? getValues ?? '' : ''">{{
getValues ?? '&nbsp;'
}}</div>
<div class="cell-content" :title="column.ellipsis ? getValues ?? '' : ''">
{{ getValues ? getValues : '&nbsp;' }}
</div>
<FormOutlined :class="`${prefixCls}__normal-icon`" v-if="!column.editRow" />
</div>
<div v-if="isEdit" :class="`${prefixCls}__wrapper`" v-click-outside="onClickOutside">
<CellComponent
v-bind="getComponentProps"
:component="getComponent"
:style="getWrapperStyle"
:popoverVisible="getRuleVisible"
:rule="getRule"
:ruleMessage="ruleMessage"
:class="getWrapperClass"
ref="elRef"
@change="handleChange"
@options-change="handleOptionsChange"
@pressEnter="handleEnter"
/>
<div :class="`${prefixCls}__action`" v-if="!getRowEditable">
<CheckOutlined :class="[`${prefixCls}__icon`, 'mx-2']" @click="handleSubmitClick" />
<CloseOutlined :class="`${prefixCls}__icon `" @click="handleCancel" />
<a-spin v-if="isEdit" :spinning="spinning">
<div :class="`${prefixCls}__wrapper`" v-click-outside="onClickOutside">
<CellComponent
v-bind="getComponentProps"
:component="getComponent"
:style="getWrapperStyle"
:popoverVisible="getRuleVisible"
:rule="getRule"
:ruleMessage="ruleMessage"
:class="getWrapperClass"
ref="elRef"
@change="handleChange"
@options-change="handleOptionsChange"
@pressEnter="handleEnter"
/>
<div :class="`${prefixCls}__action`" v-if="!getRowEditable">
<CheckOutlined :class="[`${prefixCls}__icon`, 'mx-2']" @click="handleSubmitClick" />
<CloseOutlined :class="`${prefixCls}__icon `" @click="handleCancel" />
</div>
</div>
</div>
</a-spin>
</div>
</template>
<script lang="ts">
@@ -48,12 +50,13 @@
import { propTypes } from '/@/utils/propTypes';
import { isArray, isBoolean, isFunction, isNumber, isString } from '/@/utils/is';
import { createPlaceholderMessage } from './helper';
import { omit, set } from 'lodash-es';
import { omit, pick, set } from 'lodash-es';
import { treeToList } from '/@/utils/helper/treeHelper';
import { Spin } from 'ant-design-vue';
export default defineComponent({
name: 'EditableCell',
components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent },
components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent, ASpin: Spin },
directives: {
clickOutside,
},
@@ -80,6 +83,7 @@
const optionsRef = ref<LabelValueOptions>([]);
const currentValueRef = ref<any>(props.value);
const defaultValueRef = ref<any>(props.value);
const spinning = ref<boolean>(false);
const { prefixCls } = useDesign('editable-cell');
@@ -246,6 +250,35 @@
const dataKey = (dataIndex || key) as string;
if (!record.editable) {
const { getBindValues } = table;
const { beforeEditSubmit, columns } = unref(getBindValues);
if (beforeEditSubmit && isFunction(beforeEditSubmit)) {
spinning.value = true;
const keys: string[] = columns
.map((_column) => _column.dataIndex)
.filter((field) => !!field) as string[];
let result: any = true;
try {
result = await beforeEditSubmit({
record: pick(record, keys),
index,
key,
value,
});
} catch (e) {
result = false;
} finally {
spinning.value = false;
}
if (result === false) {
return;
}
}
}
set(record, dataKey, value);
//const record = await table.updateTableData(index, dataKey, value);
needEmit && table.emit?.('edit-end', { record, index, key, value });
@@ -331,13 +364,7 @@
/* eslint-disable */
props.record.onSubmitEdit = async () => {
if (isArray(props.record?.submitCbs)) {
const validFns = (props.record?.validCbs || []).map((fn) => fn());
const res = await Promise.all(validFns);
const pass = res.every((item) => !!item);
if (!pass) return;
if (!props.record?.onValid?.()) return;
const submitFns = props.record?.submitCbs || [];
submitFns.forEach((fn) => fn(false, false));
table.emit?.('edit-row-end');
@@ -368,6 +395,7 @@
getValues,
handleEnter,
handleSubmitClick,
spinning,
};
},
});

View File

@@ -3,6 +3,7 @@ import type { BasicColumn } from '/@/components/Table/src/types/table';
import { h, Ref } from 'vue';
import EditableCell from './EditableCell.vue';
import { isArray } from '/@/utils/is';
interface Params {
text: string;
@@ -12,12 +13,23 @@ interface Params {
export function renderEditCell(column: BasicColumn) {
return ({ text: value, record, index }: Params) => {
record.onValid = async () => {
if (isArray(record?.validCbs)) {
const validFns = (record?.validCbs || []).map((fn) => fn());
const res = await Promise.all(validFns);
return res.every((item) => !!item);
} else {
return false;
}
};
record.onEdit = async (edit: boolean, submit = false) => {
if (!submit) {
record.editable = edit;
}
if (!edit && submit) {
if (!(await record.onValid())) return false;
const res = await record.onSubmitEdit?.();
if (res) {
record.editable = false;
@@ -44,6 +56,7 @@ export function renderEditCell(column: BasicColumn) {
export type EditRecordRow<T = Recordable> = Partial<
{
onEdit: (editable: boolean, submit?: boolean) => Promise<boolean>;
onValid: () => Promise<boolean>;
editable: boolean;
onCancel: Fn;
onSubmit: Fn;

View File

@@ -42,7 +42,7 @@
<ScrollContainer>
<CheckboxGroup v-model:value="checkedList" @change="onChange" ref="columnListRef">
<template v-for="item in plainOptions" :key="item.value">
<div :class="`${prefixCls}__check-item`">
<div :class="`${prefixCls}__check-item`" v-if="!('ifShow' in item && !item.ifShow)">
<DragOutlined class="table-coulmn-drag-icon" />
<Checkbox :value="item.value">
{{ item.label }}
@@ -351,7 +351,7 @@
const visible =
columns.findIndex(
(c: BasicColumn | string) =>
c === col.value || (typeof c !== 'string' && c.dataIndex === col.value)
c === col.value || (typeof c !== 'string' && c.dataIndex === col.value),
) !== -1;
return { dataIndex: col.value, fixed: col.fixed, visible };
});

View File

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

View File

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

View File

@@ -40,7 +40,7 @@ export function useDataSource(
clearSelectedRowKeys,
tableData,
}: ActionType,
emit: EmitType
emit: EmitType,
) {
const searchState = reactive<SearchState>({
sortInfo: {},
@@ -61,13 +61,13 @@ export function useDataSource(
},
{
immediate: true,
}
},
);
function handleTableChange(
pagination: PaginationProps,
filters: Partial<Recordable<string[]>>,
sorter: SorterResult
sorter: SorterResult,
) {
const { clearSelectOnPageChange, sortFn, filterFn } = unref(propsRef);
if (clearSelectOnPageChange) {
@@ -148,7 +148,7 @@ export function useDataSource(
function updateTableDataRecord(
rowKey: string | number,
record: Recordable
record: Recordable,
): Recordable | undefined {
const row = findTableDataRecord(rowKey);
@@ -160,6 +160,31 @@ export function useDataSource(
}
}
function deleteTableDataRecord(record: Recordable | Recordable[]): Recordable | undefined {
if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
const records = !Array.isArray(record) ? [record] : record;
const recordIndex = records
.map((item) => dataSourceRef.value.findIndex((s) => s.key === item.key)) // 取序号
.filter((item) => item !== undefined)
.sort((a, b) => b - a); // 从大到小排序
for (const index of recordIndex) {
unref(dataSourceRef).splice(index, 1);
unref(propsRef).dataSource?.splice(index, 1);
}
setPagination({
total: unref(propsRef).dataSource?.length,
});
return unref(propsRef).dataSource;
}
function insertTableDataRecord(record: Recordable, index: number): Recordable | undefined {
if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
index = index ?? dataSourceRef.value?.length;
unref(dataSourceRef).splice(index, 0, record);
unref(propsRef).dataSource?.splice(index, 0, record);
return unref(propsRef).dataSource;
}
function findTableDataRecord(rowKey: string | number) {
if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
@@ -206,7 +231,7 @@ export function useDataSource(
const { pageField, sizeField, listField, totalField } = Object.assign(
{},
FETCH_SETTING,
fetchSetting
fetchSetting,
);
let pageParams: Recordable = {};
@@ -314,6 +339,8 @@ export function useDataSource(
reload,
updateTableData,
updateTableDataRecord,
deleteTableDataRecord,
insertTableDataRecord,
findTableDataRecord,
handleTableChange,
};

View File

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

View File

@@ -8,7 +8,7 @@ import { findNodeAll } from '/@/utils/helper/treeHelper';
export function useRowSelection(
propsRef: ComputedRef<BasicTableProps>,
tableData: Ref<Recordable[]>,
emit: EmitType
emit: EmitType,
) {
const selectedRowKeysRef = ref<string[]>([]);
const selectedRowRef = ref<Recordable[]>([]);
@@ -35,7 +35,7 @@ export function useRowSelection(
() => unref(propsRef).rowSelection?.selectedRowKeys,
(v: string[]) => {
setSelectedRowKeys(v);
}
},
);
watch(
@@ -53,7 +53,7 @@ export function useRowSelection(
});
});
},
{ deep: true }
{ deep: true },
);
const getAutoCreateKey = computed(() => {
@@ -72,7 +72,7 @@ export function useRowSelection(
(item) => rowKeys.includes(item[unref(getRowKey) as string]),
{
children: propsRef.value.childrenColumnName ?? 'children',
}
},
);
const trueSelectedRows: any[] = [];
rowKeys.forEach((key: string) => {

View File

@@ -18,7 +18,7 @@ export function useTable(tableProps?: Props): [
(instance: TableActionType, formInstance: UseTableMethod) => void,
TableActionType & {
getForm: () => FormActionType;
}
},
] {
const tableRef = ref<Nullable<TableActionType>>(null);
const loadedRef = ref<Nullable<boolean>>(false);
@@ -50,7 +50,7 @@ export function useTable(tableProps?: Props): [
{
immediate: true,
deep: true,
}
},
);
}
@@ -58,7 +58,7 @@ export function useTable(tableProps?: Props): [
const table = unref(tableRef);
if (!table) {
error(
'The table instance has not been obtained yet, please make sure the table is presented when performing the table operation!'
'The table instance has not been obtained yet, please make sure the table is presented when performing the table operation!',
);
}
return table as TableActionType;
@@ -122,6 +122,12 @@ export function useTable(tableProps?: Props): [
updateTableData: (index: number, key: string, value: any) => {
return getTableInstance().updateTableData(index, key, value);
},
deleteTableDataRecord: (record: Recordable | Recordable[]) => {
return getTableInstance().deleteTableDataRecord(record);
},
insertTableDataRecord: (record: Recordable | Recordable[], index?: number) => {
return getTableInstance().insertTableDataRecord(record, index);
},
updateTableDataRecord: (rowKey: string | number, record: Recordable) => {
return getTableInstance().updateTableDataRecord(rowKey, record);
},

View File

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

View File

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

View File

@@ -8,7 +8,7 @@ export function useTableForm(
propsRef: ComputedRef<BasicTableProps>,
slots: Slots,
fetch: (opt?: FetchParams | undefined) => Promise<void>,
getLoading: ComputedRef<boolean | undefined>
getLoading: ComputedRef<boolean | undefined>,
) {
const getFormProps = computed((): Partial<FormProps> => {
const { formConfig } = unref(propsRef);

View File

@@ -8,7 +8,7 @@ import { getSlot } from '/@/utils/helper/tsxHelper';
export function useTableHeader(
propsRef: ComputedRef<BasicTableProps>,
slots: Slots,
handlers: InnerHandlers
handlers: InnerHandlers,
) {
const getHeaderProps = computed((): Recordable => {
const { title, showTableSetting, titleHelpMessage, tableSetting } = unref(propsRef);
@@ -46,7 +46,7 @@ export function useTableHeader(
headerTop: () => getSlot(slots, 'headerTop'),
}
: {}),
}
},
),
};
});

View File

@@ -13,7 +13,7 @@ export function useTableScroll(
tableElRef: Ref<ComponentRef>,
columnsRef: ComputedRef<BasicColumn[]>,
rowSelectionRef: ComputedRef<TableRowSelection<any> | null>,
getDataSourceRef: ComputedRef<Recordable[]>
getDataSourceRef: ComputedRef<Recordable[]>,
) {
const tableHeightRef: Ref<Nullable<number>> = ref(null);
@@ -34,7 +34,7 @@ export function useTableScroll(
},
{
flush: 'post',
}
},
);
function redoHeight() {

View File

@@ -6,11 +6,14 @@ import { isFunction } from '/@/utils/is';
export function useTableStyle(propsRef: ComputedRef<BasicTableProps>, prefixCls: string) {
function getRowClassName(record: TableCustomRecord, index: number) {
const { striped, rowClassName } = unref(propsRef);
if (!striped) return;
if (rowClassName && isFunction(rowClassName)) {
return rowClassName(record);
const classNames: string[] = [];
if (striped) {
classNames.push((index || 0) % 2 === 1 ? `${prefixCls}-row__striped` : '');
}
return (index || 0) % 2 === 1 ? `${prefixCls}-row__striped` : '';
if (rowClassName && isFunction(rowClassName)) {
classNames.push(rowClassName(record, index));
}
return classNames.filter((cls) => !!cls).join(' ');
}
return { getRowClassName };

View File

@@ -126,4 +126,14 @@ export const basicProps = {
type: Object as PropType<{ x: number | true; y: number }>,
default: null,
},
beforeEditSubmit: {
type: Function as PropType<
(data: {
record: Recordable;
index: number;
key: string | number;
value: any;
}) => Promise<any>
>,
},
};

View File

@@ -25,7 +25,7 @@ export interface TableRowSelection<T = any> extends ITableRowSelection {
/**
* Callback executed when select/deselect one row
* @type FunctionT
* @type Function
*/
onSelect?: (record: T, selected: boolean, selectedRows: Object[], nativeEvent: Event) => any;
@@ -95,6 +95,8 @@ export interface TableActionType {
setPagination: (info: Partial<PaginationProps>) => void;
setTableData: <T = Recordable>(values: T[]) => void;
updateTableDataRecord: (rowKey: string | number, record: Recordable) => Recordable | void;
deleteTableDataRecord: (record: Recordable | Recordable[]) => Recordable | void;
insertTableDataRecord: (record: Recordable, index?: number) => Recordable | void;
findTableDataRecord: (rowKey: string | number) => Recordable | void;
getColumns: (opt?: GetColumnsParams) => BasicColumn[];
setColumns: (columns: BasicColumn[] | string[]) => void;
@@ -289,7 +291,7 @@ export interface BasicTableProps<T = any> {
* Row's className
* @type Function
*/
rowClassName?: (record: TableCustomRecord<T>) => string;
rowClassName?: (record: TableCustomRecord<T>, index: number) => string;
/**
* Row selection config
@@ -362,6 +364,18 @@ export interface BasicTableProps<T = any> {
*/
transformCellText?: Function;
/**
* Callback executed before editable cell submit value, not for row-editor
*
* The cell will not submit data while callback return false
*/
beforeEditSubmit?: (data: {
record: Recordable;
index: number;
key: string | number;
value: any;
}) => Promise<any>;
/**
* Callback executed when pagination, filters or sorter is changed
* @param pagination

View File

@@ -34,7 +34,7 @@
() => {
setTime();
},
{ immediate: true }
{ immediate: true },
);
function getTime() {

View File

@@ -8,12 +8,18 @@
v-show="editorRef"
:disabled="disabled"
/>
<textarea :id="tinymceId" ref="elRef" :style="{ visibility: 'hidden' }"></textarea>
<textarea
:id="tinymceId"
ref="elRef"
:style="{ visibility: 'hidden' }"
v-if="!initOptions.inline"
></textarea>
<slot v-else></slot>
</div>
</template>
<script lang="ts">
import type { RawEditorSettings } from 'tinymce';
import type { Editor, RawEditorSettings } from 'tinymce';
import tinymce from 'tinymce/tinymce';
import 'tinymce/themes/silver';
import 'tinymce/icons/default/icons';
@@ -54,8 +60,8 @@
ref,
unref,
watch,
onUnmounted,
onDeactivated,
onBeforeUnmount,
} from 'vue';
import ImgUpload from './ImgUpload.vue';
import { toolbar, plugins } from './tinymce';
@@ -108,9 +114,9 @@
components: { ImgUpload },
inheritAttrs: false,
props: tinymceProps,
emits: ['change', 'update:modelValue'],
emits: ['change', 'update:modelValue', 'inited', 'init-error'],
setup(props, { emit, attrs }) {
const editorRef = ref();
const editorRef = ref<Nullable<Editor>>(null);
const fullscreen = ref(false);
const tinymceId = ref<string>(buildShortUUID('tiny-vue'));
const elRef = ref<Nullable<HTMLElement>>(null);
@@ -159,7 +165,7 @@
content_css:
publicPath + 'resource/tinymce/skins/ui/' + skinName.value + '/content.min.css',
...options,
setup: (editor) => {
setup: (editor: Editor) => {
editorRef.value = editor;
editor.on('init', (e) => initSetup(e));
},
@@ -184,11 +190,13 @@
return;
}
editor.setMode(attrs.disabled ? 'readonly' : 'design');
}
},
);
onMountedOrActivated(() => {
tinymceId.value = buildShortUUID('tiny-vue');
if (!initOptions.value.inline) {
tinymceId.value = buildShortUUID('tiny-vue');
}
nextTick(() => {
setTimeout(() => {
initEditor();
@@ -196,7 +204,7 @@
});
});
onUnmounted(() => {
onBeforeUnmount(() => {
destory();
});
@@ -206,7 +214,7 @@
function destory() {
if (tinymce !== null) {
tinymce?.remove?.(unref(editorRef));
tinymce?.remove?.(unref(initOptions).selector!);
}
}
@@ -215,7 +223,14 @@
if (el) {
el.style.visibility = '';
}
tinymce.init(unref(initOptions));
tinymce
.init(unref(initOptions))
.then((editor) => {
emit('inited', editor);
})
.catch((err) => {
emit('init-error', err);
});
}
function initSetup(e) {
@@ -249,7 +264,7 @@
() => props.modelValue,
(val: string, prevVal: string) => {
setValue(editor, val, prevVal);
}
},
);
watch(
@@ -259,7 +274,7 @@
},
{
immediate: true,
}
},
);
editor.on(normalizedEvents ? normalizedEvents : 'change keyup undo redo', () => {

View File

@@ -18,10 +18,10 @@ export const ScaleRotateTransition = createSimpleTransition('scale-rotate-transi
export const ExpandXTransition = createJavascriptTransition(
'expand-x-transition',
ExpandTransitionGenerator('', true)
ExpandTransitionGenerator('', true),
);
export const ExpandTransition = createJavascriptTransition(
'expand-transition',
ExpandTransitionGenerator('')
ExpandTransitionGenerator(''),
);

View File

@@ -41,7 +41,7 @@ export function createSimpleTransition(name: string, origin = 'top center 0', mo
export function createJavascriptTransition(
name: string,
functions: Recordable,
mode: Mode = 'in-out'
mode: Mode = 'in-out',
) {
return defineComponent({
name,

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