diff --git a/.eslintignore b/.eslintignore index b1ee5549..8e5f2798 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,5 @@ template src/components/meKeepAlive dist -vite.config.ts.* \ No newline at end of file +vite.config.ts.* +src/components/meVxeTable/vxe-table-plugin-element \ No newline at end of file diff --git a/.eslintrc.cjs b/.eslintrc.cjs index b7259e5e..3c213c6f 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -46,16 +46,15 @@ module.exports = { 'vue/no-parsing-error': 'off', 'vue/require-default-prop': 'off', 'vue/no-v-html': 'off', - 'no-unused-vars': [ + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/no-unused-vars': [ 'error', // we are only using this rule to check for unused arguments since TS // catches unused variables but not args. { varsIgnorePattern: '.*', args: 'none' }, ], - '@typescript-eslint/no-non-null-assertion': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/ban-ts-comment': 'off', - '@typescript-eslint/no-unused-vars': 'off', 'no-undef': 'off', // ts(2304) '@typescript-eslint/naming-convention': [ 'error', @@ -65,7 +64,7 @@ module.exports = { leadingUnderscore: 'allow', filter: { // you can expand this regex to add more allowed names - regex: '^__v_.*$', + regex: '^((__v_.*)|[0-9]+)$', match: false, }, }, @@ -81,7 +80,7 @@ module.exports = { leadingUnderscore: 'allow', filter: { // you can expand this regex to add more allowed names - regex: '^__v_.*$', + regex: '^((__v_.*)|[0-9]+)$', match: false, }, }, diff --git a/.husky/pre-commit b/.husky/pre-commit index d24fdfc6..7b252062 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -2,3 +2,4 @@ . "$(dirname -- "$0")/_/husky.sh" npx lint-staged +npx vue-tsc --noEmit diff --git a/README.md b/README.md index d4182230..87817f93 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,6 @@ Me-admin template是一个免费开源的中后台模板,基于vue3、vite3、 p - clone 代码 ``` git clone https://github.com/meadmin-cn/meadmin-template.git - ``` - 安装依赖 ``` @@ -54,13 +53,43 @@ git clone https://github.com/meadmin-cn/meadmin-template.git ## 贡献代码 -规范文档正在整理中 +- 只允许向main分支贡献代码,template分支由作者自行维护,如果template分支有bug提issus,作者会及时跟进。 +- main分支只允许对不在template分支中的文件(不包括语言包文件)/新文件贡献代码 +- 贡献代码统一在github而非gitee +### Pull Request: +1.Fork 代码! + +2.创建自己的分支: `git checkout -b feat/xxxx` + +3.初始化:(`npm run i`) 或( `npm install` `npx husky install`) + +4.eslint检查:`npm run eslint`(husky 会自动运行eslint、prettier、type-check,但是不会自动修复eslint的warn,需要自己运行解决下warn) + +5.提交修改: git commit -am 'feat: add xxxxx' + +6.推送: `git push origin feat/xxxx` + +7.提交`pull request` + +## Git 贡献提交规范 +- 需符合 [commitlint](https://commitlint.js.org/#/concepts-commit-conventions)规范,建议安装`vscode`的`Conventional Commits`扩展 + - `feat` 新功能 + - `fix` Bug 修复 + - `chore` 其他 + - `docs` 文档更改 + - `style` 样式更改 + - `refactor` 重构 + - `perf` 性能改进 + - `test` 测试添加/更正 + - `revert` 还原提交 + - `ignore` 临时暂存可忽略 + - `ci` CI发版 ## 打赏作者 -作者还在为孩子奶粉钱苦苦挣扎,如果能帮到您欢迎打赏。 +作者还在为孩子奶粉钱苦苦挣扎,如果能帮到您欢迎打赏。打赏时请务必备注github name 后续会维护到打赏鸣谢列表 -![](./payCode.jpg) +![./payCode.jpg](https://gitee.com/meadmin-cn/meadmin-template/raw/main/payCode.jpg) ## License diff --git a/TEMPLATE-CHANGELOG.md b/TEMPLATE-CHANGELOG.md index e1f66260..7b381004 100644 --- a/TEMPLATE-CHANGELOG.md +++ b/TEMPLATE-CHANGELOG.md @@ -1,5 +1,54 @@ +## [1.0.7](https://github.com/meadmin-cn/meadmin-template/compare/template-1.0.6...template-1.0.7) (2022-09-23) + + +### 新功能[feat] + +* 加上请求成功提示 ([683c69a](https://github.com/meadmin-cn/meadmin-template/commit/683c69af8716bfc3cb39212fdbcaaadab2268b40)) +* 加上全局popover-scrollbar-y 类 ([af84a4b](https://github.com/meadmin-cn/meadmin-template/commit/af84a4bc06b06ad09ab20eca6edcbdd227647744)) +* 全局语言包支持引入ts、json格式,支持子孙文件夹引入 ([b92081a](https://github.com/meadmin-cn/meadmin-template/commit/b92081a5c9f7a2b3970fd80fd0c4a8bf9fa9b2d6)) +* 自动生成加载组件类型 ([9d7f3d9](https://github.com/meadmin-cn/meadmin-template/commit/9d7f3d93906f8a63df376e9a97dd9bc30d452f16)) +* page 背景色更改 ([ecaa1d9](https://github.com/meadmin-cn/meadmin-template/commit/ecaa1d95ccef5f7eb7e066ef0c4103ac084511c2)) + + +### CI发版[ci] + +* 去掉无用eslint规则,加上提交自动vue-tsc ([32f2bfe](https://github.com/meadmin-cn/meadmin-template/commit/32f2bfec1710b97e5365d09ed1ff960e66a073e5)) + + +### 文档更改[docs] + +* 格式优化 ([e612861](https://github.com/meadmin-cn/meadmin-template/commit/e612861fe93491e637c1c320b39337c029565f02)) +* 加上贡献说明 ([2e8472b](https://github.com/meadmin-cn/meadmin-template/commit/2e8472b05d5f2e1bf108c2ef0dd1a684007b2e08)) +* 说明更改 ([99569c4](https://github.com/meadmin-cn/meadmin-template/commit/99569c4927b65e4f81b2fb8f46b472859fbadc43)) + + +### 其他[chore] + +* 加上element函数声明 ([a1b08a6](https://github.com/meadmin-cn/meadmin-template/commit/a1b08a6e3bda3da9e732c90ed318bf4e5b7998c7)) + + +### 性能改进[perf] + +* 加上element动态函数默认缓存 ([34da538](https://github.com/meadmin-cn/meadmin-template/commit/34da538019ddfa77ee65f15caf6af7d647305edc)) +* 强制依赖项扫描src,会导致首次启动变慢,但是不会每次第一次打开新页面都刷新 ([5635d36](https://github.com/meadmin-cn/meadmin-template/commit/5635d36df0c12dcdfa75a9a9130f09c6a697d570)) + + +### Bug 修复[fix] + +* 修复菜单收起时,感觉卡顿问题 ([81a18a3](https://github.com/meadmin-cn/meadmin-template/commit/81a18a31385dc84250e66dce55bf86b52201b4c8)) +* 修复跟字体不生效bug ([fe8c558](https://github.com/meadmin-cn/meadmin-template/commit/fe8c558f76378d1c9266016989713d34aabfcaf1)) +* 修复两个组件引入通一子组件热更新报错问题 ([add16a9](https://github.com/meadmin-cn/meadmin-template/commit/add16a923c320c8dce0ee82c38ba5ce64c47df1d)) +* a标签默认样式去除修复 ([f758914](https://github.com/meadmin-cn/meadmin-template/commit/f758914f340b0fd43dcbf5172bb21562740d2b58)) +* eslint检查支持数字属性 ([e0e5a4b](https://github.com/meadmin-cn/meadmin-template/commit/e0e5a4bc074759534b96744d06701d769fbec692)) + + +### 重构[refactor] + +* 移除vite-plugin-mock包改为@meadmin-cn/vite-plugin-mock ([8fd1bf6](https://github.com/meadmin-cn/meadmin-template/commit/8fd1bf65d3c4bd16ebae6311f621a7970ca54700)) +* logo ico添加,登录页背景色设为page color ([f292910](https://github.com/meadmin-cn/meadmin-template/commit/f2929100aaaa2fde01ba9db2a01f3326194f4bff)) + ## [1.0.6](https://github.com/meadmin-cn/meadmin-template/compare/template-1.0.5...template-1.0.6) (2022-09-16) diff --git a/index.html b/index.html index 361c8d43..961a82eb 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ - + me-admin diff --git a/mock/apiDemo/admin.ts b/mock/apiDemo/admin.ts new file mode 100644 index 00000000..e0dbba0c --- /dev/null +++ b/mock/apiDemo/admin.ts @@ -0,0 +1,312 @@ +import { success, fail } from '../helper'; + +let id = 10000; +const group = [ + { + id: 1, + name: '超级管理员', + status: 1, + parentId: 0, + rules: [ + 'example', + 'permission', + 'componentLang', + 'example/request', + 'link', + 'pagePermission', + 'moreMenu', + 'moreMenu1', + 'moreMenu1-1', + 'moreMenu1-1-1', + 'moreMenu1-1-lang', + 'moreMenu1-2', + 'component', + 'meNumber', + 'editor', + 'wangEditor', + 'table', + 'vxeTable', + 'customComponent', + 'roleRule', + 'roleRuleIndex', + 'roleRuleAdd', + 'roleRuleEdit', + 'roleRuleDel', + ], + children: [ + { + id: 2, + name: '一级管理员1', + status: 1, + parentId: 1, + rules: [ + 'example', + 'permission', + 'componentLang', + 'example/request', + 'link', + 'pagePermission', + 'moreMenu', + 'moreMenu1', + 'moreMenu1-1', + 'moreMenu1-1-1', + 'moreMenu1-1-lang', + 'moreMenu1-2', + ], + children: [ + { + id: 21, + name: '二级管理员1-1', + parentId: 2, + status: 1, + rules: ['example', 'permission', 'example/request'], + }, + { + id: 22, + name: '二级管理员1-2', + parentId: 2, + status: 1, + rules: ['example', 'componentLang'], + }, + { + id: 23, + name: '二级管理员1-3', + parentId: 2, + status: 0, + rules: [ + 'example', + 'moreMenu', + 'moreMenu1', + 'moreMenu1-1', + 'moreMenu1-1-1', + 'moreMenu1-1-lang', + 'moreMenu1-2', + ], + children: [ + { + id: 231, + name: '三级管理员1-3-1', + parentId: 23, + status: 1, + rules: ['example', 'moreMenu', 'moreMenu1', 'moreMenu1-1', 'moreMenu1-1-1'], + }, + { + id: 232, + name: '三级管理员1-3-2', + parentId: 23, + status: 1, + rules: ['example', 'moreMenu', 'moreMenu1', 'moreMenu1-1', 'moreMenu1-1-lang'], + }, + { + id: 233, + name: '三级管理员1-3-3', + parentId: 23, + status: 1, + rules: ['example', 'moreMenu', 'moreMenu1', 'moreMenu1-2'], + }, + { + id: 234, + name: '三级管理员1-3-4', + parentId: 23, + status: 1, + rules: ['example', 'moreMenu', 'moreMenu1', 'moreMenu1-1', 'moreMenu1-1-1', 'moreMenu1-1-lang'], + children: [ + { + id: 2341, + name: '四级管理员1-3-4-1', + parentId: 234, + status: 1, + rules: ['example', 'moreMenu', 'moreMenu1', 'moreMenu1-1', 'moreMenu1-1-1'], + }, + ], + }, + ], + }, + { + id: 24, + name: '二级管理员1-4', + parentId: 2, + status: 1, + rules: ['example', 'permission', 'componentLang', 'example/request', 'pagePermission'], + }, + { + id: 25, + name: '二级管理员1-5', + parentId: 2, + status: 1, + rules: ['example', 'permission', 'componentLang', 'example/request', 'link', 'pagePermission'], + children: [ + { + id: 251, + name: '三级管理员1-5-1', + parentId: 25, + status: 1, + rules: ['example', 'permission', 'componentLang'], + }, + { + id: 252, + name: '三级管理员1-5-2', + parentId: 25, + status: 1, + rules: ['example', 'link', 'componentLang'], + }, + { + id: 253, + name: '三级管理员1-5-3', + parentId: 25, + status: 1, + rules: ['example', 'pagePermission'], + }, + ], + }, + { + id: 26, + name: '二级管理员1-6', + parentId: 2, + status: 0, + rules: ['example', 'permission', 'componentLang', 'example/request'], + }, + { + id: 27, + name: '二级管理员1-7', + parentId: 2, + status: 1, + rules: ['example', 'example/request'], + }, + ], + }, + { + id: 3, + parentId: 1, + name: '一级管理员2', + status: 1, + rules: ['component', 'meNumber', 'editor', 'wangEditor', 'table', 'vxeTable'], + children: [ + { + id: 31, + parentId: 3, + name: '二级管理员2-1', + status: 1, + rules: ['component', 'meNumber'], + }, + { + id: 32, + parentId: 3, + name: '二级管理员2-2', + status: 1, + rules: ['component', 'table'], + }, + { + id: 33, + parentId: 3, + name: '二级管理员2-3', + status: 1, + rules: ['component', 'vxeTable'], + }, + { + id: 34, + parentId: 3, + name: '二级管理员2-4', + status: 1, + rules: ['component', 'editor', 'wangEditor'], + }, + { + id: 35, + parentId: 3, + name: '二级管理员2-5', + status: 1, + rules: ['component', 'table', 'vxeTable'], + }, + ], + }, + { + id: 4, + parentId: 1, + name: '一级管理员3', + status: 1, + rules: ['customComponent', 'roleRule', 'roleRuleIndex', 'roleRuleAdd', 'roleRuleEdit', 'roleRuleDel'], + }, + ], + }, +]; +function getGroupItem(id: number, groupList?: typeof group) { + if (!groupList) { + return; + } + for (const key in groupList) { + if (groupList[key].id === id) { + return groupList[key]; + } + const item = getGroupItem(id, groupList[key].children as any) as typeof group[number]; + if (item) { + return item; + } + } +} +export default [ + { + url: '/api/admin/group/index', + method: 'get', + timeout: 500 + Math.floor(Math.random() * 1000), + response: () => success(group), + }, + { + url: '/api/admin/group/add', + method: 'post', + timeout: 500 + Math.floor(Math.random() * 1000), + response: (req: any) => { + const info = req.body; + delete info._X_ROW_KEY; + info.id = id++; + let item = group as any; + if (info.parentId) { + item = getGroupItem(info.parentId, group); + if (!item) { + return fail('错误的父级'); + } + if (!item.children) { + item.children = []; + } + item = item.children; + } + item.push({ ...info }); + return success('操作成功'); + }, + }, + { + url: /\/api\/admin\/group\/[0-9]+/, + method: 'post', + timeout: 500 + Math.floor(Math.random() * 1000), + response: (req: any) => { + const info = req.body; + delete info._X_ROW_KEY; + const item = getGroupItem(+req.url.replace('/api/admin/group/', ''), group); + if (!item) { + return fail('错误的id'); + } + Object.assign(item, info); + return success('操作成功'); + }, + }, + { + url: /\/api\/admin\/group\/[0-9]+/, + method: 'DELETE', + timeout: 500 + Math.floor(Math.random() * 1000), + response: (req: any) => { + const id = +req.url.replace('/api/admin/group/', ''); + const item = getGroupItem(id, group); + if (!item) { + return fail('错误的id'); + } + let parent = group; + if (item.parentId) { + parent = getGroupItem(item.parentId, group)?.children as any; + } + parent.splice( + parent.findIndex((item) => item.id === id), + 1, + ); + return success('操作成功'); + }, + }, +]; diff --git a/mock/apiDemo/menu.ts b/mock/apiDemo/menu.ts new file mode 100644 index 00000000..f94456b5 --- /dev/null +++ b/mock/apiDemo/menu.ts @@ -0,0 +1,343 @@ +import { objectEach } from 'xe-utils'; +import { success, fail } from '../helper'; +let id = 100000; +const menu = [ + { + id: 1, + name: '示例', + rule: 'example', + type: 1, + sort: 1, + status: 1, + parentId: 0, + children: [ + { + id: 11, + parentId: 1, + name: '权限', + rule: 'permission', + type: 1, + sort: 1, + status: 1, + }, + { + id: 12, + parentId: 1, + name: '组件语言包', + rule: 'componentLang', + type: 1, + sort: 2, + status: 1, + }, + { + id: 13, + parentId: 1, + name: '请求示例', + rule: 'example/request', + type: 1, + sort: 3, + status: 1, + }, + { + id: 14, + parentId: 1, + name: '外链', + rule: 'link', + type: 1, + sort: 4, + status: 1, + }, + { + id: 15, + parentId: 1, + name: '页面权限', + rule: 'pagePermission', + type: 1, + sort: 5, + status: 1, + }, + { + id: 16, + parentId: 1, + name: '多级菜单', + rule: 'moreMenu', + type: 1, + sort: 6, + status: 1, + children: [ + { + id: 161, + parentId: 16, + name: '多级菜单1', + rule: 'moreMenu1', + type: 1, + sort: 1, + status: 1, + children: [ + { + id: 1611, + parentId: 161, + name: '多级菜单1-1', + rule: 'moreMenu1-1', + type: 1, + sort: 1, + status: 1, + children: [ + { + id: 16111, + parentId: 1611, + name: '多级菜单1-1-1', + rule: 'moreMenu1-1-1', + type: 1, + sort: 1, + status: 1, + }, + { + id: 16112, + parentId: 1611, + name: '组件语言包', + rule: 'moreMenu1-1-lang', + type: 1, + sort: 1, + status: 1, + }, + ], + }, + { + id: 1612, + parentId: 161, + name: '多级菜单1-2', + rule: 'moreMenu1-2', + type: 1, + sort: 1, + status: 1, + }, + ], + }, + ], + }, + ], + }, + { + id: 2, + parentId: 0, + name: '组件', + sort: 2, + status: 1, + rule: 'component', + type: 1, + children: [ + { + id: 21, + parentId: 2, + name: '数字动画', + rule: 'meNumber', + type: 1, + sort: 1, + status: 1, + }, + { + id: 22, + parentId: 2, + name: '编辑器', + sort: 2, + rule: 'editor', + type: 1, + status: 1, + children: [ + { + id: 221, + parentId: 22, + name: 'WangEditor', + rule: 'wangEditor', + type: 1, + sort: 1, + status: 1, + }, + ], + }, + { + id: 23, + parentId: 2, + name: '表格', + sort: 3, + rule: 'table', + type: 1, + status: 1, + }, + { + id: 24, + parentId: 2, + name: 'vxeTable', + sort: 4, + rule: 'vxeTable', + type: 1, + status: 1, + }, + ], + }, + { + id: 3, + parentId: 0, + name: '自定义组件', + sort: 3, + status: 1, + rule: 'customComponent', + type: 1, + }, + { + id: 4, + parentId: 0, + name: '角色权限', + sort: 3, + status: 1, + rule: 'roleRule', + type: 1, + children: [ + { + id: 41, + parentId: 4, + name: '查看', + sort: 3, + status: 1, + rule: 'roleRuleIndex', + type: 2, + }, + { + id: 42, + parentId: 4, + name: '新增', + sort: 3, + status: 1, + rule: 'roleRuleAdd', + type: 3, + }, + { + id: 43, + parentId: 4, + name: '编辑', + sort: 3, + status: 1, + rule: 'roleRuleEdit', + type: 3, + }, + { + id: 44, + parentId: 4, + name: '删除', + sort: 3, + status: 1, + rule: 'roleRuleDel', + type: 3, + }, + ], + }, +]; +function getMenuItem(id: number, menuList?: typeof menu) { + if (!menuList) { + return; + } + for (const key in menuList) { + if (menuList[key].id === id) { + return menuList[key]; + } + const item = getMenuItem(id, menuList[key].children as any) as typeof menu[number]; + if (item) { + return item; + } + } +} +function delMenu(id: number) { + const item = getMenuItem(id, menu); + if (!item) { + throw new Error('错误的id'); + } + let parent = menu; + if (item.parentId) { + parent = getMenuItem(item.parentId, menu)?.children as any; + } + parent.splice( + parent.findIndex((item) => item.id === id), + 1, + ); + return item; +} +function addMenu(info: any) { + let item = menu as any; + if (info.parentId) { + item = getMenuItem(info.parentId, menu); + if (!item) { + throw new Error('错误的父级'); + } + if (!item.children) { + item.children = []; + } + item = item.children; + } + item.push({ ...info }); + return true; +} +export default [ + { + url: '/api/menu/index', + method: 'get', + timeout: 500 + Math.floor(Math.random() * 1000), + response: () => success(menu), + }, + { + url: '/api/admin/menu/add', + method: 'post', + timeout: 500 + Math.floor(Math.random() * 1000), + response: (req: any) => { + try { + const info = req.body; + delete info._X_ROW_KEY; + info.id = id++; + addMenu(info); + return success('操作成功'); + } catch (e) { + return fail('' + e); + } + }, + }, + { + url: /\/api\/admin\/menu\/[0-9]+/, + method: 'post', + timeout: 500 + Math.floor(Math.random() * 1000), + response: (req: any) => { + const id = +req.url.replace('/api/admin/menu/', ''); + const info = req.body; + delete info._X_ROW_KEY; + const item = getMenuItem(id, menu); + if (!item) { + return fail('错误的id'); + } + if (item?.parentId === info.parentId) { + Object.assign(item, info); + return success('操作成功'); + } + try { + const item = delMenu(id); + Object.assign(item, info); + addMenu(item); + return success('操作成功'); + } catch (e) { + return fail('' + e); + } + }, + }, + { + url: /\/api\/admin\/menu\/[0-9]+/, + method: 'DELETE', + timeout: 500 + Math.floor(Math.random() * 1000), + response: (req: any) => { + const id = +req.url.replace('/api/admin/menu/', ''); + try { + delMenu(id); + return success('操作成功'); + } catch (e) { + return fail('' + e); + } + }, + }, +]; diff --git a/mock/index.ts b/mock/index.ts index 44908e3f..071c72b8 100644 --- a/mock/index.ts +++ b/mock/index.ts @@ -1,5 +1,5 @@ // mockProdServer.ts -import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'; +import { createProdMockServer } from '@meadmin-cn/vite-plugin-mock/es/createProdMockServer'; export function setupProdMockServer() { const modules = import.meta.glob('./apiDemo/*.ts', { diff --git a/package.json b/package.json index f23c0f02..57a71139 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,17 @@ { "name": "meadmin-template", "private": true, - "version": "1.0.6", + "version": "1.0.7", "type": "module", "scripts": { "format": "prettier --write --cache .", "dev": "vite", "build": "vite build -m prod && npm run type-check", "build-github": "vite build -m prod --base=/meadmin-template/ && npm run type-check", - "type-check": "vue-tsc --noEmit", + "type-check": "vue-tsc --noEmit --skipLibCheck", "preview": "vite preview", - "release-main": "vue-tsc --noEmit & release-it -c .release-it-main.json", - "release-template": "vue-tsc --noEmit & release-it", + "release-main": "release-it -c .release-it-main.json", + "release-template": "release-it", "eslint": "eslint . --cache --ext .vue,.ts,.tsx", "eslint:fix": "eslint . --ext .vue,.ts,.tsx --fix", "prettier": "prettier --cache -l \"./**/*\"", @@ -19,6 +19,7 @@ "i": "npm install --registry=https://registry.npm.taobao.org && npx husky install" }, "dependencies": { + "@meadmin-cn/vite-plugin-mock": "^2.9.7", "@vueuse/core": "^9.1.0", "@wangeditor/editor": "^5.1.15", "@wangeditor/editor-for-vue": "^5.1.12", @@ -39,7 +40,8 @@ "vue-form-create": "^1.2.10", "vue-i18n": "^9.1.10", "vue-request": "^2.0.0-rc.2", - "vue-router": "^4.1.1" + "vue-router": "^4.1.1", + "vxe-table": "^4.3.5" }, "devDependencies": { "@babel/core": "^7.18.10", @@ -75,7 +77,6 @@ "vite": "^3.0.0", "vite-plugin-autogeneration-import-file": "^2.1.0", "vite-plugin-compression": "^0.5.1", - "vite-plugin-mock": "^2.9.6", "vite-svg-loader": "^3.4.0", "vue-eslint-parser": "^9.0.3", "vue-tsc": "^0.34.7", diff --git a/plugin/vueSetupExtend.ts b/plugin/vueSetupExtend.ts index 3528679c..c5f3cd40 100644 --- a/plugin/vueSetupExtend.ts +++ b/plugin/vueSetupExtend.ts @@ -83,10 +83,10 @@ export function supportScript(code: string, options: ExtendOptions) { attrs.langImport = `{{${langImport}}}`; } } - if (options.setComponents) { + if (options.setComponents && !attrs.getComponents) { const components = getComponent(descriptor); if (components.length) { - attrs.components = `{{[${components}]}}`; + attrs.getComponents = `{{()=>[${components}]}}`; } } let scriptStr = ''; diff --git a/public/favicon.ico b/public/favicon.ico index df36fcfb..a4d91736 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 00000000..4067c90b Binary files /dev/null and b/public/logo.png differ diff --git a/src/api/admin.ts b/src/api/admin.ts new file mode 100644 index 00000000..8d7db454 --- /dev/null +++ b/src/api/admin.ts @@ -0,0 +1,62 @@ +import request from '@/utils/request'; + +const enum Api { + GROUP = '/api/admin/group/index', + ADD_GROUP = '/api/admin/group/add', + EDIT_GROUP = '/api/admin/group/{id}', + DEL_GROUP = '/api/admin/group/{id}', +} + +// 管理员组 +export class GroupInfo { + id?: number; + parentId?: number; + name = ''; //名称 + rules = [] as string[]; //权限数组 + status = 1 as 0 | 1; //状态 +} +export function addGroupApi() { + return request( + (info) => ({ + url: Api.ADD_GROUP, + method: 'POST', + data: info, + }), + { success: true }, + ); +} + +export function editGroupApi() { + return request]>( + (id, info) => ({ + url: Api.EDIT_GROUP.replace('{id}', id + ''), + method: 'POST', + data: info, + }), + { success: true }, + ); +} + +export function delGroupApi() { + return request( + (id) => ({ + url: Api.DEL_GROUP.replace('{id}', id + ''), + method: 'DELETE', + }), + { success: true }, + ); +} + +export type GroupListResult = (Required & { + children: GroupListResult; +})[]; + +export function groupListApi() { + return request( + () => ({ + url: Api.GROUP, + method: 'get', + }), + { noLoading: true, cacheKey: 'groupList', cacheTime: 5 * 60 * 1000 }, + ); +} diff --git a/src/api/menu.ts b/src/api/menu.ts new file mode 100644 index 00000000..cf358e98 --- /dev/null +++ b/src/api/menu.ts @@ -0,0 +1,65 @@ +import request from '@/utils/request'; + +const enum Api { + LIST = '/api/menu/index', + ADD = '/api/admin/menu/add', + EDIT = '/api/admin/menu/{id}', + DEL = '/api/admin/menu/{id}', +} + +// 菜单列表 +export class MenuInfo { + id?: number; + parentId?: number; //父级id + name = ''; //名称 + rule = ''; //规则 + sort = 0; //排序 + status = 1 as 0 | 1; //状态0停用1启用 + type = 1 as 1 | 2 | 3; //1菜单2页面3按钮 +} + +export function addMenuApi() { + return request( + (info) => ({ + url: Api.ADD, + method: 'POST', + data: info, + }), + { success: true }, + ); +} + +export function editMenuApi() { + return request]>( + (id, info) => ({ + url: Api.EDIT.replace('{id}', id + ''), + method: 'POST', + data: info, + }), + { success: true }, + ); +} + +export function delMenuApi() { + return request( + (id) => ({ + url: Api.DEL.replace('{id}', id + ''), + method: 'DELETE', + }), + { success: true }, + ); +} + +export type MenuListResult = (Required & { + children: MenuListResult; +})[]; + +export function menuListApi() { + return request( + () => ({ + url: Api.LIST, + method: 'get', + }), + { noLoading: true, cacheKey: 'menuList', cacheTime: 5 * 60 * 1000 }, + ); +} diff --git a/src/components/meTable/hooks/exportTable.ts b/src/components/meTable/hooks/exportTable.ts index 177c4898..050b5356 100644 --- a/src/components/meTable/hooks/exportTable.ts +++ b/src/components/meTable/hooks/exportTable.ts @@ -1,6 +1,6 @@ import { Defaults, TableExport } from 'tableexport'; type ExportType = 'csv' | 'txt' | 'xlsx'; -export default (elTable: ELTable, type: ExportType, filename?: string, options?: Defaults) => { +export default (elTable: ELTableInstance, type: ExportType, filename?: string, options?: Defaults) => { const selectionIndexs = elTable.getSelectionIndexs(); const ignoreRows = [] as number[]; if (selectionIndexs.length) { diff --git a/src/components/meTable/hooks/print.ts b/src/components/meTable/hooks/print.ts index a2fd82e3..0b1bce64 100644 --- a/src/components/meTable/hooks/print.ts +++ b/src/components/meTable/hooks/print.ts @@ -56,7 +56,7 @@ export function handlePrint(content: string, title = '', head: string[] = [], ty printFrame.src = URL.createObjectURL(blob); } -export default async (elTable: ELTable, title = '', head: string[] = []) => { +export default async (elTable: ELTableInstance, title = '', head: string[] = []) => { head.unshift(` diff --git a/src/components/meVxeTable/install.ts b/src/components/meVxeTable/install.ts new file mode 100644 index 00000000..bfb95bf5 --- /dev/null +++ b/src/components/meVxeTable/install.ts @@ -0,0 +1,14 @@ +import { app } from '@/app'; +import VXETable from 'vxe-table'; +import VXETablePluginElement from './vxe-table-plugin-element'; +import './style.scss'; +import './vxe-table-plugin-element/style.scss'; +VXETable.use(VXETablePluginElement); +if (app.config.globalProperties.$t) { + //为了兼容热更新重新拉取 + VXETable.setup({ + // 对组件内置的提示语进行国际化翻译 + i18n: app.config.globalProperties.$t, + }); + app.use(VXETable); +} diff --git a/src/components/meVxeTable/style.scss b/src/components/meVxeTable/style.scss new file mode 100644 index 00000000..a53cd2db --- /dev/null +++ b/src/components/meVxeTable/style.scss @@ -0,0 +1,155 @@ +@import 'vxe-table/lib/style.min.css'; + +.vxe-table--render-default .vxe-cell--checkbox .vxe-checkbox--icon { + font-weight: 500 !important; + font-size: 1em !important; +} + +.vxe-table { + ::-webkit-scrollbar-corner { + background: unset; + } + + ::-webkit-scrollbar { + z-index: 1; + border-radius: 4px; + width: 6px; + } + + ::-webkit-scrollbar:horizontal { + height: 5px; + } + + ::-webkit-scrollbar-thumb { + background-color: rgba(144, 147, 153, 0.3); + opacity: 0.3; + border-radius: 4px; + } +} +[class*='vxe-'] .el-checkbox__inner::after { + box-sizing: content-box !important; +} +.vxe-table--body-wrapper, +.vxe-table--fixed-left-body-wrapper, +.vxe-table--fixed-right-body-wrapper { + overflow-y: overlay !important; + overflow-x: overlay !important; +} + +.vxe-table--render-default .vxe-table--footer-wrapper, +.vxe-table--render-default .vxe-table--header-wrapper { + overflow-x: hidden !important; + overflow-y: hidden !important; +} + +.vxe-table--footer-wrapper.body--wrapper { + overflow-x: overlay !important; +} + +.dark .wxe-table ::-webkit-scrollbar-thumb { + background-color: rgba(163, 166, 173, 0.3); +} + +//暗黑模式暂时只加上table相关,vxetable不支持css变量 只能写死,后续vxetable升级支持css变量后会更新一版完整的暗黑样式。 +.dark { + /*font*/ + $vxe-font-color: #cfd3dc !default; + + /*color*/ + $vxe-primary-color: #409eff !default; + $vxe-success-color: #67c23a !default; + $vxe-info-color: #909399 !default; + $vxe-warning-color: #e6a23c !default; + $vxe-danger-color: #f56c6c !default; + $vxe-disabled-color: #2b2b2c !default; + $vxe-primary-disabled-color: #6c6e72 !default; + + /*input/radio/checkbox*/ + $vxe-input-border-color: #4c4d4f !default; + $vxe-input-disabled-color: #4c4d4f !default; + $vxe-input-disabled-background-color: #262727 !default; + $vxe-input-placeholder-color: #8d9095 !default; + + /*table*/ + $vxe-table-font-color: #cfd3dc !default; + $vxe-table-header-font-color: #a3a6ad !default; + $vxe-table-footer-font-color: #cfd3dc !default; + // $vxe-table-border-radius: $vxe-border-radius !default; + $vxe-table-border-width: 1px !default; + $vxe-table-border-color: #414243 !default; + $vxe-table-resizable-line-color: #363637 !default; + $vxe-table-resizable-drag-line-color: #363637 !default; + $vxe-table-header-background-color: #262727 !default; + $vxe-table-body-background-color: transparent !default; + $vxe-table-footer-background-color: transparent !default; + $vxe-table-tree-node-line-color: #414243 !default; + $vxe-table-tree-node-line-style: dotted !default; + $vxe-table-header-font-weight: bold !default; + + $vxe-table-row-height-default: 48px !default; + $vxe-table-row-height-medium: 44px !default; + $vxe-table-row-height-small: 40px !default; + $vxe-table-row-height-mini: 36px !default; + $vxe-table-row-line-height: 22px !default; + $vxe-table-row-hover-background-color: #262727 !default; + $vxe-table-row-striped-background-color: #1d1d1d !default; + $vxe-table-row-hover-striped-background-color: #262727 !default; + $vxe-table-row-radio-checked-background-color: #7d5b28 !default; + $vxe-table-row-hover-radio-checked-background-color: #e6a23c !default; + $vxe-table-row-checkbox-checked-background-color: #7d5b28 !default; + $vxe-table-row-hover-checkbox-checked-background-color: #e6a23c !default; + $vxe-table-row-current-background-color: #18222c !default; + $vxe-table-row-hover-current-background-color: #213d5b !default; + + $vxe-table-column-padding-default: 13px 0 !default; + $vxe-table-column-padding-medium: 11px 0 !default; + $vxe-table-column-padding-small: 9px 0 !default; + $vxe-table-column-padding-mini: 7px 0 !default; + $vxe-table-column-hover-background-color: #213d5b !default; + $vxe-table-column-current-background-color: #18222c !default; + $vxe-table-column-icon-border-color: #6c6e72 !default; + $vxe-table-column-icon-border-hover-color: #a3a6ad !default; + + $vxe-table-cell-placeholder-color: #8d9095 !default; + $vxe-table-cell-padding-left: 10px !default; + $vxe-table-cell-padding-right: 10px !default; + $vxe-table-cell-input-height-default: $vxe-table-row-height-default - 6 !default; + $vxe-table-cell-input-height-medium: $vxe-table-row-height-medium - 6 !default; + $vxe-table-cell-input-height-small: $vxe-table-row-height-small - 6 !default; + $vxe-table-cell-input-height-mini: $vxe-table-row-height-mini - 6 !default; + $vxe-table-cell-dirty-width: 5px !default; + $vxe-table-cell-dirty-update-color: #f56c6c !default; + $vxe-table-cell-dirty-insert-color: #67c23a !default; + $vxe-table-cell-area-border-color: $vxe-primary-color !default; + $vxe-table-cell-area-border-width: 1px !default; + $vxe-table-cell-main-area-extension-border-color: #141414; + $vxe-table-cell-main-area-extension-background-color: $vxe-primary-color !default; + $vxe-table-cell-extend-area-border-width: 2px !default; + $vxe-table-cell-copy-area-border-width: 3px !default; + $vxe-table-cell-active-area-border-width: 2px !default; + $vxe-table-cell-copy-area-border-color: $vxe-table-cell-area-border-color !default; + $vxe-table-cell-extend-area-border-color: $vxe-table-cell-area-border-color !default; + $vxe-table-cell-active-area-border-color: $vxe-table-cell-area-border-color !default; + $vxe-table-cell-area-background-color: rgba(64, 158, 255, 0.2) !default; + + $vxe-table-checkbox-range-border-width: 1px !default; + $vxe-table-checkbox-range-border-color: #006af1 !default; + $vxe-table-checkbox-range-background-color: rgba(50, 128, 252, 0.2) !default; + + $vxe-table-fixed-left-scrolling-box-shadow: 4px 3px 4px 0px rgba(0, 0, 0, 0.12) !default; + $vxe-table-fixed-right-scrolling-box-shadow: -4px 3px 4px 0px rgba(0, 0, 0, 0.12) !default; + + /*toolbar*/ + $vxe-toolbar-background-color: #141414 !default; + $vxe-toolbar-custom-active-background-color: #262727 !default; + $vxe-toolbar-panel-background-color: #141414 !default; + + /*tooltip*/ + $vxe-tooltip-dark-color: #141414 !default; + $vxe-tooltip-dark-background-color: #e5eaf3 !default; + $vxe-tooltip-light-background-color: #141414 !default; + $vxe-tooltip-validate-error-color: #fff !default; + $vxe-tooltip-validate-error-background-color: #f56c6c !default; + + @import 'vxe-table/styles/index.scss'; +} diff --git a/src/components/meVxeTable/vxe-table-plugin-element/index.ts b/src/components/meVxeTable/vxe-table-plugin-element/index.ts new file mode 100644 index 00000000..19666d63 --- /dev/null +++ b/src/components/meVxeTable/vxe-table-plugin-element/index.ts @@ -0,0 +1,990 @@ +//vxe-table-plugin-element插件过不去vue-tsc检查,提bug没人理无奈只能自己copy下来改一下 +import { h, resolveComponent, ComponentOptions } from 'vue'; +import XEUtils from 'xe-utils'; +import { + VXETableCore, + VxeTableDefines, + VxeColumnPropTypes, + VxeGlobalRendererHandles, + VxeGlobalInterceptorHandles, + FormItemRenderOptions, + FormItemContentRenderParams, +} from 'vxe-table'; +import dayjs from 'dayjs'; + +let vxetable: VXETableCore; + +function isEmptyValue(cellValue: any) { + return cellValue === null || cellValue === undefined || cellValue === ''; +} + +function getOnName(type: string) { + return 'on' + type.substring(0, 1).toLocaleUpperCase() + type.substring(1); +} + +function getModelProp(renderOpts: VxeGlobalRendererHandles.RenderOptions) { + return 'modelValue'; +} + +function getModelEvent(renderOpts: VxeGlobalRendererHandles.RenderOptions) { + return 'update:modelValue'; +} + +function getChangeEvent(renderOpts: VxeGlobalRendererHandles.RenderOptions) { + let type = 'change'; + switch (renderOpts.name) { + case 'ElAutocomplete': + type = 'select'; + break; + case 'ElInput': + case 'ElInputNumber': + type = 'input'; + break; + } + return type; +} + +function toDayStringDate(value: any, format: string) { + return dayjs(value, format).date; +} + +function toDayDateString(date: any, format: string) { + return dayjs(date).format(format); +} + +function parseDate(value: any, props: { [key: string]: any }) { + return value && props.valueFormat ? toDayStringDate(value, props.valueFormat) : value; +} + +function getFormatDate(value: any, props: { [key: string]: any }, defaultFormat: string) { + return value ? toDayDateString(parseDate(value, props), props.format || defaultFormat) : value; +} + +function getFormatDates(values: any[], props: { [key: string]: any }, separator: string, defaultFormat: string) { + return XEUtils.map(values, (date: any) => getFormatDate(date, props, defaultFormat)).join(separator); +} + +function equalDaterange(cellValue: any, data: any, props: { [key: string]: any }, defaultFormat: string) { + cellValue = getFormatDate(cellValue, props, defaultFormat); + return ( + cellValue >= getFormatDate(data[0], props, defaultFormat) && + cellValue <= getFormatDate(data[1], props, defaultFormat) + ); +} + +function getCellEditFilterProps( + renderOpts: VxeGlobalRendererHandles.RenderOptions, + params: VxeGlobalRendererHandles.RenderEditParams | VxeGlobalRendererHandles.RenderFilterParams, + value: any, + defaultProps?: { [prop: string]: any }, +) { + return XEUtils.assign({}, defaultProps, renderOpts.props, { [getModelProp(renderOpts)]: value }); +} + +function getItemProps( + renderOpts: VxeGlobalRendererHandles.RenderOptions, + params: FormItemContentRenderParams, + value: any, + defaultProps?: { [prop: string]: any }, +) { + return XEUtils.assign({}, defaultProps, renderOpts.props, { [getModelProp(renderOpts)]: value }); +} + +function formatText(cellValue: any) { + return '' + (isEmptyValue(cellValue) ? '' : cellValue); +} + +function getCellLabelVNs( + renderOpts: VxeColumnPropTypes.EditRender, + params: VxeGlobalRendererHandles.RenderCellParams, + cellLabel: any, +) { + const { placeholder } = renderOpts; + return [ + h( + 'span', + { + class: 'vxe-cell--label', + }, + placeholder && isEmptyValue(cellLabel) + ? [ + h( + 'span', + { + class: 'vxe-cell--placeholder', + }, + formatText(vxetable._t(placeholder)), + ), + ] + : formatText(cellLabel), + ), + ]; +} + +function getOns( + renderOpts: VxeGlobalRendererHandles.RenderOptions, + params: VxeGlobalRendererHandles.RenderParams, + inputFunc?: Function, + changeFunc?: Function, +) { + const { events } = renderOpts; + const modelEvent = getModelEvent(renderOpts); + const changeEvent = getChangeEvent(renderOpts); + const isSameEvent = changeEvent === modelEvent; + const ons: { [type: string]: Function } = {}; + XEUtils.objectEach(events, (func: Function, key: string) => { + ons[getOnName(key)] = function (...args: any[]) { + func(params, ...args); + }; + }); + if (inputFunc) { + ons[getOnName(modelEvent)] = function (targetEvnt: any) { + inputFunc(targetEvnt); + if (events && events[modelEvent]) { + events[modelEvent](params, targetEvnt); + } + if (isSameEvent && changeFunc) { + changeFunc(targetEvnt); + } + }; + } + if (!isSameEvent && changeFunc) { + ons[getOnName(changeEvent)] = function (...args: any[]) { + changeFunc(...args); + if (events && events[changeEvent]) { + events[changeEvent](params, ...args); + } + }; + } + return ons; +} + +function getEditOns( + renderOpts: VxeGlobalRendererHandles.RenderOptions, + params: VxeGlobalRendererHandles.RenderEditParams, +) { + const { $table, row, column } = params; + return getOns( + renderOpts, + params, + (value: any) => { + // 处理 model 值双向绑定 + XEUtils.set(row, column.property, value); + }, + () => { + // 处理 change 事件相关逻辑 + $table.updateStatus(params); + }, + ); +} + +function getFilterOns( + renderOpts: VxeGlobalRendererHandles.RenderOptions, + params: VxeGlobalRendererHandles.RenderFilterParams, + option: VxeTableDefines.FilterOption, + changeFunc: Function, +) { + return getOns( + renderOpts, + params, + (value: any) => { + // 处理 model 值双向绑定 + option.data = value; + }, + changeFunc, + ); +} + +function getItemOns(renderOpts: VxeGlobalRendererHandles.RenderOptions, params: FormItemContentRenderParams) { + const { $form, data, property } = params; + return getOns( + renderOpts, + params, + (value: any) => { + // 处理 model 值双向绑定 + XEUtils.set(data, property, value); + }, + () => { + // 处理 change 事件相关逻辑 + $form.updateStatus(params); + }, + ); +} + +function matchCascaderData(index: number, list: any[], values: any[], labels: any[]) { + const val = values[index]; + if (list && values.length > index) { + XEUtils.each(list, (item) => { + if (item.value === val) { + labels.push(item.label); + matchCascaderData(++index, item.children, values, labels); + } + }); + } +} + +function getSelectCellValue( + renderOpts: VxeColumnPropTypes.EditRender, + params: VxeGlobalRendererHandles.RenderCellParams, +) { + const { options = [], optionGroups, props = {}, optionProps = {}, optionGroupProps = {} } = renderOpts; + const { $table, rowid, row, column } = params; + const { filterable, multiple } = props; + const labelProp = optionProps.label || 'label'; + const valueProp = optionProps.value || 'value'; + const groupOptions = optionGroupProps.options || 'options'; + const cellValue = XEUtils.get(row, column.property); + const colid = column.id; + let cellData: any; + if (filterable) { + const { internalData } = $table; + const { fullAllDataRowIdData } = internalData; + const rest: any = fullAllDataRowIdData[rowid]; + if (rest) { + cellData = rest.cellData; + if (!cellData) { + cellData = rest.cellData = {}; + } + } + if (rest && cellData[colid] && cellData[colid].value === cellValue) { + return cellData[colid].label; + } + } + if (!isEmptyValue(cellValue)) { + const selectlabel = XEUtils.map( + multiple ? cellValue : [cellValue], + optionGroups + ? (value) => { + let selectItem: any; + for (let index = 0; index < optionGroups.length; index++) { + selectItem = XEUtils.find(optionGroups[index][groupOptions], (item) => item[valueProp] === value); + if (selectItem) { + break; + } + } + return selectItem ? selectItem[labelProp] : value; + } + : (value) => { + const selectItem = XEUtils.find(options, (item) => item[valueProp] === value); + return selectItem ? selectItem[labelProp] : value; + }, + ).join(', '); + if (cellData && options && options.length) { + cellData[colid] = { value: cellValue, label: selectlabel }; + } + return selectlabel; + } + return ''; +} + +function getCascaderCellValue( + renderOpts: VxeGlobalRendererHandles.RenderOptions, + params: VxeGlobalRendererHandles.RenderCellParams, +) { + const { props = {} } = renderOpts; + const { row, column } = params; + const cellValue = XEUtils.get(row, column.property); + const values: any[] = cellValue || []; + const labels: any[] = []; + matchCascaderData(0, props.options, values, labels); + return (props.showAllLevels === false ? labels.slice(labels.length - 1, labels.length) : labels).join( + ` ${props.separator || '/'} `, + ); +} + +function getDatePickerCellValue( + renderOpts: VxeGlobalRendererHandles.RenderOptions, + params: VxeGlobalRendererHandles.RenderCellParams | VxeGlobalRendererHandles.ExportMethodParams, +) { + const { props = {} } = renderOpts; + const { row, column } = params; + const { rangeSeparator = '-' } = props; + let cellValue = XEUtils.get(row, column.property); + switch (props.type) { + case 'week': + cellValue = getFormatDate(cellValue, props, 'YYYYwWW'); + break; + case 'month': + cellValue = getFormatDate(cellValue, props, 'YYYY-MM'); + break; + case 'year': + cellValue = getFormatDate(cellValue, props, 'YYYY'); + break; + case 'dates': + cellValue = getFormatDates(cellValue, props, ', ', 'YYYY-MM-DD'); + break; + case 'daterange': + cellValue = getFormatDates(cellValue, props, ` ${rangeSeparator} `, 'YYYY-MM-DD'); + break; + case 'datetimerange': + cellValue = getFormatDates(cellValue, props, ` ${rangeSeparator} `, 'YYYY-MM-DD HH:ss:mm'); + break; + case 'monthrange': + cellValue = getFormatDates(cellValue, props, ` ${rangeSeparator} `, 'YYYY-MM'); + break; + default: + cellValue = getFormatDate(cellValue, props, 'YYYY-MM-DD'); + } + return cellValue; +} + +function getTimePickerCellValue( + renderOpts: VxeGlobalRendererHandles.RenderOptions, + params: VxeGlobalRendererHandles.RenderCellParams | VxeGlobalRendererHandles.RenderEditParams, +) { + const { props = {} } = renderOpts; + const { row, column } = params; + const { isRange, format = 'hh:mm:ss', rangeSeparator = '-' } = props; + let cellValue = XEUtils.get(row, column.property); + if (cellValue && isRange) { + cellValue = XEUtils.map(cellValue, (date) => toDayDateString(parseDate(date, props), format)).join( + ` ${rangeSeparator} `, + ); + } + return toDayDateString(parseDate(cellValue, props), format); +} + +function createEditRender(defaultProps?: { [key: string]: any }) { + return function (renderOpts: VxeColumnPropTypes.EditRender, params: VxeGlobalRendererHandles.RenderEditParams) { + const { row, column } = params; + const { name, attrs } = renderOpts; + const cellValue = XEUtils.get(row, column.property); + return [ + h(resolveComponent(name!), { + ...attrs, + ...getCellEditFilterProps(renderOpts, params, cellValue, defaultProps), + ...getEditOns(renderOpts, params), + }), + ]; + }; +} + +function defaultButtonEditRender( + renderOpts: VxeColumnPropTypes.EditRender, + params: VxeGlobalRendererHandles.RenderEditParams, +) { + const { attrs } = renderOpts; + return [ + h( + resolveComponent('el-button'), + { + ...attrs, + ...getCellEditFilterProps(renderOpts, params, null), + ...getOns(renderOpts, params), + }, + cellText(renderOpts.content), + ), + ]; +} + +function defaultButtonsEditRender( + renderOpts: VxeColumnPropTypes.EditRender, + params: VxeGlobalRendererHandles.RenderEditParams, +) { + const { children } = renderOpts; + if (children) { + return children.map( + (childRenderOpts: VxeColumnPropTypes.EditRender) => defaultButtonEditRender(childRenderOpts, params)[0], + ); + } + return []; +} + +function createFilterRender(defaultProps?: { [key: string]: any }) { + return function (renderOpts: VxeColumnPropTypes.FilterRender, params: VxeGlobalRendererHandles.RenderFilterParams) { + const { column } = params; + const { name, attrs } = renderOpts; + return [ + h( + 'div', + { + class: 'vxe-table--filter-element-wrapper', + }, + column.filters.map((option, oIndex) => { + const optionValue = option.data; + return h(resolveComponent(name!), { + key: oIndex, + ...attrs, + ...getCellEditFilterProps(renderOpts, params, optionValue, defaultProps), + ...getFilterOns(renderOpts, params, option, () => { + // 处理 change 事件相关逻辑 + handleConfirmFilter(params, !!option.data, option); + }), + }); + }), + ), + ]; + }; +} + +function handleConfirmFilter( + params: VxeGlobalRendererHandles.RenderFilterParams, + checked: boolean, + option: VxeTableDefines.FilterOption, +) { + const { $panel } = params; + $panel.changeOption(null, checked, option); +} + +/** + * 模糊匹配 + * @param params + */ +function defaultFuzzyFilterMethod(params: VxeGlobalRendererHandles.FilterMethodParams) { + const { option, row, column } = params; + const { data } = option; + const cellValue = XEUtils.get(row, column.property); + return XEUtils.toValueString(cellValue).indexOf(data) > -1; +} + +/** + * 精确匹配 + * @param params + */ +function defaultExactFilterMethod(params: VxeGlobalRendererHandles.FilterMethodParams) { + const { option, row, column } = params; + const { data } = option; + const cellValue = XEUtils.get(row, column.property); + /* eslint-disable eqeqeq */ + return cellValue === data; +} + +function renderOptions(options: any[], optionProps: VxeGlobalRendererHandles.RenderOptionProps) { + const labelProp = optionProps.label || 'label'; + const valueProp = optionProps.value || 'value'; + return XEUtils.map(options, (item, oIndex) => { + return h(resolveComponent('el-option'), { + key: oIndex, + value: item[valueProp], + label: item[labelProp], + disabled: item.disabled, + }); + }); +} + +function cellText(cellValue: any): string[] { + return [formatText(cellValue)]; +} + +function createFormItemRender(defaultProps?: { [key: string]: any }) { + return function (renderOpts: FormItemRenderOptions, params: FormItemContentRenderParams) { + const { data, property } = params; + const { name } = renderOpts; + const { attrs } = renderOpts; + const itemValue = XEUtils.get(data, property); + return [ + h(resolveComponent(name!), { + ...attrs, + ...getItemProps(renderOpts, params, itemValue, defaultProps), + ...getItemOns(renderOpts, params), + }), + ]; + }; +} + +function defaultButtonItemRender(renderOpts: FormItemRenderOptions, params: FormItemContentRenderParams) { + const { attrs } = renderOpts; + const props = getItemProps(renderOpts, params, null); + return [ + h( + resolveComponent('el-button') as ComponentOptions, + { + ...attrs, + ...props, + ...getOns(renderOpts, params), + }, + { + default: () => cellText(renderOpts.content || props.content), + }, + ), + ]; +} + +function defaultButtonsItemRender(renderOpts: FormItemRenderOptions, params: FormItemContentRenderParams) { + const { children } = renderOpts; + if (children) { + return children.map( + (childRenderOpts: FormItemRenderOptions) => defaultButtonItemRender(childRenderOpts, params)[0], + ); + } + return []; +} + +function createExportMethod(getExportCellValue: Function) { + return function (params: VxeGlobalRendererHandles.ExportMethodParams) { + const { row, column, options } = params; + return options && options.original + ? XEUtils.get(row, column.property) + : getExportCellValue(column.editRender || column.cellRender, params); + }; +} + +function createFormItemRadioAndCheckboxRender() { + return function (renderOpts: FormItemRenderOptions, params: FormItemContentRenderParams) { + const { name, options = [], optionProps = {}, attrs } = renderOpts; + const { data, property } = params; + const labelProp = optionProps.label || 'label'; + const valueProp = optionProps.value || 'value'; + const itemValue = XEUtils.get(data, property); + return [ + h( + resolveComponent(`${name}Group`) as ComponentOptions, + { + ...attrs, + ...getItemProps(renderOpts, params, itemValue), + ...getItemOns(renderOpts, params), + }, + { + default: () => { + return options.map((option, oIndex) => { + return h( + resolveComponent(name!) as ComponentOptions, + { + key: oIndex, + label: option[valueProp], + disabled: option.disabled, + }, + { + default: () => cellText(option[labelProp]), + }, + ); + }); + }, + }, + ), + ]; + }; +} + +/** + * 检查触发源是否属于目标节点 + */ +function getEventTargetNode(evnt: any, container: HTMLElement, className: string) { + let targetElem; + let target = evnt.target; + while (target && target.nodeType && target !== document) { + if ( + className && + target.className && + target.className.split && + target.className.split(' ').indexOf(className) > -1 + ) { + targetElem = target; + } else if (target === container) { + return { flag: className ? !!targetElem : true, container, targetElem: targetElem }; + } + target = target.parentNode; + } + return { flag: false }; +} + +/** + * 事件兼容性处理 + */ +function handleClearEvent( + params: + | VxeGlobalInterceptorHandles.InterceptorClearFilterParams + | VxeGlobalInterceptorHandles.InterceptorClearActivedParams + | VxeGlobalInterceptorHandles.InterceptorClearAreasParams, +) { + const { $event } = params; + const bodyElem = document.body; + if ( + // 远程搜索 + getEventTargetNode($event, bodyElem, 'el-autocomplete-suggestion').flag || + // 下拉框 + getEventTargetNode($event, bodyElem, 'el-select-dropdown').flag || + // 级联 + getEventTargetNode($event, bodyElem, 'el-cascader__dropdown').flag || + getEventTargetNode($event, bodyElem, 'el-cascader-menus').flag || + // 日期 + getEventTargetNode($event, bodyElem, 'el-time-panel').flag || + getEventTargetNode($event, bodyElem, 'el-picker-panel').flag || + // 颜色 + getEventTargetNode($event, bodyElem, 'el-color-dropdown').flag + ) { + return false; + } +} + +declare module 'vxe-table' { + interface DefineRendererOption { + defaultFilterMethod?(params: VxeGlobalRendererHandles.FilterMethodParams): boolean; + } +} + +/** + * 基于 vxe-table 表格的适配插件,用于兼容 element-ui 组件库 + */ +export const VXETablePluginElement = { + install(vxetablecore: VXETableCore) { + const { interceptor, renderer } = vxetablecore; + + vxetable = vxetablecore; + + renderer.mixin({ + ElAutocomplete: { + autofocus: 'input.el-input__inner', + renderDefault: createEditRender(), + renderEdit: createEditRender(), + renderFilter: createFilterRender(), + defaultFilterMethod: defaultExactFilterMethod, + renderItemContent: createFormItemRender(), + }, + ElInput: { + autofocus: 'input.el-input__inner', + renderDefault: createEditRender(), + renderEdit: createEditRender(), + renderFilter: createFilterRender(), + defaultFilterMethod: defaultFuzzyFilterMethod, + renderItemContent: createFormItemRender(), + }, + ElInputNumber: { + autofocus: 'input.el-input__inner', + renderDefault: createEditRender(), + renderEdit: createEditRender(), + renderFilter: createFilterRender(), + defaultFilterMethod: defaultFuzzyFilterMethod, + renderItemContent: createFormItemRender(), + }, + ElSelect: { + renderEdit(renderOpts, params) { + const { options = [], optionGroups, optionProps = {}, optionGroupProps = {} } = renderOpts; + const { row, column } = params; + const { attrs } = renderOpts; + const cellValue = XEUtils.get(row, column.property); + const props = getCellEditFilterProps(renderOpts, params, cellValue); + const ons = getEditOns(renderOpts, params); + if (optionGroups) { + const groupOptions = optionGroupProps.options || 'options'; + const groupLabel = optionGroupProps.label || 'label'; + return [ + h( + resolveComponent('el-select') as ComponentOptions, + { + ...attrs, + ...props, + ...ons, + }, + { + default: () => { + return XEUtils.map(optionGroups, (group, gIndex) => { + return h( + resolveComponent('el-option-group') as ComponentOptions, + { + key: gIndex, + label: group[groupLabel], + }, + { + default: () => renderOptions(group[groupOptions], optionProps), + }, + ); + }); + }, + }, + ), + ]; + } + return [ + h( + resolveComponent('el-select') as ComponentOptions, + { + ...props, + ...attrs, + ...ons, + }, + { + default: () => renderOptions(options, optionProps), + }, + ), + ]; + }, + renderCell(renderOpts, params) { + return getCellLabelVNs(renderOpts, params, getSelectCellValue(renderOpts, params)); + }, + renderFilter(renderOpts, params) { + const { options = [], optionGroups, optionProps = {}, optionGroupProps = {} } = renderOpts; + const groupOptions = optionGroupProps.options || 'options'; + const groupLabel = optionGroupProps.label || 'label'; + const { column } = params; + const { attrs } = renderOpts; + return [ + h( + 'div', + { + class: 'vxe-table--filter-element-wrapper', + }, + optionGroups + ? column.filters.map((option, oIndex) => { + const optionValue = option.data; + const props = getCellEditFilterProps(renderOpts, params, optionValue); + return h( + resolveComponent('el-select') as ComponentOptions, + { + key: oIndex, + ...attrs, + ...props, + ...getFilterOns(renderOpts, params, option, () => { + // 处理 change 事件相关逻辑 + handleConfirmFilter( + params, + props.multiple ? option.data && option.data.length > 0 : !XEUtils.eqNull(option.data), + option, + ); + }), + }, + { + default: () => { + return XEUtils.map(optionGroups, (group, gIndex) => { + return h( + resolveComponent('el-option-group') as ComponentOptions, + { + key: gIndex, + label: group[groupLabel], + }, + { + default: () => renderOptions(group[groupOptions], optionProps), + }, + ); + }); + }, + }, + ); + }) + : column.filters.map((option, oIndex) => { + const optionValue = option.data; + const props = getCellEditFilterProps(renderOpts, params, optionValue); + return h( + resolveComponent('el-select') as ComponentOptions, + { + key: oIndex, + ...attrs, + ...props, + ...getFilterOns(renderOpts, params, option, () => { + // 处理 change 事件相关逻辑 + handleConfirmFilter( + params, + props.multiple ? option.data && option.data.length > 0 : !XEUtils.eqNull(option.data), + option, + ); + }), + }, + { + default: () => renderOptions(options, optionProps), + }, + ); + }), + ), + ]; + }, + defaultFilterMethod(params) { + const { option, row, column } = params; + const { data } = option; + const { property, filterRender: renderOpts } = column; + const { props = {} } = renderOpts; + const cellValue = XEUtils.get(row, property); + if (props.multiple) { + if (XEUtils.isArray(cellValue)) { + return XEUtils.includeArrays(cellValue, data); + } + return data.indexOf(cellValue) > -1; + } + /* eslint-disable eqeqeq */ + return cellValue == data; + }, + renderItemContent(renderOpts, params) { + const { options = [], optionGroups, optionProps = {}, optionGroupProps = {} } = renderOpts; + const { data, property } = params; + const { attrs } = renderOpts; + const itemValue = XEUtils.get(data, property); + const props = getItemProps(renderOpts, params, itemValue); + const ons = getItemOns(renderOpts, params); + if (optionGroups) { + const groupOptions = optionGroupProps.options || 'options'; + const groupLabel = optionGroupProps.label || 'label'; + return [ + h( + resolveComponent('el-select') as ComponentOptions, + { + ...attrs, + ...props, + ...ons, + }, + { + default: () => { + return XEUtils.map(optionGroups, (group, gIndex) => { + return h( + resolveComponent('el-option-group') as ComponentOptions, + { + label: group[groupLabel], + key: gIndex, + }, + { + default: () => renderOptions(group[groupOptions], optionProps), + }, + ); + }); + }, + }, + ), + ]; + } + return [ + h( + resolveComponent('el-select') as ComponentOptions, + { + ...attrs, + ...props, + ...ons, + }, + { + default: () => renderOptions(options, optionProps), + }, + ), + ]; + }, + exportMethod: createExportMethod(getSelectCellValue), + }, + ElCascader: { + renderEdit: createEditRender(), + renderCell(renderOpts, params) { + return getCellLabelVNs(renderOpts, params, getCascaderCellValue(renderOpts, params)); + }, + renderItemContent: createFormItemRender(), + exportMethod: createExportMethod(getCascaderCellValue), + }, + ElDatePicker: { + renderEdit: createEditRender(), + renderCell(renderOpts, params) { + return getCellLabelVNs(renderOpts, params, getDatePickerCellValue(renderOpts, params)); + }, + renderFilter(renderOpts, params) { + const { column } = params; + const { name, attrs } = renderOpts; + return [ + h( + 'div', + { + class: 'vxe-table--filter-element-wrapper', + }, + column.filters.map((option, oIndex) => { + const optionValue = option.data; + return h(resolveComponent(name!), { + key: oIndex, + ...attrs, + ...getCellEditFilterProps(renderOpts, params, optionValue), + ...getFilterOns(renderOpts, params, option, () => { + // 处理 change 事件相关逻辑 + handleConfirmFilter(params, !!option.data, option); + }), + }); + }), + ), + ]; + }, + defaultFilterMethod(params) { + const { option, row, column } = params; + const { data } = option; + const { filterRender: renderOpts } = column; + const { props = {} } = renderOpts; + const cellValue = XEUtils.get(row, column.property); + if (data) { + switch (props.type) { + case 'daterange': + return equalDaterange(cellValue, data, props, 'YYYY-MM-DD'); + case 'datetimerange': + return equalDaterange(cellValue, data, props, 'YYYY-MM-DD HH:ss:mm'); + case 'monthrange': + return equalDaterange(cellValue, data, props, 'YYYY-MM'); + default: + return cellValue === data; + } + } + return false; + }, + renderItemContent: createFormItemRender(), + exportMethod: createExportMethod(getDatePickerCellValue), + }, + ElTimePicker: { + renderEdit: createEditRender(), + renderCell(renderOpts, params) { + return getCellLabelVNs(renderOpts, params, getTimePickerCellValue(renderOpts, params)); + }, + renderItemContent: createFormItemRender(), + exportMethod: createExportMethod(getTimePickerCellValue), + }, + ElTimeSelect: { + renderEdit: createEditRender(), + renderItemContent: createFormItemRender(), + }, + ElRate: { + renderDefault: createEditRender(), + renderEdit: createEditRender(), + renderFilter: createFilterRender(), + defaultFilterMethod: defaultExactFilterMethod, + renderItemContent: createFormItemRender(), + }, + ElSwitch: { + renderDefault: createEditRender(), + renderEdit: createEditRender(), + renderFilter(renderOpts, params) { + const { column } = params; + const { name, attrs } = renderOpts; + return [ + h( + 'div', + { + class: 'vxe-table--filter-element-wrapper', + }, + column.filters.map((option, oIndex) => { + const optionValue = option.data; + return h(resolveComponent(name!), { + key: oIndex, + ...attrs, + ...getCellEditFilterProps(renderOpts, params, optionValue), + ...getFilterOns(renderOpts, params, option, () => { + // 处理 change 事件相关逻辑 + handleConfirmFilter(params, XEUtils.isBoolean(option.data), option); + }), + }); + }), + ), + ]; + }, + defaultFilterMethod: defaultExactFilterMethod, + renderItemContent: createFormItemRender(), + }, + ElSlider: { + renderDefault: createEditRender(), + renderEdit: createEditRender(), + renderFilter: createFilterRender(), + defaultFilterMethod: defaultExactFilterMethod, + renderItemContent: createFormItemRender(), + }, + ElRadio: { + renderItemContent: createFormItemRadioAndCheckboxRender(), + }, + ElCheckbox: { + renderItemContent: createFormItemRadioAndCheckboxRender(), + }, + ElButton: { + renderDefault: defaultButtonEditRender, + renderItemContent: defaultButtonItemRender, + }, + ElButtons: { + renderDefault: defaultButtonsEditRender, + renderItemContent: defaultButtonsItemRender, + }, + }); + + interceptor.add('event.clearFilter', handleClearEvent); + interceptor.add('event.clearActived', handleClearEvent); + interceptor.add('event.clearAreas', handleClearEvent); + }, +}; + +if (typeof window !== 'undefined' && window.VXETable && window.VXETable.use) { + window.VXETable.use(VXETablePluginElement); +} + +export default VXETablePluginElement; diff --git a/src/components/meVxeTable/vxe-table-plugin-element/style.scss b/src/components/meVxeTable/vxe-table-plugin-element/style.scss new file mode 100644 index 00000000..5e8d9b62 --- /dev/null +++ b/src/components/meVxeTable/vxe-table-plugin-element/style.scss @@ -0,0 +1,98 @@ +$vxe-table-validate-error-color: #f56c6c; + +%ResetBorder { + border: 0; +} + +%SliderStyle { + .el-slider__runway { + margin: 8px 0; + .el-slider__button-wrapper { + z-index: auto; + } + } +} + +%CompWidth { + & > .el-input, + & > .el-autocomplete, + & > .el-input-number, + & > .el-select, + & > .el-cascader, + & > .el-date-editor, + & > .el-slider { + width: 100%; + } + & > .el-color-picker { + vertical-align: middle; + } +} +.vxe-form { + .vxe-form--item-content { + @extend %CompWidth; + } +} +.vxe-table--filter-element-wrapper { + padding: 0.8em 1em; + & > .el-input, + & > .el-input-number, + & > .el-autocomplete, + & > .el-select, + & > .el-rate, + & > .el-slider { + width: 180px; + } + & > .el-slider { + @extend %SliderStyle; + } +} +.vxe-table { + .vxe-cell, + .vxe-tree-cell { + @extend %CompWidth; + & > .el-slider { + @extend %SliderStyle; + } + } +} +.col--valid-error { + & > .vxe-cell, + & > .vxe-tree-cell { + & > .el-input .el-input__inner, + & > .el-autocomplete .el-input__inner, + & > .el-input-number .el-input__inner, + & > .el-select .el-input__inner, + & > .el-cascader .el-input__inner, + & > .el-date-picker .el-input__inner { + border-color: $vxe-table-validate-error-color; + } + } +} +.vxe-table.cell--highlight { + .vxe-cell, + .vxe-tree-cell { + & > .el-input:not(.el-date-editor), + & > .el-autocomplete, + & > .el-select, + & > .el-cascader { + .el-input__inner { + padding: 0; + @extend %ResetBorder; + } + } + & > .el-input-number { + .el-input-number__decrease, + .el-input-number__increase { + @extend %ResetBorder; + } + .el-input__inner { + @extend %ResetBorder; + } + } + & > .el-date-editor { + .el-input__inner { + @extend %ResetBorder; + } + } + } +} diff --git a/src/event/modules/core.ts b/src/event/modules/core.ts index 8b6ec480..f5fba227 100644 --- a/src/event/modules/core.ts +++ b/src/event/modules/core.ts @@ -1,8 +1,6 @@ import { installRoute } from '@/router'; import { installStore } from '@/store'; import { event, mitter } from '../index'; -import 'element-plus/dist/index.css'; -import 'element-plus/theme-chalk/dark/css-vars.css'; import { installIcon } from '@/icons'; import { installI18n } from '@/locales/i18n'; import nProgress from 'nprogress'; diff --git a/src/layout/components/header/components/topBar/components/right/index.vue b/src/layout/components/header/components/topBar/components/right/index.vue index 0744a1af..294186b9 100644 --- a/src/layout/components/header/components/topBar/components/right/index.vue +++ b/src/layout/components/header/components/topBar/components/right/index.vue @@ -11,9 +11,6 @@ + diff --git a/src/views/customForm.vue b/src/views/customForm.vue index 8cc6874a..41c19e46 100644 --- a/src/views/customForm.vue +++ b/src/views/customForm.vue @@ -130,27 +130,12 @@ if (app && !app.config.globalProperties.$initCreate) { } } //为了兼容暗黑模式对create-form样式做的覆盖 -:global(#app) { +:global(body #app) { color: unset; font-family: unset; min-height: unset; } -:global(::-webkit-scrollbar) { - width: unset; - height: unset; -} -:global(::-webkit-scrollbar-thumb) { - border-radius: unset; - background-color: unset; -} -:global(::-webkit-scrollbar-track) { - border-radius: unset; - background-color: unset; -} -:global(.fc-style ::-webkit-scrollbar) { - width: 5px; - height: 5px; -} + :global(.fc-style ::-webkit-scrollbar-thumb) { border-radius: 1rem; background-color: rgba(144, 147, 153, 0.3); diff --git a/src/views/login/index.vue b/src/views/login/index.vue index 21998307..edff2024 100644 --- a/src/views/login/index.vue +++ b/src/views/login/index.vue @@ -99,14 +99,8 @@ const login = async () => { }; diff --git a/src/views/rolePermissions/components/group/group.vue b/src/views/rolePermissions/components/group/group.vue new file mode 100644 index 00000000..7c0e1ad8 --- /dev/null +++ b/src/views/rolePermissions/components/group/group.vue @@ -0,0 +1,120 @@ + + + diff --git a/src/views/rolePermissions/components/menu/components/add.vue b/src/views/rolePermissions/components/menu/components/add.vue new file mode 100644 index 00000000..b116c474 --- /dev/null +++ b/src/views/rolePermissions/components/menu/components/add.vue @@ -0,0 +1,102 @@ + + + diff --git a/src/views/rolePermissions/components/menu/dict.ts b/src/views/rolePermissions/components/menu/dict.ts new file mode 100644 index 00000000..67e077b4 --- /dev/null +++ b/src/views/rolePermissions/components/menu/dict.ts @@ -0,0 +1,9 @@ +export const type = { + '1': '菜单', + '2': '页面', + '3': '按钮', +}; +export const status = { + '0': '关闭', + '1': '开启', +}; diff --git a/src/views/rolePermissions/components/menu/menu.vue b/src/views/rolePermissions/components/menu/menu.vue new file mode 100644 index 00000000..c69d4c71 --- /dev/null +++ b/src/views/rolePermissions/components/menu/menu.vue @@ -0,0 +1,131 @@ + + + diff --git a/src/views/rolePermissions/rolePermissions.vue b/src/views/rolePermissions/rolePermissions.vue new file mode 100644 index 00000000..64d306da --- /dev/null +++ b/src/views/rolePermissions/rolePermissions.vue @@ -0,0 +1,45 @@ + + + diff --git a/template/components.d.ts b/template/components.d.ts index ceec6cbb..dc6fc9ab 100644 --- a/template/components.d.ts +++ b/template/components.d.ts @@ -3,4 +3,7 @@ declare module '@vue/runtime-core' { //code } } +declare global { + //typeCode +} export {}; diff --git a/types/global.d.ts b/types/global.d.ts index 1095d10a..3d2a2460 100644 --- a/types/global.d.ts +++ b/types/global.d.ts @@ -2,6 +2,11 @@ import { Component, AllowedComponentProps, DefineComponent, VNodeProps } from 'v import { ElTable } from 'element-plus'; export {}; declare global { + //unplugin-auto-import的Element是在页面加载到的时候才生成类型,这里全局声明一下 + const ElLoading: typeof import('element-plus/es')['ElLoading']; + const ElMessage: typeof import('element-plus/es')['ElMessage']; + const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']; + const ElNotification: typeof import('element-plus/es')['ElNotification']; // svg-icon /el-cion-*组件定义 type Icon = DefineComponent<{ size: (StringConstructor | NumberConstructor)[]; @@ -24,7 +29,7 @@ declare global { >]: InstanceType['$props'][K]; }; - type ELTable = InstanceType & { + type ELTableInstance = InstanceType & { getSelectionIndexs: () => number[]; //获取选中行的索引 }; } diff --git a/vite.config.ts b/vite.config.ts index e78364b9..aebee153 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,7 +4,7 @@ import { resolve } from 'path'; import * as fs from 'fs'; import { autoImport, resolver } from 'vite-plugin-autogeneration-import-file'; import vueSetUpExtend from './plugin/vueSetupExtend'; -import { viteMockServe } from 'vite-plugin-mock'; +import { viteMockServe } from '@meadmin-cn/vite-plugin-mock'; import { ConfigEnv, UserConfigExport } from 'vite'; import { visualizer } from 'rollup-plugin-visualizer'; //打包大小分析(stats.html) import AutoImport from 'unplugin-auto-import/vite'; @@ -89,7 +89,7 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => { toFile: 'types/meIconComments.d.ts', name: 'MeIcon_{{name}}', template: fs.readFileSync('./template/meIconComments.d.ts', 'utf-8'), - codeTemplates: [{ key: '//code', template: '{{name}}: Icon;\n ' }], + codeTemplates: [{ key: '//code', template: '{{name}}: Icon;\n ' }], }, { // pinia module @@ -123,6 +123,10 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => { key: '//code', template: '{{name}}: typeof import("{{path}}")["default"];\n ', }, + { + key: '//typeCode', + template: 'type {{name}}Instance = InstanceType;\n ', + }, ], name: '_{{name}}', }, @@ -184,5 +188,15 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => { }, }, }, + optimizeDeps: { + //因为项目中很多用到了自动引入和动态加载,所以vite首次扫描依赖项会扫描不全,这里强制扫描全局。 + entries: ['./src/**/*.{ts,tsx,vue}'], + include: [ + 'element-plus/es/components/loading/style/css', + 'element-plus/es/components/message/style/css', + 'element-plus/es/components/message-box/style/css', + 'element-plus/es/components/notification/style/css', + ], + }, }; };