From 0a3027eccd3b0bb6542e5fc831f7e02740dcfc95 Mon Sep 17 00:00:00 2001 From: Your Name <123456> Date: 星期一, 27 六月 2022 15:58:48 +0800 Subject: [PATCH] 'lct' --- src/components/auth/auth.vue | 30 source.d.ts | 6 src/layout/index.vue | 54 src/views/system/department/index.vue | 121 src/views/pages/formRules/component/formRulesThree.vue | 50 src/layout/routerView/parent.vue | 88 src/theme/media/error.scss | 45 src/components/cropper/index.vue | 149 src/views/pages/dynamicForm/index.vue | 204 src/views/visualizing/demo1.vue | 1278 ++ src/views/dashboard/index.vue | 35 src/utils/authDirective.ts | 40 src/views/make/selector/index.vue | 126 src/api/department/index.ts | 26 src/views/login/component/account.vue | 196 src/views/pages/filtering/details1.vue | 39 src/layout/lockScreen/index.vue | 372 src/utils/customDirective.ts | 178 src/views/error/404.vue | 115 src/views/system/role/component/editRole.vue | 242 src/layout/navBars/breadcrumb/search.vue | 138 src/views/system/user/component/editUser.vue | 202 src/views/menu/menu2/index.vue | 21 .env.development | 7 src/views/pages/filtering/details.vue | 39 src/layout/navBars/index.vue | 40 yarn.lock | 2236 +++ src/theme/media/home.scss | 23 src/views/pages/dynamicForm/mock.ts | 119 src/views/pages/element/index.vue | 89 src/views/system/menu/component/menuDialog.vue | 247 src/views/system/role/index.vue | 167 package-lock.json | 7716 +++++++++++++ src/theme/media/dialog.scss | 12 src/views/login/index.vue | 190 src/views/pages/workflow/component/tool/index.vue | 79 src/i18n/pages/login/zh-cn.ts | 28 src/views/pages/listAdapt/mock.ts | 93 vite.config.ts | 79 src/views/chart/index.vue | 492 src/views/pages/tableRules/index.vue | 129 src/views/pages/formRules/component/formRulesOne.vue | 68 src/views/error/401.vue | 117 src/i18n/pages/formI18n/en.ts | 13 src/views/pages/workflow/js/mock.ts | 262 src/views/pages/workflow/component/drawer/index.vue | 73 src/components/editor/index.vue | 115 src/views/pages/waterfall/index.vue | 174 src/layout/navMenu/vertical.vue | 101 src/theme/mixins/index.scss | 56 src/theme/media/personal.scss | 16 src/views/visualizing/images/bathymetry.jpg | 0 src/router/backEnd.ts | 110 src/theme/media/media.scss | 13 src/main.ts | 22 src/views/menu/menu1/menu12/menu121/index.vue | 21 src/utils/commonFunction.ts | 65 src/utils/theme.ts | 59 src/views/test/index.vue | 13 src/api/menu/index.ts | 39 src/layout/navMenu/subItem.vue | 48 src/i18n/pages/login/zh-tw.ts | 28 src/layout/navBars/breadcrumb/setings.vue | 816 + src/components/auth/authAll.vue | 31 src/theme/media/cityLinkage.scss | 10 src/layout/main/transverse.vue | 17 src/theme/index.scss | 8 src/router/frontEnd.ts | 97 src/views/menu/menu1/menu12/menu122/index.vue | 21 src/views/visualizing/demo2.vue | 1344 ++ src/views/pages/lazyImg/mock.ts | 313 .eslintrc.js | 63 src/theme/loading.scss | 51 src/views/pages/workflow/component/drawer/node.vue | 272 index.html | 31 src/views/system/dic/component/editDic.vue | 162 src/views/system/dic/index.vue | 159 src/api/login/index.ts | 25 LICENSE | 21 src/i18n/pages/login/en.ts | 29 src/utils/formatTime.ts | 137 src/views/params/dynamic/index.vue | 102 CHANGELOG.md | 356 src/stores/tagsViewRoutes.ts | 24 src/views/chart/chart.ts | 59 src/views/pages/awesome/index.vue | 87 src/layout/logo/index.vue | 85 src/views/system/user/component/addUser.vue | 200 tsconfig.json | 72 src/layout/navBars/breadcrumb/userNews.vue | 115 src/theme/media/date.scss | 25 src/theme/media/tagsView.scss | 11 src/views/pages/iocnfont/index.vue | 87 src/utils/getStyleSheets.ts | 101 src/layout/main/classic.vue | 35 src/views/pages/filtering/mock.ts | 201 src/utils/setIconfont.ts | 48 src/stores/index.ts | 8 src/views/visualizing/images/world.jpg | 0 src/views/system/dic/component/addDic.vue | 129 src/views/pages/formI18n/index.vue | 59 src/views/pages/workflow/index.vue | 693 + src/views/system/user/index.vue | 177 src/views/pages/preview/index.vue | 28 src/utils/other.ts | 200 package.json | 81 src/App.vue | 100 src/layout/navBars/breadcrumb/closeFull.vue | 61 .prettierrc.js | 39 src/layout/component/aside.vue | 163 src/stores/keepAliveNames.ts | 37 src/views/visualizing/mock/demo2.ts | 131 src/layout/main/columns.vue | 41 src/theme/media/login.scss | 63 src/views/params/dynamic/details.vue | 52 src/utils/toolsValidate.ts | 370 src/utils/authFunction.ts | 38 src/theme/media/chart.scss | 94 src/router/route.ts | 102 src/views/make/noticeBar/index.vue | 164 src/views/pages/workflow/component/tool/help.vue | 39 src/views/pages/drag/index.vue | 66 src/layout/navBars/breadcrumb/user.vue | 298 src/views/pages/formRules/index.vue | 80 src/i18n/pages/formI18n/zh-tw.ts | 13 src/theme/element.scss | 282 src/theme/waves.scss | 101 src/theme/iconSelector.scss | 70 src/i18n/pages/formI18n/zh-cn.ts | 13 src/views/home/index.vue | 185 src/stores/interface/index.ts | 91 src/views/params/common/index.vue | 100 src/components/editor/toolbar.ts | 60 src/i18n/lang/en.ts | 180 src/theme/dark.scss | 236 src/views/chart/head.vue | 107 src/stores/routesList.ts | 27 src/views/pages/formAdapt/index.vue | 114 src/views/system/menu/index.vue | 128 src/views/pages/filtering/index.vue | 355 src/layout/component/main.vue | 101 plugins.d.ts | 4 src/views/menu/menu1/menu13/index.vue | 27 src/layout/routerView/iframes.vue | 66 src/utils/arrayOperation.ts | 66 src/theme/media/layout.scss | 55 src/views/pages/steps/index.vue | 51 src/theme/media/form.scss | 16 src/utils/storage.ts | 59 src/i18n/index.ts | 67 src/views/pages/listAdapt/index.vue | 209 src/components/auth/auths.vue | 36 src/layout/navBars/tagsView/tagsView.vue | 734 + src/layout/footer/index.vue | 47 src/theme/common/transition.scss | 94 src/views/system/role/component/addRole.vue | 240 .eslintignore | 18 src/views/system/department/component/editDept.vue | 179 src/views/make/svgDemo/index.vue | 59 shim.d.ts | 13 src/api/role/index.ts | 12 src/stores/themeConfig.ts | 146 src/assets/login-icon-two.svg | 1 src/theme/media/index.scss | 15 src/views/pages/waves/index.vue | 134 src/components/iconSelector/index.vue | 252 src/layout/navBars/breadcrumb/index.vue | 119 src/views/pages/lazyImg/index.vue | 194 src/utils/wartermark.ts | 47 src/theme/media/scrollbar.scss | 56 public/favicon.ico | 0 src/router/index.ts | 110 src/assets/logo-mini.svg | 9 src/theme/media/pagination.scss | 15 src/views/menu/menu1/menu11/index.vue | 21 src/layout/main/defaults.vue | 47 src/utils/request.ts | 72 src/views/system/department/component/deptDialog.vue | 161 src/theme/other.scss | 36 src/views/params/common/details.vue | 52 src/layout/component/header.vue | 34 src/components/svgIcon/index.vue | 73 .env.production | 5 src/views/chart/chart.scss | 434 src/layout/navBars/breadcrumb/breadcrumb.vue | 163 src/layout/navMenu/horizontal.vue | 157 src/i18n/lang/zh-tw.ts | 180 src/utils/loading.ts | 42 src/utils/directive.ts | 18 src/views/personal/mock.ts | 66 src/layout/routerView/link.vue | 61 src/i18n/lang/zh-cn.ts | 180 src/stores/userInfo.ts | 65 src/layout/component/columnsAside.vue | 292 src/layout/navBars/tagsView/contextmenu.vue | 138 src/views/pages/formRules/component/formRulesTwo.vue | 52 src/views/personal/index.vue | 387 src/views/visualizing/mock/demo1.ts | 51 .env | 8 src/components/noticeBar/index.vue | 195 src/stores/requestOldRoutes.ts | 17 src/theme/app.scss | 281 src/views/pages/workflow/js/config.ts | 99 src/views/pages/tree/index.vue | 258 src/views/pages/workflow/component/contextmenu/index.vue | 107 src/views/pages/workflow/component/drawer/line.vue | 62 206 files changed, 34,608 insertions(+), 0 deletions(-) diff --git a/.env b/.env new file mode 100644 index 0000000..dacb1a5 --- /dev/null +++ b/.env @@ -0,0 +1,8 @@ +# port 端口号 +VITE_PORT = 8888 + +# open 运行 npm run dev 时自动打开浏览器 +VITE_OPEN = false + +# public path 配置线上环境路径(打包)、本地通过 http-server 访问时,请置空即可 +VITE_PUBLIC_PATH = /vue-next-admin-preview/ \ No newline at end of file diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..0c99294 --- /dev/null +++ b/.env.development @@ -0,0 +1,7 @@ +# 本地环境 +ENV = 'development' + +# 本地环境接口地址 +VITE_API_URL = 'http://192.168.0.35:8008' + +# VITE_API_URL = 'http://192.168.0.8:8008' diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..0336f50 --- /dev/null +++ b/.env.production @@ -0,0 +1,5 @@ +# 线上环境 +ENV = 'production' + +# 线上环境接口地址 +VITE_API_URL = 'https://lyt-top.gitee.io/vue-next-admin-preview/' \ No newline at end of file diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..cfc877d --- /dev/null +++ b/.eslintignore @@ -0,0 +1,18 @@ + +*.sh +node_modules +lib +*.md +*.scss +*.woff +*.ttf +.vscode +.idea +dist +mock +public +bin +build +config +index.html +src/assets \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..732bfbe --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,63 @@ +module.exports = { + root: true, + env: { + browser: true, + es2021: true, + node: true, + }, + parser: 'vue-eslint-parser', + parserOptions: { + ecmaVersion: 12, + parser: '@typescript-eslint/parser', + sourceType: 'module', + }, + extends: ['plugin:vue/vue3-essential', 'plugin:vue/essential', 'eslint:recommended'], + plugins: ['vue', '@typescript-eslint'], + rules: { + // http://eslint.cn/docs/rules/ + // https://eslint.vuejs.org/rules/ + '@typescript-eslint/ban-ts-ignore': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/no-use-before-define': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/ban-types': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + 'vue/custom-event-name-casing': 'off', + 'vue/attributes-order': 'off', + 'vue/one-component-per-file': 'off', + 'vue/html-closing-bracket-newline': 'off', + 'vue/max-attributes-per-line': 'off', + 'vue/multiline-html-element-content-newline': 'off', + 'vue/singleline-html-element-content-newline': 'off', + 'vue/attribute-hyphenation': 'off', + 'vue/html-self-closing': 'off', + 'vue/no-multiple-template-root': 'off', + 'vue/require-default-prop': 'off', + 'vue/no-v-model-argument': 'off', + 'vue/no-arrow-functions-in-watch': 'off', + 'vue/no-template-key': 'off', + 'vue/no-v-html': 'off', + 'vue/comment-directive': 'off', + 'vue/no-parsing-error': 'off', + 'vue/no-deprecated-v-on-native-modifier': 'off', + 'vue/multi-word-component-names': 'off', + 'no-useless-escape': 'off', + 'no-sparse-arrays': 'off', + 'no-prototype-builtins': 'off', + 'no-constant-condition': 'off', + 'no-use-before-define': 'off', + 'no-restricted-globals': 'off', + 'no-restricted-syntax': 'off', + 'generator-star-spacing': 'off', + 'no-unreachable': 'off', + 'no-multiple-template-root': 'off', + 'no-unused-vars': 'error', + 'no-v-model-argument': 'off', + 'no-case-declarations': 'off', + 'no-console': 'error', + }, +}; diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..cff490a --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,39 @@ +module.exports = { + // 一行最多多少个字符 + printWidth: 150, + // 指定每个缩进级别的空格数 + tabWidth: 2, + // 使用制表符而不是空格缩进行 + useTabs: true, + // 在语句末尾打印分号 + semi: true, + // 使用单引号而不是双引号 + singleQuote: true, + // 更改引用对象属性的时间 可选值"<as-needed|consistent|preserve>" + quoteProps: 'as-needed', + // 在JSX中使用单引号而不是双引号 + jsxSingleQuote: false, + // 多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>",默认none + trailingComma: 'es5', + // 在对象文字中的括号之间打印空格 + bracketSpacing: true, + // jsx 标签的反尖括号需要换行 + jsxBracketSameLine: false, + // 在单独的箭头函数参数周围包括括号 always:(x) => x \ avoid:x => x + arrowParens: 'always', + // 这两个选项可用于格式化以给定字符偏移量(分别包括和不包括)开始和结束的代码 + rangeStart: 0, + rangeEnd: Infinity, + // 指定要使用的解析器,不需要写文件开头的 @prettier + requirePragma: false, + // 不需要自动在文件开头插入 @prettier + insertPragma: false, + // 使用默认的折行标准 always\never\preserve + proseWrap: 'preserve', + // 指定HTML文件的全局空格敏感度 css\strict\ignore + htmlWhitespaceSensitivity: 'css', + // Vue文件脚本和样式标签缩进 + vueIndentScriptAndStyle: false, + // 换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr>" + endOfLine: 'lf', +}; diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..34eedbe --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,356 @@ +# <a href="https://gitee.com/lyt-top/vue-next-admin" target="_blank">vue-next-admin 更新日志</a> + +🎉🎉🔥 `vue-next-admin` 基于 vue3.x 、Typescript、vite、Element plus 等,适配手机、平板、pc 的后台开源免费模板库(vue2.x 请切换 vue-prev-admin 分支) + +## 2.1.1 + +`2022.05.27` + +- 🌟 更新 依赖更新最新版本 +- 🎯 优化 深色模式下,`<el-button text></el-button>` 时,`:active` 样式 +- 🎯 优化 [页面缓存在刷新之后失效 #I58U75](https://gitee.com/lyt-top/vue-next-admin/issues/I58U75)),感谢[@ls0428](https://gitee.com/ls0428) +- 🎯 优化 [SvgIcon 对下载的 Svg 图像设置颜色无效 #I59ND0](https://gitee.com/lyt-top/vue-next-admin/issues/I59ND0)),感谢[@elus_z](https://gitee.com/elus_z) +- 🎯 优化 `/src/utils/toolsValidate.ts` 工具类 +- 🐞 修复 [布局切换,TagsView 显示的 tab 会多一个出来 #I58WGM](https://gitee.com/lyt-top/vue-next-admin/issues/I58WGM),感谢[@lg_boy](https://gitee.com/lg_boy) +- 🐞 修复 [如果设置顶部面包屑导航开启图标 isBreadcrumbIcon=true 后,样式有点问题 如果不开启就是正常的 #I58VB8](https://gitee.com/lyt-top/vue-next-admin/issues/I58VB8) +- 🐞 修复 地址栏路由地址输入错误时,返回首页后,再次输入路由地址错误时,不跳转 404 问题 +- 🐞 修复 [2.1.0 版本的图标选择组件多次点击后功能失效 #I590TH](https://gitee.com/lyt-top/vue-next-admin/issues/I590TH),感谢[@quber](https://gitee.com/quber) + +## 2.1.0 + +`2022.04.18` + +⚡⚡⚡ 此版本为破环性更新,优化内容如下:(谨慎更新!谨慎更新!!谨慎更新!!!)。因为 `vuex` 替换成 `pinia` + +- 🌟 更新 依赖更新最新版本 +- 🎯 优化 部分界面图片不显示问题(更换 gitee 在线图片地址源) +- 🎯 优化 各界面方法引入与逻辑之间添加一行空行,方便区分内容 +- 🎯 优化 图标选择器 [#I4YAHB](https://gitee.com/lyt-top/vue-next-admin/issues/I4YAHB),感谢[@真有你的](https://gitee.com/sunliusen) +- 🎯 优化 图标选择器 icon type 类型为 all 时,类型 ali、ele、awe 回显问题 +- 🎯 优化 去掉开发环境 i18n 控制台警告,页面代码:[i18n/index.ts](https://gitee.com/lyt-top/vue-next-admin/blob/master/src/i18n/index.ts) +- 🎯 优化 `NextLoading.start()` 方法,防止第一次进入界面时出现短暂空白 +- 🎯 优化 地址栏有参数退出登录,再次登录不跳之前界面问题 `src/layout/navBars/breadcrumb/user.vue` +- 🎯 优化 `SvgIcon` 组件,防止 `开启 Tagsview 图标` 时,`tagsView 右键菜单关闭` 报错问题,工作流不可连线、全屏时关闭按钮消失问题 +- 🎯 优化 [如果 url 中有中文等特殊字符,第一次切换该 tab 时 keep-alive 失效#I55JS7](https://gitee.com/lyt-top/vue-next-admin/issues/I55JS7),感谢[yuyong1566](https://gitee.com/yuyong1566) +- 🎯 优化 [wangEditor](https://www.wangeditor.com/) 更新到 v5,[vue3 版本线上示例中 wangeditor 富文本编辑器 demo 实例,无法换行#I5565B](https://gitee.com/lyt-top/vue-next-admin/issues/I5565B),感谢@[jenchih](https://gitee.com/jenchih) +- 🎯 优化 [在关闭 tagview 时,高度刷新时会会变化,出现滚动条](https://gitee.com/lyt-top/vue-next-admin/issues/I55FHM),感谢[张松](https://gitee.com/zs310071113) +- 🎯 优化 [路由参数](https://lyt-top.gitee.io/vue-next-admin-preview/#/params/common)演示 +- 🎉 新增 [vuex](https://vuex.vuejs.org/) 替换成 [pinia](https://pinia.vuejs.org/getting-started.html) +- 🎉 新增 tagsView 支持自定义 tagsView 名称(文章详情时有用),前往体验:[路由参数/普通路由](https://lyt-top.gitee.io/vue-next-admin-preview/#/params/common)。新增 tagsView 支持自定义名称国际化,感谢[@q7but](https://gitee.com/q7but)、[!22 add 添加自定义 tagVIewName 拓展,支持国际化](https://gitee.com/lyt-top/vue-next-admin/pulls/22/files)、感谢[@tony_tong_xin](https://gitee.com/tony_tong_xin) +- 🐞 修复 适配 `"element-plus": "^2.1.9",2.2.0` 版本 +- 🐞 修复 [导航栏横向布局后,一级菜单显示问题#I4Z3M3](https://gitee.com/lyt-top/vue-next-admin/issues/I4Z3M3) +- 🐞 修复 横向布局三级及以上导航菜单高亮、导航高度不统一问题 +- 🐞 修复 分栏模式下,选中的菜单是 primary 样式,鼠标移入字也变成 primary 色了,感谢群友@孤夜-流殇 +- 🐞 修复 [vuex 里面改了颜色 但是不生效 #I4WFMA](https://gitee.com/lyt-top/vue-next-admin/issues/I4WFMA) +- 🐞 修复 全局主题 primary 清空颜色后报错,[#I4X0LG](https://gitee.com/lyt-top/vue-next-admin/issues/I4X0LG),感谢[面向 BUG 编程](https://gitee.com/fhtfy) +- 🐞 修复 [.eslintrc.js 文件 rules 标签名错误 #I53IPK](https://gitee.com/lyt-top/vue-next-admin/issues/I53IPK),感谢[yuyong1566](https://gitee.com/yuyong1566) +- 🐞 修复 `开启 Tagsview 图标` 时,`tagsView 右键菜单关闭` 报错问题 +- 🐞 修复 `router.push` 路径找不到时报错问题,`404、401 界面` 已移入到 `main` 主布局里(之前全屏) +- 🐞 修复 [全局修改组件大小失效了](https://gitee.com/lyt-top/vue-next-admin/issues/I551RP),感谢[lg_boy](https://gitee.com/lg_boy) +- 🐞 修复 [修改一下配置时,需要每次都清理 `window.localStorage` 浏览器永久缓存,配置才会生效,问题解决#I567R1](https://gitee.com/lyt-top/vue-next-admin/issues/I567R1),感谢[@lanbao123](https://gitee.com/lanbao123) +- 🐞 修复 [标记为需要缓存的 tab 页后,再次从左侧菜单打开,还是显示被缓存的页面内容#I4UY3G](https://gitee.com/lyt-top/vue-next-admin/issues/I4UY3G),感谢@axcc1234、特别感谢群友@华仔 +- 🌈 重构 路由(`/src/router/index.ts`)解决 No match found for location with path "xxx"(前端控制,后端控制未解决) 问题 + +## 2.0.2 + +`2022.03.04` + +- 🌟 更新 依赖更新最新版本 +- 🎯 优化 Alert 提示添加边框 +- 🎯 优化 功能 / 数字滚动 演示界面 +- 🐞 修复 全局主题按钮颜色 :active 问题 +- 🐞 修复 Dropdown 下拉菜单样式问题 +- 🐞 修复 SvgIcon 图标组件动态切换时报警告问题,[SvgIcon 改变 name 时可能导致图像不显示](https://gitee.com/lyt-top/vue-next-admin/issues/I4VGE0),感谢@axcc1234 + +## 2.0.1 + +`2022.02.25` + +- 🌟 更新 依赖更新最新版本 +- 🎯 优化 svgIcon 图标组件 +- 🎯 优化 vite.config.ts 打包,感谢群友@YourObjec +- 🐞 修复 tagViews 开启图标不显示问题(风格 5),感谢群友@坏人 +- 🐞 修复 [Element Plus 1.2.0-beta.6 以后的版本 el-table 在移动端无法左右滑动](https://gitee.com/lyt-top/vue-next-admin/issues/I4UPTP),感谢@YGDada + +## 2.0.0 + +`2022.02.21` + +⚡⚡⚡ 此版本为破环性更新,优化内容如下:(谨慎更新!谨慎更新!!谨慎更新!!!)。演示界面建议直接覆盖文件。如需使用之前版本,请前往[gitee 发行版](https://gitee.com/lyt-top/vue-next-admin/releases) 进行对应版本下载。基础版会基于 `master` 分支进行修改 + +- 🌟 更新 依赖更新最新版本 +- 🌟 更新 登录页、首页 +- 💔 移除 vue-web-screen-shot +- 💔 移除 城市多级联动,完整 json 数据请去 [vue-next-admin-images/menu](https://gitee.com/lyt-top/vue-next-admin-images/tree/master/menu) 仓库查看 +- 💔 移除 功能/echartsTree 树图 +- 💔 移除 其它设置/Tagsview 风格 2、Tagsview 风格 3 +- 💔 移除 功能/验证器 +- 🚧 调整 src/api 编写方式 +- 🚧 调整 自定义封装公用组件演示,更好的维护 +- 🎉 新增 Volar 支持,vs code 配置参考 [Vue Language Features (Volar)](https://lyt-top.gitee.io/vue-next-admin-doc-preview/home/vscode/) +- 🎉 新增 `SvgIcon` 支持本地 svg 图标使用 +- 🎉 新增 表单表格验证演示 +- 🎯 优化 全局主题(移除 success、info、warning、danger) +- 🎯 优化 工作流(开源) +- 🎯 优化 element plus svg 图标,`elementXXX` 改成 `ele-XXX` +- 🌈 重构 深色模式 +- 🌹 合并 [处理 parent 的 h100 由于外层有 min-height 导致失效的问题](https://gitee.com/lyt-top/vue-next-admin/pulls/20),感谢@MaxNull、@21030442-mao +- 🐞 修复 element plus 升级 `^1.3.0-beta.5` 后 组件 size 大小问题(大改:涉及布局、演示界面) +- 🐞 修复 vs code 使用 Vue Language Features (Volar) 插件 代码报红问题(可以把公用的 ts 类型定义封装起来公用) + +## 1.2.2 + +`2021.12.21` + +- 🌟 更新 依赖更新最新版本 +- 🎯 优化 iframes 滚动条问题 +- 🎯 优化 部署后每次都要强制刷新清浏览器缓存问题 +- 🎉 新增 工具类百分比验证演示 +- 🐞 修复 [tag-view 标签右键会超出浏览器 #I4KN78](https://gitee.com/lyt-top/vue-next-admin/issues/I4KN78) + +## 1.2.1 + +`2021.12.12` + +- 🌟 更新 依赖更新最新版本 +- 🎯 优化 cropper 裁剪时卡顿问题 [#I4M2VQ](https://gitee.com/lyt-top/vue-next-admin/issues/I4M2VQ) +- 🎯 优化 Wangeditor 富文本编辑器的问题 [#I4LPC1](https://gitee.com/lyt-top/vue-next-admin/issues/I4LPC1)、[#I4LM7I](https://gitee.com/lyt-top/vue-next-admin/issues/I4LM7I) +- 🐞 修复 浏览器标题问题 +- 🐞 修复 element plus svg 图标引入 +- 🐞 修复 工作流不可以拖线连接问题 + +## 1.2.0 + +`2021.11.28` + +- 🌟 更新 依赖更新最新版本 +- 🎯 优化 深色模式 +- 🎯 优化 `/@/utils` 文件夹,合并删除单一内容 +- 🎯 优化 系统设置:菜单管理(新增、修改)、角色管理(新增菜单权限)、用户管理、部门管理、字典管理 +- 🎯 优化 登录界面逻辑、权限管理逻辑 +- 🎯 优化 同步 [vue-next-admin-images](https://gitee.com/lyt-top/vue-next-admin-images/tree/master/menu) 后端控制菜单模拟数据 +- 🎉 新增 适配 Font Icon 向 SVG Icon 迁移(改动大,"element-plus": "^1.2.0-beta.4" 谨慎更新) +- 🐞 修复 热更新问题,感谢@甜蜜蜜 +- 🐞 修复 页面/element 字体图标演示 +- 🐞 修复 功能/图标选择器演示,新增高级功能 [issues #I4GJXQ](https://gitee.com/lyt-top/vue-next-admin/issues/I4GJXQ) + +## 1.1.2 + +`2021.10.17` + +- 🌟 更新 依赖更新最新版本 +- 🐞 修复 开启全屏时,刷新界面被还原成未全屏的状态 +- 🎯 优化 tagsView 右键菜单关闭逻辑 +- 🎯 优化 wangeditor 富文本编辑器(增加双向绑定) +- 🎉 新增 工作流(暂不开源) +- 🎉 新增 基础版 ts(不带国际化),切换 `vue-next-admin-template` 分支 + +## 1.1.1 + +`2021.09.25` + +- 🌟 更新 依赖更新最新版本(`"element-plus": "^1.1.0-beta.13"` 版本运行错误,`^1.1.0-beta.16`修复横向菜单卡死问题) +- 🐞 修复 Dialog 弹窗位置错误、Drawer 抽屉内边距、el-menu 菜单收起时背景色问题 +- 🎯 优化 锁屏界面自动锁屏(s/秒)必须设置至少 1 秒 +- 🎉 新增 分栏布局,鼠标移入当前项时,显示当前项菜单内容 +- 🎉 新增 工作流(未完成) + +## 1.1.0 + +`2021.09.10` + +- 🌟 更新 依赖更新最新版本 +- 🎯 优化 小屏模式下登录页二维码遮挡标题问题 +- 🎉 新增 图片验证器 +- 🎉 新增 动态复杂表单 +- 🎉 新增 工作流(未完成) +- 🎉 新增 深色主题(伪深色,样式变动大,谨慎更新) + +## 1.0.18 + +`2021.08.29` + +- 🌟 更新 依赖更新最新版本 +- 🎯 优化 权限组件去掉顶级 div(`/src/components/auth`) +- 🎉 新增 布局配置添加恢复默认按钮 +- 🐞 修复 升级 <a href="https://element-plus.gitee.io/#/zh-CN/component/changelog" target="_blank">element plus 1.1.0-beta.7</a>后项目无法启动、el-menu 菜单 +- 🐞 修复 表格固定列时的层级、设置了相对定位时,遮挡左侧导航菜单问题 + +## 1.0.17 + +`2021.08.22` + +- 🌟 更新 依赖更新最新版本 +- 🎯 优化 去除设置布局切换,重置主题样式(initSetLayoutChange),切换布局需手动设置样式,设置的样式自动同步各布局 +- 🎯 优化 Dropdown 下拉菜单用户账号靠边时换行问题 +- 🎯 优化 左侧导航菜单,共用菜单树,防止 `布局配置` 设置 `菜单 / 顶栏` 时,样式丢失等问题 +- 🐞 修复 固定 header 后没有回到顶部的 bug,拉取项目后运行不起来的 bug。<a href="https://gitee.com/lyt-top/vue-next-admin/pulls/14" target="_blank">!14</a>,感谢<a href="https://gitee.com/wjs0509" target="_blank">@wjs0509</a> +- 🐞 修复 tagView 右键全屏后,浏览器窗口大小发生任何变化都会导致左边菜单显示出来,并且可点击打开对应页面。<a href="https://gitee.com/lyt-top/vue-next-admin/issues/I46E6T" target="_blank">I46E6T</a> +- 🐞 修复 默认设置 `菜单 / 顶栏` 样式不生效问题(/@/src/store/modules/themeConfig.ts) + +## 1.0.16 + +`2021.08.14` + +- 🌟 更新 依赖更新最新版本 +- 🎯 优化 菜单高亮(详情且详情设置了 meta.isHide 时,顶级菜单高亮),感谢群友@YourObject +- 🎯 优化 详情路径写法:如父级(/pages/filtering),那么详情为(/pages/filtering/details?id=1)。这样写可实现(详情时,父级菜单高亮),否则写成(/pages/filteringDetails?id=1)顶级菜单将不会高亮。可参考:`页面/过滤筛选组件`,点击当前图片进行测试 +- 🎯 优化 tagsView 右键菜单全屏时,打开的界面高度问题 +- 🎯 优化 图表批量 resize 问题 +- 🐞 修复 菜单收起时(设置全局主题:primary 且有二级菜单时),文字高亮颜色不对 +- 🐞 修复 国际化 <a href="https://gitee.com/lyt-top/vue-next-admin/issues/I43NPE" target="_blank">#I43NPE</a>。可参考:`页面/过滤筛选组件`,点击顶部语言切换,进行底部分页国际化查看 + +## 1.0.15 + +`2021.08.06` + +- 🌟 更新 依赖更新最新版本 +- 🎯 优化 tagsView 右键菜单点击时的字段名(id 已修改成 contextMenuClickId)与路由中返回的 id 名冲突问题,感谢群友@伯牙已遇钟子期 +- 🎉 新增 多个 form 表单验证界面演示 + +## 1.0.14 + +`2021.07.29` + +- 🌟 更新 依赖更新最新版本(vue、vuex、vue-router),出现问题,请手动降级。版本查看:<a href="https://www.npmjs.com/" target="_blank">vnpm</a> +- 🎯 优化 数据可视化图表演示加载卡顿问题、优化有图表的演示界面 +- 🎯 优化 路由参数演示界面 +- 🎯 优化 tagsView 操作演示界面,由于存在相同路由多标签,必须要传全部参数值(query 或者 params) +- 🎉 新增 开启 TagsView 共用,开启时:(多个路由菜单共用一个详情组件(参数为后点击的覆盖前面点击的),tagsView 中只会出现一个(不支持同时出现多个 tagsView 标签))。关闭时:(多个路由菜单共用一个详情组件,参数不同,会同时出现多个 tagsView 标签) +- 🐞 修复 tagsView 共用(单标签)时,右键菜单功能点击,参数不对的问题(第 2n+个参数未覆盖第一个参数值) +- 🐞 修复 多 tagsView 标签(参数不同)、单个 tagsView 标签公用(参数不同)所带来的刷新功能、横向自动滚动等问题 +- 🐞 修复 处理全屏若干问题,<a href="https://gitee.com/lyt-top/vue-next-admin/pulls/12" target="_blank">pr!12</a>,感谢群友@另一个前端 + +## 1.0.13 + +`2021.07.25` + +- 🌟 更新 依赖更新最新版本 +- 🎉 新增 数据可视化演示界面(/visualizingDemo1、/visualizingDemo2) +- 🎉 新增 登录页扫码登录 + +## 1.0.12 + +`2021.07.16` + +- 🌟 更新 依赖更新最新版本 +- 🎉 新增 数据可视化演示空界面(待完善) +- 🎯 优化 tagsView 动态路由(xxx/:id/:name)时的右键菜单刷新、关闭其它时参数丢失问题(2021.07.15 优化) +- 🐞 修复 路由带参数时,复制路径到登录页,跳转后参数消失的问题 +- 🐞 修复 设置多个外链,点击后,页面内容停留在上一个内容(内容未改变)、国际化处理、打开新窗口 sessionStorage 共享等 + +## 1.0.11 + +`2021.07.14` + +- 🌟 更新 依赖更新最新版本 +- 🎉 新增 路由参数、图片懒加载界面演示 +- ⚠️ 警告 Form 表单 `binding value must be a string or number`,解决:加上 `label-position="top"` 不报警告(等待官方修复) +- 🎯 优化 锁屏界面动画效果、首页图表显示 +- 🎯 优化 tagsView 右键菜单 `关闭` 功能逻辑 +- 🐞 修复 开启 TagsView 拖拽报错及小于 `1000px` 时自动设置禁止拖拽(<a href="https://gitee.com/lyt-top/vue-next-admin/issues/I3ZRRI" target="_blank">#I3ZRRI</a>) +- 🐞 修复 `iframe 内嵌、外链` 高度问题,使用 computed 进行计算 +- 🐞 修复 默认布局开启 `侧边栏 Logo` 与关闭 `菜单水平折叠`,切换到横向布局时,菜单看不见的问题 +- 🐞 修复 切换不同布局时,再去开启 `经典布局分割菜单` 功能不生效问题 +- 🐞 修复 浏览器窗口标题中/英文切换不实时生效的问题 +- 🐞 修复 切换布局时,某些功能不可以使用。部分界面不需要取消事件监听(proxy.mittBus.off('xxx')) +- 🐞 修复 动态路由带参数,router-link 跳转问题(<a href="hhttps://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G" target="_blank">#I3YX6G</a>) +- 🐞 修复 横向菜单有二级菜单时,点击子级菜单不高亮问题 +- 🐞 修复 功能 tagsView 操作演示不生效 + +## 1.0.10 + +`2021.07.07` + +- 🌟 更新 依赖更新最新版本(字体图标无问题) +- 🎯 优化 内嵌 iframe、外链,解决 tagsView 刷新问题 + +## 1.0.9 + +`2021.07.02` + +- 🌟 更新 依赖更新最新版本 +- 🎯 优化 图标选择器设置宽度、v-model 等问题 +- 🎯 优化 滚动通知栏在手机上的体验 +- 🎯 优化 系统管理/新增菜单(编辑菜单),使用 `图标选择器` 进行模拟 +- 🎯 优化 字体图标(自动载入) 逻辑 +- 🐞 修复 screenfull 全屏时,按键盘 esc 键图标不改变问题,感谢群友@伯牙已遇钟子期 + +## 1.0.8 + +`2021.06.29` + +- 🌟 更新 依赖更新最新版本 +- 🎉 新增 表单中英文切换演示 +- 🎯 优化 登录页查看密码 icon 图标 +- 🎯 优化 图标选择器 +- 🎯 优化 拖动指令 +- 🐞 修复 form 表单在页面小于 576px 时的排版问题 + +## 1.0.7 + +`2021.06.24` + +- 🌟 更新 依赖更新最新版本 +- 🎉 新增 拖动指令及其演示界面 +- 🎯 优化 锁屏界面,解锁提示 +- 🎯 优化 登录页在手机上显示的效果 + +## 1.0.6 + +`2021.06.23` + +- 🎯 优化 去掉内嵌 iframe 内边距(padding) +- 🎯 优化 城市多级联动组件 +- 🎯 优化 Tree 树形控件改成表格组件 +- 🐞 修复 Cascader 级联选择器高度问题 + +## 1.0.5 + +`2021.06.22` + +- 🌟 更新 vite 降级为@vite2.3.7,降级方法 `cnpm install vite@2.3.7`,防止 element plus 字体图标消失 +- 🐞 修复 开启后端控制路由(isRequestRoutes = true)时,内嵌 iframe、外链不可使用的问题 + +## 1.0.4 + +`2021.06.19` + +- 🌟 更新 依赖更新最新版本("vite": "^2.3.7")热更新无问题 +- 🎉 新增 深克隆工具,方便开发,感谢<a href="https://gitee.com/kangert" target="_blank">@kangert</a>(<a href="https://gitee.com/lyt-top/vue-next-admin/pulls/6" target="_blank">#6</a>) +- 🎯 优化 vuex 模块自动导入。感谢<a href="https://gitee.com/kangert" target="_blank">@kangert</a>(<a href="https://gitee.com/lyt-top/vue-next-admin/pulls/4" target="_blank">#4</a>),感谢群友@web 小学生-第五君 +- 🎯 优化 类型定义提高编码体验,修复不能将类型“string | undefined”分配给类型“string”的问题。感谢<a href="https://gitee.com/kangert" target="_blank">@kangert</a>(<a href="https://gitee.com/lyt-top/vue-next-admin/pulls/5" target="_blank">#5</a>) +- 🎯 优化 `layout` 文件夹移动到与 `views` 文件夹同级(改动较大,`/@/views/layout` 变成 `/@/layout`) +- 🎯 优化 页面有 `console.log` 时 `eslint` 不生效问题 +- 🎯 优化 页面、ts 中 `any` 类型问题(改动较大) +- 🎯 优化 登录页在手机上显示的效果 +- 🎯 优化 多行注释信息,鼠标放到方法名即可查看,更加直观的知道方法参数等。引入方法时需去掉以 `.ts` 结尾的后缀(改动较大) +- 🎯 优化 移除 `utils/storage.ts` 下的旧写法(改动较大) +- 🎯 优化 拆分 `router` 下内容,路由、前端、后端控制分开写,方便理解 +- 🐞 修复 鼠标移入顶部用户信息栏 `开/关全屏` 文字反向问题 +- 🐞 修复 热更新时,NextLoading(界面 loading) 不消失问题 `window.nextLoading === undefined` +- 🐞 修复 vuex 中不可以使用 `/@/api/xxx` 下的接口调用问题 + +## 1.0.3 + +`2021.06.02` + +- ❄️ 删除 G6 思维导图界面 +- 🌟 更新 手动更新 vue、vue-router、vuex 到最近最多人使用的版本,出现不可预测的问题请降低版本。版本查看:<a href="https://www.npmjs.com/package/vue" target="_blank">vue 版本查看</a> +- 🐞 修复 开启后端控制路由 `isRequestRoutes` 在非首页刷新页面后,回到首页的问题,感谢群友@伯牙已遇钟子期 + +## 1.0.2 + +`2021.06.01` + +- 🌟 更新 依赖更新最新版本 +- 🐞 修复 菜单搜索中文不可以搜索的问题,感谢群友@逍遥天意 + +## 1.0.1 + +`2021.05.31` + +- 🎉 新增 更新日志文件 `CHANGELOG.md`,以后每次更新都会在这里显示对应内容 +- 🌟 更新 依赖更新最新版本 +- 🐞 修复 分栏、经典布局路由设置 `meta.isHide` 为 `true` 时报错问题,感谢群友@29、@芭芭拉 +- 🐞 修复 经典布局点击 `tagsView` 左侧菜单数据不变问题 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6f6a7ea --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 lyt-Top + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..a550d07 --- /dev/null +++ b/index.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<html lang="zh-CN"> + <head> + <meta charset="utf-8" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <meta + name="keywords" + content="vue-next-admin,vue-prev-admin,vue-admin-wonderful,后台管理系统一站式平台模板,希望可以帮你完成快速开发。vue2.x,vue2.0,vue2,vue3,vue3.x,vue3.0,CompositionAPI,typescript,element plus,element,plus,admin,wonderful,wonderful-next,vue-next-admin,vite,vite-admin,快速,高效,后台模板,后台系统,管理系统" + /> + <meta + name="description" + content="vue-next-admin,基于 vue3 + CompositionAPI + typescript + vite + element plus,适配手机、平板、pc 的后台开源免费管理系统模板!vue-prev-admin,基于 vue2 + element ui,适配手机、平板、pc 的后台开源免费管理系统模板!" + /> + <title>vue-next-admin</title> + </head> + <body> + <div id="app"></div> + <script type="text/javascript"> + var _hmt = _hmt || []; + (function () { + var hm = document.createElement('script'); + hm.src = 'https://hm.baidu.com/hm.js?d9c8b87d10717013641458b300c552e4'; + var s = document.getElementsByTagName('script')[0]; + s.parentNode.insertBefore(hm, s); + })(); + </script> + <script type="module" src="/src/main.ts"></script> + <script type="text/javascript" src="https://api.map.baidu.com/api?v=3.0&ak=wsijQt8sLXrCW71YesmispvYHitfG9gv&s=1"></script> + </body> +</html> diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..1c0d853 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,7716 @@ +{ + "name": "vue-next-admin", + "version": "2.1.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "vue-next-admin", + "version": "2.1.1", + "license": "MIT", + "dependencies": { + "@element-plus/icons-vue": "^2.0.3", + "@wangeditor/editor": "^5.1.1", + "axios": "^0.27.2", + "countup.js": "^2.2.0", + "cropperjs": "^1.5.12", + "echarts": "^5.3.2", + "echarts-gl": "^2.0.9", + "echarts-wordcloud": "^2.0.0", + "element-plus": "^2.2.2", + "js-cookie": "^3.0.1", + "jsplumb": "^2.15.6", + "mitt": "^3.0.0", + "nprogress": "^0.2.0", + "pinia": "^2.0.14", + "print-js": "^1.6.0", + "qrcodejs2-fixes": "^0.0.2", + "screenfull": "^6.0.1", + "sortablejs": "^1.15.0", + "splitpanes": "^3.1.1", + "vue": "^3.2.36", + "vue-clipboard3": "^2.0.0", + "vue-grid-layout": "^3.0.0-beta1", + "vue-i18n": "^9.1.10", + "vue-router": "^4.0.15" + }, + "devDependencies": { + "@types/node": "^17.0.39", + "@types/nprogress": "^0.2.0", + "@types/sortablejs": "^1.13.0", + "@typescript-eslint/eslint-plugin": "^5.27.0", + "@typescript-eslint/parser": "^5.27.0", + "@vitejs/plugin-vue": "^2.3.3", + "@vue/compiler-sfc": "^3.2.36", + "dotenv": "^16.0.1", + "eslint": "^8.17.0", + "eslint-plugin-vue": "^9.1.0", + "prettier": "^2.6.2", + "sass": "^1.52.2", + "sass-loader": "^13.0.0", + "typescript": "^4.7.3", + "vite": "^2.9.9", + "vue-eslint-parser": "^9.0.2" + }, + "engines": { + "node": ">=12.0.0", + "npm": ">= 6.0.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-AqDccGC+m5O/iUStSJy3DGRIUFu7WbY/CppZYwrEUB4N0tZlnI8CSTsgL7v5fHVFmUbRv2sd+yy27o8Ydt4MGg==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.0.tgz", + "integrity": "sha512-YMQvx/6nKEaucl0MY56mwIG483xk8SDNdlUwb2Ts6FUpr7fm85DxEmsY18LXBNhcTz6tO6JwZV8w1W06v8UKeg==", + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ctrl/tinycolor": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz", + "integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@element-plus/icons-vue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.0.3.tgz", + "integrity": "sha512-dI9hazWIJF5AXsFDWLsdGqVIQMJ5Kq70fw1RScuMW6+UNqfJpRYFOqhya8RHpjajIZZnQx260Ll9AjTcu2HSOA==", + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.1.tgz", + "integrity": "sha512-grcqEmI8DTIolufpxhJagVeJmvloxBXE6xxSrVnSXz/Wz1uUIsC85ad+UNBqAoBOvzLxE42wvDj3YkmSGqWRxA==" + }, + "node_modules/@floating-ui/dom": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.1.tgz", + "integrity": "sha512-dkPSy5JPiQEtljc3VpG9lauYctxfLlqj/8N9f+lmsR92gQaSVMAWuBbFBH2keY5DmdQn3p4Dv1dQd+e8osH+/g==", + "dependencies": { + "@floating-ui/core": "^0.7.1" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@interactjs/actions": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/actions/-/actions-1.10.11.tgz", + "integrity": "sha512-P39zeefr4hkmKx+5nZ+mrH1s0l2YJ3gIHrthXmE81n6MlMa42m0WtHcTms4C5JTTNBP2EEDY+KGgGxSnmJKvUw==", + "optionalDependencies": { + "@interactjs/interact": "1.10.11" + }, + "peerDependencies": { + "@interactjs/core": "1.10.11", + "@interactjs/utils": "1.10.11" + } + }, + "node_modules/@interactjs/auto-scroll": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/auto-scroll/-/auto-scroll-1.10.11.tgz", + "integrity": "sha512-feHNjhi0EMNLV2nQcEgjYPz2mI54aeSW2RiaoNtFLyBvtXKp0b4DmluwDv6DvuXmUpDwD5g/Hk1gGM2rgl7iqQ==", + "optionalDependencies": { + "@interactjs/interact": "1.10.11" + }, + "peerDependencies": { + "@interactjs/utils": "1.10.11" + } + }, + "node_modules/@interactjs/auto-start": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/auto-start/-/auto-start-1.10.11.tgz", + "integrity": "sha512-cIg5CcalCPtC6AiGq6j/0hKUtL2MweEpvw12FuB19sz2Q9Dye0J4GliHKhOYvtumNinnvfVAZ4FZMqZEuX7YZA==", + "optionalDependencies": { + "@interactjs/interact": "1.10.11" + }, + "peerDependencies": { + "@interactjs/core": "1.10.11", + "@interactjs/utils": "1.10.11" + } + }, + "node_modules/@interactjs/core": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/core/-/core-1.10.11.tgz", + "integrity": "sha512-aJ50ccVeszpJt7wPH7Yfqm7f1aG1SA94qd90P0NaESh5/QUXn4CESO6igobo4DFHQ5z+1Rfdl8aphP4JxlH4gw==", + "peerDependencies": { + "@interactjs/utils": "1.10.11" + } + }, + "node_modules/@interactjs/dev-tools": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/dev-tools/-/dev-tools-1.10.11.tgz", + "integrity": "sha512-BP2FNfMbF7zLuOAUGMkDhCo1e1B0fnqyb9ih/Y8yAIJuoLrZxP/9htbsS1vZOIVZ4UgtrId4cYOwfcAZBMQtmw==", + "optionalDependencies": { + "@interactjs/interact": "1.10.11" + }, + "peerDependencies": { + "@interactjs/modifiers": "1.10.11", + "@interactjs/utils": "1.10.11" + } + }, + "node_modules/@interactjs/inertia": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/inertia/-/inertia-1.10.11.tgz", + "integrity": "sha512-h+sknCzRqBSyHy4ctPNsq56mxkAMMdwHWD6en7rDEw899gdGKYaXVDVdv1jMfiwNRw0eRFBNoCiol8r3a/a3Jw==", + "dependencies": { + "@interactjs/offset": "1.10.11" + }, + "optionalDependencies": { + "@interactjs/interact": "1.10.11" + }, + "peerDependencies": { + "@interactjs/core": "1.10.11", + "@interactjs/modifiers": "1.10.11", + "@interactjs/utils": "1.10.11" + } + }, + "node_modules/@interactjs/interact": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/interact/-/interact-1.10.11.tgz", + "integrity": "sha512-0iZJ9l547JuBA/lKxK4ARGYVmMqRSsAdA8gXL1zWe51qEIQq8PyWmMipoi8JbDaL7exC2THKwkXu5uq5ndT+iA==", + "dependencies": { + "@interactjs/core": "1.10.11", + "@interactjs/types": "1.10.11", + "@interactjs/utils": "1.10.11" + } + }, + "node_modules/@interactjs/interactjs": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/interactjs/-/interactjs-1.10.11.tgz", + "integrity": "sha512-cGOxf6rp3Y8/sk88LhIT0XDn4gCiCzAnUG5Kkj9SAqiUO6BK/9+Wbp1IBkNaPgl/8uG8gNHh/dXBrlBBNcqJAg==", + "dependencies": { + "@interactjs/actions": "1.10.11", + "@interactjs/auto-scroll": "1.10.11", + "@interactjs/auto-start": "1.10.11", + "@interactjs/core": "1.10.11", + "@interactjs/dev-tools": "1.10.11", + "@interactjs/inertia": "1.10.11", + "@interactjs/interact": "1.10.11", + "@interactjs/modifiers": "1.10.11", + "@interactjs/offset": "1.10.11", + "@interactjs/pointer-events": "1.10.11", + "@interactjs/reflow": "1.10.11", + "@interactjs/utils": "1.10.11" + } + }, + "node_modules/@interactjs/modifiers": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/modifiers/-/modifiers-1.10.11.tgz", + "integrity": "sha512-ltqX1RSqeAIikixlQBlyEUdclT5+rbfIGi3sIdLLYaIZQnltYkWqL9MHKx/w5b+hV+Mc0p5MLUFWJbTdkSCZ9g==", + "dependencies": { + "@interactjs/snappers": "1.10.11" + }, + "optionalDependencies": { + "@interactjs/interact": "1.10.11" + }, + "peerDependencies": { + "@interactjs/core": "1.10.11", + "@interactjs/utils": "1.10.11" + } + }, + "node_modules/@interactjs/offset": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/offset/-/offset-1.10.11.tgz", + "integrity": "sha512-mBT7eIfy5ivofECiv+VwtEwwIMLV54fT9ujSMWJPduxdSYIHepUWgEf/3zjJknFh6jQc7pqz9dtjvVvyzRCLlQ==", + "optionalDependencies": { + "@interactjs/interact": "1.10.11" + }, + "peerDependencies": { + "@interactjs/core": "1.10.11", + "@interactjs/utils": "1.10.11" + } + }, + "node_modules/@interactjs/pointer-events": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/pointer-events/-/pointer-events-1.10.11.tgz", + "integrity": "sha512-yBT8JJVMZ+MgBay5l1WAHnL8ch/mZsRfaFahti+QFYeQyRloDtsWmEMDSYI/Onyy9+hS3gN/ge77ArGciZZ0Ow==", + "optionalDependencies": { + "@interactjs/interact": "1.10.11" + }, + "peerDependencies": { + "@interactjs/core": "1.10.11", + "@interactjs/utils": "1.10.11" + } + }, + "node_modules/@interactjs/reflow": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/reflow/-/reflow-1.10.11.tgz", + "integrity": "sha512-NSCtcCkjImOYSbxzzv2kFqR9t49J8KlhEr9UoePc7GyLbNXsiv3WQ3n0ehZd7CgZXQDiVXnP2UnmIOv5Zd4HQg==", + "optionalDependencies": { + "@interactjs/interact": "1.10.11" + }, + "peerDependencies": { + "@interactjs/core": "1.10.11", + "@interactjs/utils": "1.10.11" + } + }, + "node_modules/@interactjs/snappers": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/snappers/-/snappers-1.10.11.tgz", + "integrity": "sha512-yYtOMUZ7aFUZ1IYheq9Tj5hZ4J1r5dnaXhLF44WsI/awQ5L0DjZf07GPWof0B+7rZHEVudxyQNbPfFmb+1K94Q==", + "optionalDependencies": { + "@interactjs/interact": "1.10.11" + }, + "peerDependencies": { + "@interactjs/utils": "1.10.11" + } + }, + "node_modules/@interactjs/types": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/types/-/types-1.10.11.tgz", + "integrity": "sha512-YRsVFWjL8Gkkvlx3qnjeaxW4fnibSJ9791g8BA7Pv5ANByI64WmtR1vU7A2rXcrOn8XvyCEfY0ss1s8NhZP+MA==" + }, + "node_modules/@interactjs/utils": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/utils/-/utils-1.10.11.tgz", + "integrity": "sha512-410ZoxKF+r1roeSelL+WHXfdryUMg5iykC1XwQ3l6XqNw43IMACzyvTH6k6Pwxj7w7x42nce0Qdn1GQ3Y8xyCw==" + }, + "node_modules/@intlify/core-base": { + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.10.tgz", + "integrity": "sha512-So9CNUavB/IsZ+zBmk2Cv6McQp6vc2wbGi1S0XQmJ8Vz+UFcNn9MFXAe9gY67PreIHrbLsLxDD0cwo1qsxM1Nw==", + "dependencies": { + "@intlify/devtools-if": "9.1.10", + "@intlify/message-compiler": "9.1.10", + "@intlify/message-resolver": "9.1.10", + "@intlify/runtime": "9.1.10", + "@intlify/shared": "9.1.10", + "@intlify/vue-devtools": "9.1.10" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@intlify/devtools-if": { + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.1.10.tgz", + "integrity": "sha512-SHaKoYu6sog3+Q8js1y3oXLywuogbH1sKuc7NSYkN3GElvXSBaMoCzW+we0ZSFqj/6c7vTNLg9nQ6rxhKqYwnQ==", + "dependencies": { + "@intlify/shared": "9.1.10" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@intlify/message-compiler": { + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.1.10.tgz", + "integrity": "sha512-+JiJpXff/XTb0EadYwdxOyRTB0hXNd4n1HaJ/a4yuV960uRmPXaklJsedW0LNdcptd/hYUZtCkI7Lc9J5C1gxg==", + "dependencies": { + "@intlify/message-resolver": "9.1.10", + "@intlify/shared": "9.1.10", + "source-map": "0.6.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@intlify/message-resolver": { + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.1.10.tgz", + "integrity": "sha512-5YixMG/M05m0cn9+gOzd4EZQTFRUu8RGhzxJbR1DWN21x/Z3bJ8QpDYj6hC4FwBj5uKsRfKpJQ3Xqg98KWoA+w==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@intlify/runtime": { + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.1.10.tgz", + "integrity": "sha512-7QsuByNzpe3Gfmhwq6hzgXcMPpxz8Zxb/XFI6s9lQdPLPe5Lgw4U1ovRPZTOs6Y2hwitR3j/HD8BJNGWpJnOFA==", + "dependencies": { + "@intlify/message-compiler": "9.1.10", + "@intlify/message-resolver": "9.1.10", + "@intlify/shared": "9.1.10" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@intlify/shared": { + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.1.10.tgz", + "integrity": "sha512-Om54xJeo1Vw+K1+wHYyXngE8cAbrxZHpWjYzMR9wCkqbhGtRV5VLhVc214Ze2YatPrWlS2WSMOWXR8JktX/IgA==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@intlify/vue-devtools": { + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.1.10.tgz", + "integrity": "sha512-5l3qYARVbkWAkagLu1XbDUWRJSL8br1Dj60wgMaKB0+HswVsrR6LloYZTg7ozyvM621V6+zsmwzbQxbVQyrytQ==", + "dependencies": { + "@intlify/message-resolver": "9.1.10", + "@intlify/runtime": "9.1.10", + "@intlify/shared": "9.1.10" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@popperjs/core": { + "name": "@sxzz/popperjs-es", + "version": "2.11.7", + "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz", + "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@transloadit/prettier-bytes": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz", + "integrity": "sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==" + }, + "node_modules/@types/eslint": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.2.tgz", + "integrity": "sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA==", + "dev": true, + "peer": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", + "dev": true, + "peer": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true, + "peer": true + }, + "node_modules/@types/event-emitter": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@types/event-emitter/-/event-emitter-0.3.3.tgz", + "integrity": "sha512-UfnOK1pIxO7P+EgPRZXD9jMpimd8QEFcEZ5R67R1UhGbv4zghU5+NE7U8M8G9H5Jc8FI51rqDWQs6FtUfq2e/Q==" + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.14.182", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", + "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.6", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.6.tgz", + "integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/node": { + "version": "17.0.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.39.tgz", + "integrity": "sha512-JDU3YLlnPK3WDao6/DlXLOgSNpG13ct+CwIO17V8q0/9fWJyeMJJ/VyZ1lv8kDprihvZMydzVwf0tQOqGiY2Nw==", + "dev": true + }, + "node_modules/@types/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@types/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-1cYJrqq9GezNFPsWTZpFut/d4CjpZqA0vhqDUPFWYKF1oIyBz5qnoYMzR+0C/T96t3ebLAC1SSnwrVOm5/j74A==", + "dev": true + }, + "node_modules/@types/sortablejs": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@types/sortablejs/-/sortablejs-1.13.0.tgz", + "integrity": "sha512-C3064MH72iEfeGCYEGCt7FCxXoAXaMPG0QPnstcxvPmbl54erpISu06d++FY37Smja64iWy5L8wOyHHBghWbJQ==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.27.0.tgz", + "integrity": "sha512-DDrIA7GXtmHXr1VCcx9HivA39eprYBIFxbQEHI6NyraRDxCGpxAFiYQAT/1Y0vh1C+o2vfBiy4IuPoXxtTZCAQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.27.0", + "@typescript-eslint/type-utils": "5.27.0", + "@typescript-eslint/utils": "5.27.0", + "debug": "^4.3.4", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.27.0.tgz", + "integrity": "sha512-8oGjQF46c52l7fMiPPvX4It3u3V3JipssqDfHQ2hcR0AeR8Zge+OYyKUCm5b70X72N1qXt0qgHenwN6Gc2SXZA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.27.0", + "@typescript-eslint/types": "5.27.0", + "@typescript-eslint/typescript-estree": "5.27.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.27.0.tgz", + "integrity": "sha512-VnykheBQ/sHd1Vt0LJ1JLrMH1GzHO+SzX6VTXuStISIsvRiurue/eRkTqSrG0CexHQgKG8shyJfR4o5VYioB9g==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.27.0", + "@typescript-eslint/visitor-keys": "5.27.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.27.0.tgz", + "integrity": "sha512-vpTvRRchaf628Hb/Xzfek+85o//zEUotr1SmexKvTfs7czXfYjXVT/a5yDbpzLBX1rhbqxjDdr1Gyo0x1Fc64g==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "5.27.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.27.0.tgz", + "integrity": "sha512-lY6C7oGm9a/GWhmUDOs3xAVRz4ty/XKlQ2fOLr8GAIryGn0+UBOoJDWyHer3UgrHkenorwvBnphhP+zPmzmw0A==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.27.0.tgz", + "integrity": "sha512-QywPMFvgZ+MHSLRofLI7BDL+UczFFHyj0vF5ibeChDAJgdTV8k4xgEwF0geFhVlPc1p8r70eYewzpo6ps+9LJQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.27.0", + "@typescript-eslint/visitor-keys": "5.27.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.27.0.tgz", + "integrity": "sha512-nZvCrkIJppym7cIbP3pOwIkAefXOmfGPnCM0LQfzNaKxJHI6VjI8NC662uoiPlaf5f6ymkTy9C3NQXev2mdXmA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.27.0", + "@typescript-eslint/types": "5.27.0", + "@typescript-eslint/typescript-estree": "5.27.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.27.0.tgz", + "integrity": "sha512-46cYrteA2MrIAjv9ai44OQDUoCZyHeGIc4lsjCUX2WT6r4C+kidz1bNiR4017wHOPUythYeH+Sc7/cFP97KEAA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.27.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@uppy/companion-client": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@uppy/companion-client/-/companion-client-2.1.0.tgz", + "integrity": "sha512-1Zsag2z9kygXuVbUxqHhkTJUmEHwbejjyf7vmm+P/AiVgK3O37JINYBGOpdTJNgbC9UydLBjleXo8peDVgpg8Q==", + "dependencies": { + "@uppy/utils": "^4.0.7", + "namespace-emitter": "^2.0.1" + } + }, + "node_modules/@uppy/core": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@uppy/core/-/core-2.2.0.tgz", + "integrity": "sha512-qdDoNCjrVjjOmFCFCxc+HEbtbQ9K0k6LKNbZZwWK7d4Cx3xEa6VsxmqVhfFL6ekH2gyboqYV8Z5IbRkJT/0Nqg==", + "dependencies": { + "@transloadit/prettier-bytes": "0.0.7", + "@uppy/store-default": "^2.0.3", + "@uppy/utils": "^4.0.7", + "lodash.throttle": "^4.1.1", + "mime-match": "^1.0.2", + "namespace-emitter": "^2.0.1", + "nanoid": "^3.1.25", + "preact": "^10.5.13" + } + }, + "node_modules/@uppy/store-default": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@uppy/store-default/-/store-default-2.0.3.tgz", + "integrity": "sha512-2BGlN1sW0cFv4rOqTK8dfSg579S984N1HxCJxLFqeW9nWD6zd/O8Omyd85tbxGQ+FLZLTmLOm/feD0YeCBMahg==" + }, + "node_modules/@uppy/utils": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@uppy/utils/-/utils-4.0.7.tgz", + "integrity": "sha512-nKViMT8XchKy+NWpb3DtVKuzZBmW7au26LrMq89EsvTwIOT6UR9+7bmz/+zr3+lc7UC7vMgNChIC6G+/Ya9wWQ==", + "dependencies": { + "lodash.throttle": "^4.1.1" + } + }, + "node_modules/@uppy/xhr-upload": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@uppy/xhr-upload/-/xhr-upload-2.1.0.tgz", + "integrity": "sha512-io1uNu7lGkhIkMnt13bu3FYSAdRbBRWl8n/6njYi+727Jyr0XhKfmBYV9OiruFSxLz5Bfxkw2gTs6e0qUb63nA==", + "dependencies": { + "@uppy/companion-client": "^2.1.0", + "@uppy/utils": "^4.0.7", + "nanoid": "^3.1.25" + }, + "peerDependencies": { + "@uppy/core": "^2.2.0" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-2.3.3.tgz", + "integrity": "sha512-SmQLDyhz+6lGJhPELsBdzXGc+AcaT8stgkbiTFGpXPe8Tl1tJaBw1A6pxDqDuRsVkD8uscrkx3hA7QDOoKYtyw==", + "dev": true, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "vite": "^2.5.10", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.36.tgz", + "integrity": "sha512-bbyZM5hvBicv0PW3KUfVi+x3ylHnfKG7DOn5wM+f2OztTzTjLEyBb/5yrarIYpmnGitVGbjZqDbODyW4iK8hqw==", + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/shared": "3.2.36", + "estree-walker": "^2.0.2", + "source-map": "^0.6.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.36.tgz", + "integrity": "sha512-tcOTAOiW4s24QLnq+ON6J+GRONXJ+A/mqKCORi0LSlIh8XQlNnlm24y8xIL8la+ZDgkdbjarQ9ZqYSvEja6gVA==", + "dependencies": { + "@vue/compiler-core": "3.2.36", + "@vue/shared": "3.2.36" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.36.tgz", + "integrity": "sha512-AvGb4bTj4W8uQ4BqaSxo7UwTEqX5utdRSMyHy58OragWlt8nEACQ9mIeQh3K4di4/SX+41+pJrLIY01lHAOFOA==", + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.36", + "@vue/compiler-dom": "3.2.36", + "@vue/compiler-ssr": "3.2.36", + "@vue/reactivity-transform": "3.2.36", + "@vue/shared": "3.2.36", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7", + "postcss": "^8.1.10", + "source-map": "^0.6.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.36.tgz", + "integrity": "sha512-+KugInUFRvOxEdLkZwE+W43BqHyhBh0jpYXhmqw1xGq2dmE6J9eZ8UUSOKNhdHtQ/iNLWWeK/wPZkVLUf3YGaw==", + "dependencies": { + "@vue/compiler-dom": "3.2.36", + "@vue/shared": "3.2.36" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.1.4.tgz", + "integrity": "sha512-IiA0SvDrJEgXvVxjNkHPFfDx6SXw0b/TUkqMcDZWNg9fnCAHbTpoo59YfJ9QLFkwa3raau5vSlRVzMSLDnfdtQ==" + }, + "node_modules/@vue/reactivity": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.36.tgz", + "integrity": "sha512-c2qvopo0crh9A4GXi2/2kfGYMxsJW4tVILrqRPydVGZHhq0fnzy6qmclWOhBFckEhmyxmpHpdJtIRYGeKcuhnA==", + "dependencies": { + "@vue/shared": "3.2.36" + } + }, + "node_modules/@vue/reactivity-transform": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.36.tgz", + "integrity": "sha512-Jk5o2BhpODC9XTA7o4EL8hSJ4JyrFWErLtClG3NH8wDS7ri9jBDWxI7/549T7JY9uilKsaNM+4pJASLj5dtRwA==", + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.36", + "@vue/shared": "3.2.36", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.36.tgz", + "integrity": "sha512-PTWBD+Lub+1U3/KhbCExrfxyS14hstLX+cBboxVHaz+kXoiDLNDEYAovPtxeTutbqtClIXtft+wcGdC+FUQ9qQ==", + "dependencies": { + "@vue/reactivity": "3.2.36", + "@vue/shared": "3.2.36" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.36.tgz", + "integrity": "sha512-gYPYblm7QXHVuBohqNRRT7Wez0f2Mx2D40rb4fleehrJU9CnkjG0phhcGEZFfGwCmHZRqBCRgbFWE98bPULqkg==", + "dependencies": { + "@vue/runtime-core": "3.2.36", + "@vue/shared": "3.2.36", + "csstype": "^2.6.8" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.36.tgz", + "integrity": "sha512-uZE0+jfye6yYXWvAQYeHZv+f50sRryvy16uiqzk3jn8hEY8zTjI+rzlmZSGoE915k+W/Ol9XSw6vxOUD8dGkUg==", + "dependencies": { + "@vue/compiler-ssr": "3.2.36", + "@vue/shared": "3.2.36" + }, + "peerDependencies": { + "vue": "3.2.36" + } + }, + "node_modules/@vue/shared": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.36.tgz", + "integrity": "sha512-JtB41wXl7Au3+Nl3gD16Cfpj7k/6aCroZ6BbOiCMFCMvrOpkg/qQUXTso2XowaNqBbnkuGHurLAqkLBxNGc1hQ==" + }, + "node_modules/@vueuse/core": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-8.5.0.tgz", + "integrity": "sha512-VEJ6sGNsPlUp0o9BGda2YISvDZbhWJSOJu5zlp2TufRGVrLcYUKr31jyFEOj6RXzG3k/H4aCYeZyjpItfU8glw==", + "dependencies": { + "@vueuse/metadata": "8.5.0", + "@vueuse/shared": "8.5.0", + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.1.0", + "vue": "^2.6.0 || ^3.2.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/@vueuse/core/node_modules/@vueuse/shared": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-8.5.0.tgz", + "integrity": "sha512-qKG+SZb44VvGD4dU5cQ63z4JE2Yk39hQUecR0a9sEdJA01cx+XrxAvFKJfPooxwoiqalAVw/ktWK6xbyc/jS3g==", + "dependencies": { + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.1.0", + "vue": "^2.6.0 || ^3.2.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/@vueuse/core/node_modules/vue-demi": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.12.5.tgz", + "integrity": "sha512-BREuTgTYlUr0zw0EZn3hnhC3I6gPWv+Kwh4MCih6QcAeaTlaIX0DwOVN0wHej7hSvDPecz4jygy/idsgKfW58Q==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.5.0.tgz", + "integrity": "sha512-WxsD+Cd+bn+HcjpY6Dl9FJ8ywTRTT9pTwk3bCQpzEhXVYAyNczKDSahk50fCfIJKeWHhyI4B2+/ZEOxQAkUr0g==", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@wangeditor/basic-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@wangeditor/basic-modules/-/basic-modules-1.1.1.tgz", + "integrity": "sha512-tQl2Pw8M2g3CM+ESx2phzr9zSKeuFCM1AMBoPdnlbatU7Dnae0CsEB/b3C+gI0dIQzM2jh34yTmqgbbhrwuRLg==", + "dependencies": { + "is-url": "^1.2.4" + }, + "peerDependencies": { + "@wangeditor/core": "1.x", + "dom7": "^3.0.0", + "lodash.throttle": "^4.1.1", + "nanoid": "^3.2.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/code-highlight": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@wangeditor/code-highlight/-/code-highlight-1.0.2.tgz", + "integrity": "sha512-SCtOcUxjKqIso/LSxGSOaYr3G6MC2En0gNTyHIMCG928T0fo0ufaqp/vIXKQzVL2Y+X/CSAOB2EbrFlgGvr0AQ==", + "dependencies": { + "prismjs": "^1.23.0" + }, + "peerDependencies": { + "@wangeditor/core": "1.x", + "dom7": "^3.0.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/core": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@wangeditor/core/-/core-1.1.1.tgz", + "integrity": "sha512-SrbvOGlONMNMOeFIJI7fC9x0/6T6LvQHTITPCqjgbCm2QF+POcrHzRKGQOqKCsyKi9UJz9hLsjsvJnvP10rxjQ==", + "dependencies": { + "@types/event-emitter": "^0.3.3", + "event-emitter": "^0.3.5", + "html-void-elements": "^2.0.0", + "i18next": "^20.4.0", + "scroll-into-view-if-needed": "^2.2.28", + "slate-history": "^0.66.0" + }, + "peerDependencies": { + "@uppy/core": "^2.1.1", + "@uppy/xhr-upload": "^2.0.3", + "dom7": "^3.0.0", + "is-hotkey": "^0.2.0", + "lodash.camelcase": "^4.3.0", + "lodash.clonedeep": "^4.5.0", + "lodash.debounce": "^4.0.8", + "lodash.foreach": "^4.5.0", + "lodash.isequal": "^4.5.0", + "lodash.throttle": "^4.1.1", + "lodash.toarray": "^4.4.0", + "nanoid": "^3.2.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/editor": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@wangeditor/editor/-/editor-5.1.1.tgz", + "integrity": "sha512-BtccuHFm0QvYunIhIu7tllQWkwppkmEkD3OJ5Mn+F0REPQ/Z3HiEXbtlss2t9c/kHO4CtiFwv2XD/k/VEg7taA==", + "dependencies": { + "@uppy/core": "^2.1.1", + "@uppy/xhr-upload": "^2.0.3", + "@wangeditor/basic-modules": "^1.1.1", + "@wangeditor/code-highlight": "^1.0.2", + "@wangeditor/core": "^1.1.1", + "@wangeditor/list-module": "^1.0.2", + "@wangeditor/table-module": "^1.1.0", + "@wangeditor/upload-image-module": "^1.0.1", + "@wangeditor/video-module": "^1.1.0", + "dom7": "^3.0.0", + "is-hotkey": "^0.2.0", + "lodash.camelcase": "^4.3.0", + "lodash.clonedeep": "^4.5.0", + "lodash.debounce": "^4.0.8", + "lodash.foreach": "^4.5.0", + "lodash.isequal": "^4.5.0", + "lodash.throttle": "^4.1.1", + "lodash.toarray": "^4.4.0", + "nanoid": "^3.2.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/list-module": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@wangeditor/list-module/-/list-module-1.0.2.tgz", + "integrity": "sha512-VfENZEFvsLTiLxN/cj8cibFGy9NVV+/cfATTiLiH9ef+8lgKv8apttXYVlqIAfnlJLLuCk0cIm8c/zH+hbtrZg==", + "peerDependencies": { + "@wangeditor/core": "1.x", + "dom7": "^3.0.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/table-module": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@wangeditor/table-module/-/table-module-1.1.0.tgz", + "integrity": "sha512-QpjCXSzsXcsR0pEI5Pu28e8aYh9+lHcVV4TTmGV6lRGE/etQF3PHUZNGUlfhkCgmGPq+E7n/Whb4RpAM3PJVhw==", + "peerDependencies": { + "@wangeditor/core": "1.x", + "dom7": "^3.0.0", + "lodash.isequal": "^4.5.0", + "lodash.throttle": "^4.1.1", + "nanoid": "^3.2.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/upload-image-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@wangeditor/upload-image-module/-/upload-image-module-1.0.1.tgz", + "integrity": "sha512-vgUV4ENttTITblqtVuzleIq732OmzmzzgrIvX6b3GRGPSw5u8glJ/87tOEhvHjHECc4oFo18B7xzJ1GpBj79/w==", + "peerDependencies": { + "@uppy/core": "^2.0.3", + "@uppy/xhr-upload": "^2.0.3", + "@wangeditor/basic-modules": "1.x", + "@wangeditor/core": "1.x", + "dom7": "^3.0.0", + "lodash.foreach": "^4.5.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/video-module": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@wangeditor/video-module/-/video-module-1.1.0.tgz", + "integrity": "sha512-VR6x7Vk9ebvXtxCPwobiNiTGZGgqEzCVc6ViWlNH3v4jlDIeo/s7N7OCgpvELR7X/X7GHecBu7wySDkHIskB5w==", + "peerDependencies": { + "@uppy/core": "^2.1.4", + "@uppy/xhr-upload": "^2.0.7", + "@wangeditor/core": "1.x", + "dom7": "^3.0.0", + "nanoid": "^3.2.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "peer": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "peer": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, + "peer": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true, + "peer": true + }, + "node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "peer": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peer": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async-validator": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.1.1.tgz", + "integrity": "sha512-p4DO/JXwjs8klJyJL8Q2oM4ks5fUTze/h5k10oPPKMiLe1fj3G1QMzPHNmN1Py4ycOk7WlO2DcGXv1qiESJCZA==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dependencies": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/batch-processor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/batch-processor/-/batch-processor-1.0.0.tgz", + "integrity": "sha512-xoLQD8gmmR32MeuBHgH0Tzd5PuSZx71ZsbhVxOCRbgktZEPe4SQy7s9Z50uPp0F/f7iw2XmkHN2xkgbMfckMDA==" + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "peer": true, + "dependencies": { + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", + "escalade": "^3.1.1", + "node-releases": "^2.0.3", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "peer": true + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001342", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001342.tgz", + "integrity": "sha512-bn6sOCu7L7jcbBbyNhLg0qzXdJ/PMbybZTH/BA6Roet9wxYRm6Tr9D0s0uhLkOZ6MSG+QU6txUgdpr3MXIVqjA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ], + "peer": true + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/claygl": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/claygl/-/claygl-1.3.0.tgz", + "integrity": "sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ==" + }, + "node_modules/clipboard": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz", + "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==", + "dependencies": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "peer": true + }, + "node_modules/compute-scroll-into-view": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz", + "integrity": "sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/countup.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/countup.js/-/countup.js-2.2.0.tgz", + "integrity": "sha512-m0TvFNXm9/eFqJm+QiKVI8e0wRUHzlQSewz9dqVjlhl2DFoZtceLbomwzxHz0hJ1+r4zBC7wSpR/TpthG49h6g==" + }, + "node_modules/cropperjs": { + "version": "1.5.12", + "resolved": "https://registry.npmjs.org/cropperjs/-/cropperjs-1.5.12.tgz", + "integrity": "sha512-re7UdjE5UnwdrovyhNzZ6gathI4Rs3KGCBSc8HCIjUo5hO42CtzyblmWLj6QWVw7huHyDMfpKxhiO2II77nhDw==" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/dayjs": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.2.tgz", + "integrity": "sha512-F4LXf1OeU9hrSYRPTTj/6FbO4HTjPKXvEIC1P2kcnFurViINCVk3ZV0xAS3XVx9MkMsXbbqlK6hjseaYbgKEHw==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom7": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/dom7/-/dom7-3.0.0.tgz", + "integrity": "sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==", + "dependencies": { + "ssr-window": "^3.0.0-alpha.1" + } + }, + "node_modules/dotenv": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", + "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/echarts": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.3.2.tgz", + "integrity": "sha512-LWCt7ohOKdJqyiBJ0OGBmE9szLdfA9sGcsMEi+GGoc6+Xo75C+BkcT/6NNGRHAWtnQl2fNow05AQjznpap28TQ==", + "dependencies": { + "tslib": "2.3.0", + "zrender": "5.3.1" + } + }, + "node_modules/echarts-gl": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/echarts-gl/-/echarts-gl-2.0.9.tgz", + "integrity": "sha512-oKeMdkkkpJGWOzjgZUsF41DOh6cMsyrGGXimbjK2l6Xeq/dBQu4ShG2w2Dzrs/1bD27b2pLTGSaUzouY191gzA==", + "dependencies": { + "claygl": "^1.2.1", + "zrender": "^5.1.1" + }, + "peerDependencies": { + "echarts": "^5.1.2" + } + }, + "node_modules/echarts-wordcloud": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/echarts-wordcloud/-/echarts-wordcloud-2.0.0.tgz", + "integrity": "sha512-K7l6pTklqdW7ZWzT/1CS0KhBSINr/cd7c5N1fVMzZMwLQHEwT7x+nivK7g5hkVh7WNcAv4Dn6/ZS5zMKRozC1g==", + "peerDependencies": { + "echarts": "^5.0.1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.137", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz", + "integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==", + "dev": true, + "peer": true + }, + "node_modules/element-plus": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.2.2.tgz", + "integrity": "sha512-yGcj2Ayb0jZO1WbI51tHJ4efhlfWKlBqqGtWbzhq+tcpfaKzJZN+IHRouuFasqn0ZV3tWCDu1jggDR1+9y7XfQ==", + "dependencies": { + "@ctrl/tinycolor": "^3.4.1", + "@element-plus/icons-vue": "^1.1.4", + "@floating-ui/dom": "^0.5.0", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", + "@types/lodash": "^4.14.182", + "@types/lodash-es": "^4.17.6", + "@vueuse/core": "^8.5.0", + "async-validator": "^4.1.1", + "dayjs": "^1.11.2", + "escape-html": "^1.0.3", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "lodash-unified": "^1.0.2", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.1.2" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/element-plus/node_modules/@element-plus/icons-vue": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-1.1.4.tgz", + "integrity": "sha512-Iz/nHqdp1sFPmdzRwHkEQQA3lKvoObk8azgABZ81QUOpW9s/lUyQVUSh0tNtEPZXQlKwlSh7SPgoVxzrE0uuVQ==", + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/element-resize-detector": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/element-resize-detector/-/element-resize-detector-1.2.4.tgz", + "integrity": "sha512-Fl5Ftk6WwXE0wqCgNoseKWndjzZlDCwuPTcoVZfCP9R3EHQF8qUtr3YUPNETegRBOKqQKPW3n4kiIWngGi8tKg==", + "dependencies": { + "batch-processor": "1.0.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", + "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==", + "dev": true, + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true, + "peer": true + }, + "node_modules/es5-ext": { + "version": "0.10.61", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.61.tgz", + "integrity": "sha512-yFhIqQAzu2Ca2I4SE2Au3rxVfmohU9Y7wqGR+s7+H7krk26NXhIRAZDgqd6xqjCEFUomDEA3/Bo/7fKmIkW1kA==", + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/esbuild": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.39.tgz", + "integrity": "sha512-2kKujuzvRWYtwvNjYDY444LQIA3TyJhJIX3Yo4+qkFlDDtGlSicWgeHVJqMUP/2sSfH10PGwfsj+O2ro1m10xQ==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "esbuild-android-64": "0.14.39", + "esbuild-android-arm64": "0.14.39", + "esbuild-darwin-64": "0.14.39", + "esbuild-darwin-arm64": "0.14.39", + "esbuild-freebsd-64": "0.14.39", + "esbuild-freebsd-arm64": "0.14.39", + "esbuild-linux-32": "0.14.39", + "esbuild-linux-64": "0.14.39", + "esbuild-linux-arm": "0.14.39", + "esbuild-linux-arm64": "0.14.39", + "esbuild-linux-mips64le": "0.14.39", + "esbuild-linux-ppc64le": "0.14.39", + "esbuild-linux-riscv64": "0.14.39", + "esbuild-linux-s390x": "0.14.39", + "esbuild-netbsd-64": "0.14.39", + "esbuild-openbsd-64": "0.14.39", + "esbuild-sunos-64": "0.14.39", + "esbuild-windows-32": "0.14.39", + "esbuild-windows-64": "0.14.39", + "esbuild-windows-arm64": "0.14.39" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.39.tgz", + "integrity": "sha512-EJOu04p9WgZk0UoKTqLId9VnIsotmI/Z98EXrKURGb3LPNunkeffqQIkjS2cAvidh+OK5uVrXaIP229zK6GvhQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.39.tgz", + "integrity": "sha512-+twajJqO7n3MrCz9e+2lVOnFplRsaGRwsq1KL/uOy7xK7QdRSprRQcObGDeDZUZsacD5gUkk6OiHiYp6RzU3CA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.39.tgz", + "integrity": "sha512-ImT6eUw3kcGcHoUxEcdBpi6LfTRWaV6+qf32iYYAfwOeV+XaQ/Xp5XQIBiijLeo+LpGci9M0FVec09nUw41a5g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.39.tgz", + "integrity": "sha512-/fcQ5UhE05OiT+bW5v7/up1bDsnvaRZPJxXwzXsMRrr7rZqPa85vayrD723oWMT64dhrgWeA3FIneF8yER0XTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.39.tgz", + "integrity": "sha512-oMNH8lJI4wtgN5oxuFP7BQ22vgB/e3Tl5Woehcd6i2r6F3TszpCnNl8wo2d/KvyQ4zvLvCWAlRciumhQg88+kQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.39.tgz", + "integrity": "sha512-1GHK7kwk57ukY2yI4ILWKJXaxfr+8HcM/r/JKCGCPziIVlL+Wi7RbJ2OzMcTKZ1HpvEqCTBT/J6cO4ZEwW4Ypg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.39.tgz", + "integrity": "sha512-g97Sbb6g4zfRLIxHgW2pc393DjnkTRMeq3N1rmjDUABxpx8SjocK4jLen+/mq55G46eE2TA0MkJ4R3SpKMu7dg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.39.tgz", + "integrity": "sha512-4tcgFDYWdI+UbNMGlua9u1Zhu0N5R6u9tl5WOM8aVnNX143JZoBZLpCuUr5lCKhnD0SCO+5gUyMfupGrHtfggQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.39.tgz", + "integrity": "sha512-t0Hn1kWVx5UpCzAJkKRfHeYOLyFnXwYynIkK54/h3tbMweGI7dj400D1k0Vvtj2u1P+JTRT9tx3AjtLEMmfVBQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.39.tgz", + "integrity": "sha512-23pc8MlD2D6Px1mV8GMglZlKgwgNKAO8gsgsLLcXWSs9lQsCYkIlMo/2Ycfo5JrDIbLdwgP8D2vpfH2KcBqrDQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.39.tgz", + "integrity": "sha512-epwlYgVdbmkuRr5n4es3B+yDI0I2e/nxhKejT9H0OLxFAlMkeQZxSpxATpDc9m8NqRci6Kwyb/SfmD1koG2Zuw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.39.tgz", + "integrity": "sha512-W/5ezaq+rQiQBThIjLMNjsuhPHg+ApVAdTz2LvcuesZFMsJoQAW2hutoyg47XxpWi7aEjJGrkS26qCJKhRn3QQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.39.tgz", + "integrity": "sha512-IS48xeokcCTKeQIOke2O0t9t14HPvwnZcy+5baG13Z1wxs9ZrC5ig5ypEQQh4QMKxURD5TpCLHw2W42CLuVZaA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.39.tgz", + "integrity": "sha512-zEfunpqR8sMomqXhNTFEKDs+ik7HC01m3M60MsEjZOqaywHu5e5682fMsqOlZbesEAAaO9aAtRBsU7CHnSZWyA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.39.tgz", + "integrity": "sha512-Uo2suJBSIlrZCe4E0k75VDIFJWfZy+bOV6ih3T4MVMRJh1lHJ2UyGoaX4bOxomYN3t+IakHPyEoln1+qJ1qYaA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.39.tgz", + "integrity": "sha512-secQU+EpgUPpYjJe3OecoeGKVvRMLeKUxSMGHnK+aK5uQM3n1FPXNJzyz1LHFOo0WOyw+uoCxBYdM4O10oaCAA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.39.tgz", + "integrity": "sha512-qHq0t5gePEDm2nqZLb+35p/qkaXVS7oIe32R0ECh2HOdiXXkj/1uQI9IRogGqKkK+QjDG+DhwiUw7QoHur/Rwg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.39.tgz", + "integrity": "sha512-XPjwp2OgtEX0JnOlTgT6E5txbRp6Uw54Isorm3CwOtloJazeIWXuiwK0ONJBVb/CGbiCpS7iP2UahGgd2p1x+Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.39.tgz", + "integrity": "sha512-E2wm+5FwCcLpKsBHRw28bSYQw0Ikxb7zIMxw3OPAkiaQhLVr3dnVO8DofmbWhhf6b97bWzg37iSZ45ZDpLw7Ow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.39.tgz", + "integrity": "sha512-sBZQz5D+Gd0EQ09tZRnz/PpVdLwvp/ufMtJ1iDFYddDaPpZXKqPyaxfYBLs3ueiaksQ26GGa7sci0OqFzNs7KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.17.0.tgz", + "integrity": "sha512-gq0m0BTJfci60Fz4nczYxNAlED+sMcihltndR8t9t1evnU/azx53x3t2UHXC/uRjcbvRw/XctpaNygSTcQD+Iw==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-vue": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.1.0.tgz", + "integrity": "sha512-EPCeInPicQ/YyfOWJDr1yfEeSNoFCMzUus107lZyYi37xejdOolNzS5MXGXp8+9bkoKZMdv/1AcZzQebME6r+g==", + "dev": true, + "dependencies": { + "eslint-utils": "^3.0.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.0.1", + "postcss-selector-parser": "^6.0.9", + "semver": "^7.3.5", + "vue-eslint-parser": "^9.0.1", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/espree": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "dev": true, + "dependencies": { + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/ext": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz", + "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==", + "dependencies": { + "type": "^2.5.0" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz", + "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.0.tgz", + "integrity": "sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "peer": true + }, + "node_modules/globals": { + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", + "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "dependencies": { + "delegate": "^3.1.2" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true, + "peer": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/html-void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz", + "integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/i18next": { + "version": "20.6.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-20.6.1.tgz", + "integrity": "sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==", + "dependencies": { + "@babel/runtime": "^7.12.0" + } + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "9.0.14", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.14.tgz", + "integrity": "sha512-ubBeqQutOSLIFCUBN03jGeOS6a3DoYlSYwYJTa+gSKEZKU5redJIqkIdZ3JVv/4RZpfcXdAWH5zCNLWPRv2WDw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/immutable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", + "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hotkey": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.2.0.tgz", + "integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==" + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-cookie": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.1.tgz", + "integrity": "sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "peer": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/jsplumb": { + "version": "2.15.6", + "resolved": "https://registry.npmjs.org/jsplumb/-/jsplumb-2.15.6.tgz", + "integrity": "sha512-sIpbpz5eMVM+vV+MQzFCidlaa1RsknrQs6LOTKYDjYUDdTAi2AN2bFi94TxB33TifcIsRNV1jebcaxg0tCoPzg==" + }, + "node_modules/klona": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "node_modules/lodash-unified": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.2.tgz", + "integrity": "sha512-OGbEy+1P+UT26CYi4opY4gebD8cWRDxAT6MAObIVQMiqYdxZr1g3QHWCToVsm31x2NkLS4K3+MC2qInaRMa39g==", + "peerDependencies": { + "@types/lodash-es": "*", + "lodash": "*", + "lodash-es": "*" + } + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + }, + "node_modules/lodash.foreach": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", + "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true, + "peer": true + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" + }, + "node_modules/lodash.toarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", + "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "peer": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mime-match/-/mime-match-1.0.2.tgz", + "integrity": "sha1-P4fDHprxpf1IX7nbE0Qosju7e6g=", + "dependencies": { + "wildcard": "^1.1.0" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mitt": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", + "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==" + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/namespace-emitter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/namespace-emitter/-/namespace-emitter-2.0.1.tgz", + "integrity": "sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==" + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + }, + "node_modules/node-releases": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", + "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", + "dev": true, + "peer": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-wheel-es": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.1.2.tgz", + "integrity": "sha512-scX83plWJXYH1J4+BhAuIHadROzxX0UBF3+HuZNY2Ks8BciE7tSTQ+5JhTsvzjaO0/EJdm4JBGrfObKxFf3Png==" + }, + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha1-y480xTIT2JVyP8urkH6UIq28r7E=" + }, + "node_modules/nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pinia": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.0.14.tgz", + "integrity": "sha512-0nPuZR4TetT/WcLN+feMSjWJku3SQU7dBbXC6uw+R6FLQJCsg+/0pzXyD82T1FmAYe0lsx+jnEDQ1BLgkRKlxA==", + "dependencies": { + "@vue/devtools-api": "^6.1.4", + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "@vue/composition-api": "^1.4.0", + "typescript": ">=4.4.4", + "vue": "^2.6.14 || ^3.2.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/pinia/node_modules/vue-demi": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.12.5.tgz", + "integrity": "sha512-BREuTgTYlUr0zw0EZn3hnhC3I6gPWv+Kwh4MCih6QcAeaTlaIX0DwOVN0wHej7hSvDPecz4jygy/idsgKfW58Q==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/postcss": { + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/preact": { + "version": "10.7.2", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.7.2.tgz", + "integrity": "sha512-GLjn0I3r6ka+NvxJUppsVFqb4V0qDTEHT/QxHlidPuClGaxF/4AI2Qti4a0cv3XMh5n1+D3hLScW10LRIm5msQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/print-js": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/print-js/-/print-js-1.6.0.tgz", + "integrity": "sha512-BfnOIzSKbqGRtO4o0rnj/K3681BSd2QUrsIZy/+WdCIugjIswjmx3lDEZpXB2ruGf9d4b3YNINri81+J0FsBWg==" + }, + "node_modules/prismjs": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.28.0.tgz", + "integrity": "sha512-8aaXdYvl1F7iC7Xm1spqSaY/OJBpYW3v+KJ+F17iYxvdc8sfjW194COK5wVhMZX45tGteiBQgdvD/nhxcRwylw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qrcodejs2-fixes": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/qrcodejs2-fixes/-/qrcodejs2-fixes-0.0.2.tgz", + "integrity": "sha512-wMUXYMOixAEJlLnjk5MbLiFaz0gQObWYm/TIFWB5+j7sTY5gPyr09Cx1EpcLYbsgfFdN3wHjrKAhZofTuCBGhg==" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "peer": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "2.74.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.74.1.tgz", + "integrity": "sha512-K2zW7kV8Voua5eGkbnBtWYfMIhYhT9Pel2uhBk2WO5eMee161nPze/XRfvEQPFYz7KgrCCnmh2Wy0AMFLGGmMA==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peer": true + }, + "node_modules/sass": { + "version": "1.52.2", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.52.2.tgz", + "integrity": "sha512-mfHB2VSeFS7sZlPv9YohB9GB7yWIgQNTGniQwfQ04EoQN0wsQEv7SwpCwy/x48Af+Z3vDeFXz+iuXM3HK/phZQ==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/sass-loader": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.0.0.tgz", + "integrity": "sha512-IHCFecI+rbPvXE2zO/mqdVFe8MU7ElGrwga9hh2H65Ru4iaBJAMRteum1c4Gsxi9Cq1FOtTEDd6+/AEYuQDM4Q==", + "dev": true, + "dependencies": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } + } + }, + "node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "peer": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/screenfull": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/screenfull/-/screenfull-6.0.1.tgz", + "integrity": "sha512-yzQW+j4zMUBQC51xxWaoDYjxOtl8Kn+xvue3p6v/fv2pIi1jH4AldgVLU8TBfFVgH2x3VXlf3+YiA/AYIPlaew==", + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/scroll-into-view-if-needed": { + "version": "2.2.29", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.29.tgz", + "integrity": "sha512-hxpAR6AN+Gh53AdAimHM6C8oTN1ppwVZITihix+WqalywBeFcQ6LdQP5ABNl26nX8GTEL7VT+b8lKpdqq65wXg==", + "dependencies": { + "compute-scroll-into-view": "^1.0.17" + } + }, + "node_modules/select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=" + }, + "node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "peer": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slate": { + "version": "0.72.8", + "resolved": "https://registry.npmjs.org/slate/-/slate-0.72.8.tgz", + "integrity": "sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==", + "dependencies": { + "immer": "^9.0.6", + "is-plain-object": "^5.0.0", + "tiny-warning": "^1.0.3" + } + }, + "node_modules/slate-history": { + "version": "0.66.0", + "resolved": "https://registry.npmjs.org/slate-history/-/slate-history-0.66.0.tgz", + "integrity": "sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==", + "dependencies": { + "is-plain-object": "^5.0.0" + }, + "peerDependencies": { + "slate": ">=0.65.3" + } + }, + "node_modules/snabbdom": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.5.0.tgz", + "integrity": "sha512-Ff5BKG18KrrPuskHJlA9aujPHqEabItaDl96l7ZZndF4zt5AYSczz7ZjjgQAX5IBd5cd25lw9NfgX21yVUJ+9g==", + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/sortablejs": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz", + "integrity": "sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w==" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "peer": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, + "node_modules/splitpanes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/splitpanes/-/splitpanes-3.1.1.tgz", + "integrity": "sha512-VUkxDJfIGSvTM/fm/+OSrx8ha9URwE/9B8FPvfzoBuAxVELIHBWpsfnJXIXv77zVwuex//QQL4kTU9SDBPeHjA==" + }, + "node_modules/ssr-window": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-3.0.0.tgz", + "integrity": "sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==" + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.13.1.tgz", + "integrity": "sha512-hn4WKOfwnwbYfe48NgrQjqNOH9jzLqRcIfbYytOXCOv46LBfWr9bDS17MQqOi+BWGD0sJK3Sj5NC/gJjiojaoA==", + "dev": true, + "peer": true, + "dependencies": { + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map": "~0.8.0-beta.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", + "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", + "dev": true, + "peer": true, + "dependencies": { + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1", + "terser": "^5.7.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser/node_modules/source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "dev": true, + "peer": true, + "dependencies": { + "whatwg-url": "^7.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "peer": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", + "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", + "devOptional": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/vite": { + "version": "2.9.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.9.tgz", + "integrity": "sha512-ffaam+NgHfbEmfw/Vuh6BHKKlI/XIAhxE5QSS7gFLIngxg171mg1P3a4LSRME0z2ZU1ScxoKzphkipcYwSD5Ew==", + "dev": true, + "dependencies": { + "esbuild": "^0.14.27", + "postcss": "^8.4.13", + "resolve": "^1.22.0", + "rollup": "^2.59.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": ">=12.2.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "less": "*", + "sass": "*", + "stylus": "*" + }, + "peerDependenciesMeta": { + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.36.tgz", + "integrity": "sha512-5yTXmrE6gW8IQgttzHW5bfBiFA6mx35ZXHjGLDmKYzW6MMmYvCwuKybANRepwkMYeXw2v1buGg3/lPICY5YlZw==", + "dependencies": { + "@vue/compiler-dom": "3.2.36", + "@vue/compiler-sfc": "3.2.36", + "@vue/runtime-dom": "3.2.36", + "@vue/server-renderer": "3.2.36", + "@vue/shared": "3.2.36" + } + }, + "node_modules/vue-clipboard3": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vue-clipboard3/-/vue-clipboard3-2.0.0.tgz", + "integrity": "sha512-Q9S7dzWGax7LN5iiSPcu/K1GGm2gcBBlYwmMsUc5/16N6w90cbKow3FnPmPs95sungns4yvd9/+JhbAznECS2A==", + "dependencies": { + "clipboard": "^2.0.6" + } + }, + "node_modules/vue-eslint-parser": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.0.2.tgz", + "integrity": "sha512-uCPQwTGjOtAYrwnU+76pYxalhjsh7iFBsHwBqDHiOPTxtICDaraO4Szw54WFTNZTAEsgHHzqFOu1mmnBOBRzDA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/vue-grid-layout": { + "version": "3.0.0-beta1", + "resolved": "https://registry.npmjs.org/vue-grid-layout/-/vue-grid-layout-3.0.0-beta1.tgz", + "integrity": "sha512-MsW0yfYNtnAO/uDhfZvkP6effxSJxvhAFbIL37x6Rn3vW9xf0WHVefKaSbQMLpSq3mXnR6ut0pg2Cd5lqIIZzg==", + "dependencies": { + "@interactjs/actions": "^1.10.2", + "@interactjs/auto-start": "^1.10.2", + "@interactjs/dev-tools": "^1.10.2", + "@interactjs/interactjs": "^1.10.2", + "@interactjs/modifiers": "^1.10.2", + "element-resize-detector": "^1.2.1", + "mitt": "^2.1.0" + } + }, + "node_modules/vue-grid-layout/node_modules/mitt": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-2.1.0.tgz", + "integrity": "sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==" + }, + "node_modules/vue-i18n": { + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.1.10.tgz", + "integrity": "sha512-jpr7gV5KPk4n+sSPdpZT8Qx3XzTcNDWffRlHV/cT2NUyEf+sEgTTmLvnBAibjOFJ0zsUyZlVTAWH5DDnYep+1g==", + "dependencies": { + "@intlify/core-base": "9.1.10", + "@intlify/shared": "9.1.10", + "@intlify/vue-devtools": "9.1.10", + "@vue/devtools-api": "^6.0.0-beta.7" + }, + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/vue-router": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.15.tgz", + "integrity": "sha512-xa+pIN9ZqORdIW1MkN2+d9Ui2pCM1b/UMgwYUCZOiFYHAvz/slKKBDha8DLrh5aCG/RibtrpyhKjKOZ85tYyWg==", + "dependencies": { + "@vue/devtools-api": "^6.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/watchpack": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", + "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", + "dev": true, + "peer": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true, + "peer": true + }, + "node_modules/webpack": { + "version": "5.72.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz", + "integrity": "sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung==", + "dev": true, + "peer": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.4.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.9.3", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.3.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "peer": true, + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-1.1.2.tgz", + "integrity": "sha1-pwIEUwhNjNLv5wup02liY94XEKU=" + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/zrender": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.3.1.tgz", + "integrity": "sha512-7olqIjy0gWfznKr6vgfnGBk7y4UtdMvdwFmK92vVQsQeDPyzkHW1OlrLEKg6GHz1W5ePf0FeN1q2vkl/HFqhXw==", + "dependencies": { + "tslib": "2.3.0" + } + } + }, + "dependencies": { + "@babel/parser": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-AqDccGC+m5O/iUStSJy3DGRIUFu7WbY/CppZYwrEUB4N0tZlnI8CSTsgL7v5fHVFmUbRv2sd+yy27o8Ydt4MGg==" + }, + "@babel/runtime": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.0.tgz", + "integrity": "sha512-YMQvx/6nKEaucl0MY56mwIG483xk8SDNdlUwb2Ts6FUpr7fm85DxEmsY18LXBNhcTz6tO6JwZV8w1W06v8UKeg==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@ctrl/tinycolor": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz", + "integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==" + }, + "@element-plus/icons-vue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.0.3.tgz", + "integrity": "sha512-dI9hazWIJF5AXsFDWLsdGqVIQMJ5Kq70fw1RScuMW6+UNqfJpRYFOqhya8RHpjajIZZnQx260Ll9AjTcu2HSOA==", + "requires": {} + }, + "@eslint/eslintrc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + } + }, + "@floating-ui/core": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.1.tgz", + "integrity": "sha512-grcqEmI8DTIolufpxhJagVeJmvloxBXE6xxSrVnSXz/Wz1uUIsC85ad+UNBqAoBOvzLxE42wvDj3YkmSGqWRxA==" + }, + "@floating-ui/dom": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.1.tgz", + "integrity": "sha512-dkPSy5JPiQEtljc3VpG9lauYctxfLlqj/8N9f+lmsR92gQaSVMAWuBbFBH2keY5DmdQn3p4Dv1dQd+e8osH+/g==", + "requires": { + "@floating-ui/core": "^0.7.1" + } + }, + "@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@interactjs/actions": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/actions/-/actions-1.10.11.tgz", + "integrity": "sha512-P39zeefr4hkmKx+5nZ+mrH1s0l2YJ3gIHrthXmE81n6MlMa42m0WtHcTms4C5JTTNBP2EEDY+KGgGxSnmJKvUw==", + "requires": { + "@interactjs/interact": "1.10.11" + } + }, + "@interactjs/auto-scroll": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/auto-scroll/-/auto-scroll-1.10.11.tgz", + "integrity": "sha512-feHNjhi0EMNLV2nQcEgjYPz2mI54aeSW2RiaoNtFLyBvtXKp0b4DmluwDv6DvuXmUpDwD5g/Hk1gGM2rgl7iqQ==", + "requires": { + "@interactjs/interact": "1.10.11" + } + }, + "@interactjs/auto-start": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/auto-start/-/auto-start-1.10.11.tgz", + "integrity": "sha512-cIg5CcalCPtC6AiGq6j/0hKUtL2MweEpvw12FuB19sz2Q9Dye0J4GliHKhOYvtumNinnvfVAZ4FZMqZEuX7YZA==", + "requires": { + "@interactjs/interact": "1.10.11" + } + }, + "@interactjs/core": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/core/-/core-1.10.11.tgz", + "integrity": "sha512-aJ50ccVeszpJt7wPH7Yfqm7f1aG1SA94qd90P0NaESh5/QUXn4CESO6igobo4DFHQ5z+1Rfdl8aphP4JxlH4gw==", + "requires": {} + }, + "@interactjs/dev-tools": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/dev-tools/-/dev-tools-1.10.11.tgz", + "integrity": "sha512-BP2FNfMbF7zLuOAUGMkDhCo1e1B0fnqyb9ih/Y8yAIJuoLrZxP/9htbsS1vZOIVZ4UgtrId4cYOwfcAZBMQtmw==", + "requires": { + "@interactjs/interact": "1.10.11" + } + }, + "@interactjs/inertia": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/inertia/-/inertia-1.10.11.tgz", + "integrity": "sha512-h+sknCzRqBSyHy4ctPNsq56mxkAMMdwHWD6en7rDEw899gdGKYaXVDVdv1jMfiwNRw0eRFBNoCiol8r3a/a3Jw==", + "requires": { + "@interactjs/interact": "1.10.11", + "@interactjs/offset": "1.10.11" + } + }, + "@interactjs/interact": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/interact/-/interact-1.10.11.tgz", + "integrity": "sha512-0iZJ9l547JuBA/lKxK4ARGYVmMqRSsAdA8gXL1zWe51qEIQq8PyWmMipoi8JbDaL7exC2THKwkXu5uq5ndT+iA==", + "requires": { + "@interactjs/core": "1.10.11", + "@interactjs/types": "1.10.11", + "@interactjs/utils": "1.10.11" + } + }, + "@interactjs/interactjs": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/interactjs/-/interactjs-1.10.11.tgz", + "integrity": "sha512-cGOxf6rp3Y8/sk88LhIT0XDn4gCiCzAnUG5Kkj9SAqiUO6BK/9+Wbp1IBkNaPgl/8uG8gNHh/dXBrlBBNcqJAg==", + "requires": { + "@interactjs/actions": "1.10.11", + "@interactjs/auto-scroll": "1.10.11", + "@interactjs/auto-start": "1.10.11", + "@interactjs/core": "1.10.11", + "@interactjs/dev-tools": "1.10.11", + "@interactjs/inertia": "1.10.11", + "@interactjs/interact": "1.10.11", + "@interactjs/modifiers": "1.10.11", + "@interactjs/offset": "1.10.11", + "@interactjs/pointer-events": "1.10.11", + "@interactjs/reflow": "1.10.11", + "@interactjs/utils": "1.10.11" + } + }, + "@interactjs/modifiers": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/modifiers/-/modifiers-1.10.11.tgz", + "integrity": "sha512-ltqX1RSqeAIikixlQBlyEUdclT5+rbfIGi3sIdLLYaIZQnltYkWqL9MHKx/w5b+hV+Mc0p5MLUFWJbTdkSCZ9g==", + "requires": { + "@interactjs/interact": "1.10.11", + "@interactjs/snappers": "1.10.11" + } + }, + "@interactjs/offset": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/offset/-/offset-1.10.11.tgz", + "integrity": "sha512-mBT7eIfy5ivofECiv+VwtEwwIMLV54fT9ujSMWJPduxdSYIHepUWgEf/3zjJknFh6jQc7pqz9dtjvVvyzRCLlQ==", + "requires": { + "@interactjs/interact": "1.10.11" + } + }, + "@interactjs/pointer-events": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/pointer-events/-/pointer-events-1.10.11.tgz", + "integrity": "sha512-yBT8JJVMZ+MgBay5l1WAHnL8ch/mZsRfaFahti+QFYeQyRloDtsWmEMDSYI/Onyy9+hS3gN/ge77ArGciZZ0Ow==", + "requires": { + "@interactjs/interact": "1.10.11" + } + }, + "@interactjs/reflow": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/reflow/-/reflow-1.10.11.tgz", + "integrity": "sha512-NSCtcCkjImOYSbxzzv2kFqR9t49J8KlhEr9UoePc7GyLbNXsiv3WQ3n0ehZd7CgZXQDiVXnP2UnmIOv5Zd4HQg==", + "requires": { + "@interactjs/interact": "1.10.11" + } + }, + "@interactjs/snappers": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/snappers/-/snappers-1.10.11.tgz", + "integrity": "sha512-yYtOMUZ7aFUZ1IYheq9Tj5hZ4J1r5dnaXhLF44WsI/awQ5L0DjZf07GPWof0B+7rZHEVudxyQNbPfFmb+1K94Q==", + "requires": { + "@interactjs/interact": "1.10.11" + } + }, + "@interactjs/types": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/types/-/types-1.10.11.tgz", + "integrity": "sha512-YRsVFWjL8Gkkvlx3qnjeaxW4fnibSJ9791g8BA7Pv5ANByI64WmtR1vU7A2rXcrOn8XvyCEfY0ss1s8NhZP+MA==" + }, + "@interactjs/utils": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@interactjs/utils/-/utils-1.10.11.tgz", + "integrity": "sha512-410ZoxKF+r1roeSelL+WHXfdryUMg5iykC1XwQ3l6XqNw43IMACzyvTH6k6Pwxj7w7x42nce0Qdn1GQ3Y8xyCw==" + }, + "@intlify/core-base": { + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.10.tgz", + "integrity": "sha512-So9CNUavB/IsZ+zBmk2Cv6McQp6vc2wbGi1S0XQmJ8Vz+UFcNn9MFXAe9gY67PreIHrbLsLxDD0cwo1qsxM1Nw==", + "requires": { + "@intlify/devtools-if": "9.1.10", + "@intlify/message-compiler": "9.1.10", + "@intlify/message-resolver": "9.1.10", + "@intlify/runtime": "9.1.10", + "@intlify/shared": "9.1.10", + "@intlify/vue-devtools": "9.1.10" + } + }, + "@intlify/devtools-if": { + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.1.10.tgz", + "integrity": "sha512-SHaKoYu6sog3+Q8js1y3oXLywuogbH1sKuc7NSYkN3GElvXSBaMoCzW+we0ZSFqj/6c7vTNLg9nQ6rxhKqYwnQ==", + "requires": { + "@intlify/shared": "9.1.10" + } + }, + "@intlify/message-compiler": { + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.1.10.tgz", + "integrity": "sha512-+JiJpXff/XTb0EadYwdxOyRTB0hXNd4n1HaJ/a4yuV960uRmPXaklJsedW0LNdcptd/hYUZtCkI7Lc9J5C1gxg==", + "requires": { + "@intlify/message-resolver": "9.1.10", + "@intlify/shared": "9.1.10", + "source-map": "0.6.1" + } + }, + "@intlify/message-resolver": { + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.1.10.tgz", + "integrity": "sha512-5YixMG/M05m0cn9+gOzd4EZQTFRUu8RGhzxJbR1DWN21x/Z3bJ8QpDYj6hC4FwBj5uKsRfKpJQ3Xqg98KWoA+w==" + }, + "@intlify/runtime": { + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.1.10.tgz", + "integrity": "sha512-7QsuByNzpe3Gfmhwq6hzgXcMPpxz8Zxb/XFI6s9lQdPLPe5Lgw4U1ovRPZTOs6Y2hwitR3j/HD8BJNGWpJnOFA==", + "requires": { + "@intlify/message-compiler": "9.1.10", + "@intlify/message-resolver": "9.1.10", + "@intlify/shared": "9.1.10" + } + }, + "@intlify/shared": { + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.1.10.tgz", + "integrity": "sha512-Om54xJeo1Vw+K1+wHYyXngE8cAbrxZHpWjYzMR9wCkqbhGtRV5VLhVc214Ze2YatPrWlS2WSMOWXR8JktX/IgA==" + }, + "@intlify/vue-devtools": { + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.1.10.tgz", + "integrity": "sha512-5l3qYARVbkWAkagLu1XbDUWRJSL8br1Dj60wgMaKB0+HswVsrR6LloYZTg7ozyvM621V6+zsmwzbQxbVQyrytQ==", + "requires": { + "@intlify/message-resolver": "9.1.10", + "@intlify/runtime": "9.1.10", + "@intlify/shared": "9.1.10" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@popperjs/core": { + "version": "npm:@sxzz/popperjs-es@2.11.7", + "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz", + "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==" + }, + "@transloadit/prettier-bytes": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz", + "integrity": "sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==" + }, + "@types/eslint": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.2.tgz", + "integrity": "sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA==", + "dev": true, + "peer": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", + "dev": true, + "peer": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true, + "peer": true + }, + "@types/event-emitter": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@types/event-emitter/-/event-emitter-0.3.3.tgz", + "integrity": "sha512-UfnOK1pIxO7P+EgPRZXD9jMpimd8QEFcEZ5R67R1UhGbv4zghU5+NE7U8M8G9H5Jc8FI51rqDWQs6FtUfq2e/Q==" + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/lodash": { + "version": "4.14.182", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", + "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==" + }, + "@types/lodash-es": { + "version": "4.17.6", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.6.tgz", + "integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==", + "requires": { + "@types/lodash": "*" + } + }, + "@types/node": { + "version": "17.0.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.39.tgz", + "integrity": "sha512-JDU3YLlnPK3WDao6/DlXLOgSNpG13ct+CwIO17V8q0/9fWJyeMJJ/VyZ1lv8kDprihvZMydzVwf0tQOqGiY2Nw==", + "dev": true + }, + "@types/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@types/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-1cYJrqq9GezNFPsWTZpFut/d4CjpZqA0vhqDUPFWYKF1oIyBz5qnoYMzR+0C/T96t3ebLAC1SSnwrVOm5/j74A==", + "dev": true + }, + "@types/sortablejs": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@types/sortablejs/-/sortablejs-1.13.0.tgz", + "integrity": "sha512-C3064MH72iEfeGCYEGCt7FCxXoAXaMPG0QPnstcxvPmbl54erpISu06d++FY37Smja64iWy5L8wOyHHBghWbJQ==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.27.0.tgz", + "integrity": "sha512-DDrIA7GXtmHXr1VCcx9HivA39eprYBIFxbQEHI6NyraRDxCGpxAFiYQAT/1Y0vh1C+o2vfBiy4IuPoXxtTZCAQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.27.0", + "@typescript-eslint/type-utils": "5.27.0", + "@typescript-eslint/utils": "5.27.0", + "debug": "^4.3.4", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/parser": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.27.0.tgz", + "integrity": "sha512-8oGjQF46c52l7fMiPPvX4It3u3V3JipssqDfHQ2hcR0AeR8Zge+OYyKUCm5b70X72N1qXt0qgHenwN6Gc2SXZA==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.27.0", + "@typescript-eslint/types": "5.27.0", + "@typescript-eslint/typescript-estree": "5.27.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.27.0.tgz", + "integrity": "sha512-VnykheBQ/sHd1Vt0LJ1JLrMH1GzHO+SzX6VTXuStISIsvRiurue/eRkTqSrG0CexHQgKG8shyJfR4o5VYioB9g==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.27.0", + "@typescript-eslint/visitor-keys": "5.27.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.27.0.tgz", + "integrity": "sha512-vpTvRRchaf628Hb/Xzfek+85o//zEUotr1SmexKvTfs7czXfYjXVT/a5yDbpzLBX1rhbqxjDdr1Gyo0x1Fc64g==", + "dev": true, + "requires": { + "@typescript-eslint/utils": "5.27.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/types": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.27.0.tgz", + "integrity": "sha512-lY6C7oGm9a/GWhmUDOs3xAVRz4ty/XKlQ2fOLr8GAIryGn0+UBOoJDWyHer3UgrHkenorwvBnphhP+zPmzmw0A==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.27.0.tgz", + "integrity": "sha512-QywPMFvgZ+MHSLRofLI7BDL+UczFFHyj0vF5ibeChDAJgdTV8k4xgEwF0geFhVlPc1p8r70eYewzpo6ps+9LJQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.27.0", + "@typescript-eslint/visitor-keys": "5.27.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/utils": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.27.0.tgz", + "integrity": "sha512-nZvCrkIJppym7cIbP3pOwIkAefXOmfGPnCM0LQfzNaKxJHI6VjI8NC662uoiPlaf5f6ymkTy9C3NQXev2mdXmA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.27.0", + "@typescript-eslint/types": "5.27.0", + "@typescript-eslint/typescript-estree": "5.27.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.27.0.tgz", + "integrity": "sha512-46cYrteA2MrIAjv9ai44OQDUoCZyHeGIc4lsjCUX2WT6r4C+kidz1bNiR4017wHOPUythYeH+Sc7/cFP97KEAA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.27.0", + "eslint-visitor-keys": "^3.3.0" + } + }, + "@uppy/companion-client": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@uppy/companion-client/-/companion-client-2.1.0.tgz", + "integrity": "sha512-1Zsag2z9kygXuVbUxqHhkTJUmEHwbejjyf7vmm+P/AiVgK3O37JINYBGOpdTJNgbC9UydLBjleXo8peDVgpg8Q==", + "requires": { + "@uppy/utils": "^4.0.7", + "namespace-emitter": "^2.0.1" + } + }, + "@uppy/core": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@uppy/core/-/core-2.2.0.tgz", + "integrity": "sha512-qdDoNCjrVjjOmFCFCxc+HEbtbQ9K0k6LKNbZZwWK7d4Cx3xEa6VsxmqVhfFL6ekH2gyboqYV8Z5IbRkJT/0Nqg==", + "requires": { + "@transloadit/prettier-bytes": "0.0.7", + "@uppy/store-default": "^2.0.3", + "@uppy/utils": "^4.0.7", + "lodash.throttle": "^4.1.1", + "mime-match": "^1.0.2", + "namespace-emitter": "^2.0.1", + "nanoid": "^3.1.25", + "preact": "^10.5.13" + } + }, + "@uppy/store-default": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@uppy/store-default/-/store-default-2.0.3.tgz", + "integrity": "sha512-2BGlN1sW0cFv4rOqTK8dfSg579S984N1HxCJxLFqeW9nWD6zd/O8Omyd85tbxGQ+FLZLTmLOm/feD0YeCBMahg==" + }, + "@uppy/utils": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@uppy/utils/-/utils-4.0.7.tgz", + "integrity": "sha512-nKViMT8XchKy+NWpb3DtVKuzZBmW7au26LrMq89EsvTwIOT6UR9+7bmz/+zr3+lc7UC7vMgNChIC6G+/Ya9wWQ==", + "requires": { + "lodash.throttle": "^4.1.1" + } + }, + "@uppy/xhr-upload": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@uppy/xhr-upload/-/xhr-upload-2.1.0.tgz", + "integrity": "sha512-io1uNu7lGkhIkMnt13bu3FYSAdRbBRWl8n/6njYi+727Jyr0XhKfmBYV9OiruFSxLz5Bfxkw2gTs6e0qUb63nA==", + "requires": { + "@uppy/companion-client": "^2.1.0", + "@uppy/utils": "^4.0.7", + "nanoid": "^3.1.25" + } + }, + "@vitejs/plugin-vue": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-2.3.3.tgz", + "integrity": "sha512-SmQLDyhz+6lGJhPELsBdzXGc+AcaT8stgkbiTFGpXPe8Tl1tJaBw1A6pxDqDuRsVkD8uscrkx3hA7QDOoKYtyw==", + "dev": true, + "requires": {} + }, + "@vue/compiler-core": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.36.tgz", + "integrity": "sha512-bbyZM5hvBicv0PW3KUfVi+x3ylHnfKG7DOn5wM+f2OztTzTjLEyBb/5yrarIYpmnGitVGbjZqDbODyW4iK8hqw==", + "requires": { + "@babel/parser": "^7.16.4", + "@vue/shared": "3.2.36", + "estree-walker": "^2.0.2", + "source-map": "^0.6.1" + } + }, + "@vue/compiler-dom": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.36.tgz", + "integrity": "sha512-tcOTAOiW4s24QLnq+ON6J+GRONXJ+A/mqKCORi0LSlIh8XQlNnlm24y8xIL8la+ZDgkdbjarQ9ZqYSvEja6gVA==", + "requires": { + "@vue/compiler-core": "3.2.36", + "@vue/shared": "3.2.36" + } + }, + "@vue/compiler-sfc": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.36.tgz", + "integrity": "sha512-AvGb4bTj4W8uQ4BqaSxo7UwTEqX5utdRSMyHy58OragWlt8nEACQ9mIeQh3K4di4/SX+41+pJrLIY01lHAOFOA==", + "requires": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.36", + "@vue/compiler-dom": "3.2.36", + "@vue/compiler-ssr": "3.2.36", + "@vue/reactivity-transform": "3.2.36", + "@vue/shared": "3.2.36", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7", + "postcss": "^8.1.10", + "source-map": "^0.6.1" + } + }, + "@vue/compiler-ssr": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.36.tgz", + "integrity": "sha512-+KugInUFRvOxEdLkZwE+W43BqHyhBh0jpYXhmqw1xGq2dmE6J9eZ8UUSOKNhdHtQ/iNLWWeK/wPZkVLUf3YGaw==", + "requires": { + "@vue/compiler-dom": "3.2.36", + "@vue/shared": "3.2.36" + } + }, + "@vue/devtools-api": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.1.4.tgz", + "integrity": "sha512-IiA0SvDrJEgXvVxjNkHPFfDx6SXw0b/TUkqMcDZWNg9fnCAHbTpoo59YfJ9QLFkwa3raau5vSlRVzMSLDnfdtQ==" + }, + "@vue/reactivity": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.36.tgz", + "integrity": "sha512-c2qvopo0crh9A4GXi2/2kfGYMxsJW4tVILrqRPydVGZHhq0fnzy6qmclWOhBFckEhmyxmpHpdJtIRYGeKcuhnA==", + "requires": { + "@vue/shared": "3.2.36" + } + }, + "@vue/reactivity-transform": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.36.tgz", + "integrity": "sha512-Jk5o2BhpODC9XTA7o4EL8hSJ4JyrFWErLtClG3NH8wDS7ri9jBDWxI7/549T7JY9uilKsaNM+4pJASLj5dtRwA==", + "requires": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.36", + "@vue/shared": "3.2.36", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7" + } + }, + "@vue/runtime-core": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.36.tgz", + "integrity": "sha512-PTWBD+Lub+1U3/KhbCExrfxyS14hstLX+cBboxVHaz+kXoiDLNDEYAovPtxeTutbqtClIXtft+wcGdC+FUQ9qQ==", + "requires": { + "@vue/reactivity": "3.2.36", + "@vue/shared": "3.2.36" + } + }, + "@vue/runtime-dom": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.36.tgz", + "integrity": "sha512-gYPYblm7QXHVuBohqNRRT7Wez0f2Mx2D40rb4fleehrJU9CnkjG0phhcGEZFfGwCmHZRqBCRgbFWE98bPULqkg==", + "requires": { + "@vue/runtime-core": "3.2.36", + "@vue/shared": "3.2.36", + "csstype": "^2.6.8" + } + }, + "@vue/server-renderer": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.36.tgz", + "integrity": "sha512-uZE0+jfye6yYXWvAQYeHZv+f50sRryvy16uiqzk3jn8hEY8zTjI+rzlmZSGoE915k+W/Ol9XSw6vxOUD8dGkUg==", + "requires": { + "@vue/compiler-ssr": "3.2.36", + "@vue/shared": "3.2.36" + } + }, + "@vue/shared": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.36.tgz", + "integrity": "sha512-JtB41wXl7Au3+Nl3gD16Cfpj7k/6aCroZ6BbOiCMFCMvrOpkg/qQUXTso2XowaNqBbnkuGHurLAqkLBxNGc1hQ==" + }, + "@vueuse/core": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-8.5.0.tgz", + "integrity": "sha512-VEJ6sGNsPlUp0o9BGda2YISvDZbhWJSOJu5zlp2TufRGVrLcYUKr31jyFEOj6RXzG3k/H4aCYeZyjpItfU8glw==", + "requires": { + "@vueuse/metadata": "8.5.0", + "@vueuse/shared": "8.5.0", + "vue-demi": "*" + }, + "dependencies": { + "@vueuse/shared": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-8.5.0.tgz", + "integrity": "sha512-qKG+SZb44VvGD4dU5cQ63z4JE2Yk39hQUecR0a9sEdJA01cx+XrxAvFKJfPooxwoiqalAVw/ktWK6xbyc/jS3g==", + "requires": { + "vue-demi": "*" + } + }, + "vue-demi": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.12.5.tgz", + "integrity": "sha512-BREuTgTYlUr0zw0EZn3hnhC3I6gPWv+Kwh4MCih6QcAeaTlaIX0DwOVN0wHej7hSvDPecz4jygy/idsgKfW58Q==", + "requires": {} + } + } + }, + "@vueuse/metadata": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.5.0.tgz", + "integrity": "sha512-WxsD+Cd+bn+HcjpY6Dl9FJ8ywTRTT9pTwk3bCQpzEhXVYAyNczKDSahk50fCfIJKeWHhyI4B2+/ZEOxQAkUr0g==" + }, + "@wangeditor/basic-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@wangeditor/basic-modules/-/basic-modules-1.1.1.tgz", + "integrity": "sha512-tQl2Pw8M2g3CM+ESx2phzr9zSKeuFCM1AMBoPdnlbatU7Dnae0CsEB/b3C+gI0dIQzM2jh34yTmqgbbhrwuRLg==", + "requires": { + "is-url": "^1.2.4" + } + }, + "@wangeditor/code-highlight": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@wangeditor/code-highlight/-/code-highlight-1.0.2.tgz", + "integrity": "sha512-SCtOcUxjKqIso/LSxGSOaYr3G6MC2En0gNTyHIMCG928T0fo0ufaqp/vIXKQzVL2Y+X/CSAOB2EbrFlgGvr0AQ==", + "requires": { + "prismjs": "^1.23.0" + } + }, + "@wangeditor/core": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@wangeditor/core/-/core-1.1.1.tgz", + "integrity": "sha512-SrbvOGlONMNMOeFIJI7fC9x0/6T6LvQHTITPCqjgbCm2QF+POcrHzRKGQOqKCsyKi9UJz9hLsjsvJnvP10rxjQ==", + "requires": { + "@types/event-emitter": "^0.3.3", + "event-emitter": "^0.3.5", + "html-void-elements": "^2.0.0", + "i18next": "^20.4.0", + "scroll-into-view-if-needed": "^2.2.28", + "slate-history": "^0.66.0" + } + }, + "@wangeditor/editor": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@wangeditor/editor/-/editor-5.1.1.tgz", + "integrity": "sha512-BtccuHFm0QvYunIhIu7tllQWkwppkmEkD3OJ5Mn+F0REPQ/Z3HiEXbtlss2t9c/kHO4CtiFwv2XD/k/VEg7taA==", + "requires": { + "@uppy/core": "^2.1.1", + "@uppy/xhr-upload": "^2.0.3", + "@wangeditor/basic-modules": "^1.1.1", + "@wangeditor/code-highlight": "^1.0.2", + "@wangeditor/core": "^1.1.1", + "@wangeditor/list-module": "^1.0.2", + "@wangeditor/table-module": "^1.1.0", + "@wangeditor/upload-image-module": "^1.0.1", + "@wangeditor/video-module": "^1.1.0", + "dom7": "^3.0.0", + "is-hotkey": "^0.2.0", + "lodash.camelcase": "^4.3.0", + "lodash.clonedeep": "^4.5.0", + "lodash.debounce": "^4.0.8", + "lodash.foreach": "^4.5.0", + "lodash.isequal": "^4.5.0", + "lodash.throttle": "^4.1.1", + "lodash.toarray": "^4.4.0", + "nanoid": "^3.2.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "@wangeditor/list-module": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@wangeditor/list-module/-/list-module-1.0.2.tgz", + "integrity": "sha512-VfENZEFvsLTiLxN/cj8cibFGy9NVV+/cfATTiLiH9ef+8lgKv8apttXYVlqIAfnlJLLuCk0cIm8c/zH+hbtrZg==", + "requires": {} + }, + "@wangeditor/table-module": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@wangeditor/table-module/-/table-module-1.1.0.tgz", + "integrity": "sha512-QpjCXSzsXcsR0pEI5Pu28e8aYh9+lHcVV4TTmGV6lRGE/etQF3PHUZNGUlfhkCgmGPq+E7n/Whb4RpAM3PJVhw==", + "requires": {} + }, + "@wangeditor/upload-image-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@wangeditor/upload-image-module/-/upload-image-module-1.0.1.tgz", + "integrity": "sha512-vgUV4ENttTITblqtVuzleIq732OmzmzzgrIvX6b3GRGPSw5u8glJ/87tOEhvHjHECc4oFo18B7xzJ1GpBj79/w==", + "requires": {} + }, + "@wangeditor/video-module": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@wangeditor/video-module/-/video-module-1.1.0.tgz", + "integrity": "sha512-VR6x7Vk9ebvXtxCPwobiNiTGZGgqEzCVc6ViWlNH3v4jlDIeo/s7N7OCgpvELR7X/X7GHecBu7wySDkHIskB5w==", + "requires": {} + }, + "@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "peer": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true, + "peer": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true, + "peer": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true, + "peer": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "peer": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true, + "peer": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "peer": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "peer": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "peer": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true, + "peer": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "peer": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "peer": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "peer": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "peer": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "peer": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, + "peer": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true, + "peer": true + }, + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true + }, + "acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "peer": true, + "requires": {} + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peer": true, + "requires": {} + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "async-validator": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.1.1.tgz", + "integrity": "sha512-p4DO/JXwjs8klJyJL8Q2oM4ks5fUTze/h5k10oPPKMiLe1fj3G1QMzPHNmN1Py4ycOk7WlO2DcGXv1qiESJCZA==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "requires": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "batch-processor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/batch-processor/-/batch-processor-1.0.0.tgz", + "integrity": "sha512-xoLQD8gmmR32MeuBHgH0Tzd5PuSZx71ZsbhVxOCRbgktZEPe4SQy7s9Z50uPp0F/f7iw2XmkHN2xkgbMfckMDA==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "dev": true, + "peer": true, + "requires": { + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", + "escalade": "^3.1.1", + "node-releases": "^2.0.3", + "picocolors": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "peer": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001342", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001342.tgz", + "integrity": "sha512-bn6sOCu7L7jcbBbyNhLg0qzXdJ/PMbybZTH/BA6Roet9wxYRm6Tr9D0s0uhLkOZ6MSG+QU6txUgdpr3MXIVqjA==", + "dev": true, + "peer": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "peer": true + }, + "claygl": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/claygl/-/claygl-1.3.0.tgz", + "integrity": "sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ==" + }, + "clipboard": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz", + "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==", + "requires": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "peer": true + }, + "compute-scroll-into-view": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz", + "integrity": "sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "countup.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/countup.js/-/countup.js-2.2.0.tgz", + "integrity": "sha512-m0TvFNXm9/eFqJm+QiKVI8e0wRUHzlQSewz9dqVjlhl2DFoZtceLbomwzxHz0hJ1+r4zBC7wSpR/TpthG49h6g==" + }, + "cropperjs": { + "version": "1.5.12", + "resolved": "https://registry.npmjs.org/cropperjs/-/cropperjs-1.5.12.tgz", + "integrity": "sha512-re7UdjE5UnwdrovyhNzZ6gathI4Rs3KGCBSc8HCIjUo5hO42CtzyblmWLj6QWVw7huHyDMfpKxhiO2II77nhDw==" + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "csstype": { + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "dayjs": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.2.tgz", + "integrity": "sha512-F4LXf1OeU9hrSYRPTTj/6FbO4HTjPKXvEIC1P2kcnFurViINCVk3ZV0xAS3XVx9MkMsXbbqlK6hjseaYbgKEHw==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom7": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/dom7/-/dom7-3.0.0.tgz", + "integrity": "sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==", + "requires": { + "ssr-window": "^3.0.0-alpha.1" + } + }, + "dotenv": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", + "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", + "dev": true + }, + "echarts": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.3.2.tgz", + "integrity": "sha512-LWCt7ohOKdJqyiBJ0OGBmE9szLdfA9sGcsMEi+GGoc6+Xo75C+BkcT/6NNGRHAWtnQl2fNow05AQjznpap28TQ==", + "requires": { + "tslib": "2.3.0", + "zrender": "5.3.1" + } + }, + "echarts-gl": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/echarts-gl/-/echarts-gl-2.0.9.tgz", + "integrity": "sha512-oKeMdkkkpJGWOzjgZUsF41DOh6cMsyrGGXimbjK2l6Xeq/dBQu4ShG2w2Dzrs/1bD27b2pLTGSaUzouY191gzA==", + "requires": { + "claygl": "^1.2.1", + "zrender": "^5.1.1" + } + }, + "echarts-wordcloud": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/echarts-wordcloud/-/echarts-wordcloud-2.0.0.tgz", + "integrity": "sha512-K7l6pTklqdW7ZWzT/1CS0KhBSINr/cd7c5N1fVMzZMwLQHEwT7x+nivK7g5hkVh7WNcAv4Dn6/ZS5zMKRozC1g==", + "requires": {} + }, + "electron-to-chromium": { + "version": "1.4.137", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz", + "integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==", + "dev": true, + "peer": true + }, + "element-plus": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.2.2.tgz", + "integrity": "sha512-yGcj2Ayb0jZO1WbI51tHJ4efhlfWKlBqqGtWbzhq+tcpfaKzJZN+IHRouuFasqn0ZV3tWCDu1jggDR1+9y7XfQ==", + "requires": { + "@ctrl/tinycolor": "^3.4.1", + "@element-plus/icons-vue": "^1.1.4", + "@floating-ui/dom": "^0.5.0", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", + "@types/lodash": "^4.14.182", + "@types/lodash-es": "^4.17.6", + "@vueuse/core": "^8.5.0", + "async-validator": "^4.1.1", + "dayjs": "^1.11.2", + "escape-html": "^1.0.3", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "lodash-unified": "^1.0.2", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.1.2" + }, + "dependencies": { + "@element-plus/icons-vue": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-1.1.4.tgz", + "integrity": "sha512-Iz/nHqdp1sFPmdzRwHkEQQA3lKvoObk8azgABZ81QUOpW9s/lUyQVUSh0tNtEPZXQlKwlSh7SPgoVxzrE0uuVQ==", + "requires": {} + } + } + }, + "element-resize-detector": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/element-resize-detector/-/element-resize-detector-1.2.4.tgz", + "integrity": "sha512-Fl5Ftk6WwXE0wqCgNoseKWndjzZlDCwuPTcoVZfCP9R3EHQF8qUtr3YUPNETegRBOKqQKPW3n4kiIWngGi8tKg==", + "requires": { + "batch-processor": "1.0.0" + } + }, + "enhanced-resolve": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", + "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==", + "dev": true, + "peer": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true, + "peer": true + }, + "es5-ext": { + "version": "0.10.61", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.61.tgz", + "integrity": "sha512-yFhIqQAzu2Ca2I4SE2Au3rxVfmohU9Y7wqGR+s7+H7krk26NXhIRAZDgqd6xqjCEFUomDEA3/Bo/7fKmIkW1kA==", + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "esbuild": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.39.tgz", + "integrity": "sha512-2kKujuzvRWYtwvNjYDY444LQIA3TyJhJIX3Yo4+qkFlDDtGlSicWgeHVJqMUP/2sSfH10PGwfsj+O2ro1m10xQ==", + "dev": true, + "requires": { + "esbuild-android-64": "0.14.39", + "esbuild-android-arm64": "0.14.39", + "esbuild-darwin-64": "0.14.39", + "esbuild-darwin-arm64": "0.14.39", + "esbuild-freebsd-64": "0.14.39", + "esbuild-freebsd-arm64": "0.14.39", + "esbuild-linux-32": "0.14.39", + "esbuild-linux-64": "0.14.39", + "esbuild-linux-arm": "0.14.39", + "esbuild-linux-arm64": "0.14.39", + "esbuild-linux-mips64le": "0.14.39", + "esbuild-linux-ppc64le": "0.14.39", + "esbuild-linux-riscv64": "0.14.39", + "esbuild-linux-s390x": "0.14.39", + "esbuild-netbsd-64": "0.14.39", + "esbuild-openbsd-64": "0.14.39", + "esbuild-sunos-64": "0.14.39", + "esbuild-windows-32": "0.14.39", + "esbuild-windows-64": "0.14.39", + "esbuild-windows-arm64": "0.14.39" + } + }, + "esbuild-android-64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.39.tgz", + "integrity": "sha512-EJOu04p9WgZk0UoKTqLId9VnIsotmI/Z98EXrKURGb3LPNunkeffqQIkjS2cAvidh+OK5uVrXaIP229zK6GvhQ==", + "dev": true, + "optional": true + }, + "esbuild-android-arm64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.39.tgz", + "integrity": "sha512-+twajJqO7n3MrCz9e+2lVOnFplRsaGRwsq1KL/uOy7xK7QdRSprRQcObGDeDZUZsacD5gUkk6OiHiYp6RzU3CA==", + "dev": true, + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.39.tgz", + "integrity": "sha512-ImT6eUw3kcGcHoUxEcdBpi6LfTRWaV6+qf32iYYAfwOeV+XaQ/Xp5XQIBiijLeo+LpGci9M0FVec09nUw41a5g==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.39.tgz", + "integrity": "sha512-/fcQ5UhE05OiT+bW5v7/up1bDsnvaRZPJxXwzXsMRrr7rZqPa85vayrD723oWMT64dhrgWeA3FIneF8yER0XTw==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.39.tgz", + "integrity": "sha512-oMNH8lJI4wtgN5oxuFP7BQ22vgB/e3Tl5Woehcd6i2r6F3TszpCnNl8wo2d/KvyQ4zvLvCWAlRciumhQg88+kQ==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.39.tgz", + "integrity": "sha512-1GHK7kwk57ukY2yI4ILWKJXaxfr+8HcM/r/JKCGCPziIVlL+Wi7RbJ2OzMcTKZ1HpvEqCTBT/J6cO4ZEwW4Ypg==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.39.tgz", + "integrity": "sha512-g97Sbb6g4zfRLIxHgW2pc393DjnkTRMeq3N1rmjDUABxpx8SjocK4jLen+/mq55G46eE2TA0MkJ4R3SpKMu7dg==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.39.tgz", + "integrity": "sha512-4tcgFDYWdI+UbNMGlua9u1Zhu0N5R6u9tl5WOM8aVnNX143JZoBZLpCuUr5lCKhnD0SCO+5gUyMfupGrHtfggQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.39.tgz", + "integrity": "sha512-t0Hn1kWVx5UpCzAJkKRfHeYOLyFnXwYynIkK54/h3tbMweGI7dj400D1k0Vvtj2u1P+JTRT9tx3AjtLEMmfVBQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.39.tgz", + "integrity": "sha512-23pc8MlD2D6Px1mV8GMglZlKgwgNKAO8gsgsLLcXWSs9lQsCYkIlMo/2Ycfo5JrDIbLdwgP8D2vpfH2KcBqrDQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.39.tgz", + "integrity": "sha512-epwlYgVdbmkuRr5n4es3B+yDI0I2e/nxhKejT9H0OLxFAlMkeQZxSpxATpDc9m8NqRci6Kwyb/SfmD1koG2Zuw==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.39.tgz", + "integrity": "sha512-W/5ezaq+rQiQBThIjLMNjsuhPHg+ApVAdTz2LvcuesZFMsJoQAW2hutoyg47XxpWi7aEjJGrkS26qCJKhRn3QQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-riscv64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.39.tgz", + "integrity": "sha512-IS48xeokcCTKeQIOke2O0t9t14HPvwnZcy+5baG13Z1wxs9ZrC5ig5ypEQQh4QMKxURD5TpCLHw2W42CLuVZaA==", + "dev": true, + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.39.tgz", + "integrity": "sha512-zEfunpqR8sMomqXhNTFEKDs+ik7HC01m3M60MsEjZOqaywHu5e5682fMsqOlZbesEAAaO9aAtRBsU7CHnSZWyA==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.39.tgz", + "integrity": "sha512-Uo2suJBSIlrZCe4E0k75VDIFJWfZy+bOV6ih3T4MVMRJh1lHJ2UyGoaX4bOxomYN3t+IakHPyEoln1+qJ1qYaA==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.39.tgz", + "integrity": "sha512-secQU+EpgUPpYjJe3OecoeGKVvRMLeKUxSMGHnK+aK5uQM3n1FPXNJzyz1LHFOo0WOyw+uoCxBYdM4O10oaCAA==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.39.tgz", + "integrity": "sha512-qHq0t5gePEDm2nqZLb+35p/qkaXVS7oIe32R0ECh2HOdiXXkj/1uQI9IRogGqKkK+QjDG+DhwiUw7QoHur/Rwg==", + "dev": true, + "optional": true + }, + "esbuild-windows-32": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.39.tgz", + "integrity": "sha512-XPjwp2OgtEX0JnOlTgT6E5txbRp6Uw54Isorm3CwOtloJazeIWXuiwK0ONJBVb/CGbiCpS7iP2UahGgd2p1x+Q==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.39.tgz", + "integrity": "sha512-E2wm+5FwCcLpKsBHRw28bSYQw0Ikxb7zIMxw3OPAkiaQhLVr3dnVO8DofmbWhhf6b97bWzg37iSZ45ZDpLw7Ow==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.39.tgz", + "integrity": "sha512-sBZQz5D+Gd0EQ09tZRnz/PpVdLwvp/ufMtJ1iDFYddDaPpZXKqPyaxfYBLs3ueiaksQ26GGa7sci0OqFzNs7KA==", + "dev": true, + "optional": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "peer": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.17.0.tgz", + "integrity": "sha512-gq0m0BTJfci60Fz4nczYxNAlED+sMcihltndR8t9t1evnU/azx53x3t2UHXC/uRjcbvRw/XctpaNygSTcQD+Iw==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "eslint-plugin-vue": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.1.0.tgz", + "integrity": "sha512-EPCeInPicQ/YyfOWJDr1yfEeSNoFCMzUus107lZyYi37xejdOolNzS5MXGXp8+9bkoKZMdv/1AcZzQebME6r+g==", + "dev": true, + "requires": { + "eslint-utils": "^3.0.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.0.1", + "postcss-selector-parser": "^6.0.9", + "semver": "^7.3.5", + "vue-eslint-parser": "^9.0.1", + "xml-name-validator": "^4.0.0" + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "dev": true, + "requires": { + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + } + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "peer": true + }, + "ext": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz", + "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==", + "requires": { + "type": "^2.5.0" + }, + "dependencies": { + "type": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz", + "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==" + } + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.0.tgz", + "integrity": "sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==" + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "peer": true + }, + "globals": { + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", + "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "requires": { + "delegate": "^3.1.2" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true, + "peer": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "html-void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz", + "integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==" + }, + "i18next": { + "version": "20.6.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-20.6.1.tgz", + "integrity": "sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==", + "requires": { + "@babel/runtime": "^7.12.0" + } + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "immer": { + "version": "9.0.14", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.14.tgz", + "integrity": "sha512-ubBeqQutOSLIFCUBN03jGeOS6a3DoYlSYwYJTa+gSKEZKU5redJIqkIdZ3JVv/4RZpfcXdAWH5zCNLWPRv2WDw==" + }, + "immutable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", + "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-hotkey": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.2.0.tgz", + "integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" + }, + "is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "peer": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-cookie": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.1.tgz", + "integrity": "sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "peer": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "jsplumb": { + "version": "2.15.6", + "resolved": "https://registry.npmjs.org/jsplumb/-/jsplumb-2.15.6.tgz", + "integrity": "sha512-sIpbpz5eMVM+vV+MQzFCidlaa1RsknrQs6LOTKYDjYUDdTAi2AN2bFi94TxB33TifcIsRNV1jebcaxg0tCoPzg==" + }, + "klona": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "peer": true + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "lodash-unified": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.2.tgz", + "integrity": "sha512-OGbEy+1P+UT26CYi4opY4gebD8cWRDxAT6MAObIVQMiqYdxZr1g3QHWCToVsm31x2NkLS4K3+MC2qInaRMa39g==", + "requires": {} + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + }, + "lodash.foreach": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", + "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=" + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true, + "peer": true + }, + "lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" + }, + "lodash.toarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", + "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "requires": { + "sourcemap-codec": "^1.4.8" + } + }, + "memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "peer": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mime-match/-/mime-match-1.0.2.tgz", + "integrity": "sha1-P4fDHprxpf1IX7nbE0Qosju7e6g=", + "requires": { + "wildcard": "^1.1.0" + } + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mitt": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", + "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "namespace-emitter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/namespace-emitter/-/namespace-emitter-2.0.1.tgz", + "integrity": "sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==" + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + }, + "node-releases": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", + "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", + "dev": true, + "peer": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-wheel-es": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.1.2.tgz", + "integrity": "sha512-scX83plWJXYH1J4+BhAuIHadROzxX0UBF3+HuZNY2Ks8BciE7tSTQ+5JhTsvzjaO0/EJdm4JBGrfObKxFf3Png==" + }, + "nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha1-y480xTIT2JVyP8urkH6UIq28r7E=" + }, + "nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pinia": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.0.14.tgz", + "integrity": "sha512-0nPuZR4TetT/WcLN+feMSjWJku3SQU7dBbXC6uw+R6FLQJCsg+/0pzXyD82T1FmAYe0lsx+jnEDQ1BLgkRKlxA==", + "requires": { + "@vue/devtools-api": "^6.1.4", + "vue-demi": "*" + }, + "dependencies": { + "vue-demi": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.12.5.tgz", + "integrity": "sha512-BREuTgTYlUr0zw0EZn3hnhC3I6gPWv+Kwh4MCih6QcAeaTlaIX0DwOVN0wHej7hSvDPecz4jygy/idsgKfW58Q==", + "requires": {} + } + } + }, + "postcss": { + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "preact": { + "version": "10.7.2", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.7.2.tgz", + "integrity": "sha512-GLjn0I3r6ka+NvxJUppsVFqb4V0qDTEHT/QxHlidPuClGaxF/4AI2Qti4a0cv3XMh5n1+D3hLScW10LRIm5msQ==" + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", + "dev": true + }, + "print-js": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/print-js/-/print-js-1.6.0.tgz", + "integrity": "sha512-BfnOIzSKbqGRtO4o0rnj/K3681BSd2QUrsIZy/+WdCIugjIswjmx3lDEZpXB2ruGf9d4b3YNINri81+J0FsBWg==" + }, + "prismjs": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.28.0.tgz", + "integrity": "sha512-8aaXdYvl1F7iC7Xm1spqSaY/OJBpYW3v+KJ+F17iYxvdc8sfjW194COK5wVhMZX45tGteiBQgdvD/nhxcRwylw==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qrcodejs2-fixes": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/qrcodejs2-fixes/-/qrcodejs2-fixes-0.0.2.tgz", + "integrity": "sha512-wMUXYMOixAEJlLnjk5MbLiFaz0gQObWYm/TIFWB5+j7sTY5gPyr09Cx1EpcLYbsgfFdN3wHjrKAhZofTuCBGhg==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "peer": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "requires": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "2.74.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.74.1.tgz", + "integrity": "sha512-K2zW7kV8Voua5eGkbnBtWYfMIhYhT9Pel2uhBk2WO5eMee161nPze/XRfvEQPFYz7KgrCCnmh2Wy0AMFLGGmMA==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "peer": true + }, + "sass": { + "version": "1.52.2", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.52.2.tgz", + "integrity": "sha512-mfHB2VSeFS7sZlPv9YohB9GB7yWIgQNTGniQwfQ04EoQN0wsQEv7SwpCwy/x48Af+Z3vDeFXz+iuXM3HK/phZQ==", + "dev": true, + "requires": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + } + }, + "sass-loader": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.0.0.tgz", + "integrity": "sha512-IHCFecI+rbPvXE2zO/mqdVFe8MU7ElGrwga9hh2H65Ru4iaBJAMRteum1c4Gsxi9Cq1FOtTEDd6+/AEYuQDM4Q==", + "dev": true, + "requires": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + } + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "peer": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "screenfull": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/screenfull/-/screenfull-6.0.1.tgz", + "integrity": "sha512-yzQW+j4zMUBQC51xxWaoDYjxOtl8Kn+xvue3p6v/fv2pIi1jH4AldgVLU8TBfFVgH2x3VXlf3+YiA/AYIPlaew==" + }, + "scroll-into-view-if-needed": { + "version": "2.2.29", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.29.tgz", + "integrity": "sha512-hxpAR6AN+Gh53AdAimHM6C8oTN1ppwVZITihix+WqalywBeFcQ6LdQP5ABNl26nX8GTEL7VT+b8lKpdqq65wXg==", + "requires": { + "compute-scroll-into-view": "^1.0.17" + } + }, + "select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=" + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "peer": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slate": { + "version": "0.72.8", + "resolved": "https://registry.npmjs.org/slate/-/slate-0.72.8.tgz", + "integrity": "sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==", + "requires": { + "immer": "^9.0.6", + "is-plain-object": "^5.0.0", + "tiny-warning": "^1.0.3" + } + }, + "slate-history": { + "version": "0.66.0", + "resolved": "https://registry.npmjs.org/slate-history/-/slate-history-0.66.0.tgz", + "integrity": "sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==", + "requires": { + "is-plain-object": "^5.0.0" + } + }, + "snabbdom": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.5.0.tgz", + "integrity": "sha512-Ff5BKG18KrrPuskHJlA9aujPHqEabItaDl96l7ZZndF4zt5AYSczz7ZjjgQAX5IBd5cd25lw9NfgX21yVUJ+9g==" + }, + "sortablejs": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz", + "integrity": "sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "peer": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, + "splitpanes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/splitpanes/-/splitpanes-3.1.1.tgz", + "integrity": "sha512-VUkxDJfIGSvTM/fm/+OSrx8ha9URwE/9B8FPvfzoBuAxVELIHBWpsfnJXIXv77zVwuex//QQL4kTU9SDBPeHjA==" + }, + "ssr-window": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-3.0.0.tgz", + "integrity": "sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==" + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "peer": true + }, + "terser": { + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.13.1.tgz", + "integrity": "sha512-hn4WKOfwnwbYfe48NgrQjqNOH9jzLqRcIfbYytOXCOv46LBfWr9bDS17MQqOi+BWGD0sJK3Sj5NC/gJjiojaoA==", + "dev": true, + "peer": true, + "requires": { + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map": "~0.8.0-beta.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "dev": true, + "peer": true, + "requires": { + "whatwg-url": "^7.0.0" + } + } + } + }, + "terser-webpack-plugin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", + "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", + "dev": true, + "peer": true, + "requires": { + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1", + "terser": "^5.7.2" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "peer": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "typescript": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", + "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", + "devOptional": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "vite": { + "version": "2.9.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.9.tgz", + "integrity": "sha512-ffaam+NgHfbEmfw/Vuh6BHKKlI/XIAhxE5QSS7gFLIngxg171mg1P3a4LSRME0z2ZU1ScxoKzphkipcYwSD5Ew==", + "dev": true, + "requires": { + "esbuild": "^0.14.27", + "fsevents": "~2.3.2", + "postcss": "^8.4.13", + "resolve": "^1.22.0", + "rollup": "^2.59.0" + } + }, + "vue": { + "version": "3.2.36", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.36.tgz", + "integrity": "sha512-5yTXmrE6gW8IQgttzHW5bfBiFA6mx35ZXHjGLDmKYzW6MMmYvCwuKybANRepwkMYeXw2v1buGg3/lPICY5YlZw==", + "requires": { + "@vue/compiler-dom": "3.2.36", + "@vue/compiler-sfc": "3.2.36", + "@vue/runtime-dom": "3.2.36", + "@vue/server-renderer": "3.2.36", + "@vue/shared": "3.2.36" + } + }, + "vue-clipboard3": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vue-clipboard3/-/vue-clipboard3-2.0.0.tgz", + "integrity": "sha512-Q9S7dzWGax7LN5iiSPcu/K1GGm2gcBBlYwmMsUc5/16N6w90cbKow3FnPmPs95sungns4yvd9/+JhbAznECS2A==", + "requires": { + "clipboard": "^2.0.6" + } + }, + "vue-eslint-parser": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.0.2.tgz", + "integrity": "sha512-uCPQwTGjOtAYrwnU+76pYxalhjsh7iFBsHwBqDHiOPTxtICDaraO4Szw54WFTNZTAEsgHHzqFOu1mmnBOBRzDA==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + }, + "dependencies": { + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "vue-grid-layout": { + "version": "3.0.0-beta1", + "resolved": "https://registry.npmjs.org/vue-grid-layout/-/vue-grid-layout-3.0.0-beta1.tgz", + "integrity": "sha512-MsW0yfYNtnAO/uDhfZvkP6effxSJxvhAFbIL37x6Rn3vW9xf0WHVefKaSbQMLpSq3mXnR6ut0pg2Cd5lqIIZzg==", + "requires": { + "@interactjs/actions": "^1.10.2", + "@interactjs/auto-start": "^1.10.2", + "@interactjs/dev-tools": "^1.10.2", + "@interactjs/interactjs": "^1.10.2", + "@interactjs/modifiers": "^1.10.2", + "element-resize-detector": "^1.2.1", + "mitt": "^2.1.0" + }, + "dependencies": { + "mitt": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-2.1.0.tgz", + "integrity": "sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==" + } + } + }, + "vue-i18n": { + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.1.10.tgz", + "integrity": "sha512-jpr7gV5KPk4n+sSPdpZT8Qx3XzTcNDWffRlHV/cT2NUyEf+sEgTTmLvnBAibjOFJ0zsUyZlVTAWH5DDnYep+1g==", + "requires": { + "@intlify/core-base": "9.1.10", + "@intlify/shared": "9.1.10", + "@intlify/vue-devtools": "9.1.10", + "@vue/devtools-api": "^6.0.0-beta.7" + } + }, + "vue-router": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.15.tgz", + "integrity": "sha512-xa+pIN9ZqORdIW1MkN2+d9Ui2pCM1b/UMgwYUCZOiFYHAvz/slKKBDha8DLrh5aCG/RibtrpyhKjKOZ85tYyWg==", + "requires": { + "@vue/devtools-api": "^6.0.0" + } + }, + "watchpack": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", + "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", + "dev": true, + "peer": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true, + "peer": true + }, + "webpack": { + "version": "5.72.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz", + "integrity": "sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung==", + "dev": true, + "peer": true, + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.4.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.9.3", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.3.1", + "webpack-sources": "^3.2.3" + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "peer": true + }, + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "peer": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wildcard": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-1.1.2.tgz", + "integrity": "sha1-pwIEUwhNjNLv5wup02liY94XEKU=" + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "zrender": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.3.1.tgz", + "integrity": "sha512-7olqIjy0gWfznKr6vgfnGBk7y4UtdMvdwFmK92vVQsQeDPyzkHW1OlrLEKg6GHz1W5ePf0FeN1q2vkl/HFqhXw==", + "requires": { + "tslib": "2.3.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..fbe32d7 --- /dev/null +++ b/package.json @@ -0,0 +1,81 @@ +{ + "name": "vue-next-admin", + "version": "2.1.1", + "description": "vue3 vite next admin template", + "author": "lyt_20201208", + "license": "MIT", + "scripts": { + "dev": "vite --force", + "build": "vite build", + "lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/" + }, + "dependencies": { + "@element-plus/icons-vue": "^2.0.3", + "@wangeditor/editor": "^5.1.1", + "axios": "^0.27.2", + "countup.js": "^2.2.0", + "cropperjs": "^1.5.12", + "echarts": "^5.3.2", + "echarts-gl": "^2.0.9", + "echarts-wordcloud": "^2.0.0", + "element-plus": "^2.2.2", + "js-cookie": "^3.0.1", + "jsplumb": "^2.15.6", + "mitt": "^3.0.0", + "nprogress": "^0.2.0", + "pinia": "^2.0.14", + "print-js": "^1.6.0", + "qrcodejs2-fixes": "^0.0.2", + "screenfull": "^6.0.1", + "sortablejs": "^1.15.0", + "splitpanes": "^3.1.1", + "vue": "^3.2.36", + "vue-clipboard3": "^2.0.0", + "vue-grid-layout": "^3.0.0-beta1", + "vue-i18n": "^9.1.10", + "vue-router": "^4.0.15" + }, + "devDependencies": { + "@types/node": "^17.0.39", + "@types/nprogress": "^0.2.0", + "@types/sortablejs": "^1.13.0", + "@typescript-eslint/eslint-plugin": "^5.27.0", + "@typescript-eslint/parser": "^5.27.0", + "@vitejs/plugin-vue": "^2.3.3", + "@vue/compiler-sfc": "^3.2.36", + "dotenv": "^16.0.1", + "eslint": "^8.17.0", + "eslint-plugin-vue": "^9.1.0", + "prettier": "^2.6.2", + "sass": "^1.52.2", + "sass-loader": "^13.0.0", + "typescript": "^4.7.3", + "vite": "^2.9.9", + "vue-eslint-parser": "^9.0.2" + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not dead" + ], + "bugs": { + "url": "https://gitee.com/lyt-top/vue-next-admin/issues" + }, + "engines": { + "node": ">=12.0.0", + "npm": ">= 6.0.0" + }, + "keywords": [ + "vue", + "vue3", + "vuejs/vue-next", + "element-ui", + "element-plus", + "vue-next-admin", + "next-admin" + ], + "repository": { + "type": "git", + "url": "https://gitee.com/lyt-top/vue-next-admin.git" + } +} diff --git a/plugins.d.ts b/plugins.d.ts new file mode 100644 index 0000000..be0457a --- /dev/null +++ b/plugins.d.ts @@ -0,0 +1,4 @@ +declare module 'vue-grid-layout'; +declare module 'qrcodejs2-fixes'; +declare module 'splitpanes'; +declare module 'js-cookie'; diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..9da231b --- /dev/null +++ b/public/favicon.ico Binary files differ diff --git a/shim.d.ts b/shim.d.ts new file mode 100644 index 0000000..3e9bfd0 --- /dev/null +++ b/shim.d.ts @@ -0,0 +1,13 @@ +/* eslint-disable */ + +// 声明文件,*.vue 后缀的文件交给 vue 模块来处理 +declare module '*.vue' { + import type { DefineComponent } from 'vue'; + const component: DefineComponent<{}, {}, any>; + export default component; +} + +// 声明文件,定义全局变量。其它 app.config.globalProperties.xxx,使用 getCurrentInstance() 来获取 +interface Window { + nextLoading: boolean; +} diff --git a/source.d.ts b/source.d.ts new file mode 100644 index 0000000..2f9c768 --- /dev/null +++ b/source.d.ts @@ -0,0 +1,6 @@ +declare module '*.json'; +declare module '*.png'; +declare module '*.jpg'; +declare module '*.scss'; +declare module '*.ts'; +declare module '*.js'; diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..e69c74b --- /dev/null +++ b/src/App.vue @@ -0,0 +1,100 @@ +<template> + <el-config-provider :size="getGlobalComponentSize" :locale="i18nLocale"> + <router-view v-show="themeConfig.lockScreenTime > 1" /> + <LockScreen v-if="themeConfig.isLockScreen" /> + <Setings ref="setingsRef" v-show="themeConfig.lockScreenTime > 1" /> + <CloseFull v-if="!themeConfig.isLockScreen" /> + </el-config-provider> +</template> + +<script lang="ts"> +import { computed, ref, getCurrentInstance, onBeforeMount, onMounted, onUnmounted, nextTick, defineComponent, watch, reactive, toRefs } from 'vue'; +import { useRoute } from 'vue-router'; +import { storeToRefs } from 'pinia'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import other from '/@/utils/other'; +import { Local, Session } from '/@/utils/storage'; +import setIntroduction from '/@/utils/setIconfont'; +import LockScreen from '/@/layout/lockScreen/index.vue'; +import Setings from '/@/layout/navBars/breadcrumb/setings.vue'; +import CloseFull from '/@/layout/navBars/breadcrumb/closeFull.vue'; +import { initBackEndControlRoutes } from './router/backEnd'; + +export default ({ + name: 'app', + components: { LockScreen, Setings, CloseFull }, + setup() { + const { proxy } = <any>getCurrentInstance(); + const setingsRef = ref(); + const route = useRoute(); + const stores = useTagsViewRoutes(); + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const state = reactive({ + i18nLocale: null, + }); + + // 获取全局组件大小 + const getGlobalComponentSize = computed(() => { + return other.globalComponentSize(); + }); + // 布局配置弹窗打开 + const openSetingsDrawer = () => { + setingsRef.value.openDrawer(); + }; + // 设置初始化,防止刷新时恢复默认 + onBeforeMount(() => { + // 设置批量第三方 icon 图标 + setIntroduction.cssCdn(); + // 设置批量第三方 js + setIntroduction.jsCdn(); + }); + // 页面加载时 + onMounted( () => { + nextTick(() => { + // 监听布局配置弹窗点击打开 + proxy.mittBus.on('openSetingsDrawer', () => { + openSetingsDrawer(); + }); + // 设置 i18n,App.vue 中的 el-config-provider + proxy.mittBus.on('getI18nConfig', (locale: string) => { + (state.i18nLocale as string | null) = locale; + }); + // 获取缓存中的布局配置 + if (Local.get('themeConfig')) { + storesThemeConfig.setThemeConfig(Local.get('themeConfig')); + document.documentElement.style.cssText = Local.get('themeConfigStyle'); + } + // 获取缓存中的全屏配置 + if (Session.get('isTagsViewCurrenFull')) { + stores.setCurrenFullscreen(Session.get('isTagsViewCurrenFull')); + } + }); + // if(!Session.get('token')) return + // initBackEndControlRoutes() + }); + // 页面销毁时,关闭监听布局配置/i18n监听 + onUnmounted(() => { + proxy.mittBus.off('openSetingsDrawer', () => {}); + proxy.mittBus.off('getI18nConfig', () => {}); + }); + // 监听路由的变化,设置网站标题 + watch( + () => route.path, + () => { + other.useTitle(); + }, + { + deep: true, + } + ); + return { + themeConfig, + setingsRef, + getGlobalComponentSize, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/api/department/index.ts b/src/api/department/index.ts new file mode 100644 index 0000000..0ed427c --- /dev/null +++ b/src/api/department/index.ts @@ -0,0 +1,26 @@ +import request from '/@/utils/request'; + +export function departmentApi() { + return { + getDepartmentList: () => { + return request({ + url: `/department/list`, + method: 'post', + }); + }, + addDepartment: (data: object) => { + return request({ + url: `/department/add`, + method: 'post', + data:data + }); + }, + modDepartment: (data: object) => { + return request({ + url: `/department/mod`, + method: 'post', + data:data + }); + }, + }; +} diff --git a/src/api/login/index.ts b/src/api/login/index.ts new file mode 100644 index 0000000..ca48515 --- /dev/null +++ b/src/api/login/index.ts @@ -0,0 +1,25 @@ +import request from '/@/utils/request'; + +/** + * 登录api接口集合 + * @method signIn 用户登录 + * @method signOut 用户退出登录 + */ +export function useLoginApi() { + return { + signIn: (params: object) => { + return request({ + url: '/auth/login', + method: 'post', + data: params, + }); + }, + signOut: (params: object) => { + return request({ + url: '/user/signOut', + method: 'post', + data: params, + }); + }, + }; +} diff --git a/src/api/menu/index.ts b/src/api/menu/index.ts new file mode 100644 index 0000000..2af998a --- /dev/null +++ b/src/api/menu/index.ts @@ -0,0 +1,39 @@ +import request from '/@/utils/request'; + +/** + * 后端控制菜单模拟json,路径在 https://gitee.com/lyt-top/vue-next-admin-images/tree/master/menu + * 后端控制路由,isRequestRoutes 为 true,则开启后端控制路由 + * @method getMenuAdmin 获取后端动态路由菜单(admin) + * @method getMenuTest 获取后端动态路由菜单(test) + */ +export function useMenuApi() { + return { + getMenuAdmin: (value?: string) => { + return request({ + url: `/auth/menu?projectId= ${value}`, + method: 'post', + }); + }, + addMenu: (value?: object) => { + return request({ + url: `/menu/add`, + method: 'post', + data:value + }); + }, + modMenu: (value?: object) => { + return request({ + url: `/menu/mod`, + method: 'post', + data:value + }); + }, + // getMenuTest: (params?: string) => { + // return request({ + // url: '/gitee/lyt-top/vue-next-admin-images/raw/master/menu/testMenu.json', + // method: 'get', + // params, + // }); + // }, + }; +} diff --git a/src/api/role/index.ts b/src/api/role/index.ts new file mode 100644 index 0000000..137195d --- /dev/null +++ b/src/api/role/index.ts @@ -0,0 +1,12 @@ +import request from '/@/utils/request'; + +export function useRoleApi() { + return { + getRoleList: () => { + return request({ + url: `/role/list`, + method: 'post', + }); + }, + }; +} diff --git a/src/assets/login-icon-two.svg b/src/assets/login-icon-two.svg new file mode 100644 index 0000000..b930211 --- /dev/null +++ b/src/assets/login-icon-two.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" data-name="Layer 1" width="1151.5635" height="842.24197" viewBox="0 0 1151.5635 842.24197" xmlns:xlink="http://www.w3.org/1999/xlink"><title>sunlight</title><path d="M1080.33549,309.07821h-.00006c-22.0216,0-39.87364,19.81184-39.87364,44.251v31.0502h9.54961l5.52868-11.50435-1.38218,11.50435h61.38126l5.02608-10.4585-1.25651,10.4585h6.91087v-24.38C1126.2196,331.87644,1105.67658,309.07821,1080.33549,309.07821Z" transform="translate(-24.21825 -28.87901)" fill="#2f2e41"/><path d="M1042.88322,452.6347l-6.62276,25.38724,61.81242-2.20758-1.1038-20.97207S1050.60977,442.70056,1042.88322,452.6347Z" transform="translate(-24.21825 -28.87901)" fill="#ffb9b9"/><polygon points="959.06 525.305 978.928 569.456 997.693 546.277 982.24 515.371 959.06 525.305" fill="#ffb9b9"/><polygon points="1008.731 687.562 1010.938 738.337 1035.222 738.337 1031.91 687.562 1008.731 687.562" fill="#ffb9b9"/><path d="M1004.25045,507.82436l11.03794,36.42517,16.55689,176.60691s15.45311,4.41518,26.491-1.10379l2.20759-24.28345,4.41517-139.07794s20.97207-11.03793,18.76448-26.491-7.72655-36.42517-7.72655-36.42517Z" transform="translate(-24.21825 -28.87901)" fill="#2f2e41"/><path d="M1038.468,755.074h-6.62276s-18.76448,19.86828-25.38724,22.07587-40.84035,20.97207-13.24552,24.28345,45.25552-11.03794,45.25552-11.03794,8.83035,5.519,20.97207,1.1038,5.519-17.66069,5.519-17.66069-6.16367-20.18749-6.39321-20.02789S1051.71356,763.90438,1038.468,755.074Z" transform="translate(-24.21825 -28.87901)" fill="#2f2e41"/><circle cx="1048.46738" cy="323.31051" r="25.38724" fill="#ffb9b9"/><path d="M1110.2146,385.30331l-11.67815,9.73547-1.56737,1.30247-1.10379,13.24551h-43.04794s5.87219-5.08847,11.32493-10.35358c.11036-.1214.23176-.25385.36427-.37532.73953-.71743,1.40178-1.37974,1.99787-1.97577.32007-.33112.6291-.64021.90505-.92721.45259-.47462.89414-.92715,1.33561-1.37974a.03829.03829,0,0,0,.01105-.022,43.07955,43.07955,0,0,0,3.17893-3.73083l.01105-.011a12.81791,12.81791,0,0,0,.73952-1.09274c3.31138-5.519-4.41517-16.5569-4.41517-16.5569l24.28345-12.14173c.84994,11.96508,10.97171,19.95654,15.49723,22.95889C1109.37571,384.85072,1110.2146,385.30331,1110.2146,385.30331Z" transform="translate(-24.21825 -28.87901)" fill="#ffb9b9"/><path d="M1169.81943,570.74057c-16.5569,4.41517-17.66069-28.69862-17.66069-28.69862l-22.59765-45.1953a104.51533,104.51533,0,0,1-9.73594-30.31979l-5.19538-32.65665-1.57841,1.88745v.01105l-2.83676,1.41288-17.24124-27.59483-4.83462-7.72655v-8.83034l16.55689-7.72656h6.62276s.1435-.02209.39735-.04419c3.04648-.32008,22.87063-1.64464,23.8861,17.70489.39969,7.59413.36519,13.88569.15854,18.82226a145.76191,145.76191,0,0,0,3.84972,40.63177c1.16857,4.79412,2.44343,8.95772,3.7183,11.18873,4.41517,7.72655,19.86827,68.43518,19.86827,68.43518S1186.37633,566.3254,1169.81943,570.74057Z" transform="translate(-24.21825 -28.87901)" fill="#ffb9b9"/><path d="M1068.27046,397.445l-4.18335,7.62718-2.47256,4.51454L1049.506,431.66263s-3.43278,2.80361-8.99594,6.42408c-9.24979,6.01562-24.4159,14.272-39.571,15.65178-24.28345,2.20759-1.10379-76.16173-1.10379-76.16173s7.72655-30.90621,18.76449-27.59483,2.20758,14.34931-5.519,35.32138S1011.977,429.455,1011.977,429.455s23.17965-14.34931,35.32138-25.38724c6.32471-5.75079,11.75542-7.30711,15.49723-7.4727h.011a14.05473,14.05473,0,0,1,3.69775.287A8.35071,8.35071,0,0,1,1068.27046,397.445Z" transform="translate(-24.21825 -28.87901)" fill="#ffb9b9"/><path d="M1071.93506,390.82228c-.04413.1214-.56294,1.10379-4.52559,5.1326A53.271,53.271,0,0,0,1071.93506,390.82228Z" transform="translate(-24.21825 -28.87901)" fill="#d0cde1"/><path d="M1114.07788,434.42211l-1.02652,1.3466-16.08228,27.90392s-20.97207-7.72655-36.42517-9.93414a21.64727,21.64727,0,0,0-22.06482,9.901l4.40413-17.62754-2.37319-7.92523c-.27594-.92721-.596-1.95373-.93819-3.1127-3.31138-11.03793,8.83034-23.17966,8.83034-23.17966l14.39344-15.19925h.011a14.05473,14.05473,0,0,1,3.69775.287c-.59609.596-1.25834,1.25834-1.99787,1.97577-.13251.12147-.25391.25392-.36427.37532-4.22754,4.3158-2.031,5.519-.05517,5.839a9.71986,9.71986,0,0,0,1.97576.09937c4.6028.66225,14.68044-3.3776,22.07587-6.75521,5.03329-2.29591,8.83034-4.28272,8.83034-4.28272l9.63609-8.83035,1.446-1.32456c1.32457.872,2.16346,1.32456,2.16346,1.32456h1.10379s.1435-.02209.39735-.04419l-5.02587,3.72943a18.68469,18.68469,0,0,0-7.5132,16.183h0Z" transform="translate(-24.21825 -28.87901)" fill="#d0cde1"/><path d="M1053.92115,465.88022l-16.1372,6.30165s-87.61936-33.89648-100.86488-6.30165,46.35931,93.82242,46.35931,93.82242l26.491-12.14173-11.03793-33.11379s64.02,54.08586,90.511,24.28345,8.83035-71.94211,8.83035-71.94211S1081.516,453.73849,1053.92115,465.88022Z" transform="translate(-24.21825 -28.87901)" fill="#2f2e41"/><path d="M1007.56183,586.19367l-9.93413,7.72656s8.83034,35.32138,5.519,40.84034-9.93414,20.97208,2.20759,19.86828,25.38724-19.86828,26.491-26.491,8.83035-26.491,8.83035-26.491,13.24552-30.90621,3.31138-32.01-25.75662-1.84256-25.75662-1.84256Z" transform="translate(-24.21825 -28.87901)" fill="#2f2e41"/><path d="M1091.67085,321.26789a20.91185,20.91185,0,0,0-16.50006-8.4201h-.78284c-15.09365,0-27.32941,13.658-27.32941,30.50606v.00006h5.05749l.81677-6.217,1.19755,6.217H1084.126l2.51307-5.25968-.62828,5.25968h5.901q4.13043,20.51274-11.86947,41.02548h10.05221l5.02608-10.51935-1.2565,10.51935h19.162l3.76958-24.19458C1116.79567,342.06532,1106.26771,326.70034,1091.67085,321.26789Z" transform="translate(-24.21825 -28.87901)" fill="#2f2e41"/><circle cx="971.03374" cy="113.59071" r="91" fill="#ff6584"/><path d="M771.29477,567.032c-1.6806,13.391-3.05862,26.28082-4.18757,38.571h36.55924q1.99625-19.38064,5.00548-38.571Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M801.19676,703.21105q-1.17629-19.19032-.9509-38.571H763.184c-.60171,14.7787-.83742,27.751-.88075,38.571Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M864.4142,361.58256C894.89157,280.388,924.75032,225.797,924.75032,225.797L893.6574,207.29872c-32.37571,48.82045-56.84558,101.59229-75.3218,154.28384Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M766.21242,615.836c-1.14212,13.751-1.97242,26.66388-2.56481,38.571h36.792q.53185-19.28516,2.25137-38.571Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M778.50126,518.22788c-2.24695,13.1965-4.19314,26.08124-5.8747,38.571h37.70491q3.28452-19.4853,7.41146-38.571Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M814.82354,371.81567q-6.5049,19.34635-11.981,38.571h44.39012c4.3882-13.35371,8.88306-26.24037,13.39195-38.571Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M787.981,469.42381q-4.29519,19.6076-7.68675,38.571H820.004q4.44783-19.61091,9.56837-38.571Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M762.3185,713.44417c.12069,16.62136.66994,25.97636.66994,25.97636l-.39358,7.478h43.29393q-2.59815-16.58382-3.96368-33.4544Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M799.97844,420.61974q-5.32646,19.46534-9.69876,38.571H832.379q5.53043-19.7784,11.542-38.571Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M1110.252,261.1651c-15.40963-32.21182-30.90977-56.23791-46.0196-73.94267l-7.89046,12.123.671-20.13755a158.22113,158.22113,0,0,0-16.6583-15.2789L1029.57149,180.496l.78947-23.69016a99.14041,99.14041,0,0,0-20.48314-10.11247l-7.97482,12.25252.48352-14.50965c-27.51475-6.905-50.1228,2.55337-63.22081,10.629l-7.86615-1.17354,13.49035-5.63347a99.1429,99.1429,0,0,0-6.25118-21.97146l-23.44384-3.4975L933.3355,115.172a158.21342,158.21342,0,0,0-12.02277-19.14149l-19.92822-2.973,13.34774-5.574c-14.68838-18.056-35.52378-37.63644-64.42682-58.60454,0,0-2.13827,18.67657-3.3293,44.71673l19.575,20.025-20.111-5.20116c-.21044,7.9976-.30047,16.41755-.20141,25.00812l14.43606,14.76794-14.20045-3.67257c.20688,6.56884.54118,13.17147,1.02835,19.7a77.7484,77.7484,0,0,0-37.38522.21323l.48352,14.50965-7.97482-12.25252A99.14066,99.14066,0,0,0,782.143,156.80588l.78947,23.69016L772.14939,163.929a158.22118,158.22118,0,0,0-16.65831,15.2789l.671,20.13755-7.89046-12.123c-15.10983,17.70476-30.61,41.73085-46.0195,73.94267,0,0,18.75584-1.2664,44.58355-4.79292l16.16488-22.86653L761.513,254.225c7.90429-1.2359,16.20236-2.66638,24.63409-4.31364l11.92111-16.86355-1.05035,14.63006c11.76-2.54214,23.55587-5.52,34.6978-8.989l8.00048,7.44239-14.31143-2.98448a99.14327,99.14327,0,0,0-7.27222,21.65494l17.35524,16.14443-19.35091-4.03541a158.216,158.216,0,0,0-.91179,22.58566l14.75256,13.72341-14.16008-2.95292c1.90026,23.19813,8.00769,51.13034,19.98347,84.7701,0,0,12.327-14.19261,28.03786-34.99356l-4.81657-27.58585,13.64313,15.66426c4.697-6.47636,9.53377-13.36913,14.311-20.50951l-3.55213-20.344L893.0578,318.329c9.67465-15.1043,18.722-30.948,25.38657-46.03838A385.08247,385.08247,0,0,0,946.086,304.50881l7.38-12.67579.33948,20.64894c6.03555,6.11391,12.08293,11.97343,17.91467,17.45027l10.45191-17.95172.46027,27.99943c19.34428,17.473,34.12174,29.09258,34.12174,29.09258,5.43182-35.29231,6.17421-63.8748,3.67531-87.01609l-13.35149,5.56466,11.9067-16.25425a158.22134,158.22134,0,0,0-5.14539-22.01061l-18.246,7.60454,8.67646-11.84438q5.59182,1.34816,11.21649,2.56145l-1.05035-14.63006,11.92111,16.86355c8.43173,1.64726,16.7298,3.07774,24.63409,4.31364l-1.48755-20.71932,16.16488,22.86653C1091.49615,259.8987,1110.252,261.1651,1110.252,261.1651Z" transform="translate(-24.21825 -28.87901)" fill="#e6a23c"/><path d="M706.516,543.343c1.1863,9.45251,2.159,18.55119,2.95593,27.2266H683.6654q-1.40913-13.68048-3.53328-27.2266Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M685.40871,639.4695q.83031-13.54614.67122-27.2266h26.16136c.42474,10.432.59112,19.589.62171,27.2266Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M640.78457,398.31967c-21.51346-57.31385-42.59025-95.84872-42.59025-95.84872l21.948-13.05765c22.85347,34.46154,40.12634,71.71229,53.16839,108.90637Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M710.10356,577.79293c.8062,9.70662,1.3923,18.82158,1.81046,27.22659H685.94319q-.37542-13.61307-1.5892-27.22659Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M701.42907,508.893c1.58609,9.31519,2.95987,18.41031,4.14686,27.22659H678.96066q-2.31847-13.75434-5.23162-27.22659Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M675.78979,405.54305q4.59169,13.65627,8.45716,27.2266H652.91271c-3.09755-9.42616-6.2704-18.52264-9.45315-27.2266Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M694.73746,474.443q3.0319,13.84068,5.42595,27.2266H672.133q-3.13965-13.843-6.75415-27.2266Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M712.85221,646.69288c-.08519,11.73274-.47289,18.33627-.47289,18.33627l.27782,5.27863H682.09668q1.834-11.70624,2.79789-23.6149Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M686.26869,439.993q3.75987,13.74026,6.8462,27.22659H663.39766q-3.90382-13.96124-8.14726-27.22659Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M467.25181,327.43668c10.87739-22.73779,21.81868-39.6974,32.48446-52.1949l5.56974,8.55742-.47364-14.21476a111.68489,111.68489,0,0,1,11.75882-10.78512l7.61163,11.69442-.55728-16.72249a69.98142,69.98142,0,0,1,14.4587-7.13822l5.6293,8.64885-.34131-10.24212c19.4222-4.8741,35.38084,1.80238,44.62651,7.50279l5.55258-.82838-9.52261-3.97657a69.98374,69.98374,0,0,1,4.4126-15.50928l16.54861-2.46883-12.87573-5.37687a111.68,111.68,0,0,1,8.48667-13.51166l14.067-2.09862-9.422-3.93455c10.36829-12.74544,25.07564-26.56694,45.47782-41.368,0,0,1.50937,13.18347,2.35009,31.56478l-13.81766,14.1353,14.196-3.67141c.14854,5.64537.21209,11.58887.14216,17.65281l-10.19016,10.42444,10.02385-2.59241c-.146,4.63684-.382,9.29752-.72589,13.90591a54.88123,54.88123,0,0,1,26.3896.15051l-.34131,10.24212,5.62929-8.64885a69.98117,69.98117,0,0,1,14.4587,7.13822l-.55727,16.72249,7.61163-11.69442a111.68687,111.68687,0,0,1,11.75882,10.78512l-.47364,14.21476,5.56974-8.55742c10.66577,12.4975,21.60706,29.45711,32.48439,52.1949,0,0-13.23943-.89394-31.47078-3.38325l-11.41052-16.1411,1.05,14.62542c-5.57951-.8724-11.437-1.88215-17.38879-3.04492l-8.41491-11.9037.74142,10.32711c-8.30116-1.79445-16.62769-3.8965-24.49259-6.34518l-5.6474,5.25346,10.10219-2.10669a69.98325,69.98325,0,0,1,5.13334,15.28586L661.2033,341.39976l13.65948-2.84853a111.68285,111.68285,0,0,1,.64362,15.94284l-10.41359,9.68713,9.99537-2.08442c-1.34137,16.37518-5.6525,36.092-14.106,59.83779,0,0-8.70142-10.01832-19.79145-24.70136l3.39993-19.47239L634.96021,388.818c-3.31556-4.57156-6.72974-9.437-10.10193-14.47732l2.50739-14.36046-6.80014,7.80752A247.60106,247.60106,0,0,1,602.64558,335.29a271.82334,271.82334,0,0,1-19.51173,22.74229l-5.20944-8.94763-.23963,14.57574c-4.2604,4.31571-8.52914,8.45185-12.64567,12.31786l-7.37783-12.67182-.32489,19.76432c-13.65481,12.33393-24.086,20.536-24.086,20.536-3.83423-24.91224-4.35827-45.08815-2.59434-61.4232l9.4246,3.928-8.40474-11.47361a111.68612,111.68612,0,0,1,3.632-15.53692l12.87953,5.36792-6.12457-8.36075q-3.94716.95164-7.91753,1.80808l.74143-10.32711-8.41492,11.9037c-5.95181,1.16277-11.80928,2.17252-17.38879,3.04492l1.05-14.62542-11.41052,16.1411C480.49124,326.54274,467.25181,327.43668,467.25181,327.43668Z" transform="translate(-24.21825 -28.87901)" fill="#e6a23c"/><ellipse cx="379.53374" cy="720.59071" rx="147.5" ry="14" fill="#3f3d56"/><ellipse cx="734.53374" cy="720.59071" rx="147.5" ry="14" fill="#3f3d56"/><path d="M870.752,606.96972s10.65,73.95-40.48,117.67c-33.09,28.29-80.27,32.92-118.99,13.01-14.38-7.39-29.72-18.62-44.37006-35.57a191.08437,191.08437,0,0,1-15.26-20.3,242.48469,242.48469,0,0,1-17.73-32.37q-4.8-10.485-9.17-22.44c-.56-1.53-1.08-3.03-1.58-4.52-26.55-78.91,25.09-101.93,72.49-107.45a243.44911,243.44911,0,0,1,29.96-1.51,268.64314,268.64314,0,0,1,35.13,2.48s.97.01,2.72.08a210.98673,210.98673,0,0,1,26.93005,2.99C827.022,525.46972,883.072,545.38971,870.752,606.96972Z" transform="translate(-24.21825 -28.87901)" fill="#e6a23c"/><path d="M544.752,626.96972c-23.34,64.07-56.95,95.47-86.53,110.68-38.72,19.91-85.9,15.28-118.99-13.01a104.52345,104.52345,0,0,1-9-8.67,108.90024,108.90024,0,0,1-15.01-20.66,128.65459,128.65459,0,0,1-12.09-30.09,161.53735,161.53735,0,0,1-5.17-35.23,140.93566,140.93566,0,0,1,.79-23.02c-11.53-57.65,36.85-78.78,73.12-86.52a215.32462,215.32462,0,0,1,31.83-4.29c3.21-.18,5.05-.19,5.05-.19a276.07877,276.07877,0,0,1,57.57-1.71C516.412,518.29968,576.402,540.09973,544.752,626.96972Z" transform="translate(-24.21825 -28.87901)" fill="#e6a23c"/><path d="M403.702,516.15973l-100.57,149.06a161.53735,161.53735,0,0,1-5.17-35.23l73.91-109.54A215.32462,215.32462,0,0,1,403.702,516.15973Z" transform="translate(-24.21825 -28.87901)" fill="#fff" opacity="0.2"/><path d="M466.322,514.2597l-136.09,201.71a108.90024,108.90024,0,0,1-15.01-20.66l122.6-181.71A262.51415,262.51415,0,0,1,466.322,514.2597Z" transform="translate(-24.21825 -28.87901)" fill="#fff" opacity="0.2"/><path d="M725.622,513.48968l-91.7,135.92q-4.8-10.485-9.17-22.44c-.56-1.53-1.08-3.03-1.58-4.52l72.49-107.45A243.44911,243.44911,0,0,1,725.622,513.48968Z" transform="translate(-24.21825 -28.87901)" fill="#fff" opacity="0.2"/><path d="M790.402,519.03973l-123.49,183.04a191.08437,191.08437,0,0,1-15.26-20.3l111.81995-165.73A210.98673,210.98673,0,0,1,790.402,519.03973Z" transform="translate(-24.21825 -28.87901)" fill="#fff" opacity="0.2"/><path d="M894.752,599.96972H871.86472c10.12915-83.03949-111.11273-84-111.11273-84a276.47448,276.47448,0,0,0-58-1.67132v-.32868h-237v.24872a276.75793,276.75793,0,0,0-57,1.75128s-121.24188.96051-111.11273,84H275.752v22H297.8389c-.22119,23.90107,4.52283,71.14319,41.39307,102.67,33.09,28.29,80.27,32.92,118.99,13.01,29.58-15.21,63.19-46.61,86.53-110.68,7.996-21.94982,10.13965-39.74377,8.07287-54.14819a635.39219,635.39219,0,0,1,63.85425,0c-2.06677,14.40442.07684,32.19837,8.07288,54.14819,23.34,64.07,56.95,95.47,86.53,110.68,38.72,19.91,85.9,15.28,118.99-13.01,36.87024-31.5268,41.61425-78.76892,41.39306-102.67H894.752Zm-360.54,27.41c-22.21,60.97-54.61,89.49-82.4,102.65-33.81,16.01-74.1,11.56-103.12-12.03-35.08-28.52-39.75-72.35-39.62-94.69.06-8.88-.34-17.74-.69-26.61-2.77-69.71,101.83-70.53,101.83-70.53S580.722,499.72973,534.212,627.3797Zm83.38928-59.56537a424.54686,424.54686,0,0,0-65.69861,0c-5.48632-24.48639-23.97729-38.28705-45.937-45.84461H663.53824C641.57859,529.52728,623.08762,543.32794,617.60129,567.81433ZM862.202,596.3797c-.36,8.95-.76,17.9-.7,26.85.14,22.55-4.58,66.79-39.98,95.56-29.28,23.81-69.92005,28.31-104.03,12.17-28.06-13.27-60.78-42.05-83.21-103.62-46.93006-128.83,125.15-102.14,125.15-102.14S864.992,526.01971,862.202,596.3797Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M428.14356,741.71275c-.11325-.18506-2.78356-4.64376-3.70932-13.90237-.84914-8.49429-.30313-22.81207,7.12226-42.7842,14.06719-37.83586-3.24186-68.36391-3.41872-68.668l.854-.49541a75.78134,75.78134,0,0,1,7.14973,20.25453,88.3638,88.3638,0,0,1-3.65968,49.253c-14.04309,37.77129-3.60282,55.65189-3.49584,55.82827Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><circle cx="398.4247" cy="578.84223" r="6.41529" fill="#3f3d56"/><circle cx="418.65754" cy="602.52946" r="6.41529" fill="#3f3d56"/><circle cx="404.83999" cy="618.32095" r="6.41529" fill="#fff"/><circle cx="421.61845" cy="631.64502" r="6.41529" fill="#fff"/><circle cx="399.90515" cy="652.37134" r="6.41529" fill="#3f3d56"/><path d="M432.01914,741.94889s-6.41529-15.79149,12.83059-27.63511Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M424.12933,741.66244s-2.91966-16.79294-25.51732-16.649Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/><path d="M363.072,370.10974a6.35543,6.35543,0,0,1-2.83,5.21l-.24.15h-106.8l.43-1.31c.07-.23,7.89-22.92005,42.5-18.54,3.26-1.12,35.12-11.52,54.19.17C358.782,360.96972,363.072,365.78973,363.072,370.10974Z" transform="translate(-24.21825 -28.87901)" fill="#f1f1f1"/><path d="M561.072,447.10974a6.35543,6.35543,0,0,1-2.83,5.21l-.24.15h-106.8l.43-1.31c.07-.23,7.89-22.92005,42.5-18.54,3.26-1.12,35.12-11.52,54.19.17C556.782,437.96972,561.072,442.78973,561.072,447.10974Z" transform="translate(-24.21825 -28.87901)" fill="#f1f1f1"/><path d="M606.072,137.10974a6.35543,6.35543,0,0,1-2.83,5.21l-.24.15h-106.8l.43-1.31c.07-.23,7.89-22.92,42.5-18.54,3.26-1.12,35.12-11.52,54.19.17C601.782,127.96972,606.072,132.78973,606.072,137.10974Z" transform="translate(-24.21825 -28.87901)" fill="#f1f1f1"/><path d="M53.17754,652.8835l9.13713,28.28159s-8.26692,26.54118-4.351,56.12807,1.7404,30.4571,1.7404,30.4571-39.12624-2.25247-35.21033,9.49526,42.172,4.86308,42.172,4.86308,7.34723-1.97821,10.828-22.86308S89.72606,698.134,89.72606,698.134l-8.22935-37.97489Z" transform="translate(-24.21825 -28.87901)" fill="#ffb8b8"/><path d="M56.22325,595.015S39.6894,601.10644,39.6894,617.64029s6.09142,39.15912,10.00733,40.46443,30.022,19.14446,34.80811,6.52652S56.22325,595.015,56.22325,595.015Z" transform="translate(-24.21825 -28.87901)" fill="#d0cde1"/><polygon points="170.367 761.932 205.175 760.626 231.717 756.71 223.885 782.816 159.49 784.557 170.367 761.932" fill="#ffb8b8"/><path d="M244.62214,794.29144s-.43511-9.57223-4.351-9.13713-1.3053-3.48081,2.17551-4.351,13.48814-5.22122,13.48814-5.22122l39.59422,2.61061S321.2,800.818,310.75754,813.0008s-37.41872,1.3053-37.41872,1.3053l-29.15179.4351S234.6148,799.07755,244.62214,794.29144Z" transform="translate(-24.21825 -28.87901)" fill="#2f2e41"/><polygon points="236.068 731.91 248.685 791.083 274.792 785.862 259.998 711.895 244.334 703.628 236.068 731.91" fill="#ffb8b8"/><path d="M110.17582,753.39191s-73.097,33.0677-42.20483,66.57051c0,0,0,15.66365,32.6326,12.61794s95.7223-8.702,98.768-6.96162,12.61793-34.373,4.351-36.11342-18.27426-3.91591-18.27426-3.91591,8.702-1.3053,8.702-8.702c0,0,24.80078-1.7404,32.1975-17.404S240.70622,732.072,240.70622,732.072l16.969,43.51013s19.57956-36.11341,34.373-20.01466c0,0-16.53385-103.98922-29.15179-113.56145s-21.32-12.61794-33.0677-3.91591-22.62527,30.89219-22.62527,30.89219Z" transform="translate(-24.21825 -28.87901)" fill="#2f2e41"/><path d="M284.65146,802.12326a98.03577,98.03577,0,0,0-8.702,7.39673c-3.48081,3.48081-8.26692,1.7404-8.702,0s-8.26692,1.3053-9.13712,13.92324-6.09142,23.93057,7.83182,27.84648,13.48814,15.22855,13.48814,15.22855a46.93427,46.93427,0,0,0,35.24321,2.17551c19.57956-6.52652,12.61794-13.48814,12.61794-13.48814l-26.10608-43.075S294.22369,799.07755,284.65146,802.12326Z" transform="translate(-24.21825 -28.87901)" fill="#2f2e41"/><path d="M212.42464,586.313s41.76972,14.35834,46.12074,17.404,23.93057,17.404,14.35834,24.80078-17.40405,12.18283-36.11341,6.52652S197.19609,611.984,197.19609,611.984Z" transform="translate(-24.21825 -28.87901)" fill="#ffb8b8"/><path d="M170.65491,567.16854s16.53385-3.04571,28.28158,3.48081,21.75507,19.57956,21.75507,19.57956S209.814,613.28928,201.9822,616.77009,179.792,602.84685,179.792,602.84685Z" transform="translate(-24.21825 -28.87901)" fill="#d0cde1"/><path d="M94.51217,554.5506s.4351,16.96895-1.3053,18.70936,20.88486,53.08236,45.68564,30.45709,5.65632-31.7624,5.65632-31.7624-9.13713-16.969-8.702-18.70936-40.46443,0-40.46443,0Z" transform="translate(-24.21825 -28.87901)" fill="#ffb8b8"/><path d="M94.51217,554.5506s.4351,16.96895-1.3053,18.70936,20.88486,53.08236,45.68564,30.45709,5.65632-31.7624,5.65632-31.7624-9.13713-16.969-8.702-18.70936-40.46443,0-40.46443,0Z" transform="translate(-24.21825 -28.87901)" opacity="0.1"/><path d="M101.47379,587.1832s16.53385,11.31263,23.49548,8.702,15.66364-13.92325,16.53385-14.79345,45.25054,88.32557,45.25054,88.32557-6.52652,32.6326-23.93058,42.20483-17.1865,17.18651-19.362,23.713-30.23954-20.66732-30.23954-20.66732L95.38237,638.96026V592.83952Z" transform="translate(-24.21825 -28.87901)" fill="#d0cde1"/><path d="M94.29462,566.951s-5.43877-1.08776-11.09508,3.69836S51.002,593.27462,52.30734,595.015s13.053,26.54118,15.66365,36.54852,6.52652,11.31263,6.52652,11.31263,9.13713,6.52652,7.83182,11.31264-6.96162,70.05131.87021,84.40966,6.52652,26.97628,4.351,30.45709,20.88486-10.00733,20.88486-10.00733,34.373-27.84649,36.98362-36.11341a97.263,97.263,0,0,0,3.48081-17.40406s-22.19017-87.89047-29.15179-92.67658S94.29462,566.951,94.29462,566.951Z" transform="translate(-24.21825 -28.87901)" fill="#575a89"/><path d="M142.0946,567.29509s10.72115-6.65307,12.89666-4.91267,22.62527,1.74041,23.06037,3.48081,1.3053,43.51014,16.09875,54.38767,5.22122,32.6326,5.22122,32.6326l10.87753,17.40406s-59.17285,56.99362-55.25787,37.41871c.21755-1.08775,0-1.3053,0-1.3053s-23.06037-98.768-20.01466-103.98922S143.55629,573.51306,142.0946,567.29509Z" transform="translate(-24.21825 -28.87901)" fill="#575a89"/><path d="M233.3095,607.19786l-59.17378,20.44976s-58.73868,13.92325-49.60156,30.022S172.39531,646.357,172.39531,646.357l78.7996-8.82909S282.476,611.11377,233.3095,607.19786Z" transform="translate(-24.21825 -28.87901)" fill="#ffb8b8"/><circle cx="93.78939" cy="509.57283" r="32.1975" fill="#ffb8b8"/><path d="M92.36668,506.4531l-5.95587-2.16578s12.45312-12.45312,29.77934-11.37019l-4.8731-4.873s11.91174-4.33148,22.74055,7.03872c5.69249,5.97707,12.27878,13.00279,16.38465,20.91719h6.37832l-2.66208,5.32415,9.31726,5.32415-9.56325-.95636a26.866,26.866,0,0,1-.90453,13.789l-2.16569,5.95579s-8.66312-17.32606-8.66312-19.49184v5.4144s-5.95587-4.87294-5.95587-8.12156l-3.24862,3.79009-1.62432-5.95587-20.0333,5.95587,3.24863-4.87294-12.45312,1.62431,4.8731-5.95587s-14.07744,7.03872-14.619,12.99459-7.58,13.536-7.58,13.536L81.538,538.93944S76.66493,514.57467,92.36668,506.4531Z" transform="translate(-24.21825 -28.87901)" fill="#2f2e41"/><path d="M146.61566,540.19858s1.05805,7.34674-4.02158,11.6902a10.68163,10.68163,0,0,1-11.82134,1.29251,14.7297,14.7297,0,0,1-4.40805-3.53378,18.98358,18.98358,0,0,1-1.516-2.01675,24.0899,24.0899,0,0,1-1.76144-3.21588q-.47687-1.04165-.911-2.22935c-.05564-.152-.1073-.301-.157-.449-2.63767-7.8395,2.49263-10.12648,7.20169-10.67488a24.18681,24.18681,0,0,1,2.97645-.15,26.68959,26.68959,0,0,1,3.49007.24639s.09637.001.27022.00794a20.96175,20.96175,0,0,1,2.67543.29706C142.2712,532.10177,147.83962,534.08077,146.61566,540.19858Z" transform="translate(-24.21825 -28.87901)" fill="#e6a23c"/><path d="M114.22842,542.18553c-2.31877,6.36518-5.65784,9.48469-8.59653,10.99576a10.68165,10.68165,0,0,1-11.82135-1.29251,10.38378,10.38378,0,0,1-.89412-.86134,10.81892,10.81892,0,0,1-1.49121-2.05252,12.78124,12.78124,0,0,1-1.2011-2.98936,16.04808,16.04808,0,0,1-.51363-3.5,14.00278,14.00278,0,0,1,.07848-2.287c-1.14547-5.72738,3.661-7.82659,7.26428-8.59554a21.39066,21.39066,0,0,1,3.16223-.42619c.3189-.01789.50171-.01888.50171-.01888a27.42839,27.42839,0,0,1,5.71942-.16989C111.41291,531.38944,117.37277,533.55522,114.22842,542.18553Z" transform="translate(-24.21825 -28.87901)" fill="#e6a23c"/><path d="M100.21547,531.17685l-9.99136,14.80871a16.04808,16.04808,0,0,1-.51363-3.5L97.05324,531.603A21.39066,21.39066,0,0,1,100.21547,531.17685Z" transform="translate(-24.21825 -28.87901)" fill="#fff" opacity="0.2"/><path d="M106.4366,530.98808,92.91642,551.02744a10.81892,10.81892,0,0,1-1.49121-2.05252l12.18-18.0524A26.08038,26.08038,0,0,1,106.4366,530.98808Z" transform="translate(-24.21825 -28.87901)" fill="#fff" opacity="0.2"/><path d="M132.19738,530.91158l-9.11016,13.5033q-.47687-1.04165-.911-2.22935c-.05564-.152-.1073-.301-.157-.449l7.20169-10.67488A24.18681,24.18681,0,0,1,132.19738,530.91158Z" transform="translate(-24.21825 -28.87901)" fill="#fff" opacity="0.2"/><path d="M138.6331,531.463l-12.26841,18.18454a18.98358,18.98358,0,0,1-1.516-2.01675l11.109-16.46485A20.96175,20.96175,0,0,1,138.6331,531.463Z" transform="translate(-24.21825 -28.87901)" fill="#fff" opacity="0.2"/><path d="M149,539.50315h-2.27379c1.0063-8.24976-11.03876-8.34518-11.03876-8.34518a27.46661,27.46661,0,0,0-5.76215-.166v-.03266H106.38v.02471a27.49535,27.49535,0,0,0-5.6628.174s-12.04507.09542-11.03876,8.34518H87.504v2.18564h2.19428c-.022,2.37451.44933,7.06789,4.11229,10.2a10.68165,10.68165,0,0,0,11.82135,1.29251c2.93869-1.51107,6.27776-4.63058,8.59653-10.99576a11.22868,11.22868,0,0,0,.802-5.37948,63.12484,63.12484,0,0,1,6.34375,0,11.22856,11.22856,0,0,0,.802,5.37948c2.31877,6.36518,5.65783,9.48469,8.59653,10.99576a10.68163,10.68163,0,0,0,11.82134-1.29251c3.663-3.1321,4.13427-7.82548,4.1123-10.2H149Zm-35.8187,2.72311c-2.20651,6.05721-5.42537,8.89059-8.18623,10.198a9.69145,9.69145,0,0,1-10.2447-1.19515c-3.48511-2.83339-3.94906-7.18778-3.93614-9.40721.006-.8822-.03378-1.76242-.06855-2.64363-.27519-6.92551,10.11654-7.007,10.11654-7.007S117.80194,529.54457,113.1813,542.22626Zm8.28451-5.91767a42.17881,42.17881,0,0,0-6.527,0c-.54505-2.43265-2.38208-3.80371-4.56371-4.55454h15.65441C123.84789,532.50488,122.01086,533.87594,121.46581,536.30859Zm24.30043,2.8379c-.03576.88916-.0755,1.77832-.06954,2.66748.01391,2.24028-.455,6.63541-3.97191,9.49363a9.77755,9.77755,0,0,1-10.33511,1.20906c-2.78768-1.31834-6.03833-4.17756-8.26669-10.29437-4.66238-12.79893,12.43332-10.14735,12.43332-10.14735S146.04342,532.15641,145.76624,539.14649Z" transform="translate(-24.21825 -28.87901)" fill="#3f3d56"/></svg> \ No newline at end of file diff --git a/src/assets/logo-mini.svg b/src/assets/logo-mini.svg new file mode 100644 index 0000000..53df94c --- /dev/null +++ b/src/assets/logo-mini.svg @@ -0,0 +1,9 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 50" width="64" height="50"> + <defs> + <image width="64" height="50" id="img1" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAAAyCAYAAADsg90UAAAAAXNSR0IB2cksfwAACI5JREFUeJy1WgtsW9UZdvNq0xU6WhZoCCVx7Gunbld1GSsMdYpGREhwr+2IMbQWqRoTk+iWPZi2wWhm1kwEmqV52feRJrbvvd6DiUnbQCAemzY2xh4tSB0wOqZIqAtLYzultIWEpt13btLq+sap/R8nRzpK4vh+5/++85///8851yEk1V+hX6B0tyE3OWwt0x789VR78AKlZ0KBz1oxBE3+BdUW9PNuQ7nJbk/BDQ/v4hi0x44z1R64jyrAVCjQ/fLNN8/ZoUWdgqGc57AFE6I86giH+QRw6XI9QE4RBz3iTAyVW3EyQdEDUmeIIhyeFNtMHO/o0B4e8qYASfVvLk2p4BKgdnioFCAvEQeddhnyFivOpOgvBaFXiAKcygQDrk927S/zjkae5xUA/X3YI/C5AFwHLrSPw+2+YYfCMugiCvDaCbGt0hc9uAXuP1OEAPACZQ+fAGguQ9nGgglx0OfsOAhq24lBcG/YYQa/kWLIz3XlCW4B6mKRCoCMEQdNu3VpnRVnMhBYA2L/LVCATCooXuNJSHXFzv58P+mMyyu5RQDAKNntdLnNjoN0+NMCM0D8901NDkGXuyBAseRZn3Ubagu3AFjTd1GXAdZdpCqurMgSIBS4BwRn8wgwje/d4pV6yz2adGQJyM/bo/ZyC+DSlWqApIiDHqtPyFdlCyBeD4Lv5xHgr5mAWO4ZjTRh9s8tlQDoryIbrOISoLYvvAIALxIHnIHn3GnFmfDfztLhH/IEv/vYd72xyKElJM/6Gdjj4fYCuNA3yYMa6ogdBwQfvIwAk+mguHZz3+MbMPsfLrEALD3v5RfAkH3UOID+Jqqwj2ULIDZeJvhF2He8I0NfX2ry8wI85VSy41LBzaUPsXT4L/Iy0OUbrTgpsXUlyI7lEOAsvGOboPRdKejK28shAPqpek1etxjHArxAiXCo/pAdB2QPLRQg8BLcv8ITi4h4bnaZBGD2+IsQQG0DCDUyv2LfjcHVQyB93iLAecz+bvY/T1x6YrnImwIkVakIAeSrAfIucdCz7qRcY8VJh8RrQDplWfvHxttaVvkGe6vg/h8tpwDoR926wpcOb9CkEhQ4Mbrqym4rTkrcydLhs5bU95Wwwwx+311m8qxPQ4CtvE6AdKjcLlCrQkNJXNXdnYUD0t+eF+AE1v76rV0/qvTEo/8kkkGJq/yFLIKhPsgtgEszl8E4cdAxPHdllgDBwGZW9k6Fguaa9A4PtMEwkrDe0chhCPAZ/E5dNn/kPiWqGe5mVSH1rJCdze2w4rDNDsi/gdn/FPtb0KTfUmeyQenvuE45WCLQd6unsc3fwKeAw0yHX+Zwu247DpbB3emQv3R7x7du8GgybdtrKGc39Ty23rQnqfKk5y9wCwD1XACZJg56xGUMZFVhx1taytjPBnWAfuihyT+3TEiAQwC1Mhzmqwrr9QhbBoeJg36A6Ou0Y/kGe2qQ+mhiGspHDcODTZfs0eRr8fkE0Z4xpyGt4RJgTnX1carq8Jw9dhzv6BB5k+VJyK9t6+y8dNK74bGHMSHK00Scc/CC7fwC6MotAjX6GuqTzsTBkosYW/f9YKUnIb1OFiAW/c4Ce5Lq18jLKKnu5xaApTWBHn0n8Nz6ixhw4zvJ5HXlvU2R3gWui02XizwhrEznbTW9vQ64nUEckBUut13EQOHzFFUA70jErBv+09xcYrXHqUXK8H9qIXXapSs1dm4FN1SF95DdzlD72LMNUt/15CMvXT65NfzIRtQOq5FCv7jAHkPppdqDZ3YvZFZgY8WEQN8dvvFxpB8hLvWT3T8uyWxckG9CEfX38fk0ahGgmboMMIk/2xg5UJKbYZ62sf9RbI7UPxGJzLgT0R2Y/RM0z1HO+QZ6Gl/3+dh2Wmdb6HQwUJc9IfI6fPc40Z5xCLeW2wvw8Pfoy0B5mfoMAuYLn+7oKE0FxZqp+YvWTHugw24PvvtLIjZLh83cAghzmxHqASb5qntz/4EvsfEy7UHroepvJoKtWdUcPPKrVGwsA6k2FuYTAPXAGoC8RfYCStflqRvv3VuB4Hc1SI9bBJjAZ1VWe+p1+TqBHpfG+M8Ksa0EgLacAnhiETNzIPjdbztLPIfPWrME0CSkQ+UfxDFmkQ5v5RPAYcYBckFTcDfUWc+hwZsw06tA+EiOi5RoDns66ctA/Qm3AE4tuhYgZ5Zl9uPR32165PtlINoMwjM5jtPfSvn9WTe/iEufw7PUW+U3a2NSKZ8CTU0s+DyzHAJgq9yuNDaywxNtkQuVWaTDBqs5SIdsQt4hjsXOCvmvzrDu6Fdnebo3Hj3u69xXngoFqkH09KL3ie2BB6y2XCsfZNt1apnOqsL7uY/KoB57k+SDJRUhIZlX2iD4UJ4b5ef+3dqabY9hlunUdPt0XXyIryqs1yKVAv3qbPFuKNNedaAR5FeD4NE8AqRTwZ1ZmxqnHv0EcI4Rxz3hNqSqxThevrEXqpJq31IJgOD3TN3+h0tYmmPpLt9bJex80W4SRBzmEF7kE8Bhbo5aONwutwCx6K4JUVyByu/JfOTn+6EFAiTNN1uoAgxyC1BvqFcAZLJo8pr8rlvuq8wExfpFUl+u/s7/dt6R9UKkS5ergHeaOP6Yc2SQLw7Mqa6SDznsHakvzLAyoeAPCyRvVoXpUGCb1ZZqRWFnhdQXPWcg3Jac5App7C2MImf/5Kb+nupJ0X8FSL1NEOACEyyHPQ9QbWA73CIEkBuEIqrCzUO9CsNB6esCqQ8pAqD/Oe33l9vs2SLQd6svuhJSWW6GeVptLFKGbMD9eltjZ2cjw5m4o60ChF4lCvBeJhjIuntAYF4N3KNEO9Lwgmo+F/D5mNt1cbr/2OeD916qx+HSB4gCsDdNdmXZM7dbjRJtYXeZd/EJ4DDX3Q4uARLSj604yO23UgVA2jRy2EO+OkNX/w+fZNm8pw5QbAAAAABJRU5ErkJggg=="/> + </defs> + <style> + tspan { white-space:pre } + </style> + <use id="Background" href="#img1" x="0" y="0" /> +</svg> \ No newline at end of file diff --git a/src/components/auth/auth.vue b/src/components/auth/auth.vue new file mode 100644 index 0000000..ae010d4 --- /dev/null +++ b/src/components/auth/auth.vue @@ -0,0 +1,30 @@ +<template> + <slot v-if="getUserAuthBtnList" /> +</template> + +<script lang="ts"> +import { computed, defineComponent } from 'vue'; +import { storeToRefs } from 'pinia'; +import { useUserInfo } from '/@/stores/userInfo'; + +export default defineComponent({ + name: 'auth', + props: { + value: { + type: String, + default: () => '', + }, + }, + setup(props) { + const stores = useUserInfo(); + const { userInfos } = storeToRefs(stores); + // 获取 vuex 中的用户权限 + const getUserAuthBtnList = computed(() => { + return userInfos.value.authBtnList.some((v: string) => v === props.value); + }); + return { + getUserAuthBtnList, + }; + }, +}); +</script> diff --git a/src/components/auth/authAll.vue b/src/components/auth/authAll.vue new file mode 100644 index 0000000..76c5e01 --- /dev/null +++ b/src/components/auth/authAll.vue @@ -0,0 +1,31 @@ +<template> + <slot v-if="getUserAuthBtnList" /> +</template> + +<script lang="ts"> +import { computed, defineComponent } from 'vue'; +import { storeToRefs } from 'pinia'; +import { useUserInfo } from '/@/stores/userInfo'; +import { judementSameArr } from '/@/utils/arrayOperation'; + +export default defineComponent({ + name: 'authAll', + props: { + value: { + type: Array, + default: () => [], + }, + }, + setup(props) { + const stores = useUserInfo(); + const { userInfos } = storeToRefs(stores); + // 获取 pinia 中的用户权限 + const getUserAuthBtnList = computed(() => { + return judementSameArr(props.value, userInfos.value.authBtnList); + }); + return { + getUserAuthBtnList, + }; + }, +}); +</script> diff --git a/src/components/auth/auths.vue b/src/components/auth/auths.vue new file mode 100644 index 0000000..ef31019 --- /dev/null +++ b/src/components/auth/auths.vue @@ -0,0 +1,36 @@ +<template> + <slot v-if="getUserAuthBtnList" /> +</template> + +<script lang="ts"> +import { computed, defineComponent } from 'vue'; +import { storeToRefs } from 'pinia'; +import { useUserInfo } from '/@/stores/userInfo'; + +export default defineComponent({ + name: 'auths', + props: { + value: { + type: Array, + default: () => [], + }, + }, + setup(props) { + const stores = useUserInfo(); + const { userInfos } = storeToRefs(stores); + // 获取 vuex 中的用户权限 + const getUserAuthBtnList = computed(() => { + let flag = false; + userInfos.value.authBtnList.map((val: string) => { + props.value.map((v) => { + if (val === v) flag = true; + }); + }); + return flag; + }); + return { + getUserAuthBtnList, + }; + }, +}); +</script> diff --git a/src/components/cropper/index.vue b/src/components/cropper/index.vue new file mode 100644 index 0000000..b23a266 --- /dev/null +++ b/src/components/cropper/index.vue @@ -0,0 +1,149 @@ +<template> + <div> + <el-dialog title="更换头像" v-model="isShowDialog" width="769px"> + <div class="cropper-warp"> + <div class="cropper-warp-left"> + <img :src="cropperImg" class="cropper-warp-left-img" /> + </div> + <div class="cropper-warp-right"> + <div class="cropper-warp-right-title">预览</div> + <div class="cropper-warp-right-item"> + <div class="cropper-warp-right-value"> + <img :src="cropperImgBase64" class="cropper-warp-right-value-img" /> + </div> + <div class="cropper-warp-right-label">100 x 100</div> + </div> + <div class="cropper-warp-right-item"> + <div class="cropper-warp-right-value"> + <img :src="cropperImgBase64" class="cropper-warp-right-value-img cropper-size" /> + </div> + <div class="cropper-warp-right-label">50 x 50</div> + </div> + </div> + </div> + <template #footer> + <span class="dialog-footer"> + <el-button @click="onCancel" size="default">取 消</el-button> + <el-button type="primary" @click="onSubmit" size="default">更 换</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script lang="ts"> +import { reactive, toRefs, nextTick, defineComponent } from 'vue'; +import Cropper from 'cropperjs'; +import 'cropperjs/dist/cropper.css'; + +export default defineComponent({ + name: 'cropperIndex', + setup() { + const state = reactive({ + isShowDialog: false, + cropperImg: '', + cropperImgBase64: '', + cropper: null, + }); + // 打开弹窗 + const openDialog = (imgs: any) => { + state.cropperImg = imgs; + state.isShowDialog = true; + nextTick(() => { + initCropper(); + }); + }; + // 关闭弹窗 + const closeDialog = () => { + state.isShowDialog = false; + }; + // 取消 + const onCancel = () => { + closeDialog(); + }; + // 更换 + const onSubmit = () => { + // state.cropperImgBase64 = state.cropper.getCroppedCanvas().toDataURL('image/jpeg'); + }; + // 初始化cropperjs图片裁剪 + const initCropper = () => { + const letImg: any = document.querySelector('.cropper-warp-left-img'); + (<any>state.cropper) = new Cropper(letImg, { + viewMode: 1, + dragMode: 'none', + initialAspectRatio: 1, + aspectRatio: 1, + preview: '.before', + background: false, + autoCropArea: 0.6, + zoomOnWheel: false, + crop: () => { + state.cropperImgBase64 = (<any>state.cropper).getCroppedCanvas().toDataURL('image/jpeg'); + }, + }); + }; + return { + openDialog, + closeDialog, + onCancel, + onSubmit, + initCropper, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.cropper-warp { + display: flex; + .cropper-warp-left { + position: relative; + display: inline-block; + height: 350px; + flex: 1; + border: 1px solid var(--el-border-color); + background: var(--el-color-white); + overflow: hidden; + background-repeat: no-repeat; + cursor: move; + border-radius: var(--el-border-radius-base); + .cropper-warp-left-img { + width: 100%; + height: 100%; + } + } + .cropper-warp-right { + width: 150px; + height: 350px; + .cropper-warp-right-title { + text-align: center; + height: 20px; + line-height: 20px; + } + .cropper-warp-right-item { + margin: 15px 0; + .cropper-warp-right-value { + display: flex; + .cropper-warp-right-value-img { + width: 100px; + height: 100px; + border-radius: var(--el-border-radius-circle); + margin: auto; + } + .cropper-size { + width: 50px; + height: 50px; + } + } + .cropper-warp-right-label { + text-align: center; + font-size: 12px; + color: var(--el-text-color-primary); + height: 30px; + line-height: 30px; + } + } + } +} +</style> diff --git a/src/components/editor/index.vue b/src/components/editor/index.vue new file mode 100644 index 0000000..78e5726 --- /dev/null +++ b/src/components/editor/index.vue @@ -0,0 +1,115 @@ +<template> + <div class="editor-container"> + <div ref="editorToolbar"></div> + <div ref="editorContent" :style="{ height }"></div> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, onMounted, watch, defineComponent } from 'vue'; +import { createEditor, createToolbar, IEditorConfig, IToolbarConfig, IDomEditor } from '@wangeditor/editor'; +import '@wangeditor/editor/dist/css/style.css'; +import { toolbarKeys } from './toolbar'; + +// 定义接口来定义对象的类型 +interface WangeditorState { + editorToolbar: HTMLDivElement | null; + editorContent: HTMLDivElement | null; + editor: any; +} + +export default defineComponent({ + name: 'wngEditor', + props: { + // 节点 id + id: { + type: String, + default: () => 'wangeditor', + }, + // 是否禁用 + isDisable: { + type: Boolean, + default: () => false, + }, + // 内容框默认 placeholder + placeholder: { + type: String, + default: () => '请输入内容', + }, + // 双向绑定:双向绑定值,字段名为固定,改了之后将不生效 + // 参考:https://v3.cn.vuejs.org/guide/migration/v-model.html#%E8%BF%81%E7%A7%BB%E7%AD%96%E7%95%A5 + modelValue: String, + // https://www.wangeditor.com/v5/getting-started.html#mode-%E6%A8%A1%E5%BC%8F + // 模式,可选 <default|simple>,默认 default + mode: { + type: String, + default: () => 'default', + }, + // 高度 + height: { + type: String, + default: () => '310px', + }, + }, + setup(props, { emit }) { + const state = reactive<WangeditorState>({ + editorToolbar: null, + editor: null, + editorContent: null, + }); + // 富文本配置 + const wangeditorConfig = () => { + const editorConfig: Partial<IEditorConfig> = { MENU_CONF: {} }; + props.isDisable ? (editorConfig.readOnly = true) : (editorConfig.readOnly = false); + editorConfig.placeholder = props.placeholder; + editorConfig.onChange = (editor: IDomEditor) => { + // console.log('content', editor.children); + // console.log('html', editor.getHtml()); + emit('update:modelValue', editor.getHtml()); + }; + (<any>editorConfig).MENU_CONF['uploadImage'] = { + base64LimitSize: 10 * 1024 * 1024, + }; + return editorConfig; + }; + // + const toolbarConfig = () => { + const toolbarConfig: Partial<IToolbarConfig> = {}; + toolbarConfig.toolbarKeys = toolbarKeys; + return toolbarConfig; + }; + // 初始化富文本 + // https://www.wangeditor.com/ + const initWangeditor = () => { + state.editor = createEditor({ + html: props.modelValue, + selector: state.editorContent!, + config: wangeditorConfig(), + mode: props.mode, + }); + createToolbar({ + editor: state.editor, + selector: state.editorToolbar!, + mode: props.mode, + config: toolbarConfig(), + }); + }; + // 页面加载时 + onMounted(() => { + initWangeditor(); + }); + // 监听双向绑定值的改变 + // https://gitee.com/lyt-top/vue-next-admin/issues/I4LM7I + watch( + () => props.modelValue, + (value) => { + state.editor.clear(); + state.editor.dangerouslyInsertHtml(value); + } + ); + return { + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/components/editor/toolbar.ts b/src/components/editor/toolbar.ts new file mode 100644 index 0000000..14a9bf3 --- /dev/null +++ b/src/components/editor/toolbar.ts @@ -0,0 +1,60 @@ +/** + * 工具栏配置 + */ +export const toolbarKeys = [ + 'headerSelect', + 'blockquote', + '|', + 'bold', + 'underline', + 'italic', + { + key: 'group-more-style', + title: '更多', + iconSvg: + '<svg viewBox="0 0 1024 1024"><path d="M204.8 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path><path d="M505.6 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path><path d="M806.4 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path></svg>', + menuKeys: ['through', 'code', 'sup', 'sub', 'clearStyle'], + }, + 'color', + 'bgColor', + '|', + 'fontSize', + 'fontFamily', + 'lineHeight', + '|', + 'bulletedList', + 'numberedList', + 'todo', + { + key: 'group-justify', + title: '对齐', + iconSvg: + '<svg viewBox="0 0 1024 1024"><path d="M768 793.6v102.4H51.2v-102.4h716.8z m204.8-230.4v102.4H51.2v-102.4h921.6z m-204.8-230.4v102.4H51.2v-102.4h716.8zM972.8 102.4v102.4H51.2V102.4h921.6z"></path></svg>', + menuKeys: ['justifyLeft', 'justifyRight', 'justifyCenter', 'justifyJustify'], + }, + { + key: 'group-indent', + title: '缩进', + iconSvg: + '<svg viewBox="0 0 1024 1024"><path d="M0 64h1024v128H0z m384 192h640v128H384z m0 192h640v128H384z m0 192h640v128H384zM0 832h1024v128H0z m0-128V320l256 192z"></path></svg>', + menuKeys: ['indent', 'delIndent'], + }, + '|', + 'emotion', + 'insertLink', + { + key: 'group-image', + title: '图片', + iconSvg: + '<svg viewBox="0 0 1024 1024"><path d="M959.877 128l0.123 0.123v767.775l-0.123 0.122H64.102l-0.122-0.122V128.123l0.122-0.123h895.775zM960 64H64C28.795 64 0 92.795 0 128v768c0 35.205 28.795 64 64 64h896c35.205 0 64-28.795 64-64V128c0-35.205-28.795-64-64-64zM832 288.01c0 53.023-42.988 96.01-96.01 96.01s-96.01-42.987-96.01-96.01S682.967 192 735.99 192 832 234.988 832 288.01zM896 832H128V704l224.01-384 256 320h64l224.01-192z"></path></svg>', + menuKeys: ['uploadImage'], + }, + 'insertTable', + 'codeBlock', + 'divider', + '|', + 'undo', + 'redo', + '|', + 'fullScreen', +]; diff --git a/src/components/iconSelector/index.vue b/src/components/iconSelector/index.vue new file mode 100644 index 0000000..07de786 --- /dev/null +++ b/src/components/iconSelector/index.vue @@ -0,0 +1,252 @@ +<template> + <div class="icon-selector w100 h100"> + <el-popover + placement="bottom" + :width="fontIconWidth" + trigger="click" + transition="el-zoom-in-top" + popper-class="icon-selector-popper" + @show="onPopoverShow" + > + <template #reference> + <el-input + v-model="fontIconSearch" + :placeholder="fontIconPlaceholder" + :clearable="clearable" + :disabled="disabled" + :size="size" + ref="inputWidthRef" + @clear="onClearFontIcon" + @focus="onIconFocus" + @blur="onIconBlur" + > + <template #prepend> + <SvgIcon + :name="fontIconPrefix === '' ? prepend : fontIconPrefix" + class="font14" + v-if="fontIconPrefix === '' ? prepend?.indexOf('ele-') > -1 : fontIconPrefix?.indexOf('ele-') > -1" + /> + <i v-else :class="fontIconPrefix === '' ? prepend : fontIconPrefix" class="font14"></i> + </template> + </el-input> + </template> + <template #default> + <div class="icon-selector-warp"> + <div class="icon-selector-warp-title flex"> + <div class="flex-auto">{{ title }}</div> + <div class="icon-selector-warp-title-tab" v-if="type === 'all'"> + <span :class="{ 'span-active': fontIconType === 'ali' }" @click="onIconChange('ali')" class="ml10" title="iconfont 图标">ali</span> + <span :class="{ 'span-active': fontIconType === 'ele' }" @click="onIconChange('ele')" class="ml10" title="elementPlus 图标">ele</span> + <span :class="{ 'span-active': fontIconType === 'awe' }" @click="onIconChange('awe')" class="ml10" title="fontawesome 图标">awe</span> + </div> + </div> + <div class="icon-selector-warp-row"> + <el-scrollbar ref="selectorScrollbarRef"> + <el-row :gutter="10" v-if="fontIconSheetsFilterList.length > 0"> + <el-col :xs="6" :sm="4" :md="4" :lg="4" :xl="4" @click="onColClick(v)" v-for="(v, k) in fontIconSheetsFilterList" :key="k"> + <div class="icon-selector-warp-item" :class="{ 'icon-selector-active': fontIconPrefix === v }"> + <div class="flex-margin"> + <div class="icon-selector-warp-item-value"> + <SvgIcon :name="v" /> + </div> + </div> + </div> + </el-col> + </el-row> + <el-empty :image-size="100" v-if="fontIconSheetsFilterList.length <= 0" :description="emptyDescription"></el-empty> + </el-scrollbar> + </div> + </div> + </template> + </el-popover> + </div> +</template> + +<script lang="ts"> +import { ref, toRefs, reactive, onMounted, nextTick, computed, watch, defineComponent } from 'vue'; +import initIconfont from '/@/utils/getStyleSheets'; + +export default defineComponent({ + name: 'iconSelector', + emits: ['update:modelValue', 'get', 'clear'], + props: { + // 输入框前置内容 + prepend: { + type: String, + default: () => 'ele-Pointer', + }, + // 输入框占位文本 + placeholder: { + type: String, + default: () => '请输入内容搜索图标或者选择图标', + }, + // 输入框占位文本 + size: { + type: String, + default: () => 'default', + }, + // 弹窗标题 + title: { + type: String, + default: () => '请选择图标', + }, + // icon 图标类型 + type: { + type: String, + default: () => 'ele', + }, + // 禁用 + disabled: { + type: Boolean, + default: () => false, + }, + // 是否可清空 + clearable: { + type: Boolean, + default: () => true, + }, + // 自定义空状态描述文字 + emptyDescription: { + type: String, + default: () => '无相关图标', + }, + // 双向绑定值,默认为 modelValue, + // 参考:https://v3.cn.vuejs.org/guide/migration/v-model.html#%E8%BF%81%E7%A7%BB%E7%AD%96%E7%95%A5 + // 参考:https://v3.cn.vuejs.org/guide/component-custom-events.html#%E5%A4%9A%E4%B8%AA-v-model-%E7%BB%91%E5%AE%9A + modelValue: String, + }, + setup(props, { emit }) { + const inputWidthRef = ref(); + const selectorScrollbarRef = ref(); + const state = reactive({ + fontIconPrefix: '', + fontIconWidth: 0, + fontIconSearch: '', + fontIconTabsIndex: 0, + fontIconSheetsList: [], + fontIconPlaceholder: '', + fontIconType: 'ali', + fontIconShow: true, + }); + // 处理 input 获取焦点时,modelValue 有值时,改变 input 的 placeholder 值 + const onIconFocus = () => { + if (!props.modelValue) return false; + state.fontIconSearch = ''; + state.fontIconPlaceholder = props.modelValue; + }; + // 处理 input 失去焦点时,为空将清空 input 值,为点击选中图标时,将取原先值 + const onIconBlur = () => { + setTimeout(() => { + const icon = state.fontIconSheetsList.filter((icon: string) => icon === state.fontIconSearch); + if (icon.length <= 0) state.fontIconSearch = ''; + }, 300); + }; + // 处理 icon 双向绑定数值回显 + const initModeValueEcho = () => { + if (props.modelValue === '') return ((<string | undefined>state.fontIconPlaceholder) = props.placeholder); + (<string | undefined>state.fontIconPlaceholder) = props.modelValue; + (<string | undefined>state.fontIconPrefix) = props.modelValue; + }; + // 处理 icon type 类型为 all 时,类型 ali、ele、awe 回显问题 + const initFontIconTypeEcho = () => { + if ((<any>props.modelValue)?.indexOf('iconfont') > -1) onIconChange('ali'); + else if ((<any>props.modelValue)?.indexOf('ele-') > -1) onIconChange('ele'); + else if ((<any>props.modelValue)?.indexOf('fa') > -1) onIconChange('awe'); + else onIconChange('ali'); + }; + // 图标搜索及图标数据显示 + const fontIconSheetsFilterList = computed(() => { + if (!state.fontIconSearch) return state.fontIconSheetsList; + let search = state.fontIconSearch.trim().toLowerCase(); + return state.fontIconSheetsList.filter((item: any) => { + if (item.toLowerCase().indexOf(search) !== -1) return item; + }); + }); + // 获取 input 的宽度 + const getInputWidth = () => { + nextTick(() => { + state.fontIconWidth = inputWidthRef.value.$el.offsetWidth; + }); + }; + // 监听页面宽度改变 + const initResize = () => { + window.addEventListener('resize', () => { + getInputWidth(); + }); + }; + // 初始化数据 + const initFontIconData = async (type: string) => { + state.fontIconSheetsList = []; + if (type === 'ali') { + await initIconfont.ali().then((res: any) => { + // 阿里字体图标使用 `iconfont xxx` + state.fontIconSheetsList = res.map((i: string) => `iconfont ${i}`); + }); + } else if (type === 'ele') { + await initIconfont.ele().then((res: any) => { + state.fontIconSheetsList = res; + }); + } else if (type === 'awe') { + await initIconfont.awe().then((res: any) => { + // fontawesome字体图标使用 `fa xxx` + state.fontIconSheetsList = res.map((i: string) => `fa ${i}`); + }); + } + // 初始化 input 的 placeholder + // 参考(单项数据流):https://cn.vuejs.org/v2/guide/components-props.html?#%E5%8D%95%E5%90%91%E6%95%B0%E6%8D%AE%E6%B5%81 + state.fontIconPlaceholder = props.placeholder; + // 初始化双向绑定回显 + initModeValueEcho(); + }; + // 图标点击切换 + const onIconChange = (type: string) => { + state.fontIconType = type; + initFontIconData(type); + }; + // 获取当前点击的 icon 图标 + const onColClick = (v: any) => { + state.fontIconPlaceholder = v; + state.fontIconPrefix = v; + emit('get', state.fontIconPrefix); + emit('update:modelValue', state.fontIconPrefix); + }; + // 清空当前点击的 icon 图标 + const onClearFontIcon = () => { + state.fontIconPrefix = ''; + emit('clear', state.fontIconPrefix); + emit('update:modelValue', state.fontIconPrefix); + }; + // 监听 Popover 打开,用于双向绑定值回显 + const onPopoverShow = () => { + initModeValueEcho(); + initFontIconTypeEcho(); + }; + // 页面加载时 + onMounted(() => { + initModeValueEcho(); + initResize(); + getInputWidth(); + }); + + // 监听双向绑定 modelValue 的变化 + watch( + () => props.modelValue, + () => { + initModeValueEcho(); + } + ); + return { + inputWidthRef, + selectorScrollbarRef, + fontIconSheetsFilterList, + onColClick, + onIconChange, + onClearFontIcon, + onIconFocus, + onIconBlur, + onPopoverShow, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/components/noticeBar/index.vue b/src/components/noticeBar/index.vue new file mode 100644 index 0000000..6a81bfd --- /dev/null +++ b/src/components/noticeBar/index.vue @@ -0,0 +1,195 @@ +<template> + <div class="notice-bar" :style="{ background, height: `${height}px` }" v-show="!isMode"> + <div class="notice-bar-warp" :style="{ color, fontSize: `${size}px` }"> + <i v-if="leftIcon" class="notice-bar-warp-left-icon" :class="leftIcon"></i> + <div class="notice-bar-warp-text-box" ref="noticeBarWarpRef"> + <div class="notice-bar-warp-text" ref="noticeBarTextRef" v-if="!scrollable">{{ text }}</div> + <div class="notice-bar-warp-slot" v-else><slot /></div> + </div> + <SvgIcon :name="rightIcon" v-if="rightIcon" class="notice-bar-warp-right-icon" @click="onRightIconClick" /> + </div> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent, ref, onMounted, nextTick } from 'vue'; + +export default defineComponent({ + name: 'noticeBar', + props: { + // 通知栏模式,可选值为 closeable link + mode: { + type: String, + default: () => '', + }, + // 通知文本内容 + text: { + type: String, + default: () => '', + }, + // 通知文本颜色 + color: { + type: String, + default: () => 'var(--el-color-warning)', + }, + // 通知背景色 + background: { + type: String, + default: () => 'var(--el-color-warning-light-9)', + }, + // 字体大小,单位px + size: { + type: [Number, String], + default: () => 14, + }, + // 通知栏高度,单位px + height: { + type: Number, + default: () => 40, + }, + // 动画延迟时间 (s) + delay: { + type: Number, + default: () => 1, + }, + // 滚动速率 (px/s) + speed: { + type: Number, + default: () => 100, + }, + // 是否开启垂直滚动 + scrollable: { + type: Boolean, + default: () => false, + }, + // 自定义左侧图标 + leftIcon: { + type: String, + default: () => '', + }, + // 自定义右侧图标 + rightIcon: { + type: String, + default: () => '', + }, + }, + setup(props, { emit }) { + const noticeBarWarpRef = ref(); + const noticeBarTextRef = ref(); + const state = reactive({ + order: 1, + oneTime: 0, + twoTime: 0, + warpOWidth: 0, + textOWidth: 0, + isMode: false, + }); + // 初始化 animation 各项参数 + const initAnimation = () => { + nextTick(() => { + state.warpOWidth = noticeBarWarpRef.value.offsetWidth; + state.textOWidth = noticeBarTextRef.value.offsetWidth; + document.styleSheets[0].insertRule(`@keyframes oneAnimation {0% {left: 0px;} 100% {left: -${state.textOWidth}px;}}`); + document.styleSheets[0].insertRule(`@keyframes twoAnimation {0% {left: ${state.warpOWidth}px;} 100% {left: -${state.textOWidth}px;}}`); + computeAnimationTime(); + setTimeout(() => { + changeAnimation(); + }, props.delay * 1000); + }); + }; + // 计算 animation 滚动时长 + const computeAnimationTime = () => { + state.oneTime = state.textOWidth / props.speed; + state.twoTime = (state.textOWidth + state.warpOWidth) / props.speed; + }; + // 改变 animation 动画调用 + const changeAnimation = () => { + if (state.order === 1) { + noticeBarTextRef.value.style.cssText = `animation: oneAnimation ${state.oneTime}s linear; opactity: 1;}`; + state.order = 2; + } else { + noticeBarTextRef.value.style.cssText = `animation: twoAnimation ${state.twoTime}s linear infinite; opacity: 1;`; + } + }; + // 监听 animation 动画的结束 + const listenerAnimationend = () => { + noticeBarTextRef.value.addEventListener( + 'animationend', + () => { + changeAnimation(); + }, + false + ); + }; + // 右侧 icon 图标点击 + const onRightIconClick = () => { + if (!props.mode) return false; + if (props.mode === 'closeable') { + state.isMode = true; + emit('close'); + } else if (props.mode === 'link') { + emit('link'); + } + }; + // 页面加载时 + onMounted(() => { + if (props.scrollable) return false; + initAnimation(); + listenerAnimationend(); + }); + return { + noticeBarWarpRef, + noticeBarTextRef, + onRightIconClick, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.notice-bar { + padding: 0 15px; + width: 100%; + border-radius: 4px; + .notice-bar-warp { + display: flex; + align-items: center; + width: 100%; + height: inherit; + .notice-bar-warp-text-box { + flex: 1; + height: inherit; + display: flex; + align-items: center; + overflow: hidden; + position: relative; + .notice-bar-warp-text { + white-space: nowrap; + position: absolute; + left: 0; + } + .notice-bar-warp-slot { + width: 100%; + white-space: nowrap; + ::v-deep(.el-carousel__item) { + display: flex; + align-items: center; + } + } + } + .notice-bar-warp-left-icon { + width: 24px; + font-size: inherit !important; + } + .notice-bar-warp-right-icon { + width: 24px; + text-align: right; + font-size: inherit !important; + &:hover { + cursor: pointer; + } + } + } +} +</style> diff --git a/src/components/svgIcon/index.vue b/src/components/svgIcon/index.vue new file mode 100644 index 0000000..1fab298 --- /dev/null +++ b/src/components/svgIcon/index.vue @@ -0,0 +1,73 @@ +<template> + <i v-if="isShowIconSvg" class="el-icon" :style="setIconSvgStyle"> + <component :is="getIconName" /> + </i> + <div v-else-if="isShowIconImg" :style="setIconImgOutStyle"> + <img :src="getIconName" :style="setIconSvgInsStyle" /> + </div> + <i v-else :class="getIconName" :style="setIconSvgStyle" /> +</template> + +<script lang="ts"> +import { computed, defineComponent } from 'vue'; + +export default defineComponent({ + name: 'svgIcon', + props: { + // svg 图标组件名字 + name: { + type: String, + }, + // svg 大小 + size: { + type: Number, + default: () => 14, + }, + // svg 颜色 + color: { + type: String, + }, + }, + setup(props) { + // 在线链接、本地引入地址前缀 + const linesString = ['https', 'http', '/src', '/assets', import.meta.env.VITE_PUBLIC_PATH]; + + // 获取 icon 图标名称 + const getIconName = computed(() => { + return props?.name; + }); + // 用于判断 element plus 自带 svg 图标的显示、隐藏 + const isShowIconSvg = computed(() => { + return props?.name?.startsWith('ele-'); + }); + // 用于判断在线链接、本地引入等图标显示、隐藏 + const isShowIconImg = computed(() => { + return linesString.find((str) => props.name?.startsWith(str)); + }); + // 设置图标样式 + const setIconSvgStyle = computed(() => { + return `font-size: ${props.size}px;color: ${props.color};`; + }); + // 设置图片样式 + const setIconImgOutStyle = computed(() => { + return `width: ${props.size}px;height: ${props.size}px;display: inline-block;overflow: hidden;`; + }); + // 设置图片样式 + // https://gitee.com/lyt-top/vue-next-admin/issues/I59ND0 + const setIconSvgInsStyle = computed(() => { + const filterStyle: string[] = []; + const compatibles: string[] = ['-webkit', '-ms', '-o', '-moz']; + compatibles.forEach((j) => filterStyle.push(`${j}-filter: drop-shadow(${props.color} 30px 0);`)); + return `width: ${props.size}px;height: ${props.size}px;position: relative;left: -${props.size}px;${filterStyle.join('')}`; + }); + return { + getIconName, + isShowIconSvg, + isShowIconImg, + setIconSvgStyle, + setIconImgOutStyle, + setIconSvgInsStyle, + }; + }, +}); +</script> diff --git a/src/i18n/index.ts b/src/i18n/index.ts new file mode 100644 index 0000000..a45e72c --- /dev/null +++ b/src/i18n/index.ts @@ -0,0 +1,67 @@ +import { createI18n } from 'vue-i18n'; +import pinia from '/@/stores/index'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import zhcnLocale from 'element-plus/lib/locale/lang/zh-cn'; +import enLocale from 'element-plus/lib/locale/lang/en'; +import zhtwLocale from 'element-plus/lib/locale/lang/zh-tw'; + +import nextZhcn from '/@/i18n/lang/zh-cn'; +import nextEn from '/@/i18n/lang/en'; +import nextZhtw from '/@/i18n/lang/zh-tw'; + +import pagesLoginZhcn from '/@/i18n/pages/login/zh-cn'; +import pagesLoginEn from '/@/i18n/pages/login/en'; +import pagesLoginZhtw from '/@/i18n/pages/login/zh-tw'; +import pagesFormI18nZhcn from '/@/i18n/pages/formI18n/zh-cn'; +import pagesFormI18nEn from '/@/i18n/pages/formI18n/en'; +import pagesFormI18nZhtw from '/@/i18n/pages/formI18n/zh-tw'; + +// 定义语言国际化内容 +/** + * 说明: + * /src/i18n/lang 下的 ts 为框架的国际化内容 + * /src/i18n/pages 下的 ts 为各界面的国际化内容 + */ +const messages = { + [zhcnLocale.name]: { + ...zhcnLocale, + message: { + ...nextZhcn, + ...pagesLoginZhcn, + ...pagesFormI18nZhcn, + }, + }, + [enLocale.name]: { + ...enLocale, + message: { + ...nextEn, + ...pagesLoginEn, + ...pagesFormI18nEn, + }, + }, + [zhtwLocale.name]: { + ...zhtwLocale, + message: { + ...nextZhtw, + ...pagesLoginZhtw, + ...pagesFormI18nZhtw, + }, + }, +}; + +// 读取 pinia 默认语言 +const stores = useThemeConfig(pinia); +const { themeConfig } = storeToRefs(stores); + +// 导出语言国际化 +// https://vue-i18n.intlify.dev/guide/essentials/fallback.html#explicit-fallback-with-one-locale +export const i18n = createI18n({ + silentTranslationWarn: true, + missingWarn: false, + silentFallbackWarn: true, + fallbackWarn: false, + locale: themeConfig.value.globalI18n, + fallbackLocale: zhcnLocale.name, + messages, +}); diff --git a/src/i18n/lang/en.ts b/src/i18n/lang/en.ts new file mode 100644 index 0000000..46ae830 --- /dev/null +++ b/src/i18n/lang/en.ts @@ -0,0 +1,180 @@ +// 定义内容 +export default { + router: { + home: 'home', + system: 'system', + systemMenu: 'systemMenu', + systemRole: 'systemRole', + systemUser: 'systemUser', + systemDept: 'systemDept', + systemDic: 'systemDic', + limits: 'limits', + limitsFrontEnd: 'FrontEnd', + limitsFrontEndPage: 'FrontEndPage', + limitsFrontEndBtn: 'FrontEndBtn', + limitsBackEnd: 'BackEnd', + limitsBackEndEndPage: 'BackEndEndPage', + menu: 'menu', + menu1: 'menu1', + menu11: 'menu11', + menu12: 'menu12', + menu121: 'menu121', + menu122: 'menu122', + menu13: 'menu13', + menu2: 'menu2', + funIndex: 'function', + funTagsView: 'funTagsView', + funCountup: 'countup', + funWangEditor: 'wangEditor', + funCropper: 'cropper', + funQrcode: 'qrcode', + funEchartsMap: 'EchartsMap', + funPrintJs: 'PrintJs', + funClipboard: 'Copy cut', + funGridLayout: 'Drag layout', + funSplitpanes: 'Pane splitter', + funDragVerify: 'Validator', + pagesIndex: 'pages', + pagesFiltering: 'Filtering', + pagesFilteringDetails: 'FilteringDetails', + pagesFilteringDetails1: 'FilteringDetails1', + pagesIocnfont: 'iconfont icon', + pagesElement: 'element icon', + pagesAwesome: 'awesome icon', + pagesFormAdapt: 'FormAdapt', + pagesTableRules: 'pagesTableRules', + pagesFormI18n: 'FormI18n', + pagesFormRules: 'Multi form validation', + pagesDynamicForm: 'Dynamic complex form', + pagesWorkflow: 'Workflow', + pagesListAdapt: 'ListAdapt', + pagesWaterfall: 'Waterfall', + pagesSteps: 'Steps', + pagesPreview: 'Large preview', + pagesWaves: 'Wave effect', + pagesTree: 'tree alter table', + pagesDrag: 'Drag command', + pagesLazyImg: 'Image lazy loading', + makeIndex: 'makeIndex', + makeSelector: 'Icon selector', + makeNoticeBar: 'notification bar', + makeSvgDemo: 'Svgicon demo', + paramsIndex: 'Routing parameters', + paramsCommon: 'General routing', + paramsDynamic: 'Dynamic routing', + paramsCommonDetails: 'General routing details', + paramsDynamicDetails: 'Dynamic routing details', + chartIndex: 'chartIndex', + visualizingIndex: 'visualizingIndex', + visualizingLinkDemo1: 'visualizingLinkDemo1', + visualizingLinkDemo2: 'visualizingLinkDemo2', + personal: 'personal', + tools: 'tools', + layoutLinkView: 'LinkView', + layoutIfameView: 'IfameView', + }, + staticRoutes: { + signIn: 'signIn', + notFound: 'notFound', + noPower: 'noPower', + }, + user: { + title0: 'Component size', + title1: 'Language switching', + title2: 'Menu search', + title3: 'Layout configuration', + title4: 'news', + title5: 'Full screen on', + title6: 'Full screen off', + dropdownLarge: 'large', + dropdownDefault: 'default', + dropdownSmall: 'small', + dropdown1: 'home page', + dropdown2: 'Personal Center', + dropdown3: '404', + dropdown4: '401', + dropdown5: 'Log out', + dropdown6: 'Code warehouse', + searchPlaceholder: 'Menu search: support Chinese, routing path', + newTitle: 'notice', + newBtn: 'All read', + newGo: 'Go to the notification center', + newDesc: 'No notice', + logOutTitle: 'Tips', + logOutMessage: 'This operation will log out. Do you want to continue?', + logOutConfirm: 'determine', + logOutCancel: 'cancel', + logOutExit: 'Exiting', + }, + tagsView: { + refresh: 'refresh', + close: 'close', + closeOther: 'closeOther', + closeAll: 'closeAll', + fullscreen: 'fullscreen', + closeFullscreen: 'closeFullscreen', + }, + notFound: { + foundTitle: 'Wrong address input, please re-enter the address~', + foundMsg: 'You can check the web address first, and then re-enter or give us feedback.', + foundBtn: 'Back to home page', + }, + noAccess: { + accessTitle: 'You are not authorized to operate~', + accessMsg: 'Contact information: add QQ group discussion 665452019', + accessBtn: 'Reauthorization', + }, + layout: { + configTitle: 'Layout configuration', + oneTitle: 'Global Themes', + twoTopTitle: 'top bar set up', + twoMenuTitle: 'Menu set up', + twoColumnsTitle: 'Columns set up', + twoTopBar: 'Top bar background', + twoTopBarColor: 'Top bar default font color', + twoIsTopBarColorGradual: 'Top bar gradient', + twoMenuBar: 'Menu background', + twoMenuBarColor: 'Menu default font color', + twoIsMenuBarColorGradual: 'Menu gradient', + twoColumnsMenuBar: 'Column menu background', + twoColumnsMenuBarColor: 'Default font color bar menu', + twoIsColumnsMenuBarColorGradual: 'Column gradient', + threeTitle: 'Interface settings', + threeIsCollapse: 'Menu horizontal collapse', + threeIsUniqueOpened: 'Menu accordion', + threeIsFixedHeader: 'Fixed header', + threeIsClassicSplitMenu: 'Classic layout split menu', + threeIsLockScreen: 'Open the lock screen', + threeLockScreenTime: 'screen locking(s/s)', + fourTitle: 'Interface display', + fourIsShowLogo: 'Sidebar logo', + fourIsBreadcrumb: 'Open breadcrumb', + fourIsBreadcrumbIcon: 'Open breadcrumb icon', + fourIsTagsview: 'Open tagsview', + fourIsTagsviewIcon: 'Open tagsview Icon', + fourIsCacheTagsView: 'Enable tagsview cache', + fourIsSortableTagsView: 'Enable tagsview drag', + fourIsShareTagsView: 'Enable tagsview sharing', + fourIsFooter: 'Open footer', + fourIsGrayscale: 'Grey model', + fourIsInvert: 'Color weak mode', + fourIsDark: 'Dark Mode', + fourIsWartermark: 'Turn on watermark', + fourWartermarkText: 'Watermark copy', + fiveTitle: 'Other settings', + fiveTagsStyle: 'Tagsview style', + fiveAnimation: 'page animation', + fiveColumnsAsideStyle: 'Column style', + fiveColumnsAsideLayout: 'Column layout', + sixTitle: 'Layout switch', + sixDefaults: 'One', + sixClassic: 'Two', + sixTransverse: 'Three', + sixColumns: 'Four', + tipText: 'Click the button below to copy the layout configuration to `/src/stores/themeConfig.ts` It has been modified in.', + copyText: 'replication configuration', + resetText: 'restore default', + copyTextSuccess: 'Copy succeeded!', + copyTextError: 'Copy failed!', + }, +}; diff --git a/src/i18n/lang/zh-cn.ts b/src/i18n/lang/zh-cn.ts new file mode 100644 index 0000000..79ef328 --- /dev/null +++ b/src/i18n/lang/zh-cn.ts @@ -0,0 +1,180 @@ +// 定义内容 +export default { + router: { + home: '首页', + system: '系统设置', + systemMenu: '菜单管理', + systemRole: '角色管理', + systemUser: '用户管理', + systemDept: '部门管理', + systemDic: '字典管理', + limits: '权限管理', + limitsFrontEnd: '前端控制', + limitsFrontEndPage: '页面权限', + limitsFrontEndBtn: '按钮权限', + limitsBackEnd: '后端控制', + limitsBackEndEndPage: '页面权限', + menu: '菜单嵌套', + menu1: '菜单1', + menu11: '菜单11', + menu12: '菜单12', + menu121: '菜单121', + menu122: '菜单122', + menu13: '菜单13', + menu2: '菜单2', + funIndex: '功能', + funTagsView: 'tagsView 操作', + funCountup: '数字滚动', + funWangEditor: 'Editor 编辑器', + funCropper: '图片裁剪', + funQrcode: '二维码生成', + funEchartsMap: '地理坐标/地图', + funPrintJs: '页面打印', + funClipboard: '复制剪切', + funGridLayout: '拖拽布局', + funSplitpanes: '窗格拆分器', + funDragVerify: '验证器', + pagesIndex: '页面', + pagesFiltering: '过滤筛选组件', + pagesFilteringDetails: '过滤筛选组件详情', + pagesFilteringDetails1: '过滤筛选组件详情111', + pagesIocnfont: 'ali 字体图标', + pagesElement: 'ele 字体图标', + pagesAwesome: 'awe 字体图标', + pagesFormAdapt: '表单自适应', + pagesTableRules: '表单表格验证', + pagesFormI18n: '表单国际化', + pagesFormRules: '多表单验证', + pagesDynamicForm: '动态复杂表单', + pagesWorkflow: '工作流', + pagesListAdapt: '列表自适应', + pagesWaterfall: '瀑布屏', + pagesSteps: '步骤条', + pagesPreview: '大图预览', + pagesWaves: '波浪效果', + pagesTree: '树形改表格', + pagesDrag: '拖动指令', + pagesLazyImg: '图片懒加载', + makeIndex: '组件封装', + makeSelector: '图标选择器', + makeNoticeBar: '滚动通知栏', + makeSvgDemo: 'svgIcon 演示', + paramsIndex: '路由参数', + paramsCommon: '普通路由', + paramsDynamic: '动态路由', + paramsCommonDetails: '普通路由详情', + paramsDynamicDetails: '动态路由详情', + chartIndex: '大数据图表', + visualizingIndex: '数据可视化', + visualizingLinkDemo1: '数据可视化演示1', + visualizingLinkDemo2: '数据可视化演示2', + personal: '个人中心', + tools: '工具类集合', + layoutLinkView: '外链', + layoutIfameView: '内嵌 iframe', + }, + staticRoutes: { + signIn: '登录', + notFound: '找不到此页面', + noPower: '没有权限', + }, + user: { + title0: '组件大小', + title1: '语言切换', + title2: '菜单搜索', + title3: '布局配置', + title4: '消息', + title5: '开全屏', + title6: '关全屏', + dropdownLarge: '大型', + dropdownDefault: '默认', + dropdownSmall: '小型', + dropdown1: '首页', + dropdown2: '个人中心', + dropdown3: '404', + dropdown4: '401', + dropdown5: '退出登录', + dropdown6: '代码仓库', + searchPlaceholder: '菜单搜索:支持中文、路由路径', + newTitle: '通知', + newBtn: '全部已读', + newGo: '前往通知中心', + newDesc: '暂无通知', + logOutTitle: '提示', + logOutMessage: '此操作将退出登录, 是否继续?', + logOutConfirm: '确定', + logOutCancel: '取消', + logOutExit: '退出中', + }, + tagsView: { + refresh: '刷新', + close: '关闭', + closeOther: '关闭其它', + closeAll: '全部关闭', + fullscreen: '当前页全屏', + closeFullscreen: '关闭全屏', + }, + notFound: { + foundTitle: '地址输入错误,请重新输入地址~', + foundMsg: '您可以先检查网址,然后重新输入或给我们反馈问题。', + foundBtn: '返回首页', + }, + noAccess: { + accessTitle: '您未被授权,没有操作权限~', + accessMsg: '联系方式:加QQ群探讨 665452019', + accessBtn: '重新授权', + }, + layout: { + configTitle: '布局配置', + oneTitle: '全局主题', + twoTopTitle: '顶栏设置', + twoMenuTitle: '菜单设置', + twoColumnsTitle: '分栏设置', + twoTopBar: '顶栏背景', + twoTopBarColor: '顶栏默认字体颜色', + twoIsTopBarColorGradual: '顶栏背景渐变', + twoMenuBar: '菜单背景', + twoMenuBarColor: '菜单默认字体颜色', + twoIsMenuBarColorGradual: '菜单背景渐变', + twoColumnsMenuBar: '分栏菜单背景', + twoColumnsMenuBarColor: '分栏菜单默认字体颜色', + twoIsColumnsMenuBarColorGradual: '分栏菜单背景渐变', + threeTitle: '界面设置', + threeIsCollapse: '菜单水平折叠', + threeIsUniqueOpened: '菜单手风琴', + threeIsFixedHeader: '固定 Header', + threeIsClassicSplitMenu: '经典布局分割菜单', + threeIsLockScreen: '开启锁屏', + threeLockScreenTime: '自动锁屏(s/秒)', + fourTitle: '界面显示', + fourIsShowLogo: '侧边栏 Logo', + fourIsBreadcrumb: '开启 Breadcrumb', + fourIsBreadcrumbIcon: '开启 Breadcrumb 图标', + fourIsTagsview: '开启 Tagsview', + fourIsTagsviewIcon: '开启 Tagsview 图标', + fourIsCacheTagsView: '开启 TagsView 缓存', + fourIsSortableTagsView: '开启 TagsView 拖拽', + fourIsShareTagsView: '开启 TagsView 共用', + fourIsFooter: '开启 Footer', + fourIsGrayscale: '灰色模式', + fourIsInvert: '色弱模式', + fourIsDark: '深色模式', + fourIsWartermark: '开启水印', + fourWartermarkText: '水印文案', + fiveTitle: '其它设置', + fiveTagsStyle: 'Tagsview 风格', + fiveAnimation: '主页面切换动画', + fiveColumnsAsideStyle: '分栏高亮风格', + fiveColumnsAsideLayout: '分栏布局风格', + sixTitle: '布局切换', + sixDefaults: '默认', + sixClassic: '经典', + sixTransverse: '横向', + sixColumns: '分栏', + tipText: '点击下方按钮,复制布局配置去 `src/stores/themeConfig.ts` 中修改。', + copyText: '一键复制配置', + resetText: '一键恢复默认', + copyTextSuccess: '复制成功!', + copyTextError: '复制失败!', + }, +}; diff --git a/src/i18n/lang/zh-tw.ts b/src/i18n/lang/zh-tw.ts new file mode 100644 index 0000000..d900abb --- /dev/null +++ b/src/i18n/lang/zh-tw.ts @@ -0,0 +1,180 @@ +// 定义内容 +export default { + router: { + home: '首頁', + system: '系統設置', + systemMenu: '選單管理', + systemRole: '角色管理', + systemUser: '用戶管理', + systemDept: '部門管理', + systemDic: '字典管理', + limits: '許可權管理', + limitsFrontEnd: '前端控制', + limitsFrontEndPage: '頁面許可權', + limitsFrontEndBtn: '按鈕許可權', + limitsBackEnd: '後端控制', + limitsBackEndEndPage: '頁面許可權', + menu: '選單嵌套', + menu1: '選單1', + menu11: '選單11', + menu12: '選單12', + menu121: '選單121', + menu122: '選單122', + menu13: '選單13', + menu2: '選單2', + funIndex: '功能', + funTagsView: 'tagsView 操作', + funCountup: '數位滾動', + funWangEditor: 'Editor 編輯器', + funCropper: '圖片裁剪', + funQrcode: '二維碼生成', + funEchartsMap: '地理座標/地圖', + funPrintJs: '頁面列印', + funClipboard: '複製剪切', + funGridLayout: '拖拽佈局', + funSplitpanes: '窗格折開器', + funDragVerify: '驗證器', + pagesIndex: '頁面', + pagesFiltering: '過濾篩選組件', + pagesFilteringDetails: '過濾篩選組件詳情', + pagesFilteringDetails1: '過濾篩選組件詳情111', + pagesIocnfont: 'ali 字體圖標', + pagesElement: 'ele 字體圖標', + pagesAwesome: 'awe 字體圖標', + pagesFormAdapt: '表單自我調整', + pagesTableRules: '表單表格驗證', + pagesFormI18n: '表單國際化', + pagesFormRules: '多表單驗證', + pagesDynamicForm: '動態複雜表單', + pagesWorkflow: '工作流', + pagesListAdapt: '清單自我調整', + pagesWaterfall: '瀑布屏', + pagesSteps: '步驟條', + pagesPreview: '大圖預覽', + pagesWaves: '波浪效果', + pagesTree: '樹形改表格', + pagesDrag: '拖動指令', + pagesLazyImg: '圖片懶加載', + makeIndex: '組件封裝', + makeSelector: '圖標選擇器', + makeNoticeBar: '滾動通知欄', + makeSvgDemo: 'svgIcon 演示', + paramsIndex: '路由參數', + paramsCommon: '普通路由', + paramsDynamic: '動態路由', + paramsCommonDetails: '普通路由詳情', + paramsDynamicDetails: '動態路由詳情', + chartIndex: '大資料圖表', + visualizingIndex: '數據視覺化', + visualizingLinkDemo1: '數據視覺化演示1', + visualizingLinkDemo2: '數據視覺化演示2', + personal: '個人中心', + tools: '工具類集合', + layoutLinkView: '外鏈', + layoutIfameView: '内嵌 iframe', + }, + staticRoutes: { + signIn: '登入', + notFound: '找不到此頁面', + noPower: '沒有許可權', + }, + user: { + title0: '組件大小', + title1: '語言切換', + title2: '選單蒐索', + title3: '佈局配寘', + title4: '消息', + title5: '開全屏', + title6: '關全屏', + dropdownLarge: '大型', + dropdownDefault: '默認', + dropdownSmall: '小型', + dropdown1: '首頁', + dropdown2: '個人中心', + dropdown3: '404', + dropdown4: '401', + dropdown5: '登出', + dropdown6: '程式碼倉庫', + searchPlaceholder: '選單蒐索:支援中文、路由路徑', + newTitle: '通知', + newBtn: '全部已讀', + newGo: '前往通知中心', + newDesc: '暫無通知', + logOutTitle: '提示', + logOutMessage: '此操作將登出,是否繼續?', + logOutConfirm: '確定', + logOutCancel: '取消', + logOutExit: '退出中', + }, + tagsView: { + refresh: '重繪', + close: '關閉', + closeOther: '關閉其它', + closeAll: '全部關閉', + fullscreen: '當前頁全屏', + closeFullscreen: '關閉全屏', + }, + notFound: { + foundTitle: '地址輸入錯誤,請重新輸入地址~', + foundMsg: '您可以先檢查網址,然後重新輸入或給我們迴響問題。', + foundBtn: '返回首頁', + }, + noAccess: { + accessTitle: '您未被授權,沒有操作許可權~', + accessMsg: '聯繫方式:加QQ群探討665452019', + accessBtn: '重新授權', + }, + layout: { + configTitle: '佈局配寘', + oneTitle: '全域主題', + twoTopTitle: '頂欄設定', + twoMenuTitle: '選單設定', + twoColumnsTitle: '分欄設定', + twoTopBar: '頂欄背景', + twoTopBarColor: '頂欄默認字體顏色', + twoIsTopBarColorGradual: '頂欄背景漸變', + twoMenuBar: '選單背景', + twoMenuBarColor: '選單默認字體顏色', + twoIsMenuBarColorGradual: '選單背景漸變', + twoColumnsMenuBar: '分欄選單背景', + twoColumnsMenuBarColor: '分欄選單默認字體顏色', + twoIsColumnsMenuBarColorGradual: '分欄選單背景漸變', + threeTitle: '介面設定', + threeIsCollapse: '選單水准折疊', + threeIsUniqueOpened: '選單手風琴', + threeIsFixedHeader: '固定 Header', + threeIsClassicSplitMenu: '經典佈局分割選單', + threeIsLockScreen: '開啟鎖屏', + threeLockScreenTime: '自動鎖屏(s/秒)', + fourTitle: '介面顯示', + fourIsShowLogo: '側邊欄 Logo', + fourIsBreadcrumb: '開啟 Breadcrumb', + fourIsBreadcrumbIcon: '開啟 Breadcrumb 圖標', + fourIsTagsview: '開啟 Tagsview', + fourIsTagsviewIcon: '開啟 Tagsview 圖標', + fourIsCacheTagsView: '開啟 TagsView 緩存', + fourIsSortableTagsView: '開啟 TagsView 拖拽', + fourIsShareTagsView: '開啟 TagsView 共用', + fourIsFooter: '開啟 Footer', + fourIsGrayscale: '灰色模式', + fourIsInvert: '色弱模式', + fourIsDark: '深色模式', + fourIsWartermark: '開啟浮水印', + fourWartermarkText: '浮水印文案', + fiveTitle: '其它設定', + fiveTagsStyle: 'Tagsview 風格', + fiveAnimation: '主頁面切換動畫', + fiveColumnsAsideStyle: '分欄高亮風格', + fiveColumnsAsideLayout: '分欄佈局風格', + sixTitle: '佈局切換', + sixDefaults: '默認', + sixClassic: '經典', + sixTransverse: '橫向', + sixColumns: '分欄', + tipText: '點擊下方按鈕,複製佈局配寘去`src/stores/themeConfig.ts`中修改。', + copyText: '一鍵複製配寘', + resetText: '一鍵恢復默認', + copyTextSuccess: '複製成功!', + copyTextError: '複製失敗!', + }, +}; diff --git a/src/i18n/pages/formI18n/en.ts b/src/i18n/pages/formI18n/en.ts new file mode 100644 index 0000000..b3c54d6 --- /dev/null +++ b/src/i18n/pages/formI18n/en.ts @@ -0,0 +1,13 @@ +// 定义内容 +export default { + formI18nLabel: { + name: 'name', + email: 'email', + autograph: 'autograph', + }, + formI18nPlaceholder: { + name: 'Please enter your name', + email: 'Please enter the users Department', + autograph: 'Please enter the login account name', + }, +}; diff --git a/src/i18n/pages/formI18n/zh-cn.ts b/src/i18n/pages/formI18n/zh-cn.ts new file mode 100644 index 0000000..0bed3ec --- /dev/null +++ b/src/i18n/pages/formI18n/zh-cn.ts @@ -0,0 +1,13 @@ +// 定义内容 +export default { + formI18nLabel: { + name: '姓名', + email: '用户归属部门', + autograph: '登陆账户名', + }, + formI18nPlaceholder: { + name: '请输入姓名', + email: '请输入用户归属部门', + autograph: '请输入登陆账户名', + }, +}; diff --git a/src/i18n/pages/formI18n/zh-tw.ts b/src/i18n/pages/formI18n/zh-tw.ts new file mode 100644 index 0000000..393ac03 --- /dev/null +++ b/src/i18n/pages/formI18n/zh-tw.ts @@ -0,0 +1,13 @@ +// 定义内容 +export default { + formI18nLabel: { + name: '姓名', + email: '用戶歸屬部門', + autograph: '登入帳戶名', + }, + formI18nPlaceholder: { + name: '請輸入姓名', + email: '請輸入用戶歸屬部門', + autograph: '請輸入登入帳戶名', + }, +}; diff --git a/src/i18n/pages/login/en.ts b/src/i18n/pages/login/en.ts new file mode 100644 index 0000000..2654a18 --- /dev/null +++ b/src/i18n/pages/login/en.ts @@ -0,0 +1,29 @@ +// 定义内容 +export default { + label: { + one1: 'User name login', + two2: 'Mobile number', + }, + link: { + one3: 'Third party login', + two4: 'Links', + }, + account: { + accountPlaceholder1: 'The user name admin or not is common', + accountPlaceholder2: 'Password: 123456', + accountPlaceholder3: 'Please enter the verification code', + accountBtnText: 'Sign in', + }, + mobile: { + placeholder1: 'Please input mobile phone number', + placeholder2: 'Please enter the verification code', + codeText: 'Get code', + btnText: 'Sign in', + msgText: + 'Warm tip: it is recommended to use Google, Microsoft edge, version 79.0.1072.62 and above browsers, and 360 browser, please use speed mode', + }, + scan: { + text: 'Open the mobile phone to scan and quickly log in / register', + }, + signInText: 'welcome back!', +}; diff --git a/src/i18n/pages/login/zh-cn.ts b/src/i18n/pages/login/zh-cn.ts new file mode 100644 index 0000000..3367b53 --- /dev/null +++ b/src/i18n/pages/login/zh-cn.ts @@ -0,0 +1,28 @@ +// 定义内容 +export default { + label: { + one1: '用户名登录', + two2: '手机号登录', + }, + link: { + one3: '第三方登录', + two4: '友情链接', + }, + account: { + accountPlaceholder1: '用户名 admin 或不输均为 common', + accountPlaceholder2: '密码:123456', + accountPlaceholder3: '请输入验证码', + accountBtnText: '登 录', + }, + mobile: { + placeholder1: '请输入手机号', + placeholder2: '请输入验证码', + codeText: '获取验证码', + btnText: '登 录', + msgText: '* 温馨提示:建议使用谷歌、Microsoft Edge,版本 79.0.1072.62 及以上浏览器,360浏览器请使用极速模式', + }, + scan: { + text: '打开手机扫一扫,快速登录/注册', + }, + signInText: '欢迎回来!', +}; diff --git a/src/i18n/pages/login/zh-tw.ts b/src/i18n/pages/login/zh-tw.ts new file mode 100644 index 0000000..138e8c8 --- /dev/null +++ b/src/i18n/pages/login/zh-tw.ts @@ -0,0 +1,28 @@ +// 定义内容 +export default { + label: { + one1: '用戶名登入', + two2: '手機號登入', + }, + link: { + one3: '協力廠商登入', + two4: '友情連結', + }, + account: { + accountPlaceholder1: '用戶名admin或不輸均為common', + accountPlaceholder2: '密碼:123456', + accountPlaceholder3: '請輸入驗證碼', + accountBtnText: '登入', + }, + mobile: { + placeholder1: '請輸入手機號', + placeholder2: '請輸入驗證碼', + codeText: '獲取驗證碼', + btnText: '登入', + msgText: '* 溫馨提示:建議使用穀歌、Microsoft Edge,版本79.0.1072.62及以上瀏覽器,360瀏覽器請使用極速模式', + }, + scan: { + text: '打開手機掃一掃,快速登錄/注册', + }, + signInText: '歡迎回來!', +}; diff --git a/src/layout/component/aside.vue b/src/layout/component/aside.vue new file mode 100644 index 0000000..d4ee363 --- /dev/null +++ b/src/layout/component/aside.vue @@ -0,0 +1,163 @@ +<template> + <div class="h100" v-show="!isTagsViewCurrenFull"> + <el-aside class="layout-aside" :class="setCollapseStyle"> + <Logo v-if="setShowLogo" /> + <el-scrollbar class="flex-auto" ref="layoutAsideScrollbarRef" @mouseenter="onAsideEnterLeave(true)" @mouseleave="onAsideEnterLeave(false)"> + <Vertical :menuList="menuList" /> + </el-scrollbar> + </el-aside> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, computed, watch, getCurrentInstance, onBeforeMount, defineComponent } from 'vue'; +import { storeToRefs } from 'pinia'; +import pinia from '/@/stores/index'; +import { useRoutesList } from '/@/stores/routesList'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; +import Logo from '/@/layout/logo/index.vue'; +import Vertical from '/@/layout/navMenu/vertical.vue'; + +export default defineComponent({ + name: 'layoutAside', + components: { Logo, Vertical }, + setup() { + const { proxy } = <any>getCurrentInstance(); + const stores = useRoutesList(); + const storesThemeConfig = useThemeConfig(); + const storesTagsViewRoutes = useTagsViewRoutes(); + const { routesList } = storeToRefs(stores); + const { themeConfig } = storeToRefs(storesThemeConfig); + const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes); + const state = reactive({ + menuList: [], + clientWidth: 0, + }); + // 设置菜单展开/收起时的宽度 + const setCollapseStyle = computed(() => { + const { layout, isCollapse, menuBar } = themeConfig.value; + const asideBrTheme = ['#FFFFFF', '#FFF', '#fff', '#ffffff']; + const asideBrColor = asideBrTheme.includes(menuBar) ? 'layout-el-aside-br-color' : ''; + // 判断是否是手机端 + if (state.clientWidth <= 1000) { + if (isCollapse) { + document.body.setAttribute('class', 'el-popup-parent--hidden'); + const asideEle = document.querySelector('.layout-container') as HTMLElement; + const modeDivs = document.createElement('div'); + modeDivs.setAttribute('class', 'layout-aside-mobile-mode'); + asideEle.appendChild(modeDivs); + modeDivs.addEventListener('click', closeLayoutAsideMobileMode); + return [asideBrColor, 'layout-aside-mobile', 'layout-aside-mobile-open']; + } else { + // 关闭弹窗 + closeLayoutAsideMobileMode(); + return [asideBrColor, 'layout-aside-mobile', 'layout-aside-mobile-close']; + } + } else { + if (layout === 'columns') { + // 分栏布局,菜单收起时宽度给 1px + if (isCollapse) return [asideBrColor, 'layout-aside-pc-1']; + else return [asideBrColor, 'layout-aside-pc-220']; + } else { + // 其它布局给 64px + if (isCollapse) return [asideBrColor, 'layout-aside-pc-64']; + else return [asideBrColor, 'layout-aside-pc-220']; + } + } + }); + // 关闭移动端蒙版 + const closeLayoutAsideMobileMode = () => { + const el = document.querySelector('.layout-aside-mobile-mode'); + el?.setAttribute('style', 'animation: error-img-two 0.3s'); + setTimeout(() => { + el?.parentNode?.removeChild(el); + }, 300); + const clientWidth = document.body.clientWidth; + if (clientWidth < 1000) themeConfig.value.isCollapse = false; + document.body.setAttribute('class', ''); + }; + // 设置显示/隐藏 logo + const setShowLogo = computed(() => { + let { layout, isShowLogo } = themeConfig.value; + return (isShowLogo && layout === 'defaults') || (isShowLogo && layout === 'columns'); + }); + // 设置/过滤路由(非静态路由/是否显示在菜单中) + const setFilterRoutes = () => { + if (themeConfig.value.layout === 'columns') return false; + (state.menuList as any) = filterRoutesFun(routesList.value); + }; + // 路由过滤递归函数 + const filterRoutesFun = (arr: Array<string>) => { + return arr + .filter((item: any) => !item.meta.isHide) + .map((item: any) => { + item = Object.assign({}, item); + if (item.children) item.children = filterRoutesFun(item.children); + return item; + }); + }; + // 设置菜单导航是否固定(移动端) + const initMenuFixed = (clientWidth: number) => { + state.clientWidth = clientWidth; + }; + // 鼠标移入、移出 + const onAsideEnterLeave = (bool: Boolean) => { + let { layout } = themeConfig.value; + if (layout !== 'columns') return false; + if (!bool) proxy.mittBus.emit('restoreDefault'); + stores.setColumnsMenuHover(bool); + }; + // 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度 + watch(themeConfig.value, (val) => { + if (val.isShowLogoChange !== val.isShowLogo) { + if (!proxy.$refs.layoutAsideScrollbarRef) return false; + proxy.$refs.layoutAsideScrollbarRef.update(); + } + }); + // 监听vuex值的变化,动态赋值给菜单中 + watch( + pinia.state, + (val) => { + let { layout, isClassicSplitMenu } = val.themeConfig.themeConfig; + if (layout === 'classic' && isClassicSplitMenu) return false; + setFilterRoutes(); + }, + { + deep: true, + } + ); + // 页面加载前 + onBeforeMount(() => { + initMenuFixed(document.body.clientWidth); + setFilterRoutes(); + // 此界面不需要取消监听(proxy.mittBus.off('setSendColumnsChildren)) + // 因为切换布局时有的监听需要使用,取消了监听,某些操作将不生效 + proxy.mittBus.on('setSendColumnsChildren', (res: any) => { + state.menuList = res.children; + }); + proxy.mittBus.on('setSendClassicChildren', (res: any) => { + let { layout, isClassicSplitMenu } = themeConfig.value; + if (layout === 'classic' && isClassicSplitMenu) { + state.menuList = []; + state.menuList = res.children; + } + }); + proxy.mittBus.on('getBreadcrumbIndexSetFilterRoutes', () => { + setFilterRoutes(); + }); + proxy.mittBus.on('layoutMobileResize', (res: any) => { + initMenuFixed(res.clientWidth); + closeLayoutAsideMobileMode(); + }); + }); + return { + setCollapseStyle, + setShowLogo, + isTagsViewCurrenFull, + onAsideEnterLeave, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/layout/component/columnsAside.vue b/src/layout/component/columnsAside.vue new file mode 100644 index 0000000..7fd7806 --- /dev/null +++ b/src/layout/component/columnsAside.vue @@ -0,0 +1,292 @@ +<template> + <div class="layout-columns-aside"> + <el-scrollbar> + <ul @mouseleave="onColumnsAsideMenuMouseleave()"> + <li + v-for="(v, k) in columnsAsideList" + :key="k" + @click="onColumnsAsideMenuClick(v, k)" + @mouseenter="onColumnsAsideMenuMouseenter(v, k)" + :ref=" + (el) => { + if (el) columnsAsideOffsetTopRefs[k] = el; + } + " + :class="{ 'layout-columns-active': liIndex === k, 'layout-columns-hover': liHoverIndex === k }" + :title="$t(v.meta.title)" + > + <div :class="themeConfig.columnsAsideLayout" v-if="!v.meta.isLink || (v.meta.isLink && v.meta.isIframe)"> + <SvgIcon :name="v.meta.icon" /> + <div class="columns-vertical-title font12"> + {{ + $t(v.meta.title) && $t(v.meta.title).length >= 4 + ? $t(v.meta.title).substr(0, themeConfig.columnsAsideLayout === 'columns-vertical' ? 4 : 3) + : $t(v.meta.title) + }} + </div> + </div> + <div :class="themeConfig.columnsAsideLayout" v-else> + <a :href="v.meta.isLink" target="_blank"> + <SvgIcon :name="v.meta.icon" /> + <div class="columns-vertical-title font12"> + {{ + $t(v.meta.title) && $t(v.meta.title).length >= 4 + ? $t(v.meta.title).substr(0, themeConfig.columnsAsideLayout === 'columns-vertical' ? 4 : 3) + : $t(v.meta.title) + }} + </div> + </a> + </div> + </li> + <div ref="columnsAsideActiveRef" :class="themeConfig.columnsAsideStyle"></div> + </ul> + </el-scrollbar> + </div> +</template> + +<script lang="ts"> +import { reactive, toRefs, ref, onMounted, nextTick, getCurrentInstance, watch, onUnmounted, defineComponent } from 'vue'; +import { useRoute, useRouter, onBeforeRouteUpdate, RouteRecordRaw } from 'vue-router'; +import { storeToRefs } from 'pinia'; +import pinia from '/@/stores/index'; +import { useRoutesList } from '/@/stores/routesList'; +import { useThemeConfig } from '/@/stores/themeConfig'; + +// 定义接口来定义对象的类型 +interface ColumnsAsideState { + columnsAsideList: any[]; + liIndex: number; + liOldIndex: null | number; + liHoverIndex: null | number; + liOldPath: null | string; + difference: number; + routeSplit: string[]; +} + +export default defineComponent({ + name: 'layoutColumnsAside', + setup() { + const columnsAsideOffsetTopRefs: any = ref([]); + const columnsAsideActiveRef = ref(); + const { proxy } = <any>getCurrentInstance(); + const stores = useRoutesList(); + const storesThemeConfig = useThemeConfig(); + const { routesList, isColumnsMenuHover, isColumnsNavHover } = storeToRefs(stores); + const { themeConfig } = storeToRefs(storesThemeConfig); + const route = useRoute(); + const router = useRouter(); + const state = reactive<ColumnsAsideState>({ + columnsAsideList: [], + liIndex: 0, + liOldIndex: null, + liHoverIndex: null, + liOldPath: null, + difference: 0, + routeSplit: [], + }); + // 设置菜单高亮位置移动 + const setColumnsAsideMove = (k: number) => { + state.liIndex = k; + columnsAsideActiveRef.value.style.top = `${columnsAsideOffsetTopRefs.value[k].offsetTop + state.difference}px`; + }; + // 菜单高亮点击事件 + const onColumnsAsideMenuClick = (v: Object, k: number) => { + setColumnsAsideMove(k); + let { path, redirect } = v as any; + if (redirect) router.push(redirect); + else router.push(path); + }; + // 鼠标移入时,显示当前的子级菜单 + const onColumnsAsideMenuMouseenter = (v: RouteRecordRaw, k: number) => { + let { path } = v; + state.liOldPath = path; + state.liOldIndex = k; + state.liHoverIndex = k; + proxy.mittBus.emit('setSendColumnsChildren', setSendChildren(path)); + stores.setColumnsMenuHover(false); + stores.setColumnsNavHover(true); + }; + // 鼠标移走时,显示原来的子级菜单 + const onColumnsAsideMenuMouseleave = async () => { + await stores.setColumnsNavHover(false); + // 添加延时器,防止拿到的 store.state.routesList 值不是最新的 + setTimeout(() => { + if (!isColumnsMenuHover && !isColumnsNavHover) proxy.mittBus.emit('restoreDefault'); + }, 100); + }; + // 设置高亮动态位置 + const onColumnsAsideDown = (k: number) => { + nextTick(() => { + setColumnsAsideMove(k); + }); + }; + // 设置/过滤路由(非静态路由/是否显示在菜单中) + const setFilterRoutes = () => { + state.columnsAsideList = filterRoutesFun(routesList.value); + const resData: any = setSendChildren(route.path); + if (Object.keys(resData).length <= 0) return false; + onColumnsAsideDown(resData.item[0].k); + proxy.mittBus.emit('setSendColumnsChildren', resData); + }; + // 传送当前子级数据到菜单中 + const setSendChildren = (path: string) => { + const currentPathSplit = path.split('/'); + let currentData: any = {}; + state.columnsAsideList.map((v: any, k: number) => { + if (v.path === `/${currentPathSplit[1]}`) { + v['k'] = k; + currentData['item'] = [{ ...v }]; + currentData['children'] = [{ ...v }]; + if (v.children) currentData['children'] = v.children; + } + }); + return currentData; + }; + // 路由过滤递归函数 + const filterRoutesFun = (arr: Array<string>) => { + return arr + .filter((item: any) => !item.meta.isHide) + .map((item: any) => { + item = Object.assign({}, item); + if (item.children) item.children = filterRoutesFun(item.children); + return item; + }); + }; + // tagsView 点击时,根据路由查找下标 columnsAsideList,实现左侧菜单高亮 + const setColumnsMenuHighlight = (path: string) => { + state.routeSplit = path.split('/'); + state.routeSplit.shift(); + const routeFirst = `/${state.routeSplit[0]}`; + const currentSplitRoute = state.columnsAsideList.find((v: any) => v.path === routeFirst); + if (!currentSplitRoute) return false; + // 延迟拿值,防止取不到 + setTimeout(() => { + onColumnsAsideDown((<any>currentSplitRoute).k); + }, 0); + }; + // 监听布局配置信息的变化,动态增加菜单高亮位置移动像素 + watch( + pinia.state, + (val) => { + val.themeConfig.themeConfig.columnsAsideStyle === 'columnsRound' ? (state.difference = 3) : (state.difference = 0); + if (!val.routesList.isColumnsMenuHover && !val.routesList.isColumnsNavHover) { + state.liHoverIndex = null; + proxy.mittBus.emit('setSendColumnsChildren', setSendChildren(route.path)); + } else { + state.liHoverIndex = state.liOldIndex; + if (!state.liOldPath) return false; + proxy.mittBus.emit('setSendColumnsChildren', setSendChildren(state.liOldPath)); + } + }, + { + deep: true, + } + ); + // 页面加载时 + onMounted(() => { + setFilterRoutes(); + // 销毁变量,防止鼠标再次移入时,保留了上次的记录 + proxy.mittBus.on('restoreDefault', () => { + state.liOldIndex = null; + state.liOldPath = null; + }); + }); + // 页面卸载时 + onUnmounted(() => { + proxy.mittBus.off('restoreDefault', () => {}); + }); + // 路由更新时 + onBeforeRouteUpdate((to) => { + setColumnsMenuHighlight(to.path); + proxy.mittBus.emit('setSendColumnsChildren', setSendChildren(to.path)); + }); + return { + themeConfig, + columnsAsideOffsetTopRefs, + columnsAsideActiveRef, + onColumnsAsideDown, + onColumnsAsideMenuClick, + onColumnsAsideMenuMouseenter, + onColumnsAsideMenuMouseleave, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.layout-columns-aside { + width: 70px; + height: 100%; + background: var(--next-bg-columnsMenuBar); + ul { + position: relative; + li { + color: var(--next-bg-columnsMenuBarColor); + width: 100%; + height: 50px; + text-align: center; + display: flex; + cursor: pointer; + position: relative; + z-index: 1; + .columns-vertical { + margin: auto; + .columns-vertical-title { + padding-top: 1px; + } + } + .columns-horizontal { + display: flex; + height: 50px; + width: 100%; + align-items: center; + padding: 0 5px; + i { + margin-right: 3px; + } + a { + display: flex; + .columns-horizontal-title { + padding-top: 1px; + } + } + } + a { + text-decoration: none; + color: var(--next-bg-columnsMenuBarColor); + } + } + .layout-columns-active { + color: var(--next-bg-columnsMenuBarColor) !important; + transition: 0.3s ease-in-out; + } + .layout-columns-hover { + color: var(--el-color-primary); + a { + color: var(--el-color-primary); + } + } + .columns-round { + background: var(--el-color-primary); + color: var(--el-color-white); + position: absolute; + left: 50%; + top: 2px; + height: 44px; + width: 65px; + transform: translateX(-50%); + z-index: 0; + transition: 0.3s ease-in-out; + border-radius: 5px; + } + .columns-card { + @extend .columns-round; + top: 0; + height: 50px; + width: 100%; + border-radius: 0; + } + } +} +</style> diff --git a/src/layout/component/header.vue b/src/layout/component/header.vue new file mode 100644 index 0000000..21c9e2d --- /dev/null +++ b/src/layout/component/header.vue @@ -0,0 +1,34 @@ +<template> + <el-header class="layout-header" :height="setHeaderHeight" v-show="!isTagsViewCurrenFull"> + <NavBarsIndex /> + </el-header> +</template> + +<script lang="ts"> +import { computed, defineComponent } from 'vue'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; +import NavBarsIndex from '/@/layout/navBars/index.vue'; + +export default defineComponent({ + name: 'layoutHeader', + components: { NavBarsIndex }, + setup() { + const storesTagsViewRoutes = useTagsViewRoutes(); + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes); + // 设置 header 的高度 + const setHeaderHeight = computed(() => { + let { isTagsview, layout } = themeConfig.value; + if (isTagsview && layout !== 'classic') return '84px'; + else return '50px'; + }); + return { + setHeaderHeight, + isTagsViewCurrenFull, + }; + }, +}); +</script> diff --git a/src/layout/component/main.vue b/src/layout/component/main.vue new file mode 100644 index 0000000..18eba60 --- /dev/null +++ b/src/layout/component/main.vue @@ -0,0 +1,101 @@ +<template> + <el-main class="layout-main"> + <el-scrollbar + ref="layoutScrollbarRef" + :class="{ + 'layout-scrollbar': + (!isClassicOrTransverse && !currentRouteMeta.isLink && !currentRouteMeta.isIframe) || + (!isClassicOrTransverse && currentRouteMeta.isLink && !currentRouteMeta.isIframe), + }" + > + <LayoutParentView + :style="{ + padding: !isClassicOrTransverse || (currentRouteMeta.isLink && currentRouteMeta.isIframe) ? '0' : '15px', + transition: 'padding 0.3s ease-in-out', + }" + /> + <Footer v-if="themeConfig.isFooter" /> + </el-scrollbar> + </el-main> +</template> + +<script lang="ts"> +import { defineComponent, toRefs, reactive, getCurrentInstance, watch, onMounted, computed } from 'vue'; +import { useRoute } from 'vue-router'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { NextLoading } from '/@/utils/loading'; +import LayoutParentView from '/@/layout/routerView/parent.vue'; +import Footer from '/@/layout/footer/index.vue'; + +// 定义接口来定义对象的类型 +interface MainState { + headerHeight: string | number; + currentRouteMeta: any; +} + +export default defineComponent({ + name: 'layoutMain', + components: { LayoutParentView, Footer }, + setup() { + const { proxy } = <any>getCurrentInstance(); + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const route = useRoute(); + const state = reactive<MainState>({ + headerHeight: '', + currentRouteMeta: {}, + }); + // 判断布局 + const isClassicOrTransverse = computed(() => { + const { layout } = themeConfig.value; + return layout === 'classic' || layout === 'transverse'; + }); + // 设置 main 的高度 + const initHeaderHeight = () => { + const bool = state.currentRouteMeta.isLink && state.currentRouteMeta.isIframe; + let { isTagsview } = themeConfig.value; + if (isTagsview) return (state.headerHeight = bool ? `86px` : `115px`); + else return (state.headerHeight = `80px`); + }; + // 初始化获取当前路由 meta,用于设置 iframes padding + const initGetMeta = () => { + state.currentRouteMeta = route.meta; + }; + // 页面加载前 + onMounted(async () => { + await initGetMeta(); + initHeaderHeight(); + NextLoading.done(); + }); + // 监听路由变化 + watch( + () => route.path, + () => { + state.currentRouteMeta = route.meta; + const bool = state.currentRouteMeta.isLink && state.currentRouteMeta.isIframe; + state.headerHeight = bool ? `86px` : `115px`; + proxy.$refs.layoutScrollbarRef.update(); + } + ); + // 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度 + watch( + themeConfig, + (val) => { + state.currentRouteMeta = route.meta; + const bool = state.currentRouteMeta.isLink && state.currentRouteMeta.isIframe; + state.headerHeight = val.isTagsview ? (bool ? `86px` : `115px`) : '51px'; + proxy.$refs?.layoutScrollbarRef?.update(); + }, + { + deep: true, + } + ); + return { + themeConfig, + isClassicOrTransverse, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/layout/footer/index.vue b/src/layout/footer/index.vue new file mode 100644 index 0000000..ef00591 --- /dev/null +++ b/src/layout/footer/index.vue @@ -0,0 +1,47 @@ +<template> + <div class="layout-footer mt15" v-show="isDelayFooter"> + <div class="layout-footer-warp"> + <div>vue-next-admin,Made by lyt with ❤️</div> + <div class="mt5">深圳市 xxx 公司版权所有</div> + </div> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent } from 'vue'; +import { onBeforeRouteUpdate } from 'vue-router'; + +export default defineComponent({ + name: 'layoutFooter', + setup() { + const state = reactive({ + isDelayFooter: true, + }); + // 路由改变时,等主界面动画加载完毕再显示 footer + onBeforeRouteUpdate(() => { + setTimeout(() => { + state.isDelayFooter = false; + setTimeout(() => { + state.isDelayFooter = true; + }, 800); + }, 0); + }); + return { + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.layout-footer { + width: 100%; + display: flex; + &-warp { + margin: auto; + color: var(--el-text-color-secondary); + text-align: center; + animation: error-num 1s ease-in-out; + } +} +</style> diff --git a/src/layout/index.vue b/src/layout/index.vue new file mode 100644 index 0000000..50643a4 --- /dev/null +++ b/src/layout/index.vue @@ -0,0 +1,54 @@ +<template> + <component :is="themeConfig.layout" /> +</template> + +<script lang="ts"> +import { onBeforeMount, onUnmounted, getCurrentInstance, defineComponent, defineAsyncComponent } from 'vue'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { Local } from '/@/utils/storage'; + +export default defineComponent({ + name: 'layout', + components: { + defaults: defineAsyncComponent(() => import('/@/layout/main/defaults.vue')), + classic: defineAsyncComponent(() => import('/@/layout/main/classic.vue')), + transverse: defineAsyncComponent(() => import('/@/layout/main/transverse.vue')), + columns: defineAsyncComponent(() => import('/@/layout/main/columns.vue')), + }, + setup() { + const { proxy } = <any>getCurrentInstance(); + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + // 窗口大小改变时(适配移动端) + const onLayoutResize = () => { + if (!Local.get('oldLayout')) Local.set('oldLayout', themeConfig.value.layout); + const clientWidth = document.body.clientWidth; + if (clientWidth < 1000) { + themeConfig.value.isCollapse = false; + proxy.mittBus.emit('layoutMobileResize', { + layout: 'defaults', + clientWidth, + }); + } else { + proxy.mittBus.emit('layoutMobileResize', { + layout: Local.get('oldLayout') ? Local.get('oldLayout') : themeConfig.value.layout, + clientWidth, + }); + } + }; + // 页面加载前 + onBeforeMount(() => { + onLayoutResize(); + window.addEventListener('resize', onLayoutResize); + }); + // 页面卸载时 + onUnmounted(() => { + window.removeEventListener('resize', onLayoutResize); + }); + return { + themeConfig, + }; + }, +}); +</script> diff --git a/src/layout/lockScreen/index.vue b/src/layout/lockScreen/index.vue new file mode 100644 index 0000000..10b8fed --- /dev/null +++ b/src/layout/lockScreen/index.vue @@ -0,0 +1,372 @@ +<template> + <div v-show="isShowLockScreen"> + <div class="layout-lock-screen-mask"></div> + <div class="layout-lock-screen-img" :class="{ 'layout-lock-screen-filter': isShowLoockLogin }"></div> + <div class="layout-lock-screen"> + <div + class="layout-lock-screen-date" + ref="layoutLockScreenDateRef" + @mousedown="onDown" + @mousemove="onMove" + @mouseup="onEnd" + @touchstart.stop="onDown" + @touchmove.stop="onMove" + @touchend.stop="onEnd" + > + <div class="layout-lock-screen-date-box"> + <div class="layout-lock-screen-date-box-time"> + {{ time.hm }}<span class="layout-lock-screen-date-box-minutes">{{ time.s }}</span> + </div> + <div class="layout-lock-screen-date-box-info">{{ time.mdq }}</div> + </div> + <div class="layout-lock-screen-date-top"> + <SvgIcon name="ele-Top" /> + <div class="layout-lock-screen-date-top-text">上滑解锁</div> + </div> + </div> + <transition name="el-zoom-in-center"> + <div v-show="isShowLoockLogin" class="layout-lock-screen-login"> + <div class="layout-lock-screen-login-box"> + <div class="layout-lock-screen-login-box-img"> + <img src="https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1813762643,1914315241&fm=26&gp=0.jpg" /> + </div> + <div class="layout-lock-screen-login-box-name">Administrator</div> + <div class="layout-lock-screen-login-box-value"> + <el-input + placeholder="请输入密码" + ref="layoutLockScreenInputRef" + v-model="lockScreenPassword" + @keyup.enter.native.stop="onLockScreenSubmit()" + > + <template #append> + <el-button @click="onLockScreenSubmit"> + <el-icon class="el-input__icon"> + <ele-Right /> + </el-icon> + </el-button> + </template> + </el-input> + </div> + </div> + <div class="layout-lock-screen-login-icon"> + <SvgIcon name="ele-Microphone" :size="20" /> + <SvgIcon name="ele-AlarmClock" :size="20" /> + <SvgIcon name="ele-SwitchButton" :size="20" /> + </div> + </div> + </transition> + </div> + </div> +</template> + +<script lang="ts"> +import { nextTick, onMounted, reactive, toRefs, ref, onUnmounted, getCurrentInstance, defineComponent } from 'vue'; +import { formatDate } from '/@/utils/formatTime'; +import { Local } from '/@/utils/storage'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; + +// 定义接口来定义对象的类型 +interface LockScreenState { + transparency: number; + downClientY: number; + moveDifference: number; + isShowLoockLogin: boolean; + isFlags: boolean; + querySelectorEl: HTMLElement | string; + time: { + hm: string; + s: string; + mdq: string; + }; + setIntervalTime: number; + isShowLockScreen: boolean; + isShowLockScreenIntervalTime: number; + lockScreenPassword: string; +} + +export default defineComponent({ + name: 'layoutLockScreen', + setup() { + const { proxy } = <any>getCurrentInstance(); + const layoutLockScreenInputRef = ref(); + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const state = reactive<LockScreenState>({ + transparency: 1, + downClientY: 0, + moveDifference: 0, + isShowLoockLogin: false, + isFlags: false, + querySelectorEl: '', + time: { + hm: '', + s: '', + mdq: '', + }, + setIntervalTime: 0, + isShowLockScreen: false, + isShowLockScreenIntervalTime: 0, + lockScreenPassword: '', + }); + // 鼠标按下 + const onDown = (down: any) => { + state.isFlags = true; + state.downClientY = down.touches ? down.touches[0].clientY : down.clientY; + }; + // 鼠标移动 + const onMove = (move: any) => { + if (state.isFlags) { + const el = <HTMLElement>state.querySelectorEl; + const opacitys = (state.transparency -= 1 / 200); + if (move.touches) { + state.moveDifference = move.touches[0].clientY - state.downClientY; + } else { + state.moveDifference = move.clientY - state.downClientY; + } + if (state.moveDifference >= 0) return false; + el.setAttribute('style', `top:${state.moveDifference}px;cursor:pointer;opacity:${opacitys};`); + if (state.moveDifference < -400) { + el.setAttribute('style', `top:${-el.clientHeight}px;cursor:pointer;transition:all 0.3s ease;`); + state.moveDifference = -el.clientHeight; + setTimeout(() => { + el && el.parentNode?.removeChild(el); + }, 300); + } + if (state.moveDifference === -el.clientHeight) { + state.isShowLoockLogin = true; + layoutLockScreenInputRef.value.focus(); + } + } + }; + // 鼠标松开 + const onEnd = () => { + state.isFlags = false; + state.transparency = 1; + if (state.moveDifference >= -400) { + (<HTMLElement>state.querySelectorEl).setAttribute('style', `top:0px;opacity:1;transition:all 0.3s ease;`); + } + }; + // 获取要拖拽的初始元素 + const initGetElement = () => { + nextTick(() => { + state.querySelectorEl = proxy.$refs.layoutLockScreenDateRef; + }); + }; + // 时间初始化 + const initTime = () => { + state.time.hm = formatDate(new Date(), 'HH:MM'); + state.time.s = formatDate(new Date(), 'SS'); + state.time.mdq = formatDate(new Date(), 'mm月dd日,WWW'); + }; + // 时间初始化定时器 + const initSetTime = () => { + initTime(); + state.setIntervalTime = window.setInterval(() => { + initTime(); + }, 1000); + }; + // 锁屏时间定时器 + const initLockScreen = () => { + if (themeConfig.value.isLockScreen) { + state.isShowLockScreenIntervalTime = window.setInterval(() => { + if (themeConfig.value.lockScreenTime <= 1) { + state.isShowLockScreen = true; + setLocalThemeConfig(); + return false; + } + themeConfig.value.lockScreenTime--; + }, 1000); + } else { + clearInterval(state.isShowLockScreenIntervalTime); + } + }; + // 存储布局配置 + const setLocalThemeConfig = () => { + themeConfig.value.isDrawer = false; + Local.set('themeConfig', themeConfig.value); + }; + // 密码输入点击事件 + const onLockScreenSubmit = () => { + themeConfig.value.isLockScreen = false; + themeConfig.value.lockScreenTime = 30; + setLocalThemeConfig(); + }; + // 页面加载时 + onMounted(() => { + initGetElement(); + initSetTime(); + initLockScreen(); + }); + // 页面卸载时 + onUnmounted(() => { + window.clearInterval(state.setIntervalTime); + window.clearInterval(state.isShowLockScreenIntervalTime); + }); + return { + layoutLockScreenInputRef, + onDown, + onMove, + onEnd, + onLockScreenSubmit, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.layout-lock-screen-fixed { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +.layout-lock-screen-filter { + filter: blur(1px); +} +.layout-lock-screen-mask { + background: var(--el-color-white); + @extend .layout-lock-screen-fixed; + z-index: 9999990; +} +.layout-lock-screen-img { + @extend .layout-lock-screen-fixed; + background-image: url('https://img-blog.csdnimg.cn/afa9c317667f47d5bea34b85af45979e.png#pic_center'); + background-size: 100% 100%; + z-index: 9999991; +} +.layout-lock-screen { + @extend .layout-lock-screen-fixed; + z-index: 9999992; + &-date { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + color: var(--el-color-white); + z-index: 9999993; + user-select: none; + &-box { + position: absolute; + left: 30px; + bottom: 50px; + &-time { + font-size: 100px; + color: var(--el-color-white); + } + &-info { + font-size: 40px; + color: var(--el-color-white); + } + &-minutes { + font-size: 16px; + } + } + &-top { + width: 40px; + height: 40px; + line-height: 40px; + border-radius: 100%; + border: 1px solid var(--el-border-color-light, #ebeef5); + background: rgba(255, 255, 255, 0.1); + color: var(--el-color-white); + opacity: 0.8; + position: absolute; + right: 30px; + bottom: 50px; + text-align: center; + overflow: hidden; + transition: all 0.3s ease; + i { + transition: all 0.3s ease; + } + &-text { + opacity: 0; + position: absolute; + top: 150%; + font-size: 12px; + color: var(--el-color-white); + left: 50%; + line-height: 1.2; + transform: translate(-50%, -50%); + transition: all 0.3s ease; + width: 35px; + } + &:hover { + border: 1px solid rgba(255, 255, 255, 0.5); + background: rgba(255, 255, 255, 0.2); + box-shadow: 0 0 12px 0 rgba(255, 255, 255, 0.5); + color: var(--el-color-white); + opacity: 1; + transition: all 0.3s ease; + i { + transform: translateY(-40px); + transition: all 0.3s ease; + } + .layout-lock-screen-date-top-text { + opacity: 1; + top: 50%; + transition: all 0.3s ease; + } + } + } + } + &-login { + position: relative; + z-index: 9999994; + width: 100%; + height: 100%; + left: 0; + top: 0; + display: flex; + flex-direction: column; + justify-content: center; + color: var(--el-color-white); + &-box { + text-align: center; + margin: auto; + &-img { + width: 180px; + height: 180px; + margin: auto; + img { + width: 100%; + height: 100%; + border-radius: 100%; + } + } + &-name { + font-size: 26px; + margin: 15px 0 30px; + } + } + &-icon { + position: absolute; + right: 30px; + bottom: 30px; + i { + font-size: 20px; + margin-left: 15px; + cursor: pointer; + opacity: 0.8; + &:hover { + opacity: 1; + } + } + } + } +} +::v-deep(.el-input-group__append) { + background: var(--el-color-white); + padding: 0px 15px; +} +::v-deep(.el-input__inner) { + border-right-color: var(--el-border-color-extra-light); + &:hover { + border-color: var(--el-border-color-extra-light); + } +} +</style> diff --git a/src/layout/logo/index.vue b/src/layout/logo/index.vue new file mode 100644 index 0000000..3d2b543 --- /dev/null +++ b/src/layout/logo/index.vue @@ -0,0 +1,85 @@ +<template> + <div class="layout-logo" v-if="setShowLogo" @click="onThemeConfigChange"> + <img :src="logoMini" class="layout-logo-medium-img" /> + <span>{{ themeConfig.globalTitle }}</span> + </div> + <div class="layout-logo-size" v-else @click="onThemeConfigChange"> + <img :src="logoMini" class="layout-logo-size-img" /> + </div> +</template> + +<script lang="ts"> +import { computed, defineComponent } from 'vue'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; + +import logoMini from '/@/assets/logo-mini.svg'; + +export default defineComponent({ + name: 'layoutLogo', + setup() { + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + // 设置 logo 的显示。classic 经典布局默认显示 logo + const setShowLogo = computed(() => { + let { isCollapse, layout } = themeConfig.value; + return !isCollapse || layout === 'classic' || document.body.clientWidth < 1000; + }); + // logo 点击实现菜单展开/收起 + const onThemeConfigChange = () => { + if (themeConfig.value.layout === 'transverse') return false; + themeConfig.value.isCollapse = !themeConfig.value.isCollapse; + }; + return { + logoMini, + setShowLogo, + themeConfig, + onThemeConfigChange, + }; + }, +}); +</script> + +<style scoped lang="scss"> +.layout-logo { + width: 220px; + height: 50px; + display: flex; + align-items: center; + justify-content: center; + box-shadow: rgb(0 21 41 / 2%) 0px 1px 4px; + color: var(--el-color-primary); + font-size: 16px; + cursor: pointer; + animation: logoAnimation 0.3s ease-in-out; + span { + white-space: nowrap; + display: inline-block; + } + &:hover { + span { + color: var(--color-primary-light-2); + } + } + &-medium-img { + width: 20px; + margin-right: 5px; + } +} +.layout-logo-size { + width: 100%; + height: 50px; + display: flex; + cursor: pointer; + animation: logoAnimation 0.3s ease-in-out; + &-img { + width: 20px; + margin: auto; + } + &:hover { + img { + animation: logoAnimation 0.3s ease-in-out; + } + } +} +</style> diff --git a/src/layout/main/classic.vue b/src/layout/main/classic.vue new file mode 100644 index 0000000..b92290f --- /dev/null +++ b/src/layout/main/classic.vue @@ -0,0 +1,35 @@ +<template> + <el-container class="layout-container flex-center"> + <Header /> + <el-container class="layout-mian-height-50"> + <Aside /> + <div class="flex-center layout-backtop"> + <TagsView v-if="themeConfig.isTagsview" /> + <Main /> + </div> + </el-container> + <el-backtop target=".layout-backtop .el-main .el-scrollbar__wrap"></el-backtop> + </el-container> +</template> + +<script lang="ts"> +import { defineComponent } from 'vue'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import Aside from '/@/layout/component/aside.vue'; +import Header from '/@/layout/component/header.vue'; +import Main from '/@/layout/component/main.vue'; +import TagsView from '/@/layout/navBars/tagsView/tagsView.vue'; + +export default defineComponent({ + name: 'layoutClassic', + components: { Aside, Header, Main, TagsView }, + setup() { + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + return { + themeConfig, + }; + }, +}); +</script> diff --git a/src/layout/main/columns.vue b/src/layout/main/columns.vue new file mode 100644 index 0000000..0aa1d31 --- /dev/null +++ b/src/layout/main/columns.vue @@ -0,0 +1,41 @@ +<template> + <el-container class="layout-container"> + <ColumnsAside /> + <div class="layout-columns-warp"> + <Aside /> + <el-container class="flex-center layout-backtop" :class="{ 'layout-backtop': !isFixedHeader }"> + <Header v-if="isFixedHeader" /> + <el-scrollbar :class="{ 'layout-backtop': isFixedHeader }"> + <Header v-if="!isFixedHeader" /> + <Main /> + </el-scrollbar> + </el-container> + </div> + <el-backtop target=".layout-backtop .el-scrollbar__wrap"></el-backtop> + </el-container> +</template> + +<script lang="ts"> +import { computed, defineComponent } from 'vue'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import Aside from '/@/layout/component/aside.vue'; +import Header from '/@/layout/component/header.vue'; +import Main from '/@/layout/component/main.vue'; +import ColumnsAside from '/@/layout/component/columnsAside.vue'; + +export default defineComponent({ + name: 'layoutColumns', + components: { Aside, Header, Main, ColumnsAside }, + setup() { + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const isFixedHeader = computed(() => { + return themeConfig.value.isFixedHeader; + }); + return { + isFixedHeader, + }; + }, +}); +</script> diff --git a/src/layout/main/defaults.vue b/src/layout/main/defaults.vue new file mode 100644 index 0000000..0cabb0c --- /dev/null +++ b/src/layout/main/defaults.vue @@ -0,0 +1,47 @@ +<template> + <el-container class="layout-container"> + <Aside /> + <el-container class="flex-center" :class="{ 'layout-backtop': !isFixedHeader }"> + <Header v-if="isFixedHeader" /> + <el-scrollbar ref="layoutDefaultsScrollbarRef" :class="{ 'layout-backtop': isFixedHeader }"> + <Header v-if="!isFixedHeader" /> + <Main /> + </el-scrollbar> + </el-container> + <el-backtop target=".layout-backtop .el-scrollbar__wrap"></el-backtop> + </el-container> +</template> + +<script lang="ts"> +import { computed, getCurrentInstance, watch, defineComponent } from 'vue'; +import { useRoute } from 'vue-router'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import Aside from '/@/layout/component/aside.vue'; +import Header from '/@/layout/component/header.vue'; +import Main from '/@/layout/component/main.vue'; + +export default defineComponent({ + name: 'layoutDefaults', + components: { Aside, Header, Main }, + setup() { + const { proxy } = <any>getCurrentInstance(); + const route = useRoute(); + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const isFixedHeader = computed(() => { + return themeConfig.value.isFixedHeader; + }); + // 监听路由的变化 + watch( + () => route.path, + () => { + proxy.$refs.layoutDefaultsScrollbarRef.wrap$.scrollTop = 0; + } + ); + return { + isFixedHeader, + }; + }, +}); +</script> diff --git a/src/layout/main/transverse.vue b/src/layout/main/transverse.vue new file mode 100644 index 0000000..538f911 --- /dev/null +++ b/src/layout/main/transverse.vue @@ -0,0 +1,17 @@ +<template> + <el-container class="layout-container flex-center layout-backtop"> + <Header /> + <Main /> + <el-backtop target=".layout-backtop .el-main .el-scrollbar__wrap"></el-backtop> + </el-container> +</template> + +<script lang="ts"> +import Header from '/@/layout/component/header.vue'; +import Main from '/@/layout/component/main.vue'; + +export default { + name: 'layoutTransverse', + components: { Header, Main }, +}; +</script> diff --git a/src/layout/navBars/breadcrumb/breadcrumb.vue b/src/layout/navBars/breadcrumb/breadcrumb.vue new file mode 100644 index 0000000..541a841 --- /dev/null +++ b/src/layout/navBars/breadcrumb/breadcrumb.vue @@ -0,0 +1,163 @@ +<template> + <div v-if="isShowBreadcrumb" class="layout-navbars-breadcrumb"> + <SvgIcon + class="layout-navbars-breadcrumb-icon" + :name="themeConfig.isCollapse ? 'ele-Expand' : 'ele-Fold'" + :size="16" + @click="onThemeConfigChange" + /> + <el-breadcrumb class="layout-navbars-breadcrumb-hide"> + <transition-group name="breadcrumb"> + <el-breadcrumb-item v-for="(v, k) in breadcrumbList" :key="!v.meta.tagsViewName ? v.meta.title : v.meta.tagsViewName"> + <span v-if="k === breadcrumbList.length - 1" class="layout-navbars-breadcrumb-span"> + <SvgIcon :name="v.meta.icon" class="layout-navbars-breadcrumb-iconfont" v-if="themeConfig.isBreadcrumbIcon" /> + <div v-if="!v.meta.tagsViewName">{{ $t(v.meta.title) }}</div> + <div v-else>{{ v.meta.tagsViewName }}</div> + </span> + <a v-else @click.prevent="onBreadcrumbClick(v)"> + <SvgIcon :name="v.meta.icon" class="layout-navbars-breadcrumb-iconfont" v-if="themeConfig.isBreadcrumbIcon" />{{ $t(v.meta.title) }} + </a> + </el-breadcrumb-item> + </transition-group> + </el-breadcrumb> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, computed, onMounted, defineComponent } from 'vue'; +import { onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router'; +import { Local } from '/@/utils/storage'; +import other from '/@/utils/other'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { useRoutesList } from '/@/stores/routesList'; + +// 定义接口来定义对象的类型 +interface BreadcrumbState { + breadcrumbList: Array<any>; + routeSplit: Array<string>; + routeSplitFirst: string; + routeSplitIndex: number; +} + +export default defineComponent({ + name: 'layoutBreadcrumb', + setup() { + const stores = useRoutesList(); + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const { routesList } = storeToRefs(stores); + const route = useRoute(); + const router = useRouter(); + const state = reactive<BreadcrumbState>({ + breadcrumbList: [], + routeSplit: [], + routeSplitFirst: '', + routeSplitIndex: 1, + }); + // 动态设置经典、横向布局不显示 + const isShowBreadcrumb = computed(() => { + initRouteSplit(route.path); + const { layout, isBreadcrumb } = themeConfig.value; + if (layout === 'classic' || layout === 'transverse') return false; + else return isBreadcrumb ? true : false; + }); + // 面包屑点击时 + const onBreadcrumbClick = (v: any) => { + const { redirect, path } = v; + if (redirect) router.push(redirect); + else router.push(path); + }; + // 展开/收起左侧菜单点击 + const onThemeConfigChange = () => { + themeConfig.value.isCollapse = !themeConfig.value.isCollapse; + setLocalThemeConfig(); + }; + // 存储布局配置 + const setLocalThemeConfig = () => { + Local.remove('themeConfig'); + Local.set('themeConfig', themeConfig.value); + }; + // 处理面包屑数据 + const getBreadcrumbList = (arr: Array<string>) => { + arr.forEach((item: any) => { + state.routeSplit.forEach((v: any, k: number, arrs: any) => { + if (state.routeSplitFirst === item.path) { + state.routeSplitFirst += `/${arrs[state.routeSplitIndex]}`; + state.breadcrumbList.push(item); + state.routeSplitIndex++; + if (item.children) getBreadcrumbList(item.children); + } + }); + }); + }; + // 当前路由字符串切割成数组,并删除第一项空内容 + const initRouteSplit = (path: string) => { + if (!themeConfig.value.isBreadcrumb) return false; + state.breadcrumbList = [routesList.value[0]]; + state.routeSplit = path.split('/'); + state.routeSplit.shift(); + state.routeSplitFirst = `/${state.routeSplit[0]}`; + state.routeSplitIndex = 1; + getBreadcrumbList(routesList.value); + if (route.name === 'home' || (route.name === 'notFound' && state.breadcrumbList.length > 1)) state.breadcrumbList.shift(); + if (state.breadcrumbList.length > 0) state.breadcrumbList[state.breadcrumbList.length - 1].meta.tagsViewName = other.setTagsViewNameI18n(route); + }; + // 页面加载时 + onMounted(() => { + initRouteSplit(route.path); + }); + // 路由更新时 + onBeforeRouteUpdate((to) => { + initRouteSplit(to.path); + }); + return { + onThemeConfigChange, + isShowBreadcrumb, + themeConfig, + onBreadcrumbClick, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.layout-navbars-breadcrumb { + flex: 1; + height: inherit; + display: flex; + align-items: center; + .layout-navbars-breadcrumb-icon { + cursor: pointer; + font-size: 18px; + color: var(--next-bg-topBarColor); + height: 100%; + width: 40px; + opacity: 0.8; + &:hover { + opacity: 1; + } + } + .layout-navbars-breadcrumb-span { + display: flex; + opacity: 0.7; + color: var(--next-bg-topBarColor); + } + .layout-navbars-breadcrumb-iconfont { + font-size: 14px; + margin-right: 5px; + } + ::v-deep(.el-breadcrumb__separator) { + opacity: 0.7; + color: var(--next-bg-topBarColor); + } + ::v-deep(.el-breadcrumb__inner a, .el-breadcrumb__inner.is-link) { + font-weight: unset !important; + color: var(--next-bg-topBarColor); + &:hover { + color: var(--el-color-primary) !important; + } + } +} +</style> diff --git a/src/layout/navBars/breadcrumb/closeFull.vue b/src/layout/navBars/breadcrumb/closeFull.vue new file mode 100644 index 0000000..a0f0525 --- /dev/null +++ b/src/layout/navBars/breadcrumb/closeFull.vue @@ -0,0 +1,61 @@ +<template> + <div class="layout-navbars-close-full" v-if="isTagsViewCurrenFull"> + <div class="layout-navbars-close-full-icon"> + <SvgIcon name="ele-Close" :title="$t('message.tagsView.closeFullscreen')" @click="onCloseFullscreen" /> + </div> + </div> +</template> + +<script lang="ts"> +import { defineComponent } from 'vue'; +import { storeToRefs } from 'pinia'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; + +export default defineComponent({ + name: 'layoutCloseFull', + setup() { + const stores = useTagsViewRoutes(); + const { isTagsViewCurrenFull } = storeToRefs(stores); + // 关闭当前全屏 + const onCloseFullscreen = () => { + stores.setCurrenFullscreen(false); + }; + return { + isTagsViewCurrenFull, + onCloseFullscreen, + }; + }, +}); +</script> + +<style scoped lang="scss"> +.layout-navbars-close-full { + position: fixed; + z-index: 9999999999; + right: -30px; + top: -30px; + .layout-navbars-close-full-icon { + width: 60px; + height: 60px; + border-radius: 100%; + cursor: pointer; + background: rgba(0, 0, 0, 0.1); + transition: all 0.3s ease; + position: relative; + ::v-deep(i) { + position: absolute; + left: 10px; + top: 35px; + color: #333333; + transition: all 0.3s ease; + } + } + &:hover { + transition: all 0.3s ease; + ::v-deep(i) { + color: var(--el-color-primary); + transition: all 0.3s ease; + } + } +} +</style> diff --git a/src/layout/navBars/breadcrumb/index.vue b/src/layout/navBars/breadcrumb/index.vue new file mode 100644 index 0000000..2810718 --- /dev/null +++ b/src/layout/navBars/breadcrumb/index.vue @@ -0,0 +1,119 @@ +<template> + <div class="layout-navbars-breadcrumb-index"> + <Logo v-if="setIsShowLogo" /> + <Breadcrumb /> + <Horizontal :menuList="menuList" v-if="isLayoutTransverse" /> + <User /> + </div> +</template> + +<script lang="ts"> +import { computed, reactive, toRefs, onMounted, onUnmounted, getCurrentInstance, defineComponent } from 'vue'; +import { useRoute } from 'vue-router'; +import { storeToRefs } from 'pinia'; +import { useRoutesList } from '/@/stores/routesList'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import Breadcrumb from '/@/layout/navBars/breadcrumb/breadcrumb.vue'; +import User from '/@/layout/navBars/breadcrumb/user.vue'; +import Logo from '/@/layout/logo/index.vue'; +import Horizontal from '/@/layout/navMenu/horizontal.vue'; + +// 定义接口来定义对象的类型 +interface IndexState { + menuList: object[]; +} + +export default defineComponent({ + name: 'layoutBreadcrumbIndex', + components: { Breadcrumb, User, Logo, Horizontal }, + setup() { + const { proxy } = <any>getCurrentInstance(); + const stores = useRoutesList(); + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const { routesList } = storeToRefs(stores); + const route = useRoute(); + const state = reactive<IndexState>({ + menuList: [], + }); + // 设置 logo 显示/隐藏 + const setIsShowLogo = computed(() => { + let { isShowLogo, layout } = themeConfig.value; + return (isShowLogo && layout === 'classic') || (isShowLogo && layout === 'transverse'); + }); + // 设置是否显示横向导航菜单 + const isLayoutTransverse = computed(() => { + let { layout, isClassicSplitMenu } = themeConfig.value; + return layout === 'transverse' || (isClassicSplitMenu && layout === 'classic'); + }); + // 设置/过滤路由(非静态路由/是否显示在菜单中) + const setFilterRoutes = () => { + let { layout, isClassicSplitMenu } = themeConfig.value; + if (layout === 'classic' && isClassicSplitMenu) { + state.menuList = delClassicChildren(filterRoutesFun(routesList.value)); + const resData = setSendClassicChildren(route.path); + proxy.mittBus.emit('setSendClassicChildren', resData); + } else { + state.menuList = filterRoutesFun(routesList.value); + } + }; + // 设置了分割菜单时,删除底下 children + const delClassicChildren = (arr: Array<object>) => { + arr.map((v: any) => { + if (v.children) delete v.children; + }); + return arr; + }; + // 路由过滤递归函数 + const filterRoutesFun = (arr: Array<string>) => { + return arr + .filter((item: any) => !item.meta.isHide) + .map((item: any) => { + item = Object.assign({}, item); + if (item.children) item.children = filterRoutesFun(item.children); + return item; + }); + }; + // 传送当前子级数据到菜单中 + const setSendClassicChildren = (path: string) => { + const currentPathSplit = path.split('/'); + let currentData: any = {}; + filterRoutesFun(routesList.value).map((v, k) => { + if (v.path === `/${currentPathSplit[1]}`) { + v['k'] = k; + currentData['item'] = [{ ...v }]; + currentData['children'] = [{ ...v }]; + if (v.children) currentData['children'] = v.children; + } + }); + return currentData; + }; + // 页面加载时 + onMounted(() => { + setFilterRoutes(); + proxy.mittBus.on('getBreadcrumbIndexSetFilterRoutes', () => { + setFilterRoutes(); + }); + }); + // 页面卸载时 + onUnmounted(() => { + proxy.mittBus.off('getBreadcrumbIndexSetFilterRoutes', () => {}); + }); + return { + setIsShowLogo, + isLayoutTransverse, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.layout-navbars-breadcrumb-index { + height: 50px; + display: flex; + align-items: center; + background: var(--next-bg-topBar); + border-bottom: 1px solid var(--next-border-color-light); +} +</style> diff --git a/src/layout/navBars/breadcrumb/search.vue b/src/layout/navBars/breadcrumb/search.vue new file mode 100644 index 0000000..431043c --- /dev/null +++ b/src/layout/navBars/breadcrumb/search.vue @@ -0,0 +1,138 @@ +<template> + <div class="layout-search-dialog"> + <el-dialog v-model="isShowSearch" width="300px" destroy-on-close :modal="false" fullscreen :show-close="false"> + <el-autocomplete + v-model="menuQuery" + :fetch-suggestions="menuSearch" + :placeholder="$t('message.user.searchPlaceholder')" + ref="layoutMenuAutocompleteRef" + @select="onHandleSelect" + @blur="onSearchBlur" + > + <template #prefix> + <el-icon class="el-input__icon"> + <ele-Search /> + </el-icon> + </template> + <template #default="{ item }"> + <div> + <SvgIcon :name="item.meta.icon" class="mr5" /> + {{ $t(item.meta.title) }} + </div> + </template> + </el-autocomplete> + </el-dialog> + </div> +</template> + +<script lang="ts"> +import { reactive, toRefs, defineComponent, ref, nextTick } from 'vue'; +import { useRouter } from 'vue-router'; +import { useI18n } from 'vue-i18n'; +import { storeToRefs } from 'pinia'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; + +// 定义接口来定义对象的类型 +interface SearchState { + isShowSearch: boolean; + menuQuery: string; + tagsViewList: object[]; +} +interface Restaurant { + path: string; + meta: { + title: string; + }; +} + +export default defineComponent({ + name: 'layoutBreadcrumbSearch', + setup() { + const storesTagsViewRoutes = useTagsViewRoutes(); + const { tagsViewRoutes } = storeToRefs(storesTagsViewRoutes); + const layoutMenuAutocompleteRef = ref(); + const { t } = useI18n(); + const router = useRouter(); + const state = reactive<SearchState>({ + isShowSearch: false, + menuQuery: '', + tagsViewList: [], + }); + // 搜索弹窗打开 + const openSearch = () => { + state.menuQuery = ''; + state.isShowSearch = true; + initTageView(); + nextTick(() => { + setTimeout(() => { + layoutMenuAutocompleteRef.value.focus(); + }); + }); + }; + // 搜索弹窗关闭 + const closeSearch = () => { + state.isShowSearch = false; + }; + // 菜单搜索数据过滤 + const menuSearch = (queryString: string, cb: Function) => { + let results = queryString ? state.tagsViewList.filter(createFilter(queryString)) : state.tagsViewList; + cb(results); + }; + // 菜单搜索过滤 + const createFilter: any = (queryString: string) => { + return (restaurant: Restaurant) => { + return ( + restaurant.path.toLowerCase().indexOf(queryString.toLowerCase()) > -1 || + restaurant.meta.title.toLowerCase().indexOf(queryString.toLowerCase()) > -1 || + t(restaurant.meta.title).indexOf(queryString.toLowerCase()) > -1 + ); + }; + }; + // 初始化菜单数据 + const initTageView = () => { + if (state.tagsViewList.length > 0) return false; + tagsViewRoutes.value.map((v: any) => { + if (!v.meta.isHide) state.tagsViewList.push({ ...v }); + }); + }; + // 当前菜单选中时 + const onHandleSelect = (item: any) => { + let { path, redirect } = item; + if (item.meta.isLink && !item.meta.isIframe) window.open(item.meta.isLink); + else if (redirect) router.push(redirect); + else router.push(path); + closeSearch(); + }; + // input 失去焦点时 + const onSearchBlur = () => { + closeSearch(); + }; + return { + layoutMenuAutocompleteRef, + openSearch, + closeSearch, + menuSearch, + onHandleSelect, + onSearchBlur, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.layout-search-dialog { + ::v-deep(.el-dialog) { + box-shadow: unset !important; + border-radius: 0 !important; + background: rgba(0, 0, 0, 0.5); + } + ::v-deep(.el-autocomplete) { + width: 560px; + position: absolute; + top: 100px; + left: 50%; + transform: translateX(-50%); + } +} +</style> diff --git a/src/layout/navBars/breadcrumb/setings.vue b/src/layout/navBars/breadcrumb/setings.vue new file mode 100644 index 0000000..856f260 --- /dev/null +++ b/src/layout/navBars/breadcrumb/setings.vue @@ -0,0 +1,816 @@ +<template> + <div class="layout-breadcrumb-seting"> + <el-drawer + :title="$t('message.layout.configTitle')" + v-model="getThemeConfig.isDrawer" + direction="rtl" + destroy-on-close + size="260px" + @close="onDrawerClose" + > + <el-scrollbar class="layout-breadcrumb-seting-bar"> + <!-- 全局主题 --> + <el-divider content-position="left">{{ $t('message.layout.oneTitle') }}</el-divider> + <div class="layout-breadcrumb-seting-bar-flex"> + <div class="layout-breadcrumb-seting-bar-flex-label">primary</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-color-picker v-model="getThemeConfig.primary" size="default" @change="onColorPickerChange"> </el-color-picker> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt15"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsDark') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch v-model="getThemeConfig.isIsDark" size="small" @change="onAddDarkChange"></el-switch> + </div> + </div> + + <!-- 顶栏设置 --> + <el-divider content-position="left">{{ $t('message.layout.twoTopTitle') }}</el-divider> + <div class="layout-breadcrumb-seting-bar-flex"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.twoTopBar') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-color-picker v-model="getThemeConfig.topBar" size="default" @change="onBgColorPickerChange('topBar')"> </el-color-picker> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.twoTopBarColor') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-color-picker v-model="getThemeConfig.topBarColor" size="default" @change="onBgColorPickerChange('topBarColor')"> </el-color-picker> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt10"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.twoIsTopBarColorGradual') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch v-model="getThemeConfig.isTopBarColorGradual" size="small" @change="onTopBarGradualChange"></el-switch> + </div> + </div> + + <!-- 菜单设置 --> + <el-divider content-position="left">{{ $t('message.layout.twoMenuTitle') }}</el-divider> + <div class="layout-breadcrumb-seting-bar-flex"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.twoMenuBar') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-color-picker v-model="getThemeConfig.menuBar" size="default" @change="onBgColorPickerChange('menuBar')"> </el-color-picker> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.twoMenuBarColor') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-color-picker v-model="getThemeConfig.menuBarColor" size="default" @change="onBgColorPickerChange('menuBarColor')"> </el-color-picker> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt14"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.twoIsMenuBarColorGradual') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch v-model="getThemeConfig.isMenuBarColorGradual" size="small" @change="onMenuBarGradualChange"></el-switch> + </div> + </div> + + <!-- 分栏设置 --> + <el-divider content-position="left" :style="{ opacity: getThemeConfig.layout !== 'columns' ? 0.5 : 1 }">{{ + $t('message.layout.twoColumnsTitle') + }}</el-divider> + <div class="layout-breadcrumb-seting-bar-flex" :style="{ opacity: getThemeConfig.layout !== 'columns' ? 0.5 : 1 }"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.twoColumnsMenuBar') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-color-picker + v-model="getThemeConfig.columnsMenuBar" + size="default" + @change="onBgColorPickerChange('columnsMenuBar')" + :disabled="getThemeConfig.layout !== 'columns'" + > + </el-color-picker> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex" :style="{ opacity: getThemeConfig.layout !== 'columns' ? 0.5 : 1 }"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.twoColumnsMenuBarColor') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-color-picker + v-model="getThemeConfig.columnsMenuBarColor" + size="default" + @change="onBgColorPickerChange('columnsMenuBarColor')" + :disabled="getThemeConfig.layout !== 'columns'" + > + </el-color-picker> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt14" :style="{ opacity: getThemeConfig.layout !== 'columns' ? 0.5 : 1 }"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.twoIsColumnsMenuBarColorGradual') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch + v-model="getThemeConfig.isColumnsMenuBarColorGradual" + size="small" + @change="onColumnsMenuBarGradualChange" + :disabled="getThemeConfig.layout !== 'columns'" + ></el-switch> + </div> + </div> + + <!-- 界面设置 --> + <el-divider content-position="left">{{ $t('message.layout.threeTitle') }}</el-divider> + <div class="layout-breadcrumb-seting-bar-flex" :style="{ opacity: getThemeConfig.layout === 'transverse' ? 0.5 : 1 }"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.threeIsCollapse') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch + v-model="getThemeConfig.isCollapse" + :disabled="getThemeConfig.layout === 'transverse'" + size="small" + @change="onThemeConfigChange" + ></el-switch> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt15" :style="{ opacity: getThemeConfig.layout === 'transverse' ? 0.5 : 1 }"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.threeIsUniqueOpened') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch + v-model="getThemeConfig.isUniqueOpened" + :disabled="getThemeConfig.layout === 'transverse'" + size="small" + @change="setLocalThemeConfig" + ></el-switch> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt15"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.threeIsFixedHeader') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch v-model="getThemeConfig.isFixedHeader" size="small" @change="onIsFixedHeaderChange"></el-switch> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt15" :style="{ opacity: getThemeConfig.layout !== 'classic' ? 0.5 : 1 }"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.threeIsClassicSplitMenu') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch + v-model="getThemeConfig.isClassicSplitMenu" + :disabled="getThemeConfig.layout !== 'classic'" + size="small" + @change="onClassicSplitMenuChange" + > + </el-switch> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt15"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.threeIsLockScreen') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch v-model="getThemeConfig.isLockScreen" size="small" @change="setLocalThemeConfig"></el-switch> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt11"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.threeLockScreenTime') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-input-number + v-model="getThemeConfig.lockScreenTime" + controls-position="right" + :min="1" + :max="9999" + @change="setLocalThemeConfig" + size="default" + style="width: 90px" + > + </el-input-number> + </div> + </div> + + <!-- 界面显示 --> + <el-divider content-position="left">{{ $t('message.layout.fourTitle') }}</el-divider> + <div class="layout-breadcrumb-seting-bar-flex mt15"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsShowLogo') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch v-model="getThemeConfig.isShowLogo" size="small" @change="onIsShowLogoChange"></el-switch> + </div> + </div> + <div + class="layout-breadcrumb-seting-bar-flex mt15" + :style="{ opacity: getThemeConfig.layout === 'classic' || getThemeConfig.layout === 'transverse' ? 0.5 : 1 }" + > + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsBreadcrumb') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch + v-model="getThemeConfig.isBreadcrumb" + :disabled="getThemeConfig.layout === 'classic' || getThemeConfig.layout === 'transverse'" + size="small" + @change="onIsBreadcrumbChange" + ></el-switch> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt15"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsBreadcrumbIcon') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch v-model="getThemeConfig.isBreadcrumbIcon" size="small" @change="setLocalThemeConfig"></el-switch> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt15"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsTagsview') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch v-model="getThemeConfig.isTagsview" size="small" @change="setLocalThemeConfig"></el-switch> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt15"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsTagsviewIcon') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch v-model="getThemeConfig.isTagsviewIcon" size="small" @change="setLocalThemeConfig"></el-switch> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt15"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsCacheTagsView') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch v-model="getThemeConfig.isCacheTagsView" size="small" @change="setLocalThemeConfig"></el-switch> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt15" :style="{ opacity: isMobile ? 0.5 : 1 }"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsSortableTagsView') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch + v-model="getThemeConfig.isSortableTagsView" + :disabled="isMobile ? true : false" + size="small" + @change="onSortableTagsViewChange" + ></el-switch> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt15"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsShareTagsView') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch v-model="getThemeConfig.isShareTagsView" size="small" @change="onShareTagsViewChange"></el-switch> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt15"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsFooter') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch v-model="getThemeConfig.isFooter" size="small" @change="setLocalThemeConfig"></el-switch> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt15"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsGrayscale') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch v-model="getThemeConfig.isGrayscale" size="small" @change="onAddFilterChange('grayscale')"></el-switch> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt15"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsInvert') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch v-model="getThemeConfig.isInvert" size="small" @change="onAddFilterChange('invert')"></el-switch> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt15"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsWartermark') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-switch v-model="getThemeConfig.isWartermark" size="small" @change="onWartermarkChange"></el-switch> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt14"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourWartermarkText') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-input v-model="getThemeConfig.wartermarkText" size="default" style="width: 90px" @input="onWartermarkTextInput($event)"></el-input> + </div> + </div> + + <!-- 其它设置 --> + <el-divider content-position="left">{{ $t('message.layout.fiveTitle') }}</el-divider> + <div class="layout-breadcrumb-seting-bar-flex mt15"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fiveTagsStyle') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-select v-model="getThemeConfig.tagsStyle" placeholder="请选择" size="default" style="width: 90px" @change="setLocalThemeConfig"> + <el-option label="风格1" value="tags-style-one"></el-option> + <el-option label="风格4" value="tags-style-four"></el-option> + <el-option label="风格5" value="tags-style-five"></el-option> + </el-select> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt15"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fiveAnimation') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-select v-model="getThemeConfig.animation" placeholder="请选择" size="default" style="width: 90px" @change="setLocalThemeConfig"> + <el-option label="slide-right" value="slide-right"></el-option> + <el-option label="slide-left" value="slide-left"></el-option> + <el-option label="opacitys" value="opacitys"></el-option> + </el-select> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt15" :style="{ opacity: getThemeConfig.layout !== 'columns' ? 0.5 : 1 }"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fiveColumnsAsideStyle') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-select + v-model="getThemeConfig.columnsAsideStyle" + placeholder="请选择" + size="default" + style="width: 90px" + :disabled="getThemeConfig.layout !== 'columns' ? true : false" + @change="setLocalThemeConfig" + > + <el-option label="圆角" value="columns-round"></el-option> + <el-option label="卡片" value="columns-card"></el-option> + </el-select> + </div> + </div> + <div class="layout-breadcrumb-seting-bar-flex mt15 mb27" :style="{ opacity: getThemeConfig.layout !== 'columns' ? 0.5 : 1 }"> + <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fiveColumnsAsideLayout') }}</div> + <div class="layout-breadcrumb-seting-bar-flex-value"> + <el-select + v-model="getThemeConfig.columnsAsideLayout" + placeholder="请选择" + size="default" + style="width: 90px" + :disabled="getThemeConfig.layout !== 'columns' ? true : false" + @change="setLocalThemeConfig" + > + <el-option label="水平" value="columns-horizontal"></el-option> + <el-option label="垂直" value="columns-vertical"></el-option> + </el-select> + </div> + </div> + + <!-- 布局切换 --> + <el-divider content-position="left">{{ $t('message.layout.sixTitle') }}</el-divider> + <div class="layout-drawer-content-flex"> + <!-- defaults 布局 --> + <div class="layout-drawer-content-item" @click="onSetLayout('defaults')"> + <section class="el-container el-circular" :class="{ 'drawer-layout-active': getThemeConfig.layout === 'defaults' }"> + <aside class="el-aside" style="width: 20px"></aside> + <section class="el-container is-vertical"> + <header class="el-header" style="height: 10px"></header> + <main class="el-main"></main> + </section> + </section> + <div class="layout-tips-warp" :class="{ 'layout-tips-warp-active': getThemeConfig.layout === 'defaults' }"> + <div class="layout-tips-box"> + <p class="layout-tips-txt">{{ $t('message.layout.sixDefaults') }}</p> + </div> + </div> + </div> + <!-- classic 布局 --> + <div class="layout-drawer-content-item" @click="onSetLayout('classic')"> + <section class="el-container is-vertical el-circular" :class="{ 'drawer-layout-active': getThemeConfig.layout === 'classic' }"> + <header class="el-header" style="height: 10px"></header> + <section class="el-container"> + <aside class="el-aside" style="width: 20px"></aside> + <section class="el-container is-vertical"> + <main class="el-main"></main> + </section> + </section> + </section> + <div class="layout-tips-warp" :class="{ 'layout-tips-warp-active': getThemeConfig.layout === 'classic' }"> + <div class="layout-tips-box"> + <p class="layout-tips-txt">{{ $t('message.layout.sixClassic') }}</p> + </div> + </div> + </div> + <!-- transverse 布局 --> + <div class="layout-drawer-content-item" @click="onSetLayout('transverse')"> + <section class="el-container is-vertical el-circular" :class="{ 'drawer-layout-active': getThemeConfig.layout === 'transverse' }"> + <header class="el-header" style="height: 10px"></header> + <section class="el-container"> + <section class="el-container is-vertical"> + <main class="el-main"></main> + </section> + </section> + </section> + <div class="layout-tips-warp" :class="{ 'layout-tips-warp-active': getThemeConfig.layout === 'transverse' }"> + <div class="layout-tips-box"> + <p class="layout-tips-txt">{{ $t('message.layout.sixTransverse') }}</p> + </div> + </div> + </div> + <!-- columns 布局 --> + <div class="layout-drawer-content-item" @click="onSetLayout('columns')"> + <section class="el-container el-circular" :class="{ 'drawer-layout-active': getThemeConfig.layout === 'columns' }"> + <aside class="el-aside-dark" style="width: 10px"></aside> + <aside class="el-aside" style="width: 20px"></aside> + <section class="el-container is-vertical"> + <header class="el-header" style="height: 10px"></header> + <main class="el-main"></main> + </section> + </section> + <div class="layout-tips-warp" :class="{ 'layout-tips-warp-active': getThemeConfig.layout === 'columns' }"> + <div class="layout-tips-box"> + <p class="layout-tips-txt">{{ $t('message.layout.sixColumns') }}</p> + </div> + </div> + </div> + </div> + <div class="copy-config"> + <el-alert :title="$t('message.layout.tipText')" type="warning" :closable="false"> </el-alert> + <el-button size="default" class="copy-config-btn" type="primary" ref="copyConfigBtnRef" @click="onCopyConfigClick"> + <el-icon class="mr5"> + <ele-CopyDocument /> + </el-icon> + {{ $t('message.layout.copyText') }} + </el-button> + <el-button size="default" class="copy-config-btn-reset" type="info" @click="onResetConfigClick"> + <el-icon class="mr5"> + <ele-RefreshRight /> + </el-icon> + {{ $t('message.layout.resetText') }} + </el-button> + </div> + </el-scrollbar> + </el-drawer> + </div> +</template> + +<script lang="ts"> +import { nextTick, onUnmounted, onMounted, getCurrentInstance, defineComponent, computed, reactive, toRefs } from 'vue'; +import { ElMessage } from 'element-plus'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { getLightColor, getDarkColor } from '/@/utils/theme'; +import { verifyAndSpace } from '/@/utils/toolsValidate'; +import { Local } from '/@/utils/storage'; +import Watermark from '/@/utils/wartermark'; +import commonFunction from '/@/utils/commonFunction'; +import other from '/@/utils/other'; + +export default defineComponent({ + name: 'layoutBreadcrumbSeting', + setup() { + const { proxy } = <any>getCurrentInstance(); + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const { copyText } = commonFunction(); + const state = reactive({ + isMobile: false, + }); + // 获取布局配置信息 + const getThemeConfig = computed(() => { + return themeConfig.value; + }); + // 1、全局主题 + const onColorPickerChange = () => { + if (!getThemeConfig.value.primary) return ElMessage.warning('全局主题 primary 颜色值不能为空'); + // 颜色加深 + document.documentElement.style.setProperty('--el-color-primary-dark-2', `${getDarkColor(getThemeConfig.value.primary, 0.1)}`); + document.documentElement.style.setProperty('--el-color-primary', getThemeConfig.value.primary); + // 颜色变浅 + for (let i = 1; i <= 9; i++) { + document.documentElement.style.setProperty(`--el-color-primary-light-${i}`, `${getLightColor(getThemeConfig.value.primary, i / 10)}`); + } + setDispatchThemeConfig(); + }; + // 2、菜单 / 顶栏 + const onBgColorPickerChange = (bg: string) => { + document.documentElement.style.setProperty(`--next-bg-${bg}`, (<any>getThemeConfig.value)[bg]); + if (bg === 'menuBar') { + document.documentElement.style.setProperty(`--next-bg-menuBar-light-1`, <any>getLightColor(getThemeConfig.value.menuBar, 0.05)); + } + onTopBarGradualChange(); + onMenuBarGradualChange(); + onColumnsMenuBarGradualChange(); + setDispatchThemeConfig(); + }; + // 2、菜单 / 顶栏 --> 顶栏背景渐变 + const onTopBarGradualChange = () => { + setGraduaFun('.layout-navbars-breadcrumb-index', getThemeConfig.value.isTopBarColorGradual, getThemeConfig.value.topBar); + }; + // 2、菜单 / 顶栏 --> 菜单背景渐变 + const onMenuBarGradualChange = () => { + setGraduaFun('.layout-container .el-aside', getThemeConfig.value.isMenuBarColorGradual, getThemeConfig.value.menuBar); + }; + // 2、菜单 / 顶栏 --> 分栏菜单背景渐变 + const onColumnsMenuBarGradualChange = () => { + setGraduaFun('.layout-container .layout-columns-aside', getThemeConfig.value.isColumnsMenuBarColorGradual, getThemeConfig.value.columnsMenuBar); + }; + // 2、菜单 / 顶栏 --> 背景渐变函数 + const setGraduaFun = (el: string, bool: boolean, color: string) => { + setTimeout(() => { + let els = document.querySelector(el); + if (!els) return false; + document.documentElement.style.setProperty('--el-menu-bg-color', document.documentElement.style.getPropertyValue('--next-bg-menuBar')); + if (bool) els.setAttribute('style', `background:linear-gradient(to bottom left , ${color}, ${getLightColor(color, 0.6)}) !important;`); + else els.setAttribute('style', ``); + setLocalThemeConfig(); + }, 200); + }; + // 3、界面设置 --> 菜单水平折叠 + const onThemeConfigChange = () => { + setDispatchThemeConfig(); + }; + // 3、界面设置 --> 固定 Header + const onIsFixedHeaderChange = () => { + getThemeConfig.value.isFixedHeaderChange = getThemeConfig.value.isFixedHeader ? false : true; + setLocalThemeConfig(); + }; + // 3、界面设置 --> 经典布局分割菜单 + const onClassicSplitMenuChange = () => { + getThemeConfig.value.isBreadcrumb = false; + setLocalThemeConfig(); + proxy.mittBus.emit('getBreadcrumbIndexSetFilterRoutes'); + }; + // 4、界面显示 --> 侧边栏 Logo + const onIsShowLogoChange = () => { + getThemeConfig.value.isShowLogoChange = getThemeConfig.value.isShowLogo ? false : true; + setLocalThemeConfig(); + }; + // 4、界面显示 --> 面包屑 Breadcrumb + const onIsBreadcrumbChange = () => { + if (getThemeConfig.value.layout === 'classic') { + getThemeConfig.value.isClassicSplitMenu = false; + } + setLocalThemeConfig(); + }; + // 4、界面显示 --> 开启 TagsView 拖拽 + const onSortableTagsViewChange = () => { + proxy.mittBus.emit('openOrCloseSortable'); + setLocalThemeConfig(); + }; + // 4、界面显示 --> 开启 TagsView 共用 + const onShareTagsViewChange = () => { + proxy.mittBus.emit('openShareTagsView'); + setLocalThemeConfig(); + }; + // 4、界面显示 --> 灰色模式/色弱模式 + const onAddFilterChange = (attr: string) => { + if (attr === 'grayscale') { + if (getThemeConfig.value.isGrayscale) getThemeConfig.value.isInvert = false; + } else { + if (getThemeConfig.value.isInvert) getThemeConfig.value.isGrayscale = false; + } + const cssAttr = + attr === 'grayscale' ? `grayscale(${getThemeConfig.value.isGrayscale ? 1 : 0})` : `invert(${getThemeConfig.value.isInvert ? '80%' : '0%'})`; + const appEle: any = document.body; + appEle.setAttribute('style', `filter: ${cssAttr}`); + setLocalThemeConfig(); + }; + // 4、界面显示 --> 深色模式 + const onAddDarkChange = () => { + const body = document.documentElement as HTMLElement; + if (getThemeConfig.value.isIsDark) body.setAttribute('data-theme', 'dark'); + else body.setAttribute('data-theme', ''); + }; + // 4、界面显示 --> 开启水印 + const onWartermarkChange = () => { + getThemeConfig.value.isWartermark ? Watermark.set(getThemeConfig.value.wartermarkText) : Watermark.del(); + setLocalThemeConfig(); + }; + // 4、界面显示 --> 水印文案 + const onWartermarkTextInput = (val: any) => { + getThemeConfig.value.wartermarkText = verifyAndSpace(val); + if (getThemeConfig.value.wartermarkText === '') return false; + if (getThemeConfig.value.isWartermark) Watermark.set(getThemeConfig.value.wartermarkText); + setLocalThemeConfig(); + }; + // 5、布局切换 + const onSetLayout = (layout: string) => { + Local.set('oldLayout', layout); + if (getThemeConfig.value.layout === layout) return false; + if (layout === 'transverse') getThemeConfig.value.isCollapse = false; + getThemeConfig.value.layout = layout; + getThemeConfig.value.isDrawer = false; + initLayoutChangeFun(); + }; + // 设置布局切换函数 + const initLayoutChangeFun = () => { + onBgColorPickerChange('menuBar'); + onBgColorPickerChange('menuBarColor'); + onBgColorPickerChange('topBar'); + onBgColorPickerChange('topBarColor'); + onBgColorPickerChange('columnsMenuBar'); + onBgColorPickerChange('columnsMenuBarColor'); + }; + // 关闭弹窗时,初始化变量。变量用于处理 proxy.$refs.layoutScrollbarRef.update() + const onDrawerClose = () => { + getThemeConfig.value.isFixedHeaderChange = false; + getThemeConfig.value.isShowLogoChange = false; + getThemeConfig.value.isDrawer = false; + setLocalThemeConfig(); + }; + // 布局配置弹窗打开 + const openDrawer = () => { + getThemeConfig.value.isDrawer = true; + }; + // 触发 store 布局配置更新 + const setDispatchThemeConfig = () => { + setLocalThemeConfig(); + setLocalThemeConfigStyle(); + }; + // 存储布局配置 + const setLocalThemeConfig = () => { + Local.remove('themeConfig'); + Local.set('themeConfig', getThemeConfig.value); + }; + // 存储布局配置全局主题样式(html根标签) + const setLocalThemeConfigStyle = () => { + Local.set('themeConfigStyle', document.documentElement.style.cssText); + }; + // 一键复制配置 + const onCopyConfigClick = () => { + let copyThemeConfig = Local.get('themeConfig'); + copyThemeConfig.isDrawer = false; + copyText(JSON.stringify(copyThemeConfig)).then(() => { + getThemeConfig.value.isDrawer = false; + }); + }; + // 一键恢复默认 + const onResetConfigClick = () => { + Local.clear(); + window.location.reload(); + }; + // 初始化菜单样式等 + const initSetStyle = () => { + // 2、菜单 / 顶栏 --> 顶栏背景渐变 + onTopBarGradualChange(); + // 2、菜单 / 顶栏 --> 菜单背景渐变 + onMenuBarGradualChange(); + // 2、菜单 / 顶栏 --> 分栏菜单背景渐变 + onColumnsMenuBarGradualChange(); + }; + onMounted(() => { + nextTick(() => { + // 判断当前布局是否不相同,不相同则初始化当前布局的样式,防止监听窗口大小改变时,布局配置logo、菜单背景等部分布局失效问题 + if (!Local.get('frequency')) initLayoutChangeFun(); + Local.set('frequency', 1); + // 监听窗口大小改变,非默认布局,设置成默认布局(适配移动端) + proxy.mittBus.on('layoutMobileResize', (res: any) => { + getThemeConfig.value.layout = res.layout; + getThemeConfig.value.isDrawer = false; + initLayoutChangeFun(); + state.isMobile = other.isMobile(); + }); + setTimeout(() => { + // 默认样式 + onColorPickerChange(); + // 灰色模式 + if (getThemeConfig.value.isGrayscale) onAddFilterChange('grayscale'); + // 色弱模式 + if (getThemeConfig.value.isInvert) onAddFilterChange('invert'); + // 深色模式 + if (getThemeConfig.value.isIsDark) onAddDarkChange(); + // 开启水印 + onWartermarkChange(); + // 语言国际化 + if (Local.get('themeConfig')) proxy.$i18n.locale = Local.get('themeConfig').globalI18n; + // 初始化菜单样式等 + initSetStyle(); + }, 100); + }); + }); + onUnmounted(() => { + proxy.mittBus.off('layoutMobileResize', () => {}); + }); + return { + openDrawer, + onColorPickerChange, + onBgColorPickerChange, + onTopBarGradualChange, + onMenuBarGradualChange, + onColumnsMenuBarGradualChange, + onThemeConfigChange, + onIsFixedHeaderChange, + onIsShowLogoChange, + getThemeConfig, + onDrawerClose, + onAddFilterChange, + onAddDarkChange, + onWartermarkChange, + onWartermarkTextInput, + onSetLayout, + setLocalThemeConfig, + onClassicSplitMenuChange, + onIsBreadcrumbChange, + onSortableTagsViewChange, + onShareTagsViewChange, + onCopyConfigClick, + onResetConfigClick, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.layout-breadcrumb-seting-bar { + height: calc(100vh - 50px); + padding: 0 15px; + ::v-deep(.el-scrollbar__view) { + overflow-x: hidden !important; + } + .layout-breadcrumb-seting-bar-flex { + display: flex; + align-items: center; + margin-bottom: 5px; + &-label { + flex: 1; + color: var(--el-text-color-primary); + } + } + .layout-drawer-content-flex { + overflow: hidden; + display: flex; + flex-wrap: wrap; + align-content: flex-start; + margin: 0 -5px; + .layout-drawer-content-item { + width: 50%; + height: 70px; + cursor: pointer; + border: 1px solid transparent; + position: relative; + padding: 5px; + .el-container { + height: 100%; + .el-aside-dark { + background-color: var(--next-color-seting-header); + } + .el-aside { + background-color: var(--next-color-seting-aside); + } + .el-header { + background-color: var(--next-color-seting-header); + } + .el-main { + background-color: var(--next-color-seting-main); + } + } + .el-circular { + border-radius: 2px; + overflow: hidden; + border: 1px solid transparent; + transition: all 0.3s ease-in-out; + } + .drawer-layout-active { + border: 1px solid; + border-color: var(--el-color-primary); + } + .layout-tips-warp, + .layout-tips-warp-active { + transition: all 0.3s ease-in-out; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + border: 1px solid; + border-color: var(--el-color-primary-light-5); + border-radius: 100%; + padding: 4px; + .layout-tips-box { + transition: inherit; + width: 30px; + height: 30px; + z-index: 9; + border: 1px solid; + border-color: var(--el-color-primary-light-5); + border-radius: 100%; + .layout-tips-txt { + transition: inherit; + position: relative; + top: 5px; + font-size: 12px; + line-height: 1; + letter-spacing: 2px; + white-space: nowrap; + color: var(--el-color-primary-light-5); + text-align: center; + transform: rotate(30deg); + left: -1px; + background-color: var(--next-color-seting-main); + width: 32px; + height: 17px; + line-height: 17px; + } + } + } + .layout-tips-warp-active { + border: 1px solid; + border-color: var(--el-color-primary); + .layout-tips-box { + border: 1px solid; + border-color: var(--el-color-primary); + .layout-tips-txt { + color: var(--el-color-primary) !important; + background-color: var(--next-color-seting-main) !important; + } + } + } + &:hover { + .el-circular { + transition: all 0.3s ease-in-out; + border: 1px solid; + border-color: var(--el-color-primary); + } + .layout-tips-warp { + transition: all 0.3s ease-in-out; + border-color: var(--el-color-primary); + .layout-tips-box { + transition: inherit; + border-color: var(--el-color-primary); + .layout-tips-txt { + transition: inherit; + color: var(--el-color-primary) !important; + background-color: var(--next-color-seting-main) !important; + } + } + } + } + } + } + .copy-config { + margin: 10px 0; + .copy-config-btn { + width: 100%; + margin-top: 15px; + } + .copy-config-btn-reset { + width: 100%; + margin: 10px 0 0; + } + } +} +</style> diff --git a/src/layout/navBars/breadcrumb/user.vue b/src/layout/navBars/breadcrumb/user.vue new file mode 100644 index 0000000..6782651 --- /dev/null +++ b/src/layout/navBars/breadcrumb/user.vue @@ -0,0 +1,298 @@ +<template> + <div class="layout-navbars-breadcrumb-user pr15" :style="{ flex: layoutUserFlexNum }"> + <el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onComponentSizeChange"> + <div class="layout-navbars-breadcrumb-user-icon"> + <i class="iconfont icon-ziti" :title="$t('message.user.title0')"></i> + </div> + <template #dropdown> + <el-dropdown-menu> + <el-dropdown-item command="large" :disabled="disabledSize === 'large'">{{ $t('message.user.dropdownLarge') }}</el-dropdown-item> + <el-dropdown-item command="default" :disabled="disabledSize === 'default'">{{ $t('message.user.dropdownDefault') }}</el-dropdown-item> + <el-dropdown-item command="small" :disabled="disabledSize === 'small'">{{ $t('message.user.dropdownSmall') }}</el-dropdown-item> + </el-dropdown-menu> + </template> + </el-dropdown> + <el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onLanguageChange"> + <div class="layout-navbars-breadcrumb-user-icon"> + <i class="iconfont" :class="disabledI18n === 'en' ? 'icon-fuhao-yingwen' : 'icon-fuhao-zhongwen'" :title="$t('message.user.title1')"></i> + </div> + <template #dropdown> + <el-dropdown-menu> + <el-dropdown-item command="zh-cn" :disabled="disabledI18n === 'zh-cn'">简体中文</el-dropdown-item> + <el-dropdown-item command="en" :disabled="disabledI18n === 'en'">English</el-dropdown-item> + <el-dropdown-item command="zh-tw" :disabled="disabledI18n === 'zh-tw'">繁體中文</el-dropdown-item> + </el-dropdown-menu> + </template> + </el-dropdown> + <div class="layout-navbars-breadcrumb-user-icon" @click="onSearchClick"> + <el-icon :title="$t('message.user.title2')"> + <ele-Search /> + </el-icon> + </div> + <div class="layout-navbars-breadcrumb-user-icon" @click="onLayoutSetingClick"> + <i class="icon-skin iconfont" :title="$t('message.user.title3')"></i> + </div> + <div class="layout-navbars-breadcrumb-user-icon"> + <el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300" :persistent="false"> + <template #reference> + <el-badge :is-dot="true"> + <el-icon :title="$t('message.user.title4')"> + <ele-Bell /> + </el-icon> + </el-badge> + </template> + <template #default> + <UserNews /> + </template> + </el-popover> + </div> + <div class="layout-navbars-breadcrumb-user-icon mr10" @click="onScreenfullClick"> + <i + class="iconfont" + :title="isScreenfull ? $t('message.user.title6') : $t('message.user.title5')" + :class="!isScreenfull ? 'icon-fullscreen' : 'icon-tuichuquanping'" + ></i> + </div> + <el-dropdown :show-timeout="70" :hide-timeout="50" @command="onHandleCommandClick"> + <span class="layout-navbars-breadcrumb-user-link"> + <img :src="userInfos.photo" class="layout-navbars-breadcrumb-user-link-photo mr5" /> + {{ userInfos.userName === '' ? 'common' : userInfos.userName }} + <el-icon class="el-icon--right"> + <ele-ArrowDown /> + </el-icon> + </span> + <template #dropdown> + <el-dropdown-menu> + <el-dropdown-item command="/home">{{ $t('message.user.dropdown1') }}</el-dropdown-item> + <el-dropdown-item command="wareHouse">{{ $t('message.user.dropdown6') }}</el-dropdown-item> + <el-dropdown-item command="/personal">{{ $t('message.user.dropdown2') }}</el-dropdown-item> + <el-dropdown-item command="/404">{{ $t('message.user.dropdown3') }}</el-dropdown-item> + <el-dropdown-item command="/401">{{ $t('message.user.dropdown4') }}</el-dropdown-item> + <el-dropdown-item divided command="logOut">{{ $t('message.user.dropdown5') }}</el-dropdown-item> + </el-dropdown-menu> + </template> + </el-dropdown> + <Search ref="searchRef" /> + </div> +</template> + +<script lang="ts"> +import { ref, getCurrentInstance, computed, reactive, toRefs, onMounted, defineComponent } from 'vue'; +import { useRouter } from 'vue-router'; +import { ElMessageBox, ElMessage } from 'element-plus'; +import screenfull from 'screenfull'; +import { useI18n } from 'vue-i18n'; +import { storeToRefs } from 'pinia'; +import { useUserInfo } from '/@/stores/userInfo'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import other from '/@/utils/other'; +import { Session, Local } from '/@/utils/storage'; +import UserNews from '/@/layout/navBars/breadcrumb/userNews.vue'; +import Search from '/@/layout/navBars/breadcrumb/search.vue'; + +export default defineComponent({ + name: 'layoutBreadcrumbUser', + components: { UserNews, Search }, + setup() { + const { t } = useI18n(); + const { proxy } = <any>getCurrentInstance(); + const router = useRouter(); + const stores = useUserInfo(); + const storesThemeConfig = useThemeConfig(); + const { userInfos } = storeToRefs(stores); + const { themeConfig } = storeToRefs(storesThemeConfig); + const searchRef = ref(); + const state = reactive({ + isScreenfull: false, + disabledI18n: 'zh-cn', + disabledSize: 'large', + }); + // 设置分割样式 + const layoutUserFlexNum = computed(() => { + let num: string | number = ''; + const { layout, isClassicSplitMenu } = themeConfig.value; + const layoutArr: string[] = ['defaults', 'columns']; + if (layoutArr.includes(layout) || (layout === 'classic' && !isClassicSplitMenu)) num = '1'; + else num = ''; + return num; + }); + // 全屏点击时 + const onScreenfullClick = () => { + if (!screenfull.isEnabled) { + ElMessage.warning('暂不不支持全屏'); + return false; + } + screenfull.toggle(); + screenfull.on('change', () => { + if (screenfull.isFullscreen) state.isScreenfull = true; + else state.isScreenfull = false; + }); + }; + // 布局配置 icon 点击时 + const onLayoutSetingClick = () => { + proxy.mittBus.emit('openSetingsDrawer'); + }; + // 下拉菜单点击时 + const onHandleCommandClick = (path: string) => { + if (path === 'logOut') { + ElMessageBox({ + closeOnClickModal: false, + closeOnPressEscape: false, + title: t('message.user.logOutTitle'), + message: t('message.user.logOutMessage'), + showCancelButton: true, + confirmButtonText: t('message.user.logOutConfirm'), + cancelButtonText: t('message.user.logOutCancel'), + buttonSize: 'default', + beforeClose: (action, instance, done) => { + if (action === 'confirm') { + instance.confirmButtonLoading = true; + instance.confirmButtonText = t('message.user.logOutExit'); + setTimeout(() => { + done(); + setTimeout(() => { + instance.confirmButtonLoading = false; + }, 300); + }, 700); + } else { + done(); + } + }, + }) + .then(async () => { + Session.clear(); // 清除缓存/token等 + // 使用 reload 时,不需要调用 resetRoute() 重置路由 + window.location.reload(); + }) + .catch(() => {}); + } else if (path === 'wareHouse') { + window.open('https://gitee.com/lyt-top/vue-next-admin'); + } else { + router.push(path); + } + }; + // 菜单搜索点击 + const onSearchClick = () => { + searchRef.value.openSearch(); + }; + // 组件大小改变 + const onComponentSizeChange = (size: string) => { + Local.remove('themeConfig'); + themeConfig.value.globalComponentSize = size; + Local.set('themeConfig', themeConfig.value); + initComponentSize(); + window.location.reload(); + }; + // 语言切换 + const onLanguageChange = (lang: string) => { + Local.remove('themeConfig'); + themeConfig.value.globalI18n = lang; + Local.set('themeConfig', themeConfig.value); + proxy.$i18n.locale = lang; + initI18n(); + other.useTitle(); + }; + // 设置 element plus 组件的国际化 + const setI18nConfig = (locale: string) => { + proxy.mittBus.emit('getI18nConfig', proxy.$i18n.messages[locale]); + }; + // 初始化言语国际化 + const initI18n = () => { + switch (Local.get('themeConfig').globalI18n) { + case 'zh-cn': + state.disabledI18n = 'zh-cn'; + setI18nConfig('zh-cn'); + break; + case 'en': + state.disabledI18n = 'en'; + setI18nConfig('en'); + break; + case 'zh-tw': + state.disabledI18n = 'zh-tw'; + setI18nConfig('zh-tw'); + break; + } + }; + // 初始化全局组件大小 + const initComponentSize = () => { + switch (Local.get('themeConfig').globalComponentSize) { + case 'large': + state.disabledSize = 'large'; + break; + case 'default': + state.disabledSize = 'default'; + break; + case 'small': + state.disabledSize = 'small'; + break; + } + }; + // 页面加载时 + onMounted(() => { + if (Local.get('themeConfig')) { + initI18n(); + initComponentSize(); + } + }); + return { + userInfos, + onLayoutSetingClick, + onHandleCommandClick, + onScreenfullClick, + onSearchClick, + onComponentSizeChange, + onLanguageChange, + searchRef, + layoutUserFlexNum, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.layout-navbars-breadcrumb-user { + display: flex; + align-items: center; + justify-content: flex-end; + &-link { + height: 100%; + display: flex; + align-items: center; + white-space: nowrap; + &-photo { + width: 25px; + height: 25px; + border-radius: 100%; + } + } + &-icon { + padding: 0 10px; + cursor: pointer; + color: var(--next-bg-topBarColor); + height: 50px; + line-height: 50px; + display: flex; + align-items: center; + &:hover { + background: var(--next-color-user-hover); + i { + display: inline-block; + animation: logoAnimation 0.3s ease-in-out; + } + } + } + ::v-deep(.el-dropdown) { + color: var(--next-bg-topBarColor); + } + ::v-deep(.el-badge) { + height: 40px; + line-height: 40px; + display: flex; + align-items: center; + } + ::v-deep(.el-badge__content.is-fixed) { + top: 12px; + } +} +</style> diff --git a/src/layout/navBars/breadcrumb/userNews.vue b/src/layout/navBars/breadcrumb/userNews.vue new file mode 100644 index 0000000..cae954a --- /dev/null +++ b/src/layout/navBars/breadcrumb/userNews.vue @@ -0,0 +1,115 @@ +<template> + <div class="layout-navbars-breadcrumb-user-news"> + <div class="head-box"> + <div class="head-box-title">{{ $t('message.user.newTitle') }}</div> + <div class="head-box-btn" v-if="newsList.length > 0" @click="onAllReadClick">{{ $t('message.user.newBtn') }}</div> + </div> + <div class="content-box"> + <template v-if="newsList.length > 0"> + <div class="content-box-item" v-for="(v, k) in newsList" :key="k"> + <div>{{ v.label }}</div> + <div class="content-box-msg"> + {{ v.value }} + </div> + <div class="content-box-time">{{ v.time }}</div> + </div> + </template> + <el-empty :description="$t('message.user.newDesc')" v-else></el-empty> + </div> + <div class="foot-box" @click="onGoToGiteeClick" v-if="newsList.length > 0">{{ $t('message.user.newGo') }}</div> + </div> +</template> + +<script lang="ts"> +import { reactive, toRefs, defineComponent } from 'vue'; + +export default defineComponent({ + name: 'layoutBreadcrumbUserNews', + setup() { + const state = reactive({ + newsList: [ + { + label: '关于版本发布的通知', + value: 'vue-next-admin,基于 vue3 + CompositionAPI + typescript + vite + element plus,正式发布时间:2021年02月28日!', + time: '2020-12-08', + }, + { + label: '关于学习交流的通知', + value: 'QQ群号码 665452019,欢迎小伙伴入群学习交流探讨!', + time: '2020-12-08', + }, + ], + }); + // 全部已读点击 + const onAllReadClick = () => { + state.newsList = []; + }; + // 前往通知中心点击 + const onGoToGiteeClick = () => { + window.open('https://gitee.com/lyt-top/vue-next-admin'); + }; + return { + onAllReadClick, + onGoToGiteeClick, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.layout-navbars-breadcrumb-user-news { + .head-box { + display: flex; + border-bottom: 1px solid var(--el-border-color-lighter); + box-sizing: border-box; + color: var(--el-text-color-primary); + justify-content: space-between; + height: 35px; + align-items: center; + .head-box-btn { + color: var(--el-color-primary); + font-size: 13px; + cursor: pointer; + opacity: 0.8; + &:hover { + opacity: 1; + } + } + } + .content-box { + font-size: 13px; + .content-box-item { + padding-top: 12px; + &:last-of-type { + padding-bottom: 12px; + } + .content-box-msg { + color: var(--el-text-color-secondary); + margin-top: 5px; + margin-bottom: 5px; + } + .content-box-time { + color: var(--el-text-color-secondary); + } + } + } + .foot-box { + height: 35px; + color: var(--el-color-primary); + font-size: 13px; + cursor: pointer; + opacity: 0.8; + display: flex; + align-items: center; + justify-content: center; + border-top: 1px solid var(--el-border-color-lighter); + &:hover { + opacity: 1; + } + } + ::v-deep(.el-empty__description p) { + font-size: 13px; + } +} +</style> diff --git a/src/layout/navBars/index.vue b/src/layout/navBars/index.vue new file mode 100644 index 0000000..f41a0cf --- /dev/null +++ b/src/layout/navBars/index.vue @@ -0,0 +1,40 @@ +<template> + <div class="layout-navbars-container"> + <BreadcrumbIndex /> + <TagsView v-if="setShowTagsView" /> + </div> +</template> + +<script lang="ts"> +import { computed, defineComponent } from 'vue'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import BreadcrumbIndex from '/@/layout/navBars/breadcrumb/index.vue'; +import TagsView from '/@/layout/navBars/tagsView/tagsView.vue'; + +export default defineComponent({ + name: 'layoutNavBars', + components: { BreadcrumbIndex, TagsView }, + setup() { + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + // 是否显示 tagsView + const setShowTagsView = computed(() => { + let { layout, isTagsview } = themeConfig.value; + return layout !== 'classic' && isTagsview; + }); + return { + setShowTagsView, + }; + }, +}); +</script> + +<style scoped lang="scss"> +.layout-navbars-container { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; +} +</style> diff --git a/src/layout/navBars/tagsView/contextmenu.vue b/src/layout/navBars/tagsView/contextmenu.vue new file mode 100644 index 0000000..c717aae --- /dev/null +++ b/src/layout/navBars/tagsView/contextmenu.vue @@ -0,0 +1,138 @@ +<template> + <transition name="el-zoom-in-center"> + <div + aria-hidden="true" + class="el-dropdown__popper el-popper is-light is-pure custom-contextmenu" + role="tooltip" + data-popper-placement="bottom" + :style="`top: ${dropdowns.y + 5}px;left: ${dropdowns.x}px;`" + :key="Math.random()" + v-show="isShow" + > + <ul class="el-dropdown-menu"> + <template v-for="(v, k) in dropdownList"> + <li + class="el-dropdown-menu__item" + aria-disabled="false" + tabindex="-1" + :key="k" + v-if="!v.affix" + @click="onCurrentContextmenuClick(v.contextMenuClickId)" + > + <SvgIcon :name="v.icon" /> + <span>{{ $t(v.txt) }}</span> + </li> + </template> + </ul> + <div class="el-popper__arrow" :style="{ left: `${arrowLeft}px` }"></div> + </div> + </transition> +</template> + +<script lang="ts"> +import { computed, defineComponent, reactive, toRefs, onMounted, onUnmounted, watch } from 'vue'; + +export default defineComponent({ + name: 'layoutTagsViewContextmenu', + props: { + dropdown: { + type: Object, + default: () => { + return { + x: 0, + y: 0, + }; + }, + }, + }, + setup(props, { emit }) { + const state = reactive({ + isShow: false, + dropdownList: [ + { contextMenuClickId: 0, txt: 'message.tagsView.refresh', affix: false, icon: 'ele-RefreshRight' }, + { contextMenuClickId: 1, txt: 'message.tagsView.close', affix: false, icon: 'ele-Close' }, + { contextMenuClickId: 2, txt: 'message.tagsView.closeOther', affix: false, icon: 'ele-CircleClose' }, + { contextMenuClickId: 3, txt: 'message.tagsView.closeAll', affix: false, icon: 'ele-FolderDelete' }, + { + contextMenuClickId: 4, + txt: 'message.tagsView.fullscreen', + affix: false, + icon: 'iconfont icon-fullscreen', + }, + ], + item: {}, + arrowLeft: 10, + }); + // 父级传过来的坐标 x,y 值 + const dropdowns = computed(() => { + // 117 为 `Dropdown 下拉菜单` 的宽度 + if (props.dropdown.x + 117 > document.documentElement.clientWidth) { + return { + x: document.documentElement.clientWidth - 117 - 5, + y: props.dropdown.y, + }; + } else { + return props.dropdown; + } + }); + // 当前项菜单点击 + const onCurrentContextmenuClick = (contextMenuClickId: number) => { + emit('currentContextmenuClick', Object.assign({}, { contextMenuClickId }, state.item)); + }; + // 打开右键菜单:判断是否固定,固定则不显示关闭按钮 + const openContextmenu = (item: any) => { + state.item = item; + item.meta.isAffix ? (state.dropdownList[1].affix = true) : (state.dropdownList[1].affix = false); + closeContextmenu(); + setTimeout(() => { + state.isShow = true; + }, 10); + }; + // 关闭右键菜单 + const closeContextmenu = () => { + state.isShow = false; + }; + // 监听页面监听进行右键菜单的关闭 + onMounted(() => { + document.body.addEventListener('click', closeContextmenu); + }); + // 页面卸载时,移除右键菜单监听事件 + onUnmounted(() => { + document.body.removeEventListener('click', closeContextmenu); + }); + // 监听下拉菜单位置 + watch( + () => props.dropdown, + ({ x }) => { + if (x + 117 > document.documentElement.clientWidth) state.arrowLeft = 117 - (document.documentElement.clientWidth - x); + else state.arrowLeft = 10; + }, + { + deep: true, + } + ); + return { + dropdowns, + openContextmenu, + closeContextmenu, + onCurrentContextmenuClick, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.custom-contextmenu { + transform-origin: center top; + z-index: 2190; + position: fixed; + .el-dropdown-menu__item { + font-size: 12px !important; + white-space: nowrap; + i { + font-size: 12px !important; + } + } +} +</style> diff --git a/src/layout/navBars/tagsView/tagsView.vue b/src/layout/navBars/tagsView/tagsView.vue new file mode 100644 index 0000000..67e1b57 --- /dev/null +++ b/src/layout/navBars/tagsView/tagsView.vue @@ -0,0 +1,734 @@ +<template> + <div class="layout-navbars-tagsview" :class="{ 'layout-navbars-tagsview-shadow': getThemeConfig.layout === 'classic' }"> + <el-scrollbar ref="scrollbarRef" @wheel.prevent="onHandleScroll"> + <ul class="layout-navbars-tagsview-ul" :class="setTagsStyle" ref="tagsUlRef"> + <li + v-for="(v, k) in tagsViewList" + :key="k" + class="layout-navbars-tagsview-ul-li" + :data-url="v.url" + :class="{ 'is-active': isActive(v) }" + @contextmenu.prevent="onContextmenu(v, $event)" + @click="onTagsClick(v, k)" + :ref=" + (el) => { + if (el) tagsRefs[k] = el; + } + " + > + <i class="iconfont icon-webicon318 layout-navbars-tagsview-ul-li-iconfont" v-if="isActive(v)"></i> + <SvgIcon :name="v.meta.icon" v-if="!isActive(v) && getThemeConfig.isTagsviewIcon" class="pr5" /> + <span>{{ setTagsViewNameI18n(v) }}</span> + <template v-if="isActive(v)"> + <SvgIcon + name="ele-RefreshRight" + class="ml5 layout-navbars-tagsview-ul-li-refresh" + @click.stop="refreshCurrentTagsView($route.fullPath)" + /> + <SvgIcon + name="ele-Close" + class="layout-navbars-tagsview-ul-li-icon layout-icon-active" + v-if="!v.meta.isAffix" + @click.stop="closeCurrentTagsView(getThemeConfig.isShareTagsView ? v.path : v.url)" + /> + </template> + <SvgIcon + name="ele-Close" + class="layout-navbars-tagsview-ul-li-icon layout-icon-three" + v-if="!v.meta.isAffix" + @click.stop="closeCurrentTagsView(getThemeConfig.isShareTagsView ? v.path : v.url)" + /> + </li> + </ul> + </el-scrollbar> + <Contextmenu :dropdown="dropdown" ref="contextmenuRef" @currentContextmenuClick="onCurrentContextmenuClick" /> + </div> +</template> + +<script lang="ts"> +import { + toRefs, + reactive, + onMounted, + computed, + ref, + nextTick, + onBeforeUpdate, + onBeforeMount, + onUnmounted, + getCurrentInstance, + watch, + defineComponent, +} from 'vue'; +import { useRoute, useRouter, onBeforeRouteUpdate } from 'vue-router'; +import Sortable from 'sortablejs'; +import { ElMessage } from 'element-plus'; +import { storeToRefs } from 'pinia'; +import pinia from '/@/stores/index'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { useKeepALiveNames } from '/@/stores/keepAliveNames'; +import { Session } from '/@/utils/storage'; +import { isObjectValueEqual } from '/@/utils/arrayOperation'; +import other from '/@/utils/other'; +import Contextmenu from '/@/layout/navBars/tagsView/contextmenu.vue'; + +// 定义接口来定义对象的类型 +interface TagsViewState { + routeActive: string; + routePath: string | unknown; + dropdown: { + x: string | number; + y: string | number; + }; + sortable: any; + tagsRefsIndex: number; + tagsViewList: any[]; + tagsViewRoutesList: any[]; +} +interface RouteParams { + path: string; + url: string; + query: object; + params: object; +} +interface CurrentContextmenu { + meta: { + isDynamic: boolean; + }; + params: any; + query: any; + path: string; + contextMenuClickId: string | number; +} + +export default defineComponent({ + name: 'layoutTagsView', + components: { Contextmenu }, + setup() { + const { proxy } = <any>getCurrentInstance(); + const tagsRefs = ref<any[]>([]); + const scrollbarRef = ref(); + const contextmenuRef = ref(); + const tagsUlRef = ref(); + const stores = useTagsViewRoutes(); + const storesThemeConfig = useThemeConfig(); + const storesTagsViewRoutes = useTagsViewRoutes(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const { tagsViewRoutes } = storeToRefs(storesTagsViewRoutes); + const storesKeepALiveNames = useKeepALiveNames(); + const route = useRoute(); + const router = useRouter(); + const state = reactive<TagsViewState>({ + routeActive: '', + routePath: route.path, + dropdown: { x: '', y: '' }, + sortable: '', + tagsRefsIndex: 0, + tagsViewList: [], + tagsViewRoutesList: [], + }); + // 动态设置 tagsView 风格样式 + const setTagsStyle = computed(() => { + return themeConfig.value.tagsStyle; + }); + // 获取布局配置信息 + const getThemeConfig = computed(() => { + return themeConfig.value; + }); + // 设置 自定义 tagsView 名称、 自定义 tagsView 名称国际化 + const setTagsViewNameI18n = computed(() => { + return (v: any) => { + return other.setTagsViewNameI18n(v); + }; + }); + // 设置 tagsView 高亮 + const isActive = (v: RouteParams) => { + if (getThemeConfig.value.isShareTagsView) { + return v.path === state.routePath; + } else { + if ((v.query && Object.keys(v.query).length) || (v.params && Object.keys(v.params).length)) { + // 普通传参 + return v.url ? v.url === state.routeActive : v.path === state.routeActive; + } else { + // 通过 name 传参,params 取值,刷新页面参数消失 + // https://gitee.com/lyt-top/vue-next-admin/issues/I51RS9 + return v.path === state.routePath; + } + } + }; + // 存储 tagsViewList 到浏览器临时缓存中,页面刷新时,保留记录 + const addBrowserSetSession = (tagsViewList: Array<object>) => { + Session.set('tagsViewList', tagsViewList); + }; + // 获取 vuex 中的 tagsViewRoutes 列表 + const getTagsViewRoutes = async () => { + state.routeActive = await setTagsViewHighlight(route); + state.routePath = (await route.meta.isDynamic) ? route.meta.isDynamicPath : route.path; + state.tagsViewList = []; + state.tagsViewRoutesList = tagsViewRoutes.value; + initTagsView(); + }; + // vuex 中获取路由信息:如果是设置了固定的(isAffix),进行初始化显示 + const initTagsView = async () => { + if (Session.get('tagsViewList') && getThemeConfig.value.isCacheTagsView) { + state.tagsViewList = await Session.get('tagsViewList'); + } else { + await state.tagsViewRoutesList.map((v: any) => { + if (v.meta.isAffix && !v.meta.isHide) { + v.url = setTagsViewHighlight(v); + state.tagsViewList.push({ ...v }); + storesKeepALiveNames.addCachedView(v); + } + }); + await addTagsView(route.path, route); + } + // 初始化当前元素(li)的下标 + getTagsRefsIndex(getThemeConfig.value.isShareTagsView ? state.routePath : state.routeActive); + }; + // 处理可开启多标签详情,单标签详情(动态路由(xxx/:id/:name"),普通路由处理) + const solveAddTagsView = async (path: string, to?: any) => { + let isDynamicPath = to.meta.isDynamic ? to.meta.isDynamicPath : path; + let current = state.tagsViewList.filter( + (v: any) => + v.path === isDynamicPath && + isObjectValueEqual( + to.meta.isDynamic ? (v.params ? v.params : null) : v.query ? v.query : null, + to.meta.isDynamic ? (to?.params ? to?.params : null) : to?.query ? to?.query : null + ) + ); + if (current.length <= 0) { + // 防止:Avoid app logic that relies on enumerating keys on a component instance. The keys will be empty in production mode to avoid performance overhead. + let findItem = state.tagsViewRoutesList.find((v: any) => v.path === isDynamicPath); + if (!findItem) return false; + if (findItem.meta.isAffix) return false; + if (findItem.meta.isLink && !findItem.meta.isIframe) return false; + to.meta.isDynamic ? (findItem.params = to.params) : (findItem.query = to.query); + findItem.url = setTagsViewHighlight(findItem); + state.tagsViewList.push({ ...findItem }); + await storesKeepALiveNames.addCachedView(findItem); + addBrowserSetSession(state.tagsViewList); + } + }; + // 处理单标签时,第二次的值未覆盖第一次的 tagsViewList 值(Session Storage) + const singleAddTagsView = (path: string, to?: any) => { + let isDynamicPath = to.meta.isDynamic ? to.meta.isDynamicPath : path; + state.tagsViewList.forEach((v) => { + if ( + v.path === isDynamicPath && + !isObjectValueEqual( + to.meta.isDynamic ? (v.params ? v.params : null) : v.query ? v.query : null, + to.meta.isDynamic ? (to?.params ? to?.params : null) : to?.query ? to?.query : null + ) + ) { + to.meta.isDynamic ? (v.params = to.params) : (v.query = to.query); + v.url = setTagsViewHighlight(v); + addBrowserSetSession(state.tagsViewList); + } + }); + }; + // 1、添加 tagsView:未设置隐藏(isHide)也添加到在 tagsView 中(可开启多标签详情,单标签详情) + const addTagsView = (path: string, to?: any) => { + // 防止拿取不到路由信息 + nextTick(async () => { + // 修复:https://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G + let item: any = ''; + if (to && to.meta.isDynamic) { + // 动态路由(xxx/:id/:name"):参数不同,开启多个 tagsview + if (!getThemeConfig.value.isShareTagsView) await solveAddTagsView(path, to); + else await singleAddTagsView(path, to); + if (state.tagsViewList.some((v: any) => v.path === to.meta.isDynamicPath)) return false; + item = state.tagsViewRoutesList.find((v: any) => v.path === to.meta.isDynamicPath); + } else { + // 普通路由:参数不同,开启多个 tagsview + if (!getThemeConfig.value.isShareTagsView) await solveAddTagsView(path, to); + else await singleAddTagsView(path, to); + if (state.tagsViewList.some((v: any) => v.path === path)) return false; + item = state.tagsViewRoutesList.find((v: any) => v.path === path); + } + if (!item) return false; + if (item.meta.isLink && !item.meta.isIframe) return false; + if (to && to.meta.isDynamic) item.params = to?.params ? to?.params : route.params; + else item.query = to?.query ? to?.query : route.query; + item.url = setTagsViewHighlight(item); + await storesKeepALiveNames.addCachedView(item); + await state.tagsViewList.push({ ...item }); + await addBrowserSetSession(state.tagsViewList); + }); + }; + // 2、刷新当前 tagsView: + const refreshCurrentTagsView = async (fullPath: string) => { + const item = state.tagsViewList.find((v: any) => (getThemeConfig.value.isShareTagsView ? v.path === fullPath : v.url === fullPath)); + if (item != null) { + await storesKeepALiveNames.delCachedView(item); + proxy.mittBus.emit('onTagsViewRefreshRouterView', fullPath); + if (item.meta.isKeepAlive) storesKeepALiveNames.addCachedView(item); + } + }; + // 3、关闭当前 tagsView:如果是设置了固定的(isAffix),不可以关闭 + const closeCurrentTagsView = (path: string) => { + state.tagsViewList.map((v: any, k: number, arr: any) => { + if (!v.meta.isAffix) { + if (getThemeConfig.value.isShareTagsView ? v.path === path : v.url === path) { + storesKeepALiveNames.delCachedView(v); + state.tagsViewList.splice(k, 1); + setTimeout(() => { + if (state.tagsViewList.length === k && getThemeConfig.value.isShareTagsView ? state.routePath === path : state.routeActive === path) { + // 最后一个且高亮时 + if (arr[arr.length - 1].meta.isDynamic) { + // 动态路由(xxx/:id/:name") + if (k !== arr.length) router.push({ name: arr[k].name, params: arr[k].params }); + else router.push({ name: arr[arr.length - 1].name, params: arr[arr.length - 1].params }); + } else { + // 普通路由 + if (k !== arr.length) router.push({ path: arr[k].path, query: arr[k].query }); + else router.push({ path: arr[arr.length - 1].path, query: arr[arr.length - 1].query }); + } + } else { + // 非最后一个且高亮时,跳转到下一个 + if (state.tagsViewList.length !== k && getThemeConfig.value.isShareTagsView ? state.routePath === path : state.routeActive === path) { + if (arr[k].meta.isDynamic) { + // 动态路由(xxx/:id/:name") + router.push({ name: arr[k].name, params: arr[k].params }); + } else { + // 普通路由 + router.push({ path: arr[k].path, query: arr[k].query }); + } + } + } + }, 0); + } + } + }); + addBrowserSetSession(state.tagsViewList); + }; + // 4、关闭其它 tagsView:如果是设置了固定的(isAffix),不进行关闭 + const closeOtherTagsView = (path: string) => { + if (Session.get('tagsViewList')) { + state.tagsViewList = []; + Session.get('tagsViewList').map((v: any) => { + if (v.meta.isAffix && !v.meta.isHide) { + v.url = setTagsViewHighlight(v); + storesKeepALiveNames.delOthersCachedViews(v); + state.tagsViewList.push({ ...v }); + } + }); + addTagsView(path, route); + addBrowserSetSession(state.tagsViewList); + } + }; + // 5、关闭全部 tagsView:如果是设置了固定的(isAffix),不进行关闭 + const closeAllTagsView = () => { + if (Session.get('tagsViewList')) { + storesKeepALiveNames.delAllCachedViews(); + state.tagsViewList = []; + Session.get('tagsViewList').map((v: any) => { + if (v.meta.isAffix && !v.meta.isHide) { + v.url = setTagsViewHighlight(v); + state.tagsViewList.push({ ...v }); + router.push({ path: state.tagsViewList[state.tagsViewList.length - 1].path }); + } + }); + addBrowserSetSession(state.tagsViewList); + } + }; + // 6、开启当前页面全屏 + const openCurrenFullscreen = async (path: string) => { + const item = state.tagsViewList.find((v: any) => (getThemeConfig.value.isShareTagsView ? v.path === path : v.url === path)); + if (item.meta.isDynamic) await router.push({ name: item.name, params: item.params }); + else await router.push({ name: item.name, query: item.query }); + stores.setCurrenFullscreen(true); + }; + // 当前项右键菜单点击,拿当前点击的路由路径对比 浏览器缓存中的 tagsView 路由数组,取当前点击项的详细路由信息 + // 防止 tagsView 非当前页演示时,操作异常 + const getCurrentRouteItem = (path: string, cParams: any) => { + const itemRoute = Session.get('tagsViewList') ? Session.get('tagsViewList') : state.tagsViewList; + return itemRoute.find((v: any) => { + if ( + v.path === path && + isObjectValueEqual( + v.meta.isDynamic ? (v.params ? v.params : null) : v.query ? v.query : null, + cParams && Object.keys(cParams ? cParams : {}).length > 0 ? cParams : null + ) + ) { + return v; + } else if (v.path === path && Object.keys(cParams ? cParams : {}).length <= 0) { + return v; + } + }); + }; + // 当前项右键菜单点击 + const onCurrentContextmenuClick = async (item: CurrentContextmenu) => { + const cParams = item.meta.isDynamic ? item.params : item.query; + if (!getCurrentRouteItem(item.path, cParams)) return ElMessage({ type: 'warning', message: '请正确输入路径及完整参数(query、params)' }); + const { path, name, params, query, meta, url } = getCurrentRouteItem(item.path, cParams); + switch (item.contextMenuClickId) { + case 0: + // 刷新当前 + if (meta.isDynamic) await router.push({ name, params }); + else await router.push({ path, query }); + refreshCurrentTagsView(route.fullPath); + break; + case 1: + // 关闭当前 + closeCurrentTagsView(getThemeConfig.value.isShareTagsView ? path : url); + break; + case 2: + // 关闭其它 + if (meta.isDynamic) await router.push({ name, params }); + else await router.push({ path, query }); + closeOtherTagsView(path); + break; + case 3: + // 关闭全部 + closeAllTagsView(); + break; + case 4: + // 开启当前页面全屏 + openCurrenFullscreen(getThemeConfig.value.isShareTagsView ? path : url); + break; + } + }; + // 右键点击时:传 x,y 坐标值到子组件中(props) + const onContextmenu = (v: any, e: any) => { + const { clientX, clientY } = e; + state.dropdown.x = clientX; + state.dropdown.y = clientY; + contextmenuRef.value.openContextmenu(v); + }; + // 当前的 tagsView 项点击时 + const onTagsClick = (v: any, k: number) => { + state.tagsRefsIndex = k; + router.push(v); + }; + // 处理 tagsView 高亮(多标签详情时使用,单标签详情未使用) + const setTagsViewHighlight = (v: any) => { + let params = v.query && Object.keys(v.query).length > 0 ? v.query : v.params; + if (!params || Object.keys(params).length <= 0) return v.path; + let path = ''; + for (let i in params) { + path += params[i]; + } + // 判断是否是动态路由(xxx/:id/:name") + return `${v.meta.isDynamic ? v.meta.isDynamicPath : v.path}-${path}`; + }; + // 更新滚动条显示 + const updateScrollbar = () => { + proxy.$refs.scrollbarRef.update(); + }; + // 鼠标滚轮滚动 + const onHandleScroll = (e: any) => { + proxy.$refs.scrollbarRef.$refs.wrap$.scrollLeft += e.wheelDelta / 4; + }; + // tagsView 横向滚动 + const tagsViewmoveToCurrentTag = () => { + nextTick(() => { + if (tagsRefs.value.length <= 0) return false; + // 当前 li 元素 + let liDom = tagsRefs.value[state.tagsRefsIndex]; + // 当前 li 元素下标 + let liIndex = state.tagsRefsIndex; + // 当前 ul 下 li 元素总长度 + let liLength = tagsRefs.value.length; + // 最前 li + let liFirst: any = tagsRefs.value[0]; + // 最后 li + let liLast: any = tagsRefs.value[tagsRefs.value.length - 1]; + // 当前滚动条的值 + let scrollRefs = proxy.$refs.scrollbarRef.$refs.wrap$; + // 当前滚动条滚动宽度 + let scrollS = scrollRefs.scrollWidth; + // 当前滚动条偏移宽度 + let offsetW = scrollRefs.offsetWidth; + // 当前滚动条偏移距离 + let scrollL = scrollRefs.scrollLeft; + // 上一个 tags li dom + let liPrevTag: any = tagsRefs.value[state.tagsRefsIndex - 1]; + // 下一个 tags li dom + let liNextTag: any = tagsRefs.value[state.tagsRefsIndex + 1]; + // 上一个 tags li dom 的偏移距离 + let beforePrevL: any = ''; + // 下一个 tags li dom 的偏移距离 + let afterNextL: any = ''; + if (liDom === liFirst) { + // 头部 + scrollRefs.scrollLeft = 0; + } else if (liDom === liLast) { + // 尾部 + scrollRefs.scrollLeft = scrollS - offsetW; + } else { + // 非头/尾部 + if (liIndex === 0) beforePrevL = liFirst.offsetLeft - 5; + else beforePrevL = liPrevTag?.offsetLeft - 5; + if (liIndex === liLength) afterNextL = liLast.offsetLeft + liLast.offsetWidth + 5; + else afterNextL = liNextTag.offsetLeft + liNextTag.offsetWidth + 5; + if (afterNextL > scrollL + offsetW) { + scrollRefs.scrollLeft = afterNextL - offsetW; + } else if (beforePrevL < scrollL) { + scrollRefs.scrollLeft = beforePrevL; + } + } + // 更新滚动条,防止不出现 + updateScrollbar(); + }); + }; + // 获取 tagsView 的下标:用于处理 tagsView 点击时的横向滚动 + const getTagsRefsIndex = (path: string | unknown) => { + nextTick(async () => { + // await 使用该写法,防止拿取不到 tagsViewList 列表数据不完整 + let tagsViewList = await state.tagsViewList; + state.tagsRefsIndex = tagsViewList.findIndex((v: any) => { + if (getThemeConfig.value.isShareTagsView) { + return v.path === path; + } else { + return v.url === path; + } + }); + // 添加初始化横向滚动条移动到对应位置 + tagsViewmoveToCurrentTag(); + }); + }; + // 设置 tagsView 可以进行拖拽 + const initSortable = async () => { + const el = <HTMLElement>document.querySelector('.layout-navbars-tagsview-ul'); + if (!el) return false; + state.sortable.el && state.sortable.destroy(); + state.sortable = Sortable.create(el, { + animation: 300, + dataIdAttr: 'data-url', + disabled: getThemeConfig.value.isSortableTagsView ? false : true, + onEnd: () => { + const sortEndList: any = []; + state.sortable.toArray().map((val: any) => { + state.tagsViewList.map((v: any) => { + if (v.url === val) sortEndList.push({ ...v }); + }); + }); + addBrowserSetSession(sortEndList); + }, + }); + }; + // 拖动问题,https://gitee.com/lyt-top/vue-next-admin/issues/I3ZRRI + const onSortableResize = async () => { + await initSortable(); + if (other.isMobile()) state.sortable.el && state.sortable.destroy(); + }; + // 页面加载前 + onBeforeMount(() => { + // 初始化,防止手机端直接访问时还可以拖拽 + onSortableResize(); + // 拖动问题,https://gitee.com/lyt-top/vue-next-admin/issues/I3ZRRI + window.addEventListener('resize', onSortableResize); + // 监听非本页面调用 0 刷新当前,1 关闭当前,2 关闭其它,3 关闭全部 4 当前页全屏 + proxy.mittBus.on('onCurrentContextmenuClick', (data: CurrentContextmenu) => { + onCurrentContextmenuClick(data); + }); + // 监听布局配置界面开启/关闭拖拽 + proxy.mittBus.on('openOrCloseSortable', () => { + initSortable(); + }); + // 监听布局配置开启 TagsView 共用,为了演示还原默认值 + proxy.mittBus.on('openShareTagsView', () => { + if (getThemeConfig.value.isShareTagsView) { + router.push('/home'); + state.tagsViewList = []; + state.tagsViewRoutesList.map((v: any) => { + if (v.meta.isAffix && !v.meta.isHide) { + v.url = setTagsViewHighlight(v); + state.tagsViewList.push({ ...v }); + } + }); + } + }); + }); + // 页面卸载时 + onUnmounted(() => { + // 取消非本页面调用监听 + proxy.mittBus.off('onCurrentContextmenuClick', () => {}); + // 取消监听布局配置界面开启/关闭拖拽 + proxy.mittBus.off('openOrCloseSortable', () => {}); + // 取消监听布局配置开启 TagsView 共用 + proxy.mittBus.off('openShareTagsView', () => {}); + // 取消窗口 resize 监听 + window.removeEventListener('resize', onSortableResize); + }); + // 页面更新时 + onBeforeUpdate(() => { + tagsRefs.value = []; + }); + // 页面加载时 + onMounted(() => { + // 初始化 pinia 中的 tagsViewRoutes 列表 + getTagsViewRoutes(); + initSortable(); + }); + // 路由更新时(组件内生命钩子) + onBeforeRouteUpdate(async (to) => { + state.routeActive = setTagsViewHighlight(to); + state.routePath = to.meta.isDynamic ? to.meta.isDynamicPath : to.path; + await addTagsView(to.path, to); + getTagsRefsIndex(getThemeConfig.value.isShareTagsView ? state.routePath : state.routeActive); + }); + // 监听路由的变化,动态赋值给 tagsView + watch( + pinia.state, + (val) => { + if (val.tagsViewRoutes.tagsViewRoutes.length === state.tagsViewRoutesList.length) return false; + getTagsViewRoutes(); + }, + { + deep: true, + } + ); + return { + isActive, + onContextmenu, + onTagsClick, + tagsRefs, + contextmenuRef, + scrollbarRef, + tagsUlRef, + onHandleScroll, + getThemeConfig, + setTagsStyle, + setTagsViewNameI18n, + refreshCurrentTagsView, + closeCurrentTagsView, + onCurrentContextmenuClick, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.layout-navbars-tagsview { + background-color: var(--el-color-white); + border-bottom: 1px solid var(--next-border-color-light); + position: relative; + z-index: 4; + ::v-deep(.el-scrollbar__wrap) { + overflow-x: auto !important; + } + &-ul { + list-style: none; + margin: 0; + padding: 0; + height: 34px; + display: flex; + align-items: center; + color: var(--el-text-color-regular); + font-size: 12px; + white-space: nowrap; + padding: 0 15px; + &-li { + height: 26px; + line-height: 26px; + display: flex; + align-items: center; + border: 1px solid var(--el-border-color-lighter); + padding: 0 15px; + margin-right: 5px; + border-radius: 2px; + position: relative; + z-index: 0; + cursor: pointer; + justify-content: space-between; + &:hover { + background-color: var(--el-color-primary-light-9); + color: var(--el-color-primary); + border-color: var(--el-color-primary-light-5); + } + &-iconfont { + position: relative; + left: -5px; + font-size: 12px; + } + &-icon { + border-radius: 100%; + position: relative; + height: 14px; + width: 14px; + text-align: center; + line-height: 14px; + right: -5px; + &:hover { + color: var(--el-color-white); + background-color: var(--el-color-primary-light-3); + } + } + .layout-icon-active { + display: block; + } + .layout-icon-three { + display: none; + } + } + .is-active { + color: var(--el-color-white); + background: var(--el-color-primary); + border-color: var(--el-color-primary); + transition: border-color 3s ease; + } + } + // 风格4 + .tags-style-four { + .layout-navbars-tagsview-ul-li { + margin-right: 0 !important; + border: none !important; + position: relative; + border-radius: 3px !important; + .layout-icon-active { + display: none; + } + .layout-icon-three { + display: block; + } + &:hover { + background: none !important; + } + } + .is-active { + background: none !important; + color: var(--el-color-primary) !important; + } + } + // 风格5 + .tags-style-five { + align-items: flex-end; + .tags-style-five-svg { + -webkit-mask-box-image: url("data:image/svg+xml,%3Csvg width='68' height='34' viewBox='0 0 68 34' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='m27,0c-7.99582,0 -11.95105,0.00205 -12,12l0,6c0,8.284 -0.48549,16.49691 -8.76949,16.49691l54.37857,-0.11145c-8.284,0 -8.60908,-8.10146 -8.60908,-16.38546l0,-6c0.11145,-12.08445 -4.38441,-12 -12,-12l-13,0z' fill='%23409eff'/%3E%3C/svg%3E") + 12 27 15; + } + .layout-navbars-tagsview-ul-li { + padding: 0 5px; + border-width: 15px 27px 15px; + border-style: solid; + border-color: transparent; + margin: 0 -15px; + .layout-icon-active, + .layout-navbars-tagsview-ul-li-iconfont, + .layout-navbars-tagsview-ul-li-refresh { + display: none; + } + .layout-icon-three { + display: block; + } + &:hover { + @extend .tags-style-five-svg; + background: var(--el-color-primary-light-9); + color: unset; + } + } + .is-active { + @extend .tags-style-five-svg; + background: var(--el-color-primary-light-9) !important; + color: var(--el-color-primary) !important; + z-index: 1; + } + } +} +.layout-navbars-tagsview-shadow { + box-shadow: rgb(0 21 41 / 4%) 0px 1px 4px; +} +</style> diff --git a/src/layout/navMenu/horizontal.vue b/src/layout/navMenu/horizontal.vue new file mode 100644 index 0000000..f738dd6 --- /dev/null +++ b/src/layout/navMenu/horizontal.vue @@ -0,0 +1,157 @@ +<template> + <div class="el-menu-horizontal-warp"> + <el-scrollbar @wheel.native.prevent="onElMenuHorizontalScroll" ref="elMenuHorizontalScrollRef"> + <el-menu router :default-active="defaultActive" :ellipsis="false" background-color="transparent" mode="horizontal"> + <template v-for="val in menuLists"> + <el-sub-menu :index="val.path" v-if="val.children && val.children.length > 0" :key="val.path"> + <template #title> + <SvgIcon :name="val.meta.icon" /> + <span>{{ $t(val.meta.title) }}</span> + </template> + <SubItem :chil="val.children" /> + </el-sub-menu> + <template v-else> + <el-menu-item :index="val.path" :key="val.path"> + <template #title v-if="!val.meta.isLink || (val.meta.isLink && val.meta.isIframe)"> + <SvgIcon :name="val.meta.icon" /> + {{ $t(val.meta.title) }} + </template> + <template #title v-else> + <a :href="val.meta.isLink" target="_blank" rel="opener" class="w100"> + <SvgIcon :name="val.meta.icon" /> + {{ $t(val.meta.title) }} + </a> + </template> + </el-menu-item> + </template> + </template> + </el-menu> + </el-scrollbar> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, computed, defineComponent, getCurrentInstance, onMounted, nextTick, onBeforeMount } from 'vue'; +import { useRoute, onBeforeRouteUpdate } from 'vue-router'; +import { storeToRefs } from 'pinia'; +import { useRoutesList } from '/@/stores/routesList'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import SubItem from '/@/layout/navMenu/subItem.vue'; + +export default defineComponent({ + name: 'navMenuHorizontal', + components: { SubItem }, + props: { + menuList: { + type: Array, + default: () => [], + }, + }, + setup(props) { + const { proxy } = <any>getCurrentInstance(); + const stores = useRoutesList(); + const storesThemeConfig = useThemeConfig(); + const { routesList } = storeToRefs(stores); + const { themeConfig } = storeToRefs(storesThemeConfig); + const route = useRoute(); + const state = reactive({ + defaultActive: null, + }); + // 获取父级菜单数据 + const menuLists = computed(() => { + return <any>props.menuList; + }); + // 设置横向滚动条可以鼠标滚轮滚动 + const onElMenuHorizontalScroll = (e: any) => { + const eventDelta = e.wheelDelta || -e.deltaY * 40; + proxy.$refs.elMenuHorizontalScrollRef.$refs.wrap$.scrollLeft = proxy.$refs.elMenuHorizontalScrollRef.$refs.wrap$.scrollLeft + eventDelta / 4; + }; + // 初始化数据,页面刷新时,滚动条滚动到对应位置 + const initElMenuOffsetLeft = () => { + nextTick(() => { + let els: any = document.querySelector('.el-menu.el-menu--horizontal li.is-active'); + if (!els) return false; + proxy.$refs.elMenuHorizontalScrollRef.$refs.wrap$.scrollLeft = els.offsetLeft; + }); + }; + // 路由过滤递归函数 + const filterRoutesFun = (arr: Array<string>) => { + return arr + .filter((item: any) => !item.meta.isHide) + .map((item: any) => { + item = Object.assign({}, item); + if (item.children) item.children = filterRoutesFun(item.children); + return item; + }); + }; + // 传送当前子级数据到菜单中 + const setSendClassicChildren = (path: string) => { + const currentPathSplit = path.split('/'); + let currentData: any = {}; + filterRoutesFun(routesList.value).map((v, k) => { + if (v.path === `/${currentPathSplit[1]}`) { + v['k'] = k; + currentData['item'] = [{ ...v }]; + currentData['children'] = [{ ...v }]; + if (v.children) currentData['children'] = v.children; + } + }); + return currentData; + }; + // 设置页面当前路由高亮 + const setCurrentRouterHighlight = (currentRoute: any) => { + const { path, meta } = currentRoute; + if (themeConfig.value.layout === 'classic') { + (<any>state.defaultActive) = `/${path.split('/')[1]}`; + } else { + const pathSplit = meta.isDynamic ? meta.isDynamicPath.split('/') : path.split('/'); + if (pathSplit.length >= 4 && meta.isHide) state.defaultActive = pathSplit.splice(0, 3).join('/'); + else state.defaultActive = path; + } + }; + // 页面加载前 + onBeforeMount(() => { + setCurrentRouterHighlight(route); + }); + // 页面加载时 + onMounted(() => { + initElMenuOffsetLeft(); + }); + // 路由更新时 + onBeforeRouteUpdate((to) => { + // 修复:https://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G + setCurrentRouterHighlight(to); + // 修复经典布局开启切割菜单时,点击tagsView后左侧导航菜单数据不变的问题 + let { layout, isClassicSplitMenu } = themeConfig.value; + if (layout === 'classic' && isClassicSplitMenu) { + proxy.mittBus.emit('setSendClassicChildren', setSendClassicChildren(to.path)); + } + }); + return { + menuLists, + onElMenuHorizontalScroll, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.el-menu-horizontal-warp { + flex: 1; + overflow: hidden; + margin-right: 30px; + ::v-deep(.el-scrollbar__bar.is-vertical) { + display: none; + } + ::v-deep(a) { + width: 100%; + } + .el-menu.el-menu--horizontal { + display: flex; + height: 100%; + width: 100%; + box-sizing: border-box; + } +} +</style> diff --git a/src/layout/navMenu/subItem.vue b/src/layout/navMenu/subItem.vue new file mode 100644 index 0000000..3fcefd3 --- /dev/null +++ b/src/layout/navMenu/subItem.vue @@ -0,0 +1,48 @@ +<template> + <template v-for="val in chils"> + <el-sub-menu :index="val.path" :key="val.path" v-if="val.children && val.children.length > 0"> + <template #title> + <SvgIcon :name="val.meta.icon" /> + <span>{{ $t(val.meta.title) }}</span> + </template> + <sub-item :chil="val.children" /> + </el-sub-menu> + <template v-else> + <el-menu-item :index="val.path" :key="val.path"> + <template v-if="!val.meta.isLink || (val.meta.isLink && val.meta.isIframe)"> + <SvgIcon :name="val.meta.icon" /> + <span>{{ $t(val.meta.title) }}</span> + </template> + <template v-else> + <a :href="val.meta.isLink" target="_blank" rel="opener" class="w100"> + <SvgIcon :name="val.meta.icon" /> + {{ $t(val.meta.title) }} + </a> + </template> + </el-menu-item> + </template> + </template> +</template> + +<script lang="ts"> +import { computed, defineComponent } from 'vue'; + +export default defineComponent({ + name: 'navMenuSubItem', + props: { + chil: { + type: Array, + default: () => [], + }, + }, + setup(props) { + // 获取父级菜单数据 + const chils = computed(() => { + return <any>props.chil; + }); + return { + chils, + }; + }, +}); +</script> diff --git a/src/layout/navMenu/vertical.vue b/src/layout/navMenu/vertical.vue new file mode 100644 index 0000000..1bfa825 --- /dev/null +++ b/src/layout/navMenu/vertical.vue @@ -0,0 +1,101 @@ +<template> + <el-menu + router + :default-active="defaultActive" + background-color="transparent" + :collapse="isCollapse" + :unique-opened="getThemeConfig.isUniqueOpened" + :collapse-transition="false" + > + <template v-for="val in menuLists"> + <el-sub-menu :index="val.path" v-if="val.children && val.children.length > 0" :key="val.path"> + <template #title> + <SvgIcon :name="val.meta.icon" /> + <span>{{ $t(val.meta.title) }}</span> + </template> + <SubItem :chil="val.children" /> + </el-sub-menu> + <template v-else> + <el-menu-item :index="val.path" :key="val.path"> + <SvgIcon :name="val.meta.icon" /> + <template #title v-if="!val.meta.isLink || (val.meta.isLink && val.meta.isIframe)"> + <span>{{ $t(val.meta.title) }}</span> + </template> + <template #title v-else> + <a :href="val.meta.isLink" target="_blank" rel="opener" class="w100">{{ $t(val.meta.title) }}</a> + </template> + </el-menu-item> + </template> + </template> + </el-menu> +</template> + +<script lang="ts"> +import { toRefs, reactive, computed, defineComponent, onMounted, watch } from 'vue'; +import { useRoute, onBeforeRouteUpdate } from 'vue-router'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import SubItem from '/@/layout/navMenu/subItem.vue'; + +export default defineComponent({ + name: 'navMenuVertical', + components: { SubItem }, + props: { + menuList: { + type: Array, + default: () => [], + }, + }, + setup(props) { + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const route = useRoute(); + const state = reactive({ + // 修复:https://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G + defaultActive: route.meta.isDynamic ? route.meta.isDynamicPath : route.path, + isCollapse: false, + }); + // 获取父级菜单数据 + const menuLists = computed(() => { + return <any>props.menuList; + }); + // 获取布局配置信息 + const getThemeConfig = computed(() => { + return themeConfig.value; + }); + // 菜单高亮(详情时,父级高亮) + const setParentHighlight = (currentRoute: any) => { + const { path, meta } = currentRoute; + const pathSplit = meta.isDynamic ? meta.isDynamicPath.split('/') : path.split('/'); + if (pathSplit.length >= 4 && meta.isHide) return pathSplit.splice(0, 3).join('/'); + else return path; + }; + // 设置菜单的收起/展开 + watch( + themeConfig.value, + () => { + document.body.clientWidth <= 1000 ? (state.isCollapse = false) : (state.isCollapse = themeConfig.value.isCollapse); + }, + { + immediate: true, + } + ); + // 页面加载时 + onMounted(() => { + state.defaultActive = setParentHighlight(route); + }); + // 路由更新时 + onBeforeRouteUpdate((to) => { + // 修复:https://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G + state.defaultActive = setParentHighlight(to); + const clientWidth = document.body.clientWidth; + if (clientWidth < 1000) themeConfig.value.isCollapse = false; + }); + return { + menuLists, + getThemeConfig, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/layout/routerView/iframes.vue b/src/layout/routerView/iframes.vue new file mode 100644 index 0000000..43e71c5 --- /dev/null +++ b/src/layout/routerView/iframes.vue @@ -0,0 +1,66 @@ +<template> + <div class="layout-view-bg-white flex mt1" :style="{ height: `calc(100vh - ${setIframeHeight}`, border: 'none' }" v-loading="iframeLoading"> + <iframe :src="iframeUrl" frameborder="0" height="100%" width="100%" ref="iframeDom" v-show="!iframeLoading"></iframe> + </div> +</template> + +<script lang="ts"> +import { defineComponent, reactive, toRefs, onMounted, nextTick, watch, computed } from 'vue'; +import { storeToRefs } from 'pinia'; +import { useRoute } from 'vue-router'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; + +export default defineComponent({ + name: 'layoutIfameView', + setup() { + const storesThemeConfig = useThemeConfig(); + const storesTagsViewRoutes = useTagsViewRoutes(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes); + const route = useRoute(); + const state = reactive({ + iframeDom: null as HTMLIFrameElement | null, + iframeLoading: true, + iframeUrl: '', + }); + // 初始化页面加载 loading + const initIframeLoad = () => { + state.iframeUrl = <any>route.meta.isLink; + nextTick(() => { + state.iframeLoading = true; + const iframe = state.iframeDom; + if (!iframe) return false; + iframe.onload = () => { + state.iframeLoading = false; + }; + }); + }; + // 设置 iframe 的高度 + const setIframeHeight = computed(() => { + let { isTagsview } = themeConfig.value; + if (isTagsViewCurrenFull.value) { + return `1px`; + } else { + if (isTagsview) return `86px`; + else return `51px`; + } + }); + // 页面加载时 + onMounted(() => { + initIframeLoad(); + }); + // 监听路由变化,多个 iframe 时使用 + watch( + () => route.path, + () => { + initIframeLoad(); + } + ); + return { + setIframeHeight, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/layout/routerView/link.vue b/src/layout/routerView/link.vue new file mode 100644 index 0000000..a48f002 --- /dev/null +++ b/src/layout/routerView/link.vue @@ -0,0 +1,61 @@ +<template> + <div class="layout-view-bg-white flex layout-view-link" :style="{ height: `calc(100vh - ${setLinkHeight}` }"> + <a :href="currentRouteMeta.isLink" target="_blank" rel="opener" class="flex-margin"> + {{ $t(currentRouteMeta.title) }}:{{ currentRouteMeta.isLink }} + </a> + </div> +</template> + +<script lang="ts"> +import { defineComponent, toRefs, reactive, computed, watch } from 'vue'; +import { useRoute, RouteMeta } from 'vue-router'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; + +// 定义接口来定义对象的类型 +interface LinkViewState { + currentRouteMeta: { + isLink: string; + title: string; + }; +} +interface LinkViewRouteMeta extends RouteMeta { + isLink: string; + title: string; +} + +export default defineComponent({ + name: 'layoutLinkView', + setup() { + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const route = useRoute(); + const state = reactive<LinkViewState>({ + currentRouteMeta: { + isLink: '', + title: '', + }, + }); + // 设置 link 的高度 + const setLinkHeight = computed(() => { + let { isTagsview } = themeConfig.value; + if (isTagsview) return `115px`; + else return `80px`; + }); + // 监听路由的变化,设置内容 + watch( + () => route.path, + () => { + state.currentRouteMeta = <LinkViewRouteMeta>route.meta; + }, + { + immediate: true, + } + ); + return { + setLinkHeight, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/layout/routerView/parent.vue b/src/layout/routerView/parent.vue new file mode 100644 index 0000000..db22141 --- /dev/null +++ b/src/layout/routerView/parent.vue @@ -0,0 +1,88 @@ +<template> + <div class="h100"> + <router-view v-slot="{ Component }"> + <transition :name="setTransitionName" mode="out-in"> + <keep-alive :include="getKeepAliveNames"> + <component :is="Component" :key="refreshRouterViewKey" class="w100" /> + </keep-alive> + </transition> + </router-view> + </div> +</template> + +<script lang="ts"> +import { computed, defineComponent, toRefs, reactive, getCurrentInstance, onBeforeMount, onUnmounted, nextTick, watch, onMounted } from 'vue'; +import { useRoute } from 'vue-router'; +import { storeToRefs } from 'pinia'; +import { useKeepALiveNames } from '/@/stores/keepAliveNames'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { Session } from '/@/utils/storage'; + +// 定义接口来定义对象的类型 +interface ParentViewState { + refreshRouterViewKey: null | string; + keepAliveNameList: string[]; +} + +export default defineComponent({ + name: 'layoutParentView', + setup() { + const { proxy } = <any>getCurrentInstance(); + const route = useRoute(); + const storesKeepAliveNames = useKeepALiveNames(); + const storesThemeConfig = useThemeConfig(); + const { keepAliveNames, cachedViews } = storeToRefs(storesKeepAliveNames); + const { themeConfig } = storeToRefs(storesThemeConfig); + const state = reactive<ParentViewState>({ + refreshRouterViewKey: null, + keepAliveNameList: [], + }); + // 设置主界面切换动画 + const setTransitionName = computed(() => { + return themeConfig.value.animation; + }); + // 获取组件缓存列表(name值) + const getKeepAliveNames = computed(() => { + return themeConfig.value.isTagsview ? cachedViews.value : state.keepAliveNameList; + }); + // 页面加载前,处理缓存,页面刷新时路由缓存处理 + onBeforeMount(() => { + state.keepAliveNameList = keepAliveNames.value; + proxy.mittBus.on('onTagsViewRefreshRouterView', (fullPath: string) => { + state.keepAliveNameList = keepAliveNames.value.filter((name: string) => route.name !== name); + state.refreshRouterViewKey = null; + nextTick(() => { + state.refreshRouterViewKey = fullPath; + state.keepAliveNameList = keepAliveNames.value; + }); + }); + }); + // 页面加载时 + onMounted(() => { + // https://gitee.com/lyt-top/vue-next-admin/issues/I58U75 + // https://gitee.com/lyt-top/vue-next-admin/issues/I59RXK + nextTick(() => { + setTimeout(() => { + if (themeConfig.value.isCacheTagsView) cachedViews.value = Session.get('tagsViewList')?.map((item: any) => item.name); + }, 0); + }); + }); + // 页面卸载时 + onUnmounted(() => { + proxy.mittBus.off('onTagsViewRefreshRouterView', () => {}); + }); + // 监听路由变化,防止 tagsView 多标签时,切换动画消失 + watch( + () => route.fullPath, + () => { + state.refreshRouterViewKey = decodeURI(route.fullPath); + } + ); + return { + setTransitionName, + getKeepAliveNames, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..acd3d24 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,22 @@ +import { createApp } from 'vue'; +import pinia from '/@/stores/index'; +import App from './App.vue'; +import router from './router'; +import { directive } from '/@/utils/directive'; +import { i18n } from '/@/i18n/index'; +import other from '/@/utils/other'; + +import ElementPlus from 'element-plus'; +import 'element-plus/dist/index.css'; +import '/@/theme/index.scss'; +import mitt from 'mitt'; +import VueGridLayout from 'vue-grid-layout'; + +const app = createApp(App); + +directive(app); +other.elSvg(app); + +app.use(pinia).use(router).use(ElementPlus, { i18n: i18n.global.t }).use(i18n).use(VueGridLayout).mount('#app'); + +app.config.globalProperties.mittBus = mitt(); diff --git a/src/router/backEnd.ts b/src/router/backEnd.ts new file mode 100644 index 0000000..6d7f365 --- /dev/null +++ b/src/router/backEnd.ts @@ -0,0 +1,110 @@ +import { RouteRecordRaw } from 'vue-router'; +import { storeToRefs } from 'pinia'; +import pinia from '/@/stores/index'; +import { useUserInfo } from '/@/stores/userInfo'; +import { useRequestOldRoutes } from '/@/stores/requestOldRoutes'; +import { Session } from '/@/utils/storage'; +import { NextLoading } from '/@/utils/loading'; +import { dynamicRoutes, notFoundAndNoPower } from '/@/router/route'; +import { formatTwoStageRoutes, formatFlatteningRoutes, router } from '/@/router/index'; +import { useRoutesList } from '/@/stores/routesList'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; +import { useMenuApi } from '/@/api/menu/index'; +import { ElMessage } from 'element-plus'; + +const menuApi = useMenuApi(); + +const layouModules: any = import.meta.glob('../layout/routerView/*.{vue,tsx}'); +const viewsModules: any = import.meta.glob('../views/**/*.{vue,tsx}'); + + +/** + * 获取目录下的 .vue、.tsx 全部文件 + * @method import.meta.glob + * @link 参考:https://cn.vitejs.dev/guide/features.html#json + */ +const dynamicViewsModules: Record<string, Function> = Object.assign({}, { ...layouModules }, { ...viewsModules }); + + +export async function initBackEndControlRoutes() { + if (window.nextLoading === undefined) NextLoading.start(); + if (!Session.get('token')) return false; + useUserInfo().setUserInfos(); + // if(Session.get('ifMenu')) + const res = await getBackEndControlRoutes(Session.get('projectId')); + useRequestOldRoutes().setRequestOldRoutes(JSON.parse(JSON.stringify(res.data.data))); + dynamicRoutes[0].children = await backEndComponent(res.data.data); + await setAddRoute(); + await setFilterMenuAndCacheTagsViewRoutes(); + } + + +export function setFilterMenuAndCacheTagsViewRoutes() { + const storesRoutesList = useRoutesList(pinia); + storesRoutesList.setRoutesList(dynamicRoutes[0].children as any); + setCacheTagsViewRoutes(); +} + + +export function setCacheTagsViewRoutes() { + const storesTagsView = useTagsViewRoutes(pinia); + storesTagsView.setTagsViewRoutes(formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes))[0].children); +} + + +export function setFilterRouteEnd() { + let filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes)); + filterRouteEnd[0].children = [...filterRouteEnd[0].children, ...notFoundAndNoPower]; + return filterRouteEnd; +} + + +export async function setAddRoute() { + await setFilterRouteEnd().forEach((route: RouteRecordRaw) => { + router.addRoute(route); + }); +} + + +export async function getBackEndControlRoutes(value : string) { + const stores = useUserInfo(pinia); + const { userInfos } = storeToRefs(stores); + const auth = userInfos.value.roles[0]; + return menuApi.getMenuAdmin(value); + +} + +/** + * 重新请求后端路由菜单接口 + * @description 用于菜单管理界面刷新菜单(未进行测试) + * @description 路径:/src/views/system/menu/component/menuDialog.vue + */ +export function setBackEndControlRefreshRoutes() { + getBackEndControlRoutes(Session.get('projectId')); +} + + +export function backEndComponent(routes: any) { + if (!routes) return; + return routes.map((item: any) => { + if (item.component) item.component = dynamicImport(dynamicViewsModules, item.component as string); + item.children && backEndComponent(item.children); + return item; + }); +} + + +export function dynamicImport(dynamicViewsModules: Record<string, Function>, component: string) { + const keys = Object.keys(dynamicViewsModules); + const matchKeys = keys.filter((key) => { + const k = key.replace(/..\/views|../, ''); + return k.startsWith(`${component}`) || k.startsWith(`/${component}`); + }); + if (matchKeys?.length === 1) { + const matchKey = matchKeys[0]; + return dynamicViewsModules[matchKey]; + } + if (matchKeys?.length > 1) { + return false; + } +} diff --git a/src/router/frontEnd.ts b/src/router/frontEnd.ts new file mode 100644 index 0000000..af8432b --- /dev/null +++ b/src/router/frontEnd.ts @@ -0,0 +1,97 @@ +import { RouteRecordRaw } from 'vue-router'; +import { storeToRefs } from 'pinia'; +import { formatTwoStageRoutes, formatFlatteningRoutes, router } from '/@/router/index'; +import { dynamicRoutes, notFoundAndNoPower } from '/@/router/route'; +import pinia from '/@/stores/index'; +import { Session } from '/@/utils/storage'; +import { useUserInfo } from '/@/stores/userInfo'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; +import { useRoutesList } from '/@/stores/routesList'; +import { NextLoading } from '/@/utils/loading'; + + +export async function initFrontEndControlRoutes() { + if (window.nextLoading === undefined) NextLoading.start(); + if (!Session.get('token')) return false; + useUserInfo(pinia).setUserInfos(); + await setAddRoute(); + await setFilterMenuAndCacheTagsViewRoutes(); +} + + +export async function setAddRoute() { + await setFilterRouteEnd().forEach((route: RouteRecordRaw) => { + router.addRoute(route); + }); +} + + +export async function frontEndsResetRoute() { + await setFilterRouteEnd().forEach((route: RouteRecordRaw) => { + const routeName: any = route.name; + router.hasRoute(routeName) && router.removeRoute(routeName); + }); +} + + +export function setFilterRouteEnd() { + let filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes)); + filterRouteEnd[0].children = [...setFilterRoute(filterRouteEnd[0].children), ...notFoundAndNoPower]; + return filterRouteEnd; +} + + +export function setFilterRoute(chil: any) { + const stores = useUserInfo(pinia); + const { userInfos } = storeToRefs(stores); + let filterRoute: any = []; + chil.forEach((route: any) => { + if (route.meta.roles) { + route.meta.roles.forEach((metaRoles: any) => { + userInfos.value.roles.forEach((roles: any) => { + if (metaRoles === roles) filterRoute.push({ ...route }); + }); + }); + } + }); + return filterRoute; +} + + +export function setCacheTagsViewRoutes() { + // 获取有权限的路由,否则 tagsView、菜单搜索中无权限的路由也将显示 + const stores = useUserInfo(pinia); + const storesTagsView = useTagsViewRoutes(pinia); + const { userInfos } = storeToRefs(stores); + let rolesRoutes = setFilterHasRolesMenu(dynamicRoutes, userInfos.value.roles); + // 添加到 pinia setTagsViewRoutes 中 + storesTagsView.setTagsViewRoutes(formatTwoStageRoutes(formatFlatteningRoutes(rolesRoutes))[0].children); +} + + +export function setFilterMenuAndCacheTagsViewRoutes() { + const stores = useUserInfo(pinia); + const storesRoutesList = useRoutesList(pinia); + const { userInfos } = storeToRefs(stores); + storesRoutesList.setRoutesList(setFilterHasRolesMenu(dynamicRoutes[0].children, userInfos.value.roles)); + setCacheTagsViewRoutes(); +} + + +export function hasRoles(roles: any, route: any) { + if (route.meta && route.meta.roles) return roles.some((role: any) => route.meta.roles.includes(role)); + else return true; +} + + +export function setFilterHasRolesMenu(routes: any, roles: any) { + const menu: any = []; + routes.forEach((route: any) => { + const item = { ...route }; + if (hasRoles(roles, item)) { + if (item.children) item.children = setFilterHasRolesMenu(item.children, roles); + menu.push(item); + } + }); + return menu; +} diff --git a/src/router/index.ts b/src/router/index.ts new file mode 100644 index 0000000..1554262 --- /dev/null +++ b/src/router/index.ts @@ -0,0 +1,110 @@ +import { createRouter, createWebHashHistory } from 'vue-router'; +import NProgress from 'nprogress'; +import 'nprogress/nprogress.css'; +import pinia from '/@/stores/index'; +import { storeToRefs } from 'pinia'; +import { useKeepALiveNames } from '/@/stores/keepAliveNames'; +import { useRoutesList } from '/@/stores/routesList'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { Session } from '/@/utils/storage'; +import { staticRoutes } from '/@/router/route'; +import { initFrontEndControlRoutes } from '/@/router/frontEnd'; +import { initBackEndControlRoutes } from '/@/router/backEnd'; + + + +// 读取 `/src/stores/themeConfig.ts` 是否开启后端控制路由配置 +const storesThemeConfig = useThemeConfig(pinia); +const { themeConfig } = storeToRefs(storesThemeConfig); +const { isRequestRoutes } = themeConfig.value; +if (isRequestRoutes) staticRoutes.splice(0, 1); + + +export const router = createRouter({ + history: createWebHashHistory(), + routes: staticRoutes, +}); + + +export function formatFlatteningRoutes(arr: any) { + if (arr.length <= 0) return false; + for (let i = 0; i < arr.length; i++) { + if (arr[i].children) { + arr = arr.slice(0, i + 1).concat(arr[i].children, arr.slice(i + 1)); + } + } + return arr; +} + + +export function formatTwoStageRoutes(arr: any) { + if (arr.length <= 0) return false; + const newArr: any = []; + const cacheList: Array<string> = []; + arr.forEach((v: any) => { + if (v.path === '/') { + newArr.push({ component: v.component, name: v.name, path: v.path, redirect: v.redirect, meta: v.meta, children: [] }); + } else { + // 判断是否是动态路由(xx/:id/:name),用于 tagsView 等中使用 + // 修复:https://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G + if (v.path.indexOf('/:') > -1) { + v.meta['isDynamic'] = true; + v.meta['isDynamicPath'] = v.path; + } + newArr[0].children.push({ ...v }); + // 存 name 值,keep-alive 中 include 使用,实现路由的缓存 + // 路径:/@/layout/routerView/parent.vue + if (newArr[0].meta.isKeepAlive && v.meta.isKeepAlive) { + cacheList.push(v.name); + const stores = useKeepALiveNames(pinia); + stores.setCacheKeepAlive(cacheList); + } + } + }); + return newArr; +} + +// isRequestRoutes 为 true,则开启后端控制路由,路径:`/src/stores/themeConfig.ts` +if (!isRequestRoutes) initFrontEndControlRoutes(); + +// 路由加载前 +router.beforeEach(async (to, from, next) => { + NProgress.configure({ showSpinner: false }); + if (to.meta.title) NProgress.start(); + const token = Session.get('token'); + if (to.path === '/login' && !token) { + next(); + NProgress.done(); + } else { + if (!token) { + next(`/login?redirect=${to.path}¶ms=${JSON.stringify(to.query ? to.query : to.params)}`); + Session.clear(); + NProgress.done(); + } else if (token && to.path === '/login') { + next('/home'); + NProgress.done(); + } else { + const storesRoutesList = useRoutesList(pinia); + const { routesList } = storeToRefs(storesRoutesList); + if (routesList.value.length === 0) { + if (isRequestRoutes) { + // 后端控制路由:路由数据初始化,防止刷新时丢失 + await initBackEndControlRoutes(); + // 动态添加路由:防止非首页刷新时跳转回首页的问题 + // 确保 addRoute() 时动态添加的路由已经被完全加载上去 + next({ ...to, replace: true }); + } + } else { + next(); + } + } + } +}); + +// 路由加载后 +router.afterEach(() => { + NProgress.done(); +}); + +// 导出路由 +export default router; diff --git a/src/router/route.ts b/src/router/route.ts new file mode 100644 index 0000000..0177847 --- /dev/null +++ b/src/router/route.ts @@ -0,0 +1,102 @@ +import { RouteRecordRaw } from 'vue-router'; + +export const dynamicRoutes: Array<RouteRecordRaw> = [ + + { + path: '/', + name: '/', + component: () => import('/@/layout/index.vue'), + redirect: '/home', + meta: { + isKeepAlive: true, + }, + children: [ + { + path: '/home', + name: 'home', + component: () => import('/@/views/home/index.vue'), + meta: { + title: 'message.router.home', + isLink: '', + isHide: false, + isKeepAlive: true, + isAffix: true, + isIframe: false, + roles: ['admin', 'common'], + icon: 'iconfont icon-shouye', + button:'121231' + }, + }, + ], + }, +]; + + +export const notFoundAndNoPower = [ + { + path: '/:path(.*)*', + name: 'notFound', + component: () => import('/@/views/error/404.vue'), + meta: { + title: 'message.staticRoutes.notFound', + isHide: true, + }, + }, + { + path: '/401', + name: 'noPower', + component: () => import('/@/views/error/401.vue'), + meta: { + title: 'message.staticRoutes.noPower', + isHide: true, + }, + }, +]; + +export const staticRoutes: Array<RouteRecordRaw> = [ + { + path: '/', + name: '/', + component: () => import('/@/layout/index.vue'), + meta: { + title: '布局界面', + }, + children: [ + // 请不要往这里 `children` 中添加内容,此内容为了防止 No match found for location with path "xxx" 问题 + ...notFoundAndNoPower, + ], + }, + { + path: '/login', + name: 'login', + component: () => import('/@/views/login/index.vue'), + meta: { + title: '登录', + }, + }, + { + path: '/dashboard', + name: 'dashboard', + component: () => import('/@/views/dashboard/index.vue'), + meta: { + title: '系统选择', + }, + }, + + { + path: '/visualizingDemo1', + name: 'visualizingDemo1', + component: () => import('/@/views/visualizing/demo1.vue'), + meta: { + title: 'message.router.visualizingLinkDemo1', + }, + }, + { + path: '/visualizingDemo2', + name: 'visualizingDemo2', + component: () => import('/@/views/visualizing/demo2.vue'), + meta: { + title: 'message.router.visualizingLinkDemo2', + }, + }, +]; diff --git a/src/stores/index.ts b/src/stores/index.ts new file mode 100644 index 0000000..27c377e --- /dev/null +++ b/src/stores/index.ts @@ -0,0 +1,8 @@ +// https://pinia.vuejs.org/ +import { createPinia } from 'pinia'; + +// 创建 +const pinia = createPinia(); + +// 导出 +export default pinia; diff --git a/src/stores/interface/index.ts b/src/stores/interface/index.ts new file mode 100644 index 0000000..2690f4b --- /dev/null +++ b/src/stores/interface/index.ts @@ -0,0 +1,91 @@ +/** + * 定义接口来定义对象的类型 + * `stores` 全部类型定义在这里 + */ + +// 用户信息 +export interface UserInfosState { + authBtnList: string[]; + photo: string; + roles: string[]; + time: number; + userName: string; + sign:string; +} +export interface UserInfosStates { + userInfos: UserInfosState; +} + +// 路由缓存列表 +export interface KeepAliveNamesState { + keepAliveNames: string[]; + cachedViews: string[]; +} + +// 后端返回原始路由(未处理时) +export interface RequestOldRoutesState { + requestOldRoutes: string[]; +} + +// TagsView 路由列表 +export interface TagsViewRoutesState { + tagsViewRoutes: string[]; + isTagsViewCurrenFull: Boolean; +} + +// 路由列表 +export interface RoutesListState { + routesList: string[]; + isColumnsMenuHover: Boolean; + isColumnsNavHover: Boolean; +} + +// 布局配置 +export interface ThemeConfigState { + isDrawer: boolean; + primary: string; + topBar: string; + topBarColor: string; + isTopBarColorGradual: boolean; + menuBar: string; + menuBarColor: string; + isMenuBarColorGradual: boolean; + columnsMenuBar: string; + columnsMenuBarColor: string; + isColumnsMenuBarColorGradual: boolean; + isCollapse: boolean; + isUniqueOpened: boolean; + isFixedHeader: boolean; + isFixedHeaderChange: boolean; + isClassicSplitMenu: boolean; + isLockScreen: boolean; + lockScreenTime: number; + isShowLogo: boolean; + isShowLogoChange: boolean; + isBreadcrumb: boolean; + isTagsview: boolean; + isBreadcrumbIcon: boolean; + isTagsviewIcon: boolean; + isCacheTagsView: boolean; + isSortableTagsView: boolean; + isShareTagsView: boolean; + isFooter: boolean; + isGrayscale: boolean; + isInvert: boolean; + isIsDark: boolean; + isWartermark: boolean; + wartermarkText: string; + tagsStyle: string; + animation: string; + columnsAsideStyle: string; + columnsAsideLayout: string; + layout: string; + isRequestRoutes: boolean; + globalTitle: string; + globalViceTitle: string; + globalI18n: string; + globalComponentSize: string; +} +export interface ThemeConfigStates { + themeConfig: ThemeConfigState; +} diff --git a/src/stores/keepAliveNames.ts b/src/stores/keepAliveNames.ts new file mode 100644 index 0000000..32e0389 --- /dev/null +++ b/src/stores/keepAliveNames.ts @@ -0,0 +1,37 @@ +import { defineStore } from 'pinia'; +import { KeepAliveNamesState } from './interface'; + +/** + * 路由缓存列表 + * @methods setCacheKeepAlive 设置要缓存的路由 names(开启 Tagsview) + * @methods addCachedView 添加要缓存的路由 names(关闭 Tagsview) + * @methods delCachedView 删除要缓存的路由 names(关闭 Tagsview) + * @methods delOthersCachedViews 右键菜单`关闭其它`,删除要缓存的路由 names(关闭 Tagsview) + * @methods delAllCachedViews 右键菜单`全部关闭`,删除要缓存的路由 names(关闭 Tagsview) + */ +export const useKeepALiveNames = defineStore('keepALiveNames', { + state: (): KeepAliveNamesState => ({ + keepAliveNames: [], + cachedViews: [], + }), + actions: { + async setCacheKeepAlive(data: Array<string>) { + this.keepAliveNames = data; + }, + async addCachedView(view: any) { + if (this.cachedViews.includes(view.name)) return; + if (view.meta.isKeepAlive) this.cachedViews.push(view.name); + }, + async delCachedView(view: any) { + const index = this.cachedViews.indexOf(view.name); + index > -1 && this.cachedViews.splice(index, 1); + }, + async delOthersCachedViews(view: any) { + if (view.meta.isKeepAlive) this.cachedViews = [view.name]; + else this.cachedViews = []; + }, + async delAllCachedViews() { + this.cachedViews = []; + }, + }, +}); diff --git a/src/stores/requestOldRoutes.ts b/src/stores/requestOldRoutes.ts new file mode 100644 index 0000000..be9b5cd --- /dev/null +++ b/src/stores/requestOldRoutes.ts @@ -0,0 +1,17 @@ +import { defineStore } from 'pinia'; +import { RequestOldRoutesState } from './interface'; + +/** + * 后端返回原始路由(未处理时) + * @methods setCacheKeepAlive 设置接口原始路由数据 + */ +export const useRequestOldRoutes = defineStore('requestOldRoutes', { + state: (): RequestOldRoutesState => ({ + requestOldRoutes: [], + }), + actions: { + async setRequestOldRoutes(routes: Array<string>) { + this.requestOldRoutes = routes; + }, + }, +}); diff --git a/src/stores/routesList.ts b/src/stores/routesList.ts new file mode 100644 index 0000000..7dd2b28 --- /dev/null +++ b/src/stores/routesList.ts @@ -0,0 +1,27 @@ +import { defineStore } from 'pinia'; +import { RoutesListState } from './interface'; + +/** + * 路由列表 + * @methods setRoutesList 设置路由数据 + * @methods setColumnsMenuHover 设置分栏布局菜单鼠标移入 boolean + * @methods setColumnsNavHover 设置分栏布局最左侧导航鼠标移入 boolean + */ +export const useRoutesList = defineStore('routesList', { + state: (): RoutesListState => ({ + routesList: [], + isColumnsMenuHover: false, + isColumnsNavHover: false, + }), + actions: { + async setRoutesList(data: Array<string>) { + this.routesList = data; + }, + async setColumnsMenuHover(bool: Boolean) { + this.isColumnsMenuHover = bool; + }, + async setColumnsNavHover(bool: Boolean) { + this.isColumnsNavHover = bool; + }, + }, +}); diff --git a/src/stores/tagsViewRoutes.ts b/src/stores/tagsViewRoutes.ts new file mode 100644 index 0000000..7a5e6f4 --- /dev/null +++ b/src/stores/tagsViewRoutes.ts @@ -0,0 +1,24 @@ +import { defineStore } from 'pinia'; +import { TagsViewRoutesState } from './interface'; +import { Session } from '/@/utils/storage'; + +/** + * TagsView 路由列表 + * @methods setTagsViewRoutes 设置 TagsView 路由列表 + * @methods setCurrenFullscreen 设置开启/关闭全屏时的 boolean 状态 + */ +export const useTagsViewRoutes = defineStore('tagsViewRoutes', { + state: (): TagsViewRoutesState => ({ + tagsViewRoutes: [], + isTagsViewCurrenFull: false, + }), + actions: { + async setTagsViewRoutes(data: Array<string>) { + this.tagsViewRoutes = data; + }, + setCurrenFullscreen(bool: Boolean) { + Session.set('isTagsViewCurrenFull', bool); + this.isTagsViewCurrenFull = bool; + }, + }, +}); diff --git a/src/stores/themeConfig.ts b/src/stores/themeConfig.ts new file mode 100644 index 0000000..198e155 --- /dev/null +++ b/src/stores/themeConfig.ts @@ -0,0 +1,146 @@ +import { defineStore } from 'pinia'; +import { ThemeConfigStates, ThemeConfigState } from './interface'; + +/** + * 布局配置 + * 修复:https://gitee.com/lyt-top/vue-next-admin/issues/I567R1,感谢@lanbao123 + * 2020.05.28 by lyt 优化。开发时配置不生效问题 + * 修改配置时: + * 1、需要每次都清理 `window.localStorage` 浏览器永久缓存 + * 2、或者点击布局配置最底部 `一键恢复默认` 按钮即可看到效果 + */ +export const useThemeConfig = defineStore('themeConfig', { + state: (): ThemeConfigStates => ({ + themeConfig: { + // 是否开启布局配置抽屉 + isDrawer: false, + + /** + * 全局主题 + */ + // 默认 primary 主题颜色 + primary: '#409eff', + // 是否开启深色模式 + isIsDark: false, + + /** + * 菜单 / 顶栏 + * 注意:v1.0.17 版本去除设置布局切换,重置主题样式(initSetLayoutChange), + * 切换布局需手动设置样式,设置的样式自动同步各布局, + * 代码位置:/@/layout/navBars/breadcrumb/setings.vue + */ + // 默认顶栏导航背景颜色 + topBar: '#ffffff', + // 默认顶栏导航字体颜色 + topBarColor: '#606266', + // 是否开启顶栏背景颜色渐变 + isTopBarColorGradual: false, + // 默认菜单导航背景颜色 + menuBar: '#545c64', + // 默认菜单导航字体颜色 + menuBarColor: '#eaeaea', + // 是否开启菜单背景颜色渐变 + isMenuBarColorGradual: false, + // 默认分栏菜单背景颜色 + columnsMenuBar: '#545c64', + // 默认分栏菜单字体颜色 + columnsMenuBarColor: '#e6e6e6', + // 是否开启分栏菜单背景颜色渐变 + isColumnsMenuBarColorGradual: false, + + /** + * 界面设置 + */ + // 是否开启菜单水平折叠效果 + isCollapse: false, + // 是否开启菜单手风琴效果 + isUniqueOpened: false, + // 是否开启固定 Header + isFixedHeader: false, + // 初始化变量,用于更新菜单 el-scrollbar 的高度,请勿删除 + isFixedHeaderChange: false, + // 是否开启经典布局分割菜单(仅经典布局生效) + isClassicSplitMenu: false, + // 是否开启自动锁屏 + isLockScreen: false, + // 开启自动锁屏倒计时(s/秒) + lockScreenTime: 30, + + /** + * 界面显示 + */ + // 是否开启侧边栏 Logo + isShowLogo: false, + // 初始化变量,用于 el-scrollbar 的高度更新,请勿删除 + isShowLogoChange: false, + // 是否开启 Breadcrumb,强制经典、横向布局不显示 + isBreadcrumb: true, + // 是否开启 Tagsview + isTagsview: true, + // 是否开启 Breadcrumb 图标 + isBreadcrumbIcon: false, + // 是否开启 Tagsview 图标 + isTagsviewIcon: false, + // 是否开启 TagsView 缓存 + isCacheTagsView: false, + // 是否开启 TagsView 拖拽 + isSortableTagsView: true, + // 是否开启 TagsView 共用 + isShareTagsView: false, + // 是否开启 Footer 底部版权信息 + isFooter: false, + // 是否开启灰色模式 + isGrayscale: false, + // 是否开启色弱模式 + isInvert: false, + // 是否开启水印 + isWartermark: false, + // 水印文案 + wartermarkText: 'small@小柒', + + /** + * 其它设置 + */ + // Tagsview 风格:可选值"<tags-style-one|tags-style-four|tags-style-five>",默认 tags-style-five + // 定义的值与 `/src/layout/navBars/tagsView/tagsView.vue` 中的 class 同名 + tagsStyle: 'tags-style-five', + // 主页面切换动画:可选值"<slide-right|slide-left|opacitys>",默认 slide-right + animation: 'slide-right', + // 分栏高亮风格:可选值"<columns-round|columns-card>",默认 columns-round + columnsAsideStyle: 'columns-round', + // 分栏布局风格:可选值"<columns-horizontal|columns-vertical>",默认 columns-horizontal + columnsAsideLayout: 'columns-vertical', + + /** + * 布局切换 + * 注意:为了演示,切换布局时,颜色会被还原成默认,代码位置:/@/layout/navBars/breadcrumb/setings.vue + * 中的 `initSetLayoutChange(设置布局切换,重置主题样式)` 方法 + */ + // 布局切换:可选值"<defaults|classic|transverse|columns>",默认 defaults + layout: 'defaults', + + /** + * 后端控制路由 + */ + // 是否开启后端控制路由 + isRequestRoutes: true, + + /** + * 全局网站标题 / 副标题 + */ + // 网站主标题(菜单导航、浏览器当前网页标题) + globalTitle: 'vue-next-admin', + // 网站副标题(登录页顶部文字) + globalViceTitle: 'vueNextAdmin', + // 默认初始语言,可选值"<zh-cn|en|zh-tw>",默认 zh-cn + globalI18n: 'zh-cn', + // 默认全局组件大小,可选值"<large|'default'|small>",默认 'large' + globalComponentSize: 'large', + }, + }), + actions: { + setThemeConfig(data: ThemeConfigState) { + this.themeConfig = data; + }, + }, +}); diff --git a/src/stores/userInfo.ts b/src/stores/userInfo.ts new file mode 100644 index 0000000..97176a8 --- /dev/null +++ b/src/stores/userInfo.ts @@ -0,0 +1,65 @@ +import { defineStore } from 'pinia'; +import Cookies from 'js-cookie'; +import { UserInfosStates } from './interface'; +import { Session } from '/@/utils/storage'; + +/** + * 用户信息 + * @methods setUserInfos 设置用户信息 + */ +export const useUserInfo = defineStore('userInfo', { + state: (): UserInfosStates => ({ + userInfos: { + userName: '', + photo: 'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=317673774,2961727727&fm=26&gp=0.jpg', + time: 0, + roles: [], + authBtnList: [], + sign:'', + }, + }), + actions: { + async setUserInfos() { + const userName = Cookies.get('userName'); + // 模拟数据 + let defaultRoles: Array<string> = []; + let defaultAuthBtnList: Array<string> = []; + // admin 页面权限标识,对应路由 meta.roles,用于控制路由的显示/隐藏 + let adminRoles: Array<string> = ['admin']; + // admin 按钮权限标识 + let adminAuthBtnList: Array<string> = ['btn.add', 'btn.del', 'btn.edit', 'btn.link']; + // test 页面权限标识,对应路由 meta.roles,用于控制路由的显示/隐藏 + let testRoles: Array<string> = ['common']; + // test 按钮权限标识 + let testAuthBtnList: Array<string> = ['btn.add', 'btn.link']; + // 不同用户模拟不同的用户权限 + if (userName === 'admin') { + defaultRoles = adminRoles; + defaultAuthBtnList = adminAuthBtnList; + } else { + defaultRoles = testRoles; + defaultAuthBtnList = testAuthBtnList; + } + // 用户信息模拟数据 + const userInfos = { + userName: userName, + photo: + userName === 'admin' + ? 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1813762643,1914315241&fm=26&gp=0.jpg' + : 'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=317673774,2961727727&fm=26&gp=0.jpg', + time: new Date().getTime(), + roles: defaultRoles, + authBtnList: defaultAuthBtnList, + sign:'', + }; + // 存储用户信息到浏览器缓存 + Session.set('userInfo', userInfos); + + if (Session.get('userInfo')) { + this.userInfos = Session.get('userInfo'); + } else { + this.userInfos = userInfos; + } + }, + }, +}); diff --git a/src/theme/app.scss b/src/theme/app.scss new file mode 100644 index 0000000..4c75296 --- /dev/null +++ b/src/theme/app.scss @@ -0,0 +1,281 @@ +/* 初始化样式 +------------------------------- */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + outline: none !important; +} + +:root { + --next-color-white: #ffffff; + --next-bg-main-color: #f8f8f8; + --next-bg-color: #f5f5ff; + --next-border-color-light: #f1f2f3; + --next-color-primary-lighter: #ecf5ff; + --next-color-success-lighter: #f0f9eb; + --next-color-warning-lighter: #fdf6ec; + --next-color-danger-lighter: #fef0f0; + --next-color-dark-hover: #0000001a; + --next-color-menu-hover: rgba(0, 0, 0, 0.2); + --next-color-user-hover: rgba(0, 0, 0, 0.04); + --next-color-seting-main: #e9eef3; + --next-color-seting-aside: #d3dce6; + --next-color-seting-header: #b3c0d1; +} + +html, +body, +#app { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif; + font-weight: 400; + -webkit-font-smoothing: antialiased; + -webkit-tap-highlight-color: transparent; + background-color: var(--next-bg-main-color); + font-size: 14px; + overflow: hidden; + position: relative; +} + +/* 主布局样式 +------------------------------- */ +.layout-container { + width: 100%; + height: 100%; + .layout-aside { + background: var(--next-bg-menuBar); + box-shadow: 2px 0 6px rgb(0 21 41 / 1%); + height: inherit; + position: relative; + z-index: 1; + display: flex; + flex-direction: column; + overflow-x: hidden !important; + .el-scrollbar__view { + overflow: hidden; + } + } + .layout-header { + padding: 0 !important; + } + .layout-main { + padding: 0 !important; + overflow: hidden; + width: 100%; + background-color: var(--next-bg-main-color); + } + .el-scrollbar { + width: 100%; + } + // 此字段多次用到,建议不删除,如需修改,请重写覆盖样式 + .layout-view-bg-white { + background: var(--el-color-white); + width: 100%; + height: 100%; + border-radius: 4px; + border: 1px solid var(--el-border-color-light, #ebeef5); + } + .layout-el-aside-br-color { + border-right: 1px solid var(--el-border-color-light, #ebeef5); + } + // pc端左侧导航样式 + .layout-aside-pc-220 { + width: 220px !important; + transition: width 0.3s ease; + } + .layout-aside-pc-64 { + width: 64px !important; + transition: width 0.3s ease; + } + .layout-aside-pc-1 { + width: 1px !important; + transition: width 0.3s ease; + } + // 手机端左侧导航样式 + .layout-aside-mobile { + position: fixed; + top: 0; + left: -220px; + width: 220px; + z-index: 9999999; + } + .layout-aside-mobile-close { + left: -220px; + transition: all 0.3s cubic-bezier(0.39, 0.58, 0.57, 1); + } + .layout-aside-mobile-open { + left: 0; + transition: all 0.3s cubic-bezier(0.22, 0.61, 0.36, 1); + } + .layout-aside-mobile-mode { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + z-index: 9999998; + animation: error-img 0.3s; + } + .layout-scrollbar { + @extend .el-scrollbar; + padding: 15px; + } + .layout-mian-height-50 { + height: calc(100vh - 50px); + } + .layout-columns-warp { + flex: 1; + display: flex; + overflow: hidden; + } + .layout-hide { + display: none; + } +} + +/* element plus 全局样式 +------------------------------- */ +.layout-breadcrumb-seting { + .el-divider { + background-color: rgb(230, 230, 230); + } +} + +/* nprogress 进度条跟随主题颜色 +------------------------------- */ +#nprogress { + .bar { + background: var(--el-color-primary) !important; + z-index: 9999999 !important; + } +} + +/* flex 弹性布局 +------------------------------- */ +.flex { + display: flex; +} +.flex-auto { + flex: 1; + overflow: hidden; +} +.flex-center { + @extend .flex; + flex-direction: column; + width: 100%; + overflow: hidden; +} +.flex-margin { + margin: auto; +} +.flex-warp { + display: flex; + flex-wrap: wrap; + align-content: flex-start; + margin: 0 -5px; + .flex-warp-item { + padding: 5px; + .flex-warp-item-box { + width: 100%; + height: 100%; + } + } +} + +/* cursor 鼠标形状 +------------------------------- */ +// 默认 +.cursor-default { + cursor: default !important; +} +// 帮助 +.cursor-help { + cursor: help !important; +} +// 手指 +.cursor-pointer { + cursor: pointer !important; +} +// 移动 +.cursor-move { + cursor: move !important; +} + +/* 宽高 100% +------------------------------- */ +.w100 { + width: 100% !important; +} +.h100 { + height: 100% !important; +} +.vh100 { + height: 100vh !important; +} +.max100vh { + max-height: 100vh !important; +} +.min100vh { + min-height: 100vh !important; +} + +/* 颜色值 +------------------------------- */ +.color-primary { + color: var(--el-color-primary); +} +.color-success { + color: var(--el-color-success); +} +.color-warning { + color: var(--el-color-warning); +} +.color-danger { + color: var(--el-color-danger); +} +.color-info { + color: var(--el-color-info); +} + +/* 字体大小全局样式 +------------------------------- */ +@for $i from 10 through 32 { + .font#{$i} { + font-size: #{$i}px !important; + } +} + +/* 外边距、内边距全局样式 +------------------------------- */ +@for $i from 1 through 35 { + .mt#{$i} { + margin-top: #{$i}px !important; + } + .mr#{$i} { + margin-right: #{$i}px !important; + } + .mb#{$i} { + margin-bottom: #{$i}px !important; + } + .ml#{$i} { + margin-left: #{$i}px !important; + } + .pt#{$i} { + padding-top: #{$i}px !important; + } + .pr#{$i} { + padding-right: #{$i}px !important; + } + .pb#{$i} { + padding-bottom: #{$i}px !important; + } + .pl#{$i} { + padding-left: #{$i}px !important; + } +} diff --git a/src/theme/common/transition.scss b/src/theme/common/transition.scss new file mode 100644 index 0000000..a03a7bb --- /dev/null +++ b/src/theme/common/transition.scss @@ -0,0 +1,94 @@ +/* 页面切换动画 +------------------------------- */ +.slide-right-enter-active, +.slide-right-leave-active, +.slide-left-enter-active, +.slide-left-leave-active { + will-change: transform; + transition: all 0.3s ease; +} +// slide-right +.slide-right-enter-from { + opacity: 0; + transform: translateX(-20px); +} +.slide-right-leave-to { + opacity: 0; + transform: translateX(20px); +} +// slide-left +.slide-left-enter-from { + @extend .slide-right-leave-to; +} +.slide-left-leave-to { + @extend .slide-right-enter-from; +} +// opacitys +.opacitys-enter-active, +.opacitys-leave-active { + will-change: transform; + transition: all 0.3s ease; +} +.opacitys-enter-from, +.opacitys-leave-to { + opacity: 0; +} + +/* Breadcrumb 面包屑过渡动画 +------------------------------- */ +.breadcrumb-enter-active, +.breadcrumb-leave-active { + transition: all 0.5s ease; +} +.breadcrumb-enter-from, +.breadcrumb-leave-active { + opacity: 0; + transform: translateX(20px); +} +.breadcrumb-leave-active { + position: absolute; + z-index: -1; +} + +/* logo 过渡动画 +------------------------------- */ +@keyframes logoAnimation { + 0% { + transform: scale(0); + } + 80% { + transform: scale(1.2); + } + 100% { + transform: scale(1); + } +} + +/* 404、401 过渡动画 +------------------------------- */ +@keyframes error-num { + 0% { + transform: translateY(60px); + opacity: 0; + } + 100% { + transform: translateY(0); + opacity: 1; + } +} +@keyframes error-img { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} +@keyframes error-img-two { + 0% { + opacity: 1; + } + 100% { + opacity: 0; + } +} diff --git a/src/theme/dark.scss b/src/theme/dark.scss new file mode 100644 index 0000000..c922da1 --- /dev/null +++ b/src/theme/dark.scss @@ -0,0 +1,236 @@ +/* 深色模式样式 +------------------------------- */ +[data-theme='dark'] { + // 变量(自定义时,只需修改这里的值) + --next-bg-main: #1f1f1f; + --next-color-white: #ffffff; + --next-color-disabled: #191919; + --next-color-bar: #dadada; + --next-color-primary: #303030; + --next-border-color: #424242; + --next-border-black: #333333; + --next-border-columns: #2a2a2a; + --next-color-seting: #505050; + --next-text-color-regular: #9b9da1; + --next-text-color-placeholder: #7a7a7a; + --next-color-hover: #3c3c3c; + --next-color-hover-rgba: rgba(0, 0, 0, 0.3); + + // root + --next-bg-main-color: var(--next-bg-main) !important; + --next-bg-topBar: var(--next-color-disabled) !important; + --next-bg-topBarColor: var(--next-color-bar) !important; + --next-bg-menuBar: var(--next-color-disabled) !important; + --next-bg-menuBarColor: var(--next-color-bar) !important; + --next-bg-columnsMenuBar: var(--next-color-disabled) !important; + --next-bg-columnsMenuBarColor: var(--next-color-bar) !important; + --next-border-color-light: var(--next-border-black) !important; + --next-color-primary-lighter: var(--next-color-primary) !important; + --next-color-success-lighter: var(--next-color-primary) !important; + --next-color-warning-lighter: var(--next-color-primary) !important; + --next-color-danger-lighter: var(--next-color-primary) !important; + --next-bg-color: var(--next-color-primary) !important; + --next-color-dark-hover: var(--next-color-hover) !important; + --next-color-menu-hover: var(--next-color-hover-rgba) !important; + --next-color-user-hover: var(--next-color-hover-rgba) !important; + --next-color-seting-main: var(--next-color-seting) !important; + --next-color-seting-aside: var(--next-color-hover) !important; + --next-color-seting-header: var(--next-color-primary) !important; + + // element plus + --el-color-white: var(--next-color-disabled) !important; + --el-text-color-primary: var(--next-color-bar) !important; + --el-border-color: var(--next-border-black) !important; + --el-border-color-light: var(--next-border-black) !important; + --el-border-color-lighter: var(--next-border-black) !important; + --el-border-color-extra-light: var(--el-color-primary-light-8) !important; + --el-text-color-regular: var(--next-text-color-regular) !important; + --el-bg-color: var(--next-color-disabled) !important; + --el-color-primary-light-9: var(--next-color-hover) !important; + --el-text-color-disabled: var(--next-text-color-placeholder) !important; + --el-text-color-disabled-base: var(--el-color-primary) !important; + --el-text-color-placeholder: var(--next-text-color-placeholder) !important; + --el-disabled-bg-color: var(--next-color-disabled) !important; + --el-fill-base: var(--next-color-white) !important; + --el-fill-colo: var(--next-color-hover-rgba) !important; + --el-fill-color: var(--next-color-hover-rgba) !important; + --el-fill-color-blank: var(--next-color-disabled) !important; + --el-fill-color-light: var(--next-color-hover-rgba) !important; + --el-bg-color-overlay: var(--el-color-primary-light-9) !important; + --el-mask-color: rgb(42 42 42 / 80%); + + // button + .el-button { + &:hover { + border-color: var(--next-border-color) !important; + } + } + .el-button--primary, + .el-button--info, + .el-button--danger, + .el-button--success, + .el-button--warning { + --el-button-text-color: var(--next-color-white) !important; + --el-button-hover-text-color: var(--next-color-white) !important; + --el-button-disabled-text-color: var(--next-color-white) !important; + &:hover { + border-color: var(--el-button-hover-border-color, var(--el-button-hover-bg-color)) !important; + } + } + + // drawer + .el-divider__text { + background-color: var(--el-color-white) !important; + } + .el-drawer { + border-left: 1px solid var(--next-border-color-light) !important; + } + + // tabs + .el-tabs--border-card { + background-color: var(--el-color-white) !important; + } + .el-tabs--border-card > .el-tabs__header .el-tabs__item.is-active { + background: var(--next-color-primary-lighter); + } + + // alert / notice-bar + .home-card-item { + border: 1px solid var(--next-border-color-light) !important; + } + .el-alert, + .notice-bar { + border: 1px solid var(--next-border-color) !important; + background-color: var(--next-color-disabled) !important; + } + + // menu + .layout-aside { + border-right: 1px solid var(--next-border-color-light) !important; + } + + // colorPicker + .el-color-picker__mask { + background: unset !important; + } + .el-color-picker__trigger { + border: 1px solid var(--next-border-color-light) !important; + } + + // popper / dropdown + .el-popper { + border: 1px solid var(--next-border-color) !important; + color: var(--el-text-color-primary) !important; + .el-popper__arrow:before { + background: var(--el-color-white) !important; + border: 1px solid var(--next-border-color); + } + a { + color: var(--el-text-color-primary) !important; + } + } + .el-popper, + .el-dropdown-menu { + background: var(--el-color-white) !important; + } + .el-dropdown-menu__item:hover:not(.is-disabled) { + background: var(--el-bg-color) !important; + } + .el-dropdown-menu__item.is-disabled { + font-weight: 700 !important; + } + + // input + .el-input-group__append, + .el-input-group__prepend { + border: var(--el-input-border) !important; + border-right: none !important; + background: var(--next-color-disabled) !important; + border-left: 0 !important; + } + .el-input-number__decrease, + .el-input-number__increase { + background: var(--next-color-disabled) !important; + } + + // tag + .el-select .el-select__tags .el-tag { + background-color: var(--next-bg-color) !important; + } + + // pagination + .el-pagination.is-background .el-pager li:not(.disabled).active { + color: var(--next-color-white) !important; + } + .el-pagination.is-background .btn-next, + .el-pagination.is-background .btn-prev, + .el-pagination.is-background .el-pager li { + background-color: var(--next-bg-color); + } + + // radio + .el-radio-button:not(.is-active) .el-radio-button__inner { + border: 1px solid var(--next-border-color-light) !important; + border-left: 0 !important; + } + .el-radio-button.is-active .el-radio-button__inner { + color: var(--next-color-white) !important; + } + + // countup + .countup-card-item-flex { + color: var(--el-text-color-primary) !important; + } + + // editor + .editor-container { + .w-e-toolbar { + background: var(--el-color-white) !important; + border: 1px solid var(--next-border-color-light) !important; + .w-e-menu:hover { + background: var(--next-color-user-hover) !important; + i { + color: var(--el-text-color-primary) !important; + } + } + } + .w-e-text-container { + border: 1px solid var(--next-border-color-light) !important; + border-top: none !important; + .w-e-text { + background: var(--el-color-white) !important; + } + } + } + + // date-picker + .el-picker-panel { + background: var(--el-color-white) !important; + } + + // dialog + .el-dialog { + border: 1px solid var(--el-border-color-lighter); + .el-dialog__header { + color: var(--el-text-color-primary) !important; + } + } + + // columns + .layout-columns-aside ul .layout-columns-active { + color: var(--next-color-white) !important; + } + .layout-columns-aside { + border-right: 1px solid var(--next-border-columns); + } + + // tagsView + .tags-style-one { + .is-active { + color: var(--el-text-color-primary) !important; + } + .layout-navbars-tagsview-ul-li:hover { + border-color: var(--el-border-color-lighter) !important; + } + } +} diff --git a/src/theme/element.scss b/src/theme/element.scss new file mode 100644 index 0000000..5137cb4 --- /dev/null +++ b/src/theme/element.scss @@ -0,0 +1,282 @@ +@import 'mixins/index.scss'; + +/* Button 按钮 +------------------------------- */ +// 第三方字体图标大小 +.el-button i.el-icon, +.el-button i.iconfont, +.el-button i.fa, +.el-button--default i.iconfont, +.el-button--default i.fa { + font-size: 14px !important; + margin-right: 5px; +} +.el-button--small i.iconfont, +.el-button--small i.fa { + font-size: 12px !important; + margin-right: 5px; +} + +/* Input 输入框、InputNumber 计数器 +------------------------------- */ +.el-input { + height: 100%; +} +// 菜单搜索 +.el-autocomplete-suggestion__wrap { + max-height: 280px !important; +} + +/* Form 表单 +------------------------------- */ +.el-form { + .el-form-item:last-of-type { + margin-bottom: 0 !important; + } +} + +/* Alert 警告 +------------------------------- */ +.el-alert { + border: 1px solid; +} +.el-alert__title { + word-break: break-all; +} + +/* Message 消息提示 +------------------------------- */ +.el-message { + min-width: unset !important; + padding: 15px !important; + box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.02); +} + +/* NavMenu 导航菜单 +------------------------------- */ +// 鼠标 hover 时颜色 +.el-menu-hover-bg-color { + background-color: var(--next-color-menu-hover) !important; +} +// 默认样式修改 +.el-menu { + border-right: none !important; + width: 220px; +} +.el-menu-item { + height: 56px !important; + line-height: 56px !important; +} +.el-menu-item, +.el-sub-menu__title { + color: var(--next-bg-menuBarColor); +} +// 修复点击左侧菜单折叠再展开时,宽度不跟随问题 +.el-menu--collapse { + width: 64px !important; +} +// 外部链接时 +.el-menu-item a, +.el-menu-item a:hover, +.el-menu-item i, +.el-sub-menu__title i { + color: inherit; + text-decoration: none; +} +// 第三方图标字体间距/大小设置 +.el-menu-item .iconfont, +.el-sub-menu .iconfont, +.el-menu-item .fa, +.el-sub-menu .fa { + @include generalIcon; +} +// 水平菜单、横向菜单高亮 背景色,鼠标 hover 时,有子级菜单的背景色 +.el-menu-item.is-active, +.el-sub-menu.is-active .el-sub-menu__title, +.el-sub-menu:not(.is-opened):hover .el-sub-menu__title { + @extend .el-menu-hover-bg-color; +} +.el-sub-menu.is-active.is-opened .el-sub-menu__title { + background-color: unset !important; +} +// 子级菜单背景颜色 +// .el-menu--inline { +// background: var(--next-bg-menuBar-light-1); +// } +// 水平菜单、横向菜单折叠 a 标签 +.el-popper.is-dark a { + color: var(--el-color-white) !important; + text-decoration: none; +} +// 水平菜单、横向菜单折叠背景色 +.el-popper.is-pure.is-light { + // 水平菜单 + .el-menu--vertical { + background: var(--next-bg-menuBar); + .el-sub-menu.is-active .el-sub-menu__title { + color: var(--el-menu-active-color); + } + .el-popper.is-pure.is-light { + .el-menu--vertical { + .el-sub-menu .el-sub-menu__title { + background-color: unset !important; + color: var(--next-bg-menuBarColor); + } + .el-sub-menu.is-active .el-sub-menu__title { + color: var(--el-menu-active-color); + } + } + } + } + // 横向菜单 + .el-menu--horizontal { + background: var(--next-bg-topBar); + .el-menu-item, + .el-sub-menu { + height: 50px !important; + line-height: 50px !important; + color: var(--next-bg-topBarColor); + .el-sub-menu__title { + height: 50px !important; + line-height: 50px !important; + color: var(--next-bg-topBarColor); + } + .el-popper.is-pure.is-light { + .el-menu--horizontal { + .el-sub-menu .el-sub-menu__title { + background-color: unset !important; + color: var(--next-bg-topBarColor); + } + .el-sub-menu.is-active .el-sub-menu__title { + color: var(--el-menu-active-color); + } + } + } + } + .el-menu-item.is-active, + .el-sub-menu.is-active .el-sub-menu__title { + color: var(--el-menu-active-color); + } + } +} +// 横向菜单(经典、横向)布局 +.el-menu.el-menu--horizontal { + border-bottom: none !important; + width: 100% !important; + .el-menu-item, + .el-sub-menu__title { + height: 50px !important; + color: var(--next-bg-topBarColor); + } + .el-menu-item:not(.is-active):hover, + .el-sub-menu:not(.is-active):hover .el-sub-menu__title { + color: var(--next-bg-topBarColor); + } +} + +/* Tabs 标签页 +------------------------------- */ +.el-tabs__nav-wrap::after { + height: 1px !important; +} + +/* Dropdown 下拉菜单 +------------------------------- */ +.el-dropdown-menu { + list-style: none !important; /*修复 Dropdown 下拉菜单样式问题 2022.03.04*/ +} +.el-dropdown-menu .el-dropdown-menu__item { + white-space: nowrap; + &:not(.is-disabled):hover { + background-color: var(--el-dropdown-menuItem-hover-fill); + color: var(--el-dropdown-menuItem-hover-color); + } +} + +/* Steps 步骤条 +------------------------------- */ +.el-step__icon-inner { + font-size: 30px !important; + font-weight: 400 !important; +} +.el-step__title { + font-size: 14px; +} + +/* Dialog 对话框 +------------------------------- */ +.el-overlay { + overflow: hidden; + .el-overlay-dialog { + display: flex; + align-items: center; + justify-content: center; + position: unset !important; + width: 100%; + height: 100%; + .el-dialog { + margin: 0 auto !important; + position: absolute; + .el-dialog__body { + padding: 20px !important; + } + } + } +} +.el-dialog__body { + max-height: calc(90vh - 111px) !important; + overflow-y: auto; + overflow-x: hidden; +} + +/* Card 卡片 +------------------------------- */ +.el-card__header { + padding: 15px 20px; +} + +/* Table 表格 element plus 2.2.0 版本 +------------------------------- */ +.el-table { + .el-button.is-text { + padding: 0; + } +} + +/* scrollbar +------------------------------- */ +.el-scrollbar__bar { + z-index: 4; +} +.el-scrollbar__wrap { + max-height: 100%; /*防止页面切换时,滚动条高度不变的问题(滚动条高度非滚动条滚动高度)*/ +} +.el-select-dropdown .el-scrollbar__wrap { + overflow-x: scroll !important; +} +.el-select-dropdown__wrap { + max-height: 274px !important; /*修复Select 选择器高度问题*/ +} +.el-cascader-menu__wrap.el-scrollbar__wrap { + height: 204px !important; /*修复Cascader 级联选择器高度问题*/ +} + +/* Drawer 抽屉 +------------------------------- */ +.el-drawer { + --el-drawer-padding-primary: unset !important; + .el-drawer__header { + padding: 0 15px !important; + height: 50px; + display: flex; + align-items: center; + margin-bottom: 0 !important; + border-bottom: 1px solid var(--el-border-color); + color: var(--el-text-color-primary); + } + .el-drawer__body { + width: 100%; + height: 100%; + overflow: auto; + } +} diff --git a/src/theme/iconSelector.scss b/src/theme/iconSelector.scss new file mode 100644 index 0000000..970201e --- /dev/null +++ b/src/theme/iconSelector.scss @@ -0,0 +1,70 @@ +/* Popover 弹出框(图标选择器) +------------------------------- */ +.icon-selector-popper { + padding: 0 !important; + .icon-selector-warp { + height: 260px; + overflow: hidden; + .icon-selector-warp-title { + height: 40px; + line-height: 40px; + padding: 0 15px; + .icon-selector-warp-title-tab { + span { + cursor: pointer; + &:hover { + color: var(--el-color-primary); + text-decoration: underline; + } + } + .span-active { + color: var(--el-color-primary); + text-decoration: underline; + } + } + } + .icon-selector-warp-row { + height: 230px; + overflow: hidden; + border-top: 1px solid var(--el-border-color); + .el-row { + padding: 15px; + } + .el-scrollbar__bar.is-horizontal { + display: none; + } + .icon-selector-warp-item { + display: flex; + border: 1px solid var(--el-border-color); + padding: 5px; + border-radius: 5px; + margin-bottom: 10px; + .icon-selector-warp-item-value { + i { + font-size: 20px; + color: var(--el-text-color-regular); + } + } + &:hover { + cursor: pointer; + background-color: var(--el-color-primary-light-9); + border: 1px solid var(--el-color-primary-light-5); + .icon-selector-warp-item-value { + i { + color: var(--el-color-primary); + } + } + } + } + .icon-selector-active { + background-color: var(--el-color-primary-light-9); + border: 1px solid var(--el-color-primary-light-5); + .icon-selector-warp-item-value { + i { + color: var(--el-color-primary); + } + } + } + } + } +} diff --git a/src/theme/index.scss b/src/theme/index.scss new file mode 100644 index 0000000..c574e00 --- /dev/null +++ b/src/theme/index.scss @@ -0,0 +1,8 @@ +@import './app.scss'; +@import 'common/transition.scss'; +@import './other.scss'; +@import './element.scss'; +@import './iconSelector.scss'; +@import './media/media.scss'; +@import './waves.scss'; +@import './dark.scss'; diff --git a/src/theme/loading.scss b/src/theme/loading.scss new file mode 100644 index 0000000..c28c7b9 --- /dev/null +++ b/src/theme/loading.scss @@ -0,0 +1,51 @@ +.loading-next { + width: 100%; + height: 100%; +} +.loading-next .loading-next-box { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} +.loading-next .loading-next-box-warp { + width: 80px; + height: 80px; +} +.loading-next .loading-next-box-warp .loading-next-box-item { + width: 33.333333%; + height: 33.333333%; + background: var(--el-color-primary); + float: left; + animation: loading-next-animation 1.2s infinite ease; + border-radius: 1px; +} +.loading-next .loading-next-box-warp .loading-next-box-item:nth-child(7) { + animation-delay: 0s; +} +.loading-next .loading-next-box-warp .loading-next-box-item:nth-child(4), +.loading-next .loading-next-box-warp .loading-next-box-item:nth-child(8) { + animation-delay: 0.1s; +} +.loading-next .loading-next-box-warp .loading-next-box-item:nth-child(1), +.loading-next .loading-next-box-warp .loading-next-box-item:nth-child(5), +.loading-next .loading-next-box-warp .loading-next-box-item:nth-child(9) { + animation-delay: 0.2s; +} +.loading-next .loading-next-box-warp .loading-next-box-item:nth-child(2), +.loading-next .loading-next-box-warp .loading-next-box-item:nth-child(6) { + animation-delay: 0.3s; +} +.loading-next .loading-next-box-warp .loading-next-box-item:nth-child(3) { + animation-delay: 0.4s; +} +@keyframes loading-next-animation { + 0%, + 70%, + 100% { + transform: scale3D(1, 1, 1); + } + 35% { + transform: scale3D(0, 0, 1); + } +} diff --git a/src/theme/media/chart.scss b/src/theme/media/chart.scss new file mode 100644 index 0000000..8485e39 --- /dev/null +++ b/src/theme/media/chart.scss @@ -0,0 +1,94 @@ +@import './index.scss'; + +/* 页面宽度小于768px +------------------------------- */ +@media screen and (max-width: $sm) { + .big-data-down-left { + width: 100% !important; + flex-direction: unset !important; + flex-wrap: wrap; + .flex-warp-item { + min-height: 196.24px; + padding: 0 7.5px 15px 15px !important; + .flex-warp-item-box { + border: none !important; + border-bottom: 1px solid #ebeef5 !important; + } + } + } + .big-data-down-center { + width: 100% !important; + .big-data-down-center-one, + .big-data-down-center-two { + min-height: 196.24px; + padding-left: 15px !important; + .big-data-down-center-one-content { + border: none !important; + border-bottom: 1px solid #ebeef5 !important; + } + .flex-warp-item-box { + @extend .big-data-down-center-one-content; + } + } + } + .big-data-down-right { + .flex-warp-item { + .flex-warp-item-box { + border: none !important; + border-bottom: 1px solid #ebeef5 !important; + } + &:nth-of-type(2) { + padding-left: 15px !important; + } + &:last-of-type { + .flex-warp-item-box { + border: none !important; + } + } + } + } +} + +/* 页面宽度大于768px小于1200px +------------------------------- */ +@media screen and (min-width: $sm) and (max-width: $lg) { + .chart-warp-bottom { + .big-data-down-left { + width: 50% !important; + } + .big-data-down-center { + width: 50% !important; + } + .big-data-down-right { + .flex-warp-item { + width: 50% !important; + &:nth-of-type(2) { + padding-left: 7.5px !important; + } + } + } + } +} + +/* 页面宽度小于1200px +------------------------------- */ +@media screen and (max-width: $lg) { + .chart-warp-top { + .up-left { + display: none; + } + } + .chart-warp-bottom { + overflow-y: auto !important; + flex-wrap: wrap; + .big-data-down-right { + width: 100% !important; + flex-direction: unset !important; + flex-wrap: wrap; + .flex-warp-item { + min-height: 196.24px; + padding: 0 7.5px 15px 15px !important; + } + } + } +} diff --git a/src/theme/media/cityLinkage.scss b/src/theme/media/cityLinkage.scss new file mode 100644 index 0000000..1394156 --- /dev/null +++ b/src/theme/media/cityLinkage.scss @@ -0,0 +1,10 @@ +@import './index.scss'; + +/* 页面宽度小于576px +------------------------------- */ +@media screen and (max-width: $xs) { + .el-cascader__dropdown.el-popper { + overflow: auto; + max-width: 100%; + } +} diff --git a/src/theme/media/date.scss b/src/theme/media/date.scss new file mode 100644 index 0000000..1a50397 --- /dev/null +++ b/src/theme/media/date.scss @@ -0,0 +1,25 @@ +@import './index.scss'; + +/* 页面宽度小于768px +------------------------------- */ +@media screen and (max-width: $sm) { + // 时间选择器适配 + .el-date-range-picker { + width: 100vw; + .el-picker-panel__body { + min-width: 100%; + .el-date-range-picker__content { + .el-date-range-picker__header div { + margin-left: 22px; + margin-right: 0px; + } + & + .el-date-range-picker__content { + .el-date-range-picker__header div { + margin-left: 0px; + margin-right: 22px; + } + } + } + } + } +} diff --git a/src/theme/media/dialog.scss b/src/theme/media/dialog.scss new file mode 100644 index 0000000..023ccae --- /dev/null +++ b/src/theme/media/dialog.scss @@ -0,0 +1,12 @@ +@import './index.scss'; + +/* 页面宽度小于800px +------------------------------- */ +@media screen and (max-width: 800px) { + .el-dialog { + width: 90% !important; + } + .el-dialog.is-fullscreen { + width: 100% !important; + } +} diff --git a/src/theme/media/error.scss b/src/theme/media/error.scss new file mode 100644 index 0000000..f35015f --- /dev/null +++ b/src/theme/media/error.scss @@ -0,0 +1,45 @@ +@import './index.scss'; + +/* 页面宽度小于768px +------------------------------- */ +@media screen and (max-width: $sm) { + .error { + .error-flex { + flex-direction: column-reverse !important; + height: auto !important; + width: 100% !important; + } + .right, + .left { + flex: unset !important; + display: flex !important; + } + .left-item { + margin: auto !important; + } + .right img { + max-width: 450px !important; + @extend .left-item; + } + } +} + +/* 页面宽度大于768px小于992px +------------------------------- */ +@media screen and (min-width: $sm) and (max-width: $md) { + .error { + .error-flex { + padding-left: 30px !important; + } + } +} + +/* 页面宽度小于1200px +------------------------------- */ +@media screen and (max-width: $lg) { + .error { + .error-flex { + padding: 0 30px; + } + } +} diff --git a/src/theme/media/form.scss b/src/theme/media/form.scss new file mode 100644 index 0000000..098300b --- /dev/null +++ b/src/theme/media/form.scss @@ -0,0 +1,16 @@ +@import './index.scss'; + +/* 页面宽度小于576px +------------------------------- */ +@media screen and (max-width: $xs) { + .el-form-item__label { + width: 100% !important; + text-align: left !important; + } + .el-form-item__content { + margin-left: 0 !important; + } + .el-form-item { + display: unset !important; + } +} diff --git a/src/theme/media/home.scss b/src/theme/media/home.scss new file mode 100644 index 0000000..5a2417e --- /dev/null +++ b/src/theme/media/home.scss @@ -0,0 +1,23 @@ +@import './index.scss'; + +/* 页面宽度小于768px +------------------------------- */ +@media screen and (max-width: $sm) { + .home-media, + .home-media-sm { + margin-top: 15px; + } +} + +/* 页面宽度小于1200px +------------------------------- */ +@media screen and (max-width: $lg) { + .home-media-lg { + margin-top: 15px; + } + .home-monitor { + .flex-warp-item { + width: 33.33% !important; + } + } +} diff --git a/src/theme/media/index.scss b/src/theme/media/index.scss new file mode 100644 index 0000000..4761c0c --- /dev/null +++ b/src/theme/media/index.scss @@ -0,0 +1,15 @@ +/* 栅格布局(媒体查询变量) +* https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Media_queries +* $us ≥376px 响应式栅格 +* $xs ≥576px 响应式栅格 +* $sm ≥768px 响应式栅格 +* $md ≥992px 响应式栅格 +* $lg ≥1200px 响应式栅格 +* $xl ≥1920px 响应式栅格 +------------------------------- */ +$us: 376px; +$xs: 576px; +$sm: 768px; +$md: 992px; +$lg: 1200px; +$xl: 1920px; diff --git a/src/theme/media/layout.scss b/src/theme/media/layout.scss new file mode 100644 index 0000000..77cbec0 --- /dev/null +++ b/src/theme/media/layout.scss @@ -0,0 +1,55 @@ +@import './index.scss'; + +/* 页面宽度小于576px +------------------------------- */ +@media screen and (max-width: $xs) { + // MessageBox 弹框 + .el-message-box { + width: 80% !important; + } +} + +/* 页面宽度小于768px +------------------------------- */ +@media screen and (max-width: $sm) { + // Breadcrumb 面包屑 + .layout-navbars-breadcrumb-hide { + display: none; + } + // 外链视图 + .layout-view-link { + a { + max-width: 80%; + text-align: center; + } + } + // 菜单搜索 + .layout-search-dialog { + .el-autocomplete { + width: 80% !important; + } + } +} + +/* 页面宽度小于1000px +------------------------------- */ +@media screen and (max-width: 1000px) { + // 布局配置 + .layout-drawer-content-flex { + position: relative; + &::after { + content: '手机版不支持切换布局'; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1; + text-align: center; + height: 140px; + line-height: 140px; + background: rgba(255, 255, 255, 0.9); + color: #666666; + } + } +} diff --git a/src/theme/media/login.scss b/src/theme/media/login.scss new file mode 100644 index 0000000..41a0159 --- /dev/null +++ b/src/theme/media/login.scss @@ -0,0 +1,63 @@ +@import './index.scss'; + +/* 页面宽度小于992px +------------------------------- */ +@media screen and (max-width: $lg) { + .login-container { + .login-icon-group { + &::before { + content: ''; + height: 70% !important; + transition: all 0.3s ease; + } + &::after { + content: ''; + width: 100px !important; + height: 200px !important; + transition: all 0.3s ease; + } + } + } +} + +/* 页面宽度小于992px +------------------------------- */ +@media screen and (max-width: $md) { + .login-content { + right: unset !important; + left: 50% !important; + transform: translate(-50%, -50%) translate3d(0, 0, 0) !important; + } +} + +/* 页面宽度小于576px +------------------------------- */ +@media screen and (max-width: $xs) { + .login-container { + .login-icon-group { + display: none !important; + } + .login-content { + width: 100% !important; + height: 100% !important; + padding: 20px 0 !important; + border-radius: 0 !important; + box-shadow: unset !important; + border: none !important; + } + .el-form-item { + display: flex !important; + } + } +} + +/* 页面宽度小于375px +------------------------------- */ +@media screen and (max-width: $us) { + .login-container { + .login-content-title { + font-size: 18px !important; + transition: all 0.3s ease; + } + } +} diff --git a/src/theme/media/media.scss b/src/theme/media/media.scss new file mode 100644 index 0000000..bed1c35 --- /dev/null +++ b/src/theme/media/media.scss @@ -0,0 +1,13 @@ +@import './login.scss'; +@import './error.scss'; +@import './layout.scss'; +@import './personal.scss'; +@import './tagsView.scss'; +@import './home.scss'; +@import './chart.scss'; +@import './form.scss'; +@import './scrollbar.scss'; +@import './pagination.scss'; +@import './dialog.scss'; +@import './cityLinkage.scss'; +@import './date.scss'; diff --git a/src/theme/media/pagination.scss b/src/theme/media/pagination.scss new file mode 100644 index 0000000..400ebaa --- /dev/null +++ b/src/theme/media/pagination.scss @@ -0,0 +1,15 @@ +@import './index.scss'; + +/* 页面宽度小于576px +------------------------------- */ +@media screen and (max-width: $xs) { + .el-pager, + .el-pagination__jump { + display: none !important; + } +} + +// 默认居中对齐 +.el-pagination { + text-align: center !important; +} diff --git a/src/theme/media/personal.scss b/src/theme/media/personal.scss new file mode 100644 index 0000000..7ec0d4a --- /dev/null +++ b/src/theme/media/personal.scss @@ -0,0 +1,16 @@ +@import './index.scss'; + +/* 页面宽度小于768px +------------------------------- */ +@media screen and (max-width: $sm) { + .personal-info { + padding-left: 0 !important; + margin-top: 15px; + } + .personal-recommend-col { + margin-bottom: 15px; + &:last-of-type { + margin-bottom: 0; + } + } +} diff --git a/src/theme/media/scrollbar.scss b/src/theme/media/scrollbar.scss new file mode 100644 index 0000000..968a79d --- /dev/null +++ b/src/theme/media/scrollbar.scss @@ -0,0 +1,56 @@ +@import './index.scss'; + +/* 页面宽度小于768px +------------------------------- */ +@media screen and (max-width: $sm) { + // 滚动条的宽度 + ::-webkit-scrollbar { + width: 3px !important; + height: 3px !important; + } + ::-webkit-scrollbar-track-piece { + background-color: var(--next-bg-main-color); + } + // 滚动条的设置 + ::-webkit-scrollbar-thumb { + background-color: rgba(144, 147, 153, 0.3); + background-clip: padding-box; + min-height: 28px; + border-radius: 5px; + transition: 0.3s background-color; + } + ::-webkit-scrollbar-thumb:hover { + background-color: rgba(144, 147, 153, 0.5); + } + // element plus scrollbar + .el-scrollbar__bar.is-vertical { + width: 2px !important; + } + .el-scrollbar__bar.is-horizontal { + height: 2px !important; + } +} + +/* 页面宽度大于768px +------------------------------- */ +@media screen and (min-width: 769px) { + // 滚动条的宽度 + ::-webkit-scrollbar { + width: 7px; + height: 7px; + } + ::-webkit-scrollbar-track-piece { + background-color: var(--next-bg-main-color); + } + // 滚动条的设置 + ::-webkit-scrollbar-thumb { + background-color: rgba(144, 147, 153, 0.3); + background-clip: padding-box; + min-height: 28px; + border-radius: 5px; + transition: 0.3s background-color; + } + ::-webkit-scrollbar-thumb:hover { + background-color: rgba(144, 147, 153, 0.5); + } +} diff --git a/src/theme/media/tagsView.scss b/src/theme/media/tagsView.scss new file mode 100644 index 0000000..b71674e --- /dev/null +++ b/src/theme/media/tagsView.scss @@ -0,0 +1,11 @@ +@import './index.scss'; + +/* 页面宽度小于768px +------------------------------- */ +@media screen and (max-width: $sm) { + .tags-view-form { + .tags-view-form-col { + margin-bottom: 20px; + } + } +} diff --git a/src/theme/mixins/index.scss b/src/theme/mixins/index.scss new file mode 100644 index 0000000..61f3c6b --- /dev/null +++ b/src/theme/mixins/index.scss @@ -0,0 +1,56 @@ +/* 第三方图标字体间距/大小设置 +------------------------------- */ +@mixin generalIcon { + font-size: 14px !important; + display: inline-block; + vertical-align: middle; + margin-right: 5px; + width: 24px; + text-align: center; + justify-content: center; +} + +/* 文本不换行 +------------------------------- */ +@mixin text-no-wrap() { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} + +/* 多行文本溢出 + ------------------------------- */ +@mixin text-ellipsis($line: 2) { + overflow: hidden; + word-break: break-all; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: $line; + -webkit-box-orient: vertical; +} + +/* 滚动条(页面未使用) div 中使用: + ------------------------------- */ +// .test { +// @include scrollBar; +// } +@mixin scrollBar { + // 滚动条凹槽的颜色,还可以设置边框属性 + &::-webkit-scrollbar-track-piece { + background-color: #f8f8f8; + } + // 滚动条的宽度 + &::-webkit-scrollbar { + width: 9px; + height: 9px; + } + // 滚动条的设置 + &::-webkit-scrollbar-thumb { + background-color: #dddddd; + background-clip: padding-box; + min-height: 28px; + } + &::-webkit-scrollbar-thumb:hover { + background-color: #bbb; + } +} diff --git a/src/theme/other.scss b/src/theme/other.scss new file mode 100644 index 0000000..a0451b8 --- /dev/null +++ b/src/theme/other.scss @@ -0,0 +1,36 @@ +/* wangeditor富文本编辑器 +------------------------------- */ +.editor-container { + z-index: 9999; + .w-e-toolbar { + border: 1px solid var(--el-border-color-light, #ebeef5) !important; + border-bottom: 1px solid var(--el-border-color-light, #ebeef5) !important; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + z-index: 2 !important; + } + .w-e-text-container { + border: 1px solid var(--el-border-color-light, #ebeef5) !important; + border-top: none !important; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; + z-index: 1 !important; + } +} + +[data-theme='dark'] { + // textarea - css vars + --w-e-textarea-bg-color: var(--el-color-white) !important; + --w-e-textarea-color: var(--el-text-color-primary) !important; + + // toolbar - css vars + --w-e-toolbar-color: var(--el-text-color-primary) !important; + --w-e-toolbar-bg-color: var(--el-color-white) !important; + --w-e-toolbar-active-color: var(--el-text-color-primary) !important; + --w-e-toolbar-active-bg-color: var(--next-color-menu-hover) !important; + --w-e-toolbar-border-color: var(--el-border-color-light, #ebeef5) !important; + + // modal - css vars + --w-e-modal-button-bg-color: var(--el-color-primary) !important; + --w-e-modal-button-border-color: var(--el-color-primary) !important; +} diff --git a/src/theme/waves.scss b/src/theme/waves.scss new file mode 100644 index 0000000..23add2c --- /dev/null +++ b/src/theme/waves.scss @@ -0,0 +1,101 @@ +/* Waves v0.6.0 +* http://fian.my.id/Waves +* +* Copyright 2014 Alfiana E. Sibuea and other contributors +* Released under the MIT license +* https://github.com/fians/Waves/blob/master/LICENSE +*/ +.waves-effect { + position: relative; + cursor: pointer; + display: inline-block; + overflow: hidden; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-tap-highlight-color: transparent; + vertical-align: middle; + z-index: 1; + will-change: opacity, transform; + transition: all 0.3s ease-out; +} +.waves-effect .waves-ripple { + position: absolute; + border-radius: 50%; + width: 20px; + height: 20px; + margin-top: -10px; + margin-left: -10px; + opacity: 0; + background: rgba(0, 0, 0, 0.2); + transition: all 0.7s ease-out; + transition-property: opacity, -webkit-transform; + transition-property: transform, opacity; + transition-property: transform, opacity, -webkit-transform; + -webkit-transform: scale(0); + transform: scale(0); + pointer-events: none; +} +.waves-effect.waves-light .waves-ripple { + background-color: rgba(255, 255, 255, 0.45); +} +.waves-effect.waves-red .waves-ripple { + background-color: rgba(244, 67, 54, 0.7); +} +.waves-effect.waves-yellow .waves-ripple { + background-color: rgba(255, 235, 59, 0.7); +} +.waves-effect.waves-orange .waves-ripple { + background-color: rgba(255, 152, 0, 0.7); +} +.waves-effect.waves-purple .waves-ripple { + background-color: rgba(156, 39, 176, 0.7); +} +.waves-effect.waves-green .waves-ripple { + background-color: rgba(76, 175, 80, 0.7); +} +.waves-effect.waves-teal .waves-ripple { + background-color: rgba(0, 150, 136, 0.7); +} +.waves-effect input[type='button'], +.waves-effect input[type='reset'], +.waves-effect input[type='submit'] { + border: 0; + font-style: normal; + font-size: inherit; + text-transform: inherit; + background: none; +} +.waves-notransition { + transition: none !important; +} +.waves-circle { + -webkit-transform: translateZ(0); + transform: translateZ(0); + -webkit-mask-image: -webkit-radial-gradient(circle, #fff 100%, #000 100%); +} +.waves-input-wrapper { + border-radius: 0.2em; + vertical-align: bottom; +} +.waves-input-wrapper .waves-button-input { + position: relative; + top: 0; + left: 0; + z-index: 1; +} +.waves-circle { + text-align: center; + width: 2.5em; + height: 2.5em; + line-height: 2.5em; + border-radius: 50%; + -webkit-mask-image: none; +} +.waves-block { + display: block; +} +a.waves-effect .waves-ripple { + z-index: -1; +} diff --git a/src/utils/arrayOperation.ts b/src/utils/arrayOperation.ts new file mode 100644 index 0000000..a85deee --- /dev/null +++ b/src/utils/arrayOperation.ts @@ -0,0 +1,66 @@ +/** + * 判断两数组字符串是否相同(用于按钮权限验证),数组字符串中存在相同时会自动去重(按钮权限标识不会重复) + * @param news 新数据 + * @param old 源数据 + * @returns 两数组相同返回 `true`,反之则反 + */ +export function judementSameArr(newArr: unknown[] | string[], oldArr: string[]): boolean { + const news = removeDuplicate(newArr); + const olds = removeDuplicate(oldArr); + let count = 0; + const leng = olds.length; + for (let i in olds) { + for (let j in news) { + if (olds[i] === news[j]) count++; + } + } + return count === leng ? true : false; +} + +/** + * 判断两个对象是否相同 + * @param a 要比较的对象一 + * @param b 要比较的对象二 + * @returns 相同返回 true,反之则反 + */ +export function isObjectValueEqual(a: { [key: string]: any }, b: { [key: string]: any }) { + if (!a || !b) return false; + let aProps = Object.getOwnPropertyNames(a); + let bProps = Object.getOwnPropertyNames(b); + if (aProps.length != bProps.length) return false; + for (let i = 0; i < aProps.length; i++) { + let propName = aProps[i]; + let propA = a[propName]; + let propB = b[propName]; + if (!b.hasOwnProperty(propName)) return false; + if (propA instanceof Object) { + if (!isObjectValueEqual(propA, propB)) return false; + } else if (propA !== propB) { + return false; + } + } + return true; +} + +/** + * 数组、数组对象去重 + * @param arr 数组内容 + * @param attr 需要去重的键值(数组对象) + * @returns + */ +export function removeDuplicate(arr: any, attr?: string) { + if (!arr && !arr.length) { + return arr; + } else { + if (attr) { + const obj: any = {}; + const newArr = arr.reduce((cur: any, item: any) => { + obj[item[attr]] ? '' : (obj[item[attr]] = true && item[attr] && cur.push(item)); + return cur; + }, []); + return newArr; + } else { + return Array.from(new Set([...arr])); + } + } +} diff --git a/src/utils/authDirective.ts b/src/utils/authDirective.ts new file mode 100644 index 0000000..5971e64 --- /dev/null +++ b/src/utils/authDirective.ts @@ -0,0 +1,40 @@ +import type { App } from 'vue'; +import { useUserInfo } from '/@/stores/userInfo'; +import { judementSameArr } from '/@/utils/arrayOperation'; + +/** + * 用户权限指令 + * @directive 单个权限验证(v-auth="xxx") + * @directive 多个权限验证,满足一个则显示(v-auths="[xxx,xxx]") + * @directive 多个权限验证,全部满足则显示(v-auth-all="[xxx,xxx]") + */ +export function authDirective(app: App) { + // 单个权限验证(v-auth="xxx") + app.directive('auth', { + mounted(el, binding) { + const stores = useUserInfo(); + if (!stores.userInfos.authBtnList.some((v: string) => v === binding.value)) el.parentNode.removeChild(el); + }, + }); + // 多个权限验证,满足一个则显示(v-auths="[xxx,xxx]") + app.directive('auths', { + mounted(el, binding) { + let flag = false; + const stores = useUserInfo(); + stores.userInfos.authBtnList.map((val: string) => { + binding.value.map((v: string) => { + if (val === v) flag = true; + }); + }); + if (!flag) el.parentNode.removeChild(el); + }, + }); + // 多个权限验证,全部满足则显示(v-auth-all="[xxx,xxx]") + app.directive('auth-all', { + mounted(el, binding) { + const stores = useUserInfo(); + const flag = judementSameArr(binding.value, stores.userInfos.authBtnList); + if (!flag) el.parentNode.removeChild(el); + }, + }); +} diff --git a/src/utils/authFunction.ts b/src/utils/authFunction.ts new file mode 100644 index 0000000..84c0ab4 --- /dev/null +++ b/src/utils/authFunction.ts @@ -0,0 +1,38 @@ +import { useUserInfo } from '/@/stores/userInfo'; +import { judementSameArr } from '/@/utils/arrayOperation'; + +/** + * 单个权限验证 + * @param value 权限值 + * @returns 有权限,返回 `true`,反之则反 + */ +export function auth(value: string): boolean { + const stores = useUserInfo(); + return stores.userInfos.authBtnList.some((v: string) => v === value); +} + +/** + * 多个权限验证,满足一个则为 true + * @param value 权限值 + * @returns 有权限,返回 `true`,反之则反 + */ +export function auths(value: Array<string>): boolean { + let flag = false; + const stores = useUserInfo(); + stores.userInfos.authBtnList.map((val: string) => { + value.map((v: string) => { + if (val === v) flag = true; + }); + }); + return flag; +} + +/** + * 多个权限验证,全部满足则为 true + * @param value 权限值 + * @returns 有权限,返回 `true`,反之则反 + */ +export function authAll(value: Array<string>): boolean { + const stores = useUserInfo(); + return judementSameArr(value, stores.userInfos.authBtnList); +} diff --git a/src/utils/commonFunction.ts b/src/utils/commonFunction.ts new file mode 100644 index 0000000..1c069e6 --- /dev/null +++ b/src/utils/commonFunction.ts @@ -0,0 +1,65 @@ +// 通用函数 +import useClipboard from 'vue-clipboard3'; +import { ElMessage } from 'element-plus'; +import { formatDate } from '/@/utils/formatTime'; +import { useI18n } from 'vue-i18n'; + +export default function () { + const { t } = useI18n(); + const { toClipboard } = useClipboard(); + //百分比格式化 + const percentFormat = (row: any, column: number, cellValue: any) => { + return cellValue ? `${cellValue}%` : '-'; + }; + //列表日期时间格式化 + const dateFormatYMD = (row: any, column: number, cellValue: any) => { + if (!cellValue) return '-'; + return formatDate(new Date(cellValue), 'YYYY-mm-dd'); + }; + //列表日期时间格式化 + const dateFormatYMDHMS = (row: any, column: number, cellValue: any) => { + if (!cellValue) return '-'; + return formatDate(new Date(cellValue), 'YYYY-mm-dd HH:MM:SS'); + }; + //列表日期时间格式化 + const dateFormatHMS = (row: any, column: number, cellValue: any) => { + if (!cellValue) return '-'; + let time = 0; + if (typeof row === 'number') time = row; + if (typeof cellValue === 'number') time = cellValue; + return formatDate(new Date(time * 1000), 'HH:MM:SS'); + }; + // 小数格式化 + const scaleFormat = (value: any = 0, scale: number = 4) => { + return Number.parseFloat(value).toFixed(scale); + }; + // 小数格式化 + const scale2Format = (value: any = 0) => { + return Number.parseFloat(value).toFixed(2); + }; + // 点击复制文本 + const copyText = (text: string) => { + return new Promise((resolve, reject) => { + try { + //复制 + toClipboard(text); + //下面可以设置复制成功的提示框等操作 + ElMessage.success(t('message.layout.copyTextSuccess')); + resolve(text); + } catch (e) { + //复制失败 + ElMessage.error(t('message.layout.copyTextError')); + reject(e); + } + }); + }; + return { + percentFormat, + dateFormatYMD, + dateFormatYMDHMS, + dateFormatHMS, + scaleFormat, + scale2Format, + copyText, + }; +} diff --git a/src/utils/customDirective.ts b/src/utils/customDirective.ts new file mode 100644 index 0000000..c67350f --- /dev/null +++ b/src/utils/customDirective.ts @@ -0,0 +1,178 @@ +import type { App } from 'vue'; + +/** + * 按钮波浪指令 + * @directive 默认方式:v-waves,如 `<div v-waves></div>` + * @directive 参数方式:v-waves=" |light|red|orange|purple|green|teal",如 `<div v-waves="'light'"></div>` + */ +export function wavesDirective(app: App) { + app.directive('waves', { + mounted(el, binding) { + el.classList.add('waves-effect'); + binding.value && el.classList.add(`waves-${binding.value}`); + function setConvertStyle(obj: { [key: string]: unknown }) { + let style: string = ''; + for (let i in obj) { + if (obj.hasOwnProperty(i)) style += `${i}:${obj[i]};`; + } + return style; + } + function onCurrentClick(e: { [key: string]: unknown }) { + let elDiv = document.createElement('div'); + elDiv.classList.add('waves-ripple'); + el.appendChild(elDiv); + let styles = { + left: `${e.layerX}px`, + top: `${e.layerY}px`, + opacity: 1, + transform: `scale(${(el.clientWidth / 100) * 10})`, + 'transition-duration': `750ms`, + 'transition-timing-function': `cubic-bezier(0.250, 0.460, 0.450, 0.940)`, + }; + elDiv.setAttribute('style', setConvertStyle(styles)); + setTimeout(() => { + elDiv.setAttribute( + 'style', + setConvertStyle({ + opacity: 0, + transform: styles.transform, + left: styles.left, + top: styles.top, + }) + ); + setTimeout(() => { + elDiv && el.removeChild(elDiv); + }, 750); + }, 450); + } + el.addEventListener('mousedown', onCurrentClick, false); + }, + unmounted(el) { + el.addEventListener('mousedown', () => {}); + }, + }); +} + +/** + * 自定义拖动指令 + * @description 使用方式:v-drag="[dragDom,dragHeader]",如 `<div v-drag="['.drag-container .el-dialog', '.drag-container .el-dialog__header']"></div>` + * @description dragDom 要拖动的元素,dragHeader 要拖动的 Header 位置 + * @link 注意:https://github.com/element-plus/element-plus/issues/522 + * @lick 参考:https://blog.csdn.net/weixin_46391323/article/details/105228020?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-10&spm=1001.2101.3001.4242 + */ +export function dragDirective(app: App) { + app.directive('drag', { + mounted(el, binding) { + if (!binding.value) return false; + + const dragDom = document.querySelector(binding.value[0]) as HTMLElement; + const dragHeader = document.querySelector(binding.value[1]) as HTMLElement; + + dragHeader.onmouseover = () => (dragHeader.style.cursor = `move`); + + function down(e: any, type: string) { + // 鼠标按下,计算当前元素距离可视区的距离 + const disX = type === 'pc' ? e.clientX - dragHeader.offsetLeft : e.touches[0].clientX - dragHeader.offsetLeft; + const disY = type === 'pc' ? e.clientY - dragHeader.offsetTop : e.touches[0].clientY - dragHeader.offsetTop; + + // body当前宽度 + const screenWidth = document.body.clientWidth; + // 可见区域高度(应为body高度,可某些环境下无法获取) + const screenHeight = document.documentElement.clientHeight; + + // 对话框宽度 + const dragDomWidth = dragDom.offsetWidth; + // 对话框高度 + const dragDomheight = dragDom.offsetHeight; + + const minDragDomLeft = dragDom.offsetLeft; + const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth; + + const minDragDomTop = dragDom.offsetTop; + const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight; + + // 获取到的值带px 正则匹配替换 + let styL: any = getComputedStyle(dragDom).left; + let styT: any = getComputedStyle(dragDom).top; + + // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px + if (styL.includes('%')) { + styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100); + styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100); + } else { + styL = +styL.replace(/\px/g, ''); + styT = +styT.replace(/\px/g, ''); + } + + return { + disX, + disY, + minDragDomLeft, + maxDragDomLeft, + minDragDomTop, + maxDragDomTop, + styL, + styT, + }; + } + + function move(e: any, type: string, obj: any) { + let { disX, disY, minDragDomLeft, maxDragDomLeft, minDragDomTop, maxDragDomTop, styL, styT } = obj; + + // 通过事件委托,计算移动的距离 + let left = type === 'pc' ? e.clientX - disX : e.touches[0].clientX - disX; + let top = type === 'pc' ? e.clientY - disY : e.touches[0].clientY - disY; + + // 边界处理 + if (-left > minDragDomLeft) { + left = -minDragDomLeft; + } else if (left > maxDragDomLeft) { + left = maxDragDomLeft; + } + + if (-top > minDragDomTop) { + top = -minDragDomTop; + } else if (top > maxDragDomTop) { + top = maxDragDomTop; + } + + // 移动当前元素 + dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`; + } + + /** + * pc端 + * onmousedown 鼠标按下触发事件 + * onmousemove 鼠标按下时持续触发事件 + * onmouseup 鼠标抬起触发事件 + */ + dragHeader.onmousedown = (e) => { + const obj = down(e, 'pc'); + document.onmousemove = (e) => { + move(e, 'pc', obj); + }; + document.onmouseup = () => { + document.onmousemove = null; + document.onmouseup = null; + }; + }; + + /** + * 移动端 + * ontouchstart 当按下手指时,触发ontouchstart + * ontouchmove 当移动手指时,触发ontouchmove + * ontouchend 当移走手指时,触发ontouchend + */ + dragHeader.ontouchstart = (e) => { + const obj = down(e, 'app'); + document.ontouchmove = (e) => { + move(e, 'app', obj); + }; + document.ontouchend = () => { + document.ontouchmove = null; + document.ontouchend = null; + }; + }; + }, + }); +} diff --git a/src/utils/directive.ts b/src/utils/directive.ts new file mode 100644 index 0000000..a75b187 --- /dev/null +++ b/src/utils/directive.ts @@ -0,0 +1,18 @@ +import type { App } from 'vue'; +import { authDirective } from '/@/utils/authDirective'; +import { wavesDirective, dragDirective } from '/@/utils/customDirective'; + +/** + * 导出指令方法:v-xxx + * @methods authDirective 用户权限指令,用法:v-auth + * @methods wavesDirective 按钮波浪指令,用法:v-waves + * @methods dragDirective 自定义拖动指令,用法:v-drag + */ +export function directive(app: App) { + // 用户权限指令 + authDirective(app); + // 按钮波浪指令 + wavesDirective(app); + // 自定义拖动指令 + dragDirective(app); +} diff --git a/src/utils/formatTime.ts b/src/utils/formatTime.ts new file mode 100644 index 0000000..441e30c --- /dev/null +++ b/src/utils/formatTime.ts @@ -0,0 +1,137 @@ +/** + * 时间日期转换 + * @param date 当前时间,new Date() 格式 + * @param format 需要转换的时间格式字符串 + * @description format 字符串随意,如 `YYYY-mm、YYYY-mm-dd` + * @description format 季度:"YYYY-mm-dd HH:MM:SS QQQQ" + * @description format 星期:"YYYY-mm-dd HH:MM:SS WWW" + * @description format 几周:"YYYY-mm-dd HH:MM:SS ZZZ" + * @description format 季度 + 星期 + 几周:"YYYY-mm-dd HH:MM:SS WWW QQQQ ZZZ" + * @returns 返回拼接后的时间字符串 + */ +export function formatDate(date: Date, format: string): string { + let we = date.getDay(); // 星期 + let z = getWeek(date); // 周 + let qut = Math.floor((date.getMonth() + 3) / 3).toString(); // 季度 + const opt: { [key: string]: string } = { + 'Y+': date.getFullYear().toString(), // 年 + 'm+': (date.getMonth() + 1).toString(), // 月(月份从0开始,要+1) + 'd+': date.getDate().toString(), // 日 + 'H+': date.getHours().toString(), // 时 + 'M+': date.getMinutes().toString(), // 分 + 'S+': date.getSeconds().toString(), // 秒 + 'q+': qut, // 季度 + }; + // 中文数字 (星期) + const week: { [key: string]: string } = { + '0': '日', + '1': '一', + '2': '二', + '3': '三', + '4': '四', + '5': '五', + '6': '六', + }; + // 中文数字(季度) + const quarter: { [key: string]: string } = { + '1': '一', + '2': '二', + '3': '三', + '4': '四', + }; + if (/(W+)/.test(format)) + format = format.replace(RegExp.$1, RegExp.$1.length > 1 ? (RegExp.$1.length > 2 ? '星期' + week[we] : '周' + week[we]) : week[we]); + if (/(Q+)/.test(format)) format = format.replace(RegExp.$1, RegExp.$1.length == 4 ? '第' + quarter[qut] + '季度' : quarter[qut]); + if (/(Z+)/.test(format)) format = format.replace(RegExp.$1, RegExp.$1.length == 3 ? '第' + z + '周' : z + ''); + for (let k in opt) { + let r = new RegExp('(' + k + ')').exec(format); + // 若输入的长度不为1,则前面补零 + if (r) format = format.replace(r[1], RegExp.$1.length == 1 ? opt[k] : opt[k].padStart(RegExp.$1.length, '0')); + } + return format; +} + +/** + * 获取当前日期是第几周 + * @param dateTime 当前传入的日期值 + * @returns 返回第几周数字值 + */ +export function getWeek(dateTime: Date): number { + let temptTime = new Date(dateTime.getTime()); + // 周几 + let weekday = temptTime.getDay() || 7; + // 周1+5天=周六 + temptTime.setDate(temptTime.getDate() - weekday + 1 + 5); + let firstDay = new Date(temptTime.getFullYear(), 0, 1); + let dayOfWeek = firstDay.getDay(); + let spendDay = 1; + if (dayOfWeek != 0) spendDay = 7 - dayOfWeek + 1; + firstDay = new Date(temptTime.getFullYear(), 0, 1 + spendDay); + let d = Math.ceil((temptTime.valueOf() - firstDay.valueOf()) / 86400000); + let result = Math.ceil(d / 7); + return result; +} + +/** + * 将时间转换为 `几秒前`、`几分钟前`、`几小时前`、`几天前` + * @param param 当前时间,new Date() 格式或者字符串时间格式 + * @param format 需要转换的时间格式字符串 + * @description param 10秒: 10 * 1000 + * @description param 1分: 60 * 1000 + * @description param 1小时: 60 * 60 * 1000 + * @description param 24小时:60 * 60 * 24 * 1000 + * @description param 3天: 60 * 60* 24 * 1000 * 3 + * @returns 返回拼接后的时间字符串 + */ +export function formatPast(param: string | Date, format: string = 'YYYY-mm-dd'): string { + // 传入格式处理、存储转换值 + let t: any, s: number; + // 获取js 时间戳 + let time: number = new Date().getTime(); + // 是否是对象 + typeof param === 'string' || 'object' ? (t = new Date(param).getTime()) : (t = param); + // 当前时间戳 - 传入时间戳 + time = Number.parseInt(`${time - t}`); + if (time < 10000) { + // 10秒内 + return '刚刚'; + } else if (time < 60000 && time >= 10000) { + // 超过10秒少于1分钟内 + s = Math.floor(time / 1000); + return `${s}秒前`; + } else if (time < 3600000 && time >= 60000) { + // 超过1分钟少于1小时 + s = Math.floor(time / 60000); + return `${s}分钟前`; + } else if (time < 86400000 && time >= 3600000) { + // 超过1小时少于24小时 + s = Math.floor(time / 3600000); + return `${s}小时前`; + } else if (time < 259200000 && time >= 86400000) { + // 超过1天少于3天内 + s = Math.floor(time / 86400000); + return `${s}天前`; + } else { + // 超过3天 + let date = typeof param === 'string' || 'object' ? new Date(param) : param; + return formatDate(date, format); + } +} + +/** + * 时间问候语 + * @param param 当前时间,new Date() 格式 + * @description param 调用 `formatAxis(new Date())` 输出 `上午好` + * @returns 返回拼接后的时间字符串 + */ +export function formatAxis(param: Date): string { + let hour: number = new Date(param).getHours(); + if (hour < 6) return '凌晨好'; + else if (hour < 9) return '早上好'; + else if (hour < 12) return '上午好'; + else if (hour < 14) return '中午好'; + else if (hour < 17) return '下午好'; + else if (hour < 19) return '傍晚好'; + else if (hour < 22) return '晚上好'; + else return '夜里好'; +} diff --git a/src/utils/getStyleSheets.ts b/src/utils/getStyleSheets.ts new file mode 100644 index 0000000..90252c3 --- /dev/null +++ b/src/utils/getStyleSheets.ts @@ -0,0 +1,101 @@ +import { nextTick } from 'vue'; +import * as svg from '@element-plus/icons-vue'; + +// 获取阿里字体图标 +const getAlicdnIconfont = () => { + return new Promise((resolve, reject) => { + nextTick(() => { + const styles: any = document.styleSheets; + let sheetsList = []; + let sheetsIconList = []; + for (let i = 0; i < styles.length; i++) { + if (styles[i].href && styles[i].href.indexOf('at.alicdn.com') > -1) { + sheetsList.push(styles[i]); + } + } + for (let i = 0; i < sheetsList.length; i++) { + for (let j = 0; j < sheetsList[i].cssRules.length; j++) { + if (sheetsList[i].cssRules[j].selectorText && sheetsList[i].cssRules[j].selectorText.indexOf('.icon-') > -1) { + sheetsIconList.push( + `${sheetsList[i].cssRules[j].selectorText.substring(1, sheetsList[i].cssRules[j].selectorText.length).replace(/\:\:before/gi, '')}` + ); + } + } + } + if (sheetsIconList.length > 0) resolve(sheetsIconList); + else reject('未获取到值,请刷新重试'); + }); + }); +}; + +// 初始化获取 css 样式,获取 element plus 自带 svg 图标,增加了 ele- 前缀,使用时:ele-Aim +const getElementPlusIconfont = () => { + return new Promise((resolve, reject) => { + nextTick(() => { + const icons = svg as any; + const sheetsIconList = []; + for (const i in icons) { + sheetsIconList.push(`ele-${icons[i].name}`); + } + if (sheetsIconList.length > 0) resolve(sheetsIconList); + else reject('未获取到值,请刷新重试'); + }); + }); +}; + +// 初始化获取 css 样式,这里使用 fontawesome 的图标 +const getAwesomeIconfont = () => { + return new Promise((resolve, reject) => { + nextTick(() => { + const styles: any = document.styleSheets; + let sheetsList = []; + let sheetsIconList = []; + for (let i = 0; i < styles.length; i++) { + if (styles[i].href && styles[i].href.indexOf('netdna.bootstrapcdn.com') > -1) { + sheetsList.push(styles[i]); + } + } + for (let i = 0; i < sheetsList.length; i++) { + for (let j = 0; j < sheetsList[i].cssRules.length; j++) { + if ( + sheetsList[i].cssRules[j].selectorText && + sheetsList[i].cssRules[j].selectorText.indexOf('.fa-') === 0 && + sheetsList[i].cssRules[j].selectorText.indexOf(',') === -1 + ) { + if (/::before/.test(sheetsList[i].cssRules[j].selectorText)) { + sheetsIconList.push( + `${sheetsList[i].cssRules[j].selectorText.substring(1, sheetsList[i].cssRules[j].selectorText.length).replace(/\:\:before/gi, '')}` + ); + } + } + } + } + if (sheetsIconList.length > 0) resolve(sheetsIconList.reverse()); + else reject('未获取到值,请刷新重试'); + }); + }); +}; + +/** + * 获取字体图标 `document.styleSheets` + * @method ali 获取阿里字体图标 `<i class="iconfont 图标类名"></i>` + * @method ele 获取 element plus 自带图标 `<i class="图标类名"></i>` + * @method ali 获取 fontawesome 的图标 `<i class="fa 图标类名"></i>` + */ +const initIconfont = { + // iconfont + ali: () => { + return getAlicdnIconfont(); + }, + // element plus + ele: () => { + return getElementPlusIconfont(); + }, + // fontawesome + awe: () => { + return getAwesomeIconfont(); + }, +}; + +// 导出方法 +export default initIconfont; diff --git a/src/utils/loading.ts b/src/utils/loading.ts new file mode 100644 index 0000000..c23fb77 --- /dev/null +++ b/src/utils/loading.ts @@ -0,0 +1,42 @@ +import { nextTick } from 'vue'; +import '/@/theme/loading.scss'; + +/** + * 页面全局 Loading + * @method start 创建 loading + * @method done 移除 loading + */ +export const NextLoading = { + // 创建 loading + start: () => { + const bodys: Element = document.body; + const div = <HTMLElement>document.createElement('div'); + div.setAttribute('class', 'loading-next'); + const htmls = ` + <div class="loading-next-box"> + <div class="loading-next-box-warp"> + <div class="loading-next-box-item"></div> + <div class="loading-next-box-item"></div> + <div class="loading-next-box-item"></div> + <div class="loading-next-box-item"></div> + <div class="loading-next-box-item"></div> + <div class="loading-next-box-item"></div> + <div class="loading-next-box-item"></div> + <div class="loading-next-box-item"></div> + <div class="loading-next-box-item"></div> + </div> + </div> + `; + div.innerHTML = htmls; + bodys.insertBefore(div, bodys.childNodes[0]); + window.nextLoading = true; + }, + // 移除 loading + done: () => { + nextTick(() => { + window.nextLoading = false; + const el = <HTMLElement>document.querySelector('.loading-next'); + el?.parentNode?.removeChild(el); + }); + }, +}; diff --git a/src/utils/other.ts b/src/utils/other.ts new file mode 100644 index 0000000..6bb4fbd --- /dev/null +++ b/src/utils/other.ts @@ -0,0 +1,200 @@ +import { nextTick } from 'vue'; +import type { App } from 'vue'; +import * as svg from '@element-plus/icons-vue'; +import router from '/@/router/index'; +import pinia from '/@/stores/index'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { i18n } from '/@/i18n/index'; +import { Local } from '/@/utils/storage'; +import SvgIcon from '/@/components/svgIcon/index.vue'; + +/** + * 导出全局注册 element plus svg 图标 + * @param app vue 实例 + * @description 使用:https://element-plus.gitee.io/zh-CN/component/icon.html + */ +export function elSvg(app: App) { + const icons = svg as any; + for (const i in icons) { + app.component(`ele-${icons[i].name}`, icons[i]); + } + app.component('SvgIcon', SvgIcon); +} + +/** + * 设置浏览器标题国际化 + * @method const title = useTitle(); ==> title() + */ +export function useTitle() { + const stores = useThemeConfig(pinia); + const { themeConfig } = storeToRefs(stores); + nextTick(() => { + let webTitle = ''; + let globalTitle: string = themeConfig.value.globalTitle; + const { path, meta } = router.currentRoute.value; + if (path === '/login') { + webTitle = <any>meta.title; + } else { + webTitle = setTagsViewNameI18n(router.currentRoute.value); + } + document.title = `${webTitle} - ${globalTitle}` || globalTitle; + }); +} + +/** + * 设置 自定义 tagsView 名称、 自定义 tagsView 名称国际化 + * @param params 路由 query、params 中的 tagsViewName + * @returns 返回当前 tagsViewName 名称 + */ +export function setTagsViewNameI18n(item: any) { + let tagsViewName: any = ''; + const { query, params, meta } = item; + if (query?.tagsViewName || params?.tagsViewName) { + if (/\/zh-cn|en|zh-tw\//.test(query?.tagsViewName) || /\/(zh-cn|en|zh-tw)\//.test(params?.tagsViewName)) { + // 国际化 + const urlTagsParams = (query?.tagsViewName && JSON.parse(query?.tagsViewName)) || (params?.tagsViewName && JSON.parse(params?.tagsViewName)); + tagsViewName = urlTagsParams[i18n.global.locale]; + } else { + // 非国际化 + tagsViewName = query?.tagsViewName || params?.tagsViewName; + } + } else { + // 非自定义 tagsView 名称 + tagsViewName = i18n.global.t(<any>meta.title); + } + return tagsViewName; +} + +/** + * 图片懒加载 + * @param el dom 目标元素 + * @param arr 列表数据 + * @description data-xxx 属性用于存储页面或应用程序的私有自定义数据 + */ +export const lazyImg = (el: any, arr: any) => { + const io = new IntersectionObserver((res) => { + res.forEach((v: any) => { + if (v.isIntersecting) { + const { img, key } = v.target.dataset; + v.target.src = img; + v.target.onload = () => { + io.unobserve(v.target); + arr[key]['loading'] = false; + }; + } + }); + }); + nextTick(() => { + document.querySelectorAll(el).forEach((img) => io.observe(img)); + }); +}; + +/** + * 全局组件大小 + * @returns 返回 `window.localStorage` 中读取的缓存值 `globalComponentSize` + */ +export const globalComponentSize = (): string => { + const stores = useThemeConfig(pinia); + const { themeConfig } = storeToRefs(stores); + return Local.get('themeConfig')?.globalComponentSize || themeConfig.value?.globalComponentSize; +}; + +/** + * 对象深克隆 + * @param obj 源对象 + * @returns 克隆后的对象 + */ +export function deepClone(obj: any) { + let newObj: any; + try { + newObj = obj.push ? [] : {}; + } catch (error) { + newObj = {}; + } + for (let attr in obj) { + if (obj[attr] && typeof obj[attr] === 'object') { + newObj[attr] = deepClone(obj[attr]); + } else { + newObj[attr] = obj[attr]; + } + } + return newObj; +} + +/** + * 判断是否是移动端 + */ +export function isMobile() { + if ( + navigator.userAgent.match( + /('phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone')/i + ) + ) { + return true; + } else { + return false; + } +} + +/** + * 判断数组对象中所有属性是否为空,为空则删除当前行对象 + * @description @感谢大黄 + * @param list 数组对象 + * @returns 删除空值后的数组对象 + */ +export function handleEmpty(list: any) { + const arr = []; + for (const i in list) { + const d = []; + for (const j in list[i]) { + d.push(list[i][j]); + } + const leng = d.filter((item) => item === '').length; + if (leng !== d.length) { + arr.push(list[i]); + } + } + return arr; +} + +/** + * 统一批量导出 + * @method elSvg 导出全局注册 element plus svg 图标 + * @method useTitle 设置浏览器标题国际化 + * @method setTagsViewNameI18n 设置 自定义 tagsView 名称、 自定义 tagsView 名称国际化 + * @method lazyImg 图片懒加载 + * @method globalComponentSize() element plus 全局组件大小 + * @method deepClone 对象深克隆 + * @method isMobile 判断是否是移动端 + * @method handleEmpty 判断数组对象中所有属性是否为空,为空则删除当前行对象 + */ +const other = { + elSvg: (app: App) => { + elSvg(app); + }, + useTitle: () => { + useTitle(); + }, + setTagsViewNameI18n(route: any) { + return setTagsViewNameI18n(route); + }, + lazyImg: (el: any, arr: any) => { + lazyImg(el, arr); + }, + globalComponentSize: () => { + return globalComponentSize(); + }, + deepClone: (obj: any) => { + return deepClone(obj); + }, + isMobile: () => { + return isMobile(); + }, + handleEmpty: (list: any) => { + return handleEmpty(list); + }, +}; + +// 统一批量导出 +export default other; diff --git a/src/utils/request.ts b/src/utils/request.ts new file mode 100644 index 0000000..146e09b --- /dev/null +++ b/src/utils/request.ts @@ -0,0 +1,72 @@ +import axios from 'axios'; +import { ElMessage, ElMessageBox } from 'element-plus'; +import { Session } from '/@/utils/storage'; + +// 配置新建一个 axios 实例 +const service = axios.create({ + baseURL: import.meta.env.VITE_API_URL as any, + timeout: 50000, + headers: { 'Content-Type': 'application/json' }, +}); + +service.interceptors.request.use( + (config) => { + // 在发送请求之前做些什么 token + if (Session.get('token')) { + (<any>config.headers).common['Authorization'] = `${Session.get('token')}`; + (<any>config.headers).common['uid'] = `${Session.get('sign')}`; + } + return config; + }, + (error) => { + // 对请求错误做些什么 + return Promise.reject(error); + } +); + +service.interceptors.response.use( + + (response) => { + // 对响应数据做点什么 + if(response.data.code && (response.data.code ==='A0215' || response.data.code === 'A0214')){ + Session.clear() + window.location.href = '/' + return Promise.reject(response) + } + // if(response.data.code && response.data.code !== '200'){ + return Promise.resolve(response) + // } + // Session.clear() + // window.location.href = '/' + // return Promise.reject(response) + // const res = response.data; + // debugger + // if (res.code && res.code !== 0) { + // // `token` 过期或者账号已在别处登录 + // if (res.code === 401 || res.code === 4001) { + // Session.clear(); // 清除浏览器全部临时缓存 + // window.location.href = '/'; // 去登录页 + // ElMessageBox.alert('你已被登出,请重新登录', '提示', {}) + // .then(() => {}) + // .catch(() => {}); + // } + // return Promise.reject(service.interceptors.response); + // } else { + // return response.data; + // } + }, + (error) => { + // 对响应错误做点什么 + if (error.message.indexOf('timeout') != -1) { + ElMessage.error('网络超时'); + } else if (error.message == 'Network Error') { + ElMessage.error('网络连接错误'); + } else { + if (error.response.data) ElMessage.error(error.response.statusText); + else ElMessage.error('接口路径找不到'); + } + return Promise.reject(error); + } +); + +export default service; diff --git a/src/utils/setIconfont.ts b/src/utils/setIconfont.ts new file mode 100644 index 0000000..a6acf68 --- /dev/null +++ b/src/utils/setIconfont.ts @@ -0,0 +1,48 @@ +// 字体图标 url +const cssCdnUrlList: Array<string> = [ + '//at.alicdn.com/t/font_2298093_y6u00apwst.css', + '//netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css', +]; +// 第三方 js url +const jsCdnUrlList: Array<string> = []; + +// 动态批量设置字体图标 +export function setCssCdn() { + if (cssCdnUrlList.length <= 0) return false; + cssCdnUrlList.map((v) => { + let link = document.createElement('link'); + link.rel = 'stylesheet'; + link.href = v; + link.crossOrigin = 'anonymous'; + document.getElementsByTagName('head')[0].appendChild(link); + }); +} + +// 动态批量设置第三方js +export function setJsCdn() { + if (jsCdnUrlList.length <= 0) return false; + jsCdnUrlList.map((v) => { + let link = document.createElement('script'); + link.src = v; + document.body.appendChild(link); + }); +} + +/** + * 批量设置字体图标、动态js + * @method cssCdn 动态批量设置字体图标 + * @method jsCdn 动态批量设置第三方js + */ +const setIntroduction = { + // 设置css + cssCdn: () => { + setCssCdn(); + }, + // 设置js + jsCdn: () => { + setJsCdn(); + }, +}; + +// 导出函数方法 +export default setIntroduction; diff --git a/src/utils/storage.ts b/src/utils/storage.ts new file mode 100644 index 0000000..a983f80 --- /dev/null +++ b/src/utils/storage.ts @@ -0,0 +1,59 @@ +import Cookies from 'js-cookie'; + +/** + * window.localStorage 浏览器永久缓存 + * @method set 设置永久缓存 + * @method get 获取永久缓存 + * @method remove 移除永久缓存 + * @method clear 移除全部永久缓存 + */ +export const Local = { + // 设置永久缓存 + set(key: string, val: any) { + window.localStorage.setItem(key, JSON.stringify(val)); + }, + // 获取永久缓存 + get(key: string) { + let json: any = window.localStorage.getItem(key); + return JSON.parse(json); + }, + // 移除永久缓存 + remove(key: string) { + window.localStorage.removeItem(key); + }, + // 移除全部永久缓存 + clear() { + window.localStorage.clear(); + }, +}; + +/** + * window.sessionStorage 浏览器临时缓存 + * @method set 设置临时缓存 + * @method get 获取临时缓存 + * @method remove 移除临时缓存 + * @method clear 移除全部临时缓存 + */ +export const Session = { + // 设置临时缓存 + set(key: string, val: any) { + if (key === 'token') return Cookies.set(key, val); + window.sessionStorage.setItem(key, JSON.stringify(val)); + }, + // 获取临时缓存 + get(key: string) { + if (key === 'token') return Cookies.get(key); + let json: any = window.sessionStorage.getItem(key); + return JSON.parse(json); + }, + // 移除临时缓存 + remove(key: string) { + if (key === 'token') return Cookies.remove(key); + window.sessionStorage.removeItem(key); + }, + // 移除全部临时缓存 + clear() { + Cookies.remove('token'); + window.sessionStorage.clear(); + }, +}; diff --git a/src/utils/theme.ts b/src/utils/theme.ts new file mode 100644 index 0000000..5561e64 --- /dev/null +++ b/src/utils/theme.ts @@ -0,0 +1,59 @@ +import { ElMessage } from 'element-plus'; + +/** + * hex颜色转rgb颜色 + * @param str 颜色值字符串 + * @returns 返回处理后的颜色值 + */ +export function hexToRgb(str: any) { + let hexs: any = ''; + let reg = /^\#?[0-9A-Fa-f]{6}$/; + if (!reg.test(str)) return ElMessage.warning('输入错误的hex'); + str = str.replace('#', ''); + hexs = str.match(/../g); + for (let i = 0; i < 3; i++) hexs[i] = parseInt(hexs[i], 16); + return hexs; +} + +/** + * rgb颜色转Hex颜色 + * @param r 代表红色 + * @param g 代表绿色 + * @param b 代表蓝色 + * @returns 返回处理后的颜色值 + */ +export function rgbToHex(r: any, g: any, b: any) { + let reg = /^\d{1,3}$/; + if (!reg.test(r) || !reg.test(g) || !reg.test(b)) return ElMessage.warning('输入错误的rgb颜色值'); + let hexs = [r.toString(16), g.toString(16), b.toString(16)]; + for (let i = 0; i < 3; i++) if (hexs[i].length == 1) hexs[i] = `0${hexs[i]}`; + return `#${hexs.join('')}`; +} + +/** + * 加深颜色值 + * @param color 颜色值字符串 + * @param level 加深的程度,限0-1之间 + * @returns 返回处理后的颜色值 + */ +export function getDarkColor(color: string, level: number) { + let reg = /^\#?[0-9A-Fa-f]{6}$/; + if (!reg.test(color)) return ElMessage.warning('输入错误的hex颜色值'); + let rgb = hexToRgb(color); + for (let i = 0; i < 3; i++) rgb[i] = Math.floor(rgb[i] * (1 - level)); + return rgbToHex(rgb[0], rgb[1], rgb[2]); +} + +/** + * 变浅颜色值 + * @param color 颜色值字符串 + * @param level 加深的程度,限0-1之间 + * @returns 返回处理后的颜色值 + */ +export function getLightColor(color: string, level: number) { + let reg = /^\#?[0-9A-Fa-f]{6}$/; + if (!reg.test(color)) return ElMessage.warning('输入错误的hex颜色值'); + let rgb = hexToRgb(color); + for (let i = 0; i < 3; i++) rgb[i] = Math.floor((255 - rgb[i]) * level + rgb[i]); + return rgbToHex(rgb[0], rgb[1], rgb[2]); +} diff --git a/src/utils/toolsValidate.ts b/src/utils/toolsValidate.ts new file mode 100644 index 0000000..f2cb9d6 --- /dev/null +++ b/src/utils/toolsValidate.ts @@ -0,0 +1,370 @@ +/** + * 2020.11.29 lyt 整理 + * 工具类集合,适用于平时开发 + * 新增多行注释信息,鼠标放到方法名即可查看 + */ + +/** + * 验证百分比(不可以小数) + * @param val 当前值字符串 + * @returns 返回处理后的字符串 + */ +export function verifyNumberPercentage(val: string): string { + // 匹配空格 + let v = val.replace(/(^\s*)|(\s*$)/g, ''); + // 只能是数字和小数点,不能是其他输入 + v = v.replace(/[^\d]/g, ''); + // 不能以0开始 + v = v.replace(/^0/g, ''); + // 数字超过100,赋值成最大值100 + v = v.replace(/^[1-9]\d\d{1,3}$/, '100'); + // 返回结果 + return v; +} + +/** + * 验证百分比(可以小数) + * @param val 当前值字符串 + * @returns 返回处理后的字符串 + */ +export function verifyNumberPercentageFloat(val: string): string { + let v = verifyNumberIntegerAndFloat(val); + // 数字超过100,赋值成最大值100 + v = v.replace(/^[1-9]\d\d{1,3}$/, '100'); + // 超过100之后不给再输入值 + v = v.replace(/^100\.$/, '100'); + // 返回结果 + return v; +} + +/** + * 小数或整数(不可以负数) + * @param val 当前值字符串 + * @returns 返回处理后的字符串 + */ +export function verifyNumberIntegerAndFloat(val: string) { + // 匹配空格 + let v = val.replace(/(^\s*)|(\s*$)/g, ''); + // 只能是数字和小数点,不能是其他输入 + v = v.replace(/[^\d.]/g, ''); + // 以0开始只能输入一个 + v = v.replace(/^0{2}$/g, '0'); + // 保证第一位只能是数字,不能是点 + v = v.replace(/^\./g, ''); + // 小数只能出现1位 + v = v.replace('.', '$#$').replace(/\./g, '').replace('$#$', '.'); + // 小数点后面保留2位 + v = v.replace(/^(\-)*(\d+)\.(\d\d).*$/, '$1$2.$3'); + // 返回结果 + return v; +} + +/** + * 正整数验证 + * @param val 当前值字符串 + * @returns 返回处理后的字符串 + */ +export function verifiyNumberInteger(val: string) { + // 匹配空格 + let v = val.replace(/(^\s*)|(\s*$)/g, ''); + // 去掉 '.' , 防止贴贴的时候出现问题 如 0.1.12.12 + v = v.replace(/[\.]*/g, ''); + // 去掉以 0 开始后面的数, 防止贴贴的时候出现问题 如 00121323 + v = v.replace(/(^0[\d]*)$/g, '0'); + // 首位是0,只能出现一次 + v = v.replace(/^0\d$/g, '0'); + // 只匹配数字 + v = v.replace(/[^\d]/g, ''); + // 返回结果 + return v; +} + +/** + * 去掉中文及空格 + * @param val 当前值字符串 + * @returns 返回处理后的字符串 + */ +export function verifyCnAndSpace(val: string) { + // 匹配中文与空格 + let v = val.replace(/[\u4e00-\u9fa5\s]+/g, ''); + // 匹配空格 + v = v.replace(/(^\s*)|(\s*$)/g, ''); + // 返回结果 + return v; +} + +/** + * 去掉英文及空格 + * @param val 当前值字符串 + * @returns 返回处理后的字符串 + */ +export function verifyEnAndSpace(val: string) { + // 匹配英文与空格 + let v = val.replace(/[a-zA-Z]+/g, ''); + // 匹配空格 + v = v.replace(/(^\s*)|(\s*$)/g, ''); + // 返回结果 + return v; +} + +/** + * 禁止输入空格 + * @param val 当前值字符串 + * @returns 返回处理后的字符串 + */ +export function verifyAndSpace(val: string) { + // 匹配空格 + let v = val.replace(/(^\s*)|(\s*$)/g, ''); + // 返回结果 + return v; +} + +/** + * 金额用 `,` 区分开 + * @param val 当前值字符串 + * @returns 返回处理后的字符串 + */ +export function verifyNumberComma(val: string) { + // 调用小数或整数(不可以负数)方法 + let v: any = verifyNumberIntegerAndFloat(val); + // 字符串转成数组 + v = v.toString().split('.'); + // \B 匹配非单词边界,两边都是单词字符或者两边都是非单词字符 + v[0] = v[0].replace(/\B(?=(\d{3})+(?!\d))/g, ','); + // 数组转字符串 + v = v.join('.'); + // 返回结果 + return v; +} + +/** + * 匹配文字变色(搜索时) + * @param val 当前值字符串 + * @param text 要处理的字符串值 + * @param color 搜索到时字体高亮颜色 + * @returns 返回处理后的字符串 + */ +export function verifyTextColor(val: string, text = '', color = 'red') { + // 返回内容,添加颜色 + let v = text.replace(new RegExp(val, 'gi'), `<span style='color: ${color}'>${val}</span>`); + // 返回结果 + return v; +} + +/** + * 数字转中文大写 + * @param val 当前值字符串 + * @param unit 默认:仟佰拾亿仟佰拾万仟佰拾元角分 + * @returns 返回处理后的字符串 + */ +export function verifyNumberCnUppercase(val: any, unit = '仟佰拾亿仟佰拾万仟佰拾元角分', v = '') { + // 当前内容字符串添加 2个0,为什么?? + val += '00'; + // 返回某个指定的字符串值在字符串中首次出现的位置,没有出现,则该方法返回 -1 + let lookup = val.indexOf('.'); + // substring:不包含结束下标内容,substr:包含结束下标内容 + if (lookup >= 0) val = val.substring(0, lookup) + val.substr(lookup + 1, 2); + // 根据内容 val 的长度,截取返回对应大写 + unit = unit.substr(unit.length - val.length); + // 循环截取拼接大写 + for (let i = 0; i < val.length; i++) { + v += '零壹贰叁肆伍陆柒捌玖'.substr(val.substr(i, 1), 1) + unit.substr(i, 1); + } + // 正则处理 + v = v + .replace(/零角零分$/, '整') + .replace(/零[仟佰拾]/g, '零') + .replace(/零{2,}/g, '零') + .replace(/零([亿|万])/g, '$1') + .replace(/零+元/, '元') + .replace(/亿零{0,3}万/, '亿') + .replace(/^元/, '零元'); + // 返回结果 + return v; +} + +/** + * 手机号码 + * @param val 当前值字符串 + * @returns 返回 true: 手机号码正确 + */ +export function verifyPhone(val: string) { + // false: 手机号码不正确 + if (!/^((12[0-9])|(13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0|1,5-9]))\d{8}$/.test(val)) return false; + // true: 手机号码正确 + else return true; +} + +/** + * 国内电话号码 + * @param val 当前值字符串 + * @returns 返回 true: 国内电话号码正确 + */ +export function verifyTelPhone(val: string) { + // false: 国内电话号码不正确 + if (!/\d{3}-\d{8}|\d{4}-\d{7}/.test(val)) return false; + // true: 国内电话号码正确 + else return true; +} + +/** + * 登录账号 (字母开头,允许5-16字节,允许字母数字下划线) + * @param val 当前值字符串 + * @returns 返回 true: 登录账号正确 + */ +export function verifyAccount(val: string) { + // false: 登录账号不正确 + if (!/^[a-zA-Z][a-zA-Z0-9_]{4,15}$/.test(val)) return false; + // true: 登录账号正确 + else return true; +} + +/** + * 密码 (以字母开头,长度在6~16之间,只能包含字母、数字和下划线) + * @param val 当前值字符串 + * @returns 返回 true: 密码正确 + */ +export function verifyPassword(val: string) { + // false: 密码不正确 + if (!/^[a-zA-Z]\w{5,15}$/.test(val)) return false; + // true: 密码正确 + else return true; +} + +/** + * 强密码 (字母+数字+特殊字符,长度在6-16之间) + * @param val 当前值字符串 + * @returns 返回 true: 强密码正确 + */ +export function verifyPasswordPowerful(val: string) { + // false: 强密码不正确 + if (!/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\.*]+$)(?![a-zA-z\d]+$)(?![a-zA-z!@#$%^&\.*]+$)(?![\d!@#$%^&\.*]+$)[a-zA-Z\d!@#$%^&\.*]{6,16}$/.test(val)) + return false; + // true: 强密码正确 + else return true; +} + +/** + * 密码强度 + * @param val 当前值字符串 + * @description 弱:纯数字,纯字母,纯特殊字符 + * @description 中:字母+数字,字母+特殊字符,数字+特殊字符 + * @description 强:字母+数字+特殊字符 + * @returns 返回处理后的字符串:弱、中、强 + */ +export function verifyPasswordStrength(val: string) { + let v = ''; + // 弱:纯数字,纯字母,纯特殊字符 + if (/^(?:\d+|[a-zA-Z]+|[!@#$%^&\.*]+){6,16}$/.test(val)) v = '弱'; + // 中:字母+数字,字母+特殊字符,数字+特殊字符 + if (/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\.*]+$)[a-zA-Z\d!@#$%^&\.*]{6,16}$/.test(val)) v = '中'; + // 强:字母+数字+特殊字符 + if (/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\.*]+$)(?![a-zA-z\d]+$)(?![a-zA-z!@#$%^&\.*]+$)(?![\d!@#$%^&\.*]+$)[a-zA-Z\d!@#$%^&\.*]{6,16}$/.test(val)) + v = '强'; + // 返回结果 + return v; +} + +/** + * IP地址 + * @param val 当前值字符串 + * @returns 返回 true: IP地址正确 + */ +export function verifyIPAddress(val: string) { + // false: IP地址不正确 + if ( + !/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/.test( + val + ) + ) + return false; + // true: IP地址正确 + else return true; +} + +/** + * 邮箱 + * @param val 当前值字符串 + * @returns 返回 true: 邮箱正确 + */ +export function verifyEmail(val: string) { + // false: 邮箱不正确 + if ( + !/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test( + val + ) + ) + return false; + // true: 邮箱正确 + else return true; +} + +/** + * 身份证 + * @param val 当前值字符串 + * @returns 返回 true: 身份证正确 + */ +export function verifyIdCard(val: string) { + // false: 身份证不正确 + if (!/^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/.test(val)) return false; + // true: 身份证正确 + else return true; +} + +/** + * 姓名 + * @param val 当前值字符串 + * @returns 返回 true: 姓名正确 + */ +export function verifyFullName(val: string) { + // false: 姓名不正确 + if (!/^[\u4e00-\u9fa5]{1,6}(·[\u4e00-\u9fa5]{1,6}){0,2}$/.test(val)) return false; + // true: 姓名正确 + else return true; +} + +/** + * 邮政编码 + * @param val 当前值字符串 + * @returns 返回 true: 邮政编码正确 + */ +export function verifyPostalCode(val: string) { + // false: 邮政编码不正确 + if (!/^[1-9][0-9]{5}$/.test(val)) return false; + // true: 邮政编码正确 + else return true; +} + +/** + * url 处理 + * @param val 当前值字符串 + * @returns 返回 true: url 正确 + */ +export function verifyUrl(val: string) { + // false: url不正确 + if ( + !/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test( + val + ) + ) + return false; + // true: url正确 + else return true; +} + +/** + * 车牌号 + * @param val 当前值字符串 + * @returns 返回 true:车牌号正确 + */ +export function verifyCarNum(val: string) { + // false: 车牌号不正确 + if ( + !/^(([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z](([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳使领]))$/.test( + val + ) + ) + return false; + // true:车牌号正确 + else return true; +} diff --git a/src/utils/wartermark.ts b/src/utils/wartermark.ts new file mode 100644 index 0000000..b897ed1 --- /dev/null +++ b/src/utils/wartermark.ts @@ -0,0 +1,47 @@ +// 页面添加水印效果 +const setWatermark = (str: string) => { + const id = '1.23452384164.123412416'; + if (document.getElementById(id) !== null) document.body.removeChild(<HTMLElement>document.getElementById(id)); + const can = document.createElement('canvas'); + can.width = 200; + can.height = 130; + const cans: any = can.getContext('2d'); + cans.rotate((-20 * Math.PI) / 180); + cans.font = '12px Vedana'; + cans.fillStyle = 'rgba(200, 200, 200, 0.30)'; + cans.textBaseline = 'Middle'; + cans.fillText(str, can.width / 10, can.height / 2); + const div = document.createElement('div'); + div.id = id; + div.style.pointerEvents = 'none'; + div.style.top = '15px'; + div.style.left = '0px'; + div.style.position = 'fixed'; + div.style.zIndex = '10000000'; + div.style.width = `${document.documentElement.clientWidth}px`; + div.style.height = `${document.documentElement.clientHeight}px`; + div.style.background = `url(${can.toDataURL('image/png')}) left top repeat`; + document.body.appendChild(div); + return id; +}; + +/** + * 页面添加水印效果 + * @method set 设置水印 + * @method del 删除水印 + */ +const watermark = { + // 设置水印 + set: (str: string) => { + let id = setWatermark(str); + if (document.getElementById(id) === null) id = setWatermark(str); + }, + // 删除水印 + del: () => { + let id = '1.23452384164.123412416'; + if (document.getElementById(id) !== null) document.body.removeChild(<HTMLElement>document.getElementById(id)); + }, +}; + +// 导出方法 +export default watermark; diff --git a/src/views/chart/chart.scss b/src/views/chart/chart.scss new file mode 100644 index 0000000..32409e5 --- /dev/null +++ b/src/views/chart/chart.scss @@ -0,0 +1,434 @@ +.chart-scrollbar { + .chart-warp { + display: flex; + flex-direction: column; + height: 100%; + .chart-warp-bottom { + flex: 1; + overflow: hidden; + display: flex; + .big-data-down-left, + .big-data-down-right { + width: 30%; + display: flex; + flex-direction: column; + .flex-warp-item { + padding: 0 7.5px 15px 15px; + width: 100%; + height: 33.33%; + .flex-warp-item-box { + width: 100%; + height: 100%; + background: var(--el-color-white); + border: 1px solid var(--el-border-color-lighter); + border-radius: 4px; + display: flex; + flex-direction: column; + padding: 15px; + transition: all ease 0.3s; + &:hover { + box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%); + transition: all ease 0.3s; + } + .flex-title { + margin-bottom: 15px; + display: flex; + justify-content: space-between; + .flex-title-small { + font-size: 12px; + } + } + .flex-content { + flex: 1; + font-size: 12px; + } + .flex-content-overflow { + overflow: hidden; + } + } + } + } + .big-data-down-left { + color: var(--el-text-color-primary); + .sky { + display: flex; + align-items: center; + .sky-left { + font-size: 30px; + } + .sky-center { + flex: 1; + overflow: hidden; + padding: 0 10px; + font { + margin-right: 15px; + } + .span { + background: #22bc76; + border-radius: 2px; + padding: 0 5px; + color: var(--el-color-white); + } + } + .sky-right { + span { + font-size: 30px; + } + font { + font-size: 20px; + } + } + } + .sky-dd { + .sky-dl { + display: flex; + align-items: center; + height: 28px; + overflow: hidden; + div { + flex: 1; + overflow: hidden; + i { + font-size: 14px; + } + } + .tip { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + } + .sky-dl-first { + color: var(--el-color-primary); + } + } + .d-states { + display: flex; + .d-states-item { + flex: 1; + display: flex; + align-items: center; + overflow: hidden; + i { + font-size: 20px; + height: 33px; + width: 33px; + line-height: 33px; + text-align: center; + border-radius: 100%; + flex-shrink: 1; + color: var(--el-color-white); + display: flex; + align-items: center; + justify-content: center; + } + .i-bg1 { + background: #22bc76; + } + .i-bg2 { + background: #e2356d; + } + .i-bg3 { + background: #43bbef; + } + .d-states-flex { + overflow: hidden; + padding: 0 10px 0; + .d-states-item-label { + color: var(--el-color-primary); + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + .d-states-item-value { + font-size: 14px; + text-align: center; + margin-top: 3px; + color: var(--el-color-primary); + } + } + } + } + .d-btn { + margin-top: 5px; + .d-btn-item { + border: 1px solid var(--el-color-primary); + display: flex; + width: 100%; + border-radius: 35px; + align-items: center; + padding: 5px; + margin-top: 15px; + cursor: pointer; + transition: all ease 0.3s; + color: var(--el-color-primary); + .d-btn-item-left { + font-size: 20px; + border: 1px solid var(--el-color-primary); + width: 25px; + height: 25px; + line-height: 25px; + border-radius: 100%; + text-align: center; + font-size: 14px; + } + .d-btn-item-center { + padding: 0 10px; + flex: 1; + } + .d-btn-item-eight { + text-align: right; + padding-right: 10px; + } + } + } + } + .big-data-down-center { + width: 40%; + display: flex; + flex-direction: column; + .big-data-down-center-one { + height: 66.67%; + padding: 0 7.5px 15px; + .big-data-down-center-one-content { + height: 100%; + background: var(--el-color-white); + padding: 15px; + border: 1px solid var(--el-border-color-lighter); + border-radius: 4px; + transition: all ease 0.3s; + &:hover { + box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%); + transition: all ease 0.3s; + } + } + } + .big-data-down-center-two { + padding: 0 7.5px 15px; + height: 33.33%; + .flex-warp-item-box { + width: 100%; + height: 100%; + background: var(--el-color-white); + display: flex; + flex-direction: column; + padding: 15px; + border: 1px solid var(--el-border-color-lighter); + border-radius: 4px; + transition: all ease 0.3s; + &:hover { + box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%); + transition: all ease 0.3s; + } + .flex-title { + margin-bottom: 15px; + color: var(--el-text-color-primary); + display: flex; + justify-content: space-between; + .flex-title-small { + font-size: 12px; + } + } + .flex-content { + flex: 1; + font-size: 12px; + display: flex; + height: calc(100% - 30px); + .flex-content-left { + display: flex; + flex-wrap: wrap; + width: 120px; + height: 100%; + .monitor-item { + width: 50%; + display: flex; + align-items: center; + .monitor-wave { + cursor: pointer; + width: 40px; + height: 40px; + position: relative; + background-color: var(--el-color-primary); + border-radius: 50%; + overflow: hidden; + text-align: center; + &::before, + &::after { + content: ''; + position: absolute; + left: 50%; + width: 40px; + height: 40px; + background: #f4f4f4; + animation: roateOne 10s linear infinite; + transform: translateX(-50%); + z-index: 1; + } + &::before { + bottom: 10px; + border-radius: 60%; + } + &::after { + bottom: 8px; + opacity: 0.7; + border-radius: 37%; + } + .monitor-z-index { + position: relative; + z-index: 2; + color: var(--el-color-primary); + display: flex; + align-items: center; + height: 100%; + justify-content: center; + } + } + @keyframes roateOne { + 0% { + transform: translate(-50%, 0) rotateZ(0deg); + } + 50% { + transform: translate(-50%, -2%) rotateZ(180deg); + } + 100% { + transform: translate(-50%, 0%) rotateZ(360deg); + } + } + .monitor-active { + background-color: #22bc76; + .monitor-z-index { + color: #22bc76; + } + } + } + } + .flex-content-right { + flex: 1; + } + } + } + } + } + .big-data-down-right { + .flex-warp-item { + padding: 0 15px 15px 7.5px; + .flex-title { + color: var(--el-text-color-primary); + } + .flex-content { + display: flex; + flex-direction: column; + .task { + display: flex; + height: 45px; + .task-item { + flex: 1; + color: var(--el-color-white); + display: flex; + justify-content: center; + .task-item-box { + position: relative; + width: 45px; + height: 45px; + overflow: hidden; + border-radius: 100%; + z-index: 0; + display: flex; + align-items: center; + flex-direction: column; + justify-content: center; + box-shadow: 0 10px 12px 0 rgba(0, 0, 0, 0.3); + &::before { + content: ''; + position: absolute; + z-index: -2; + left: -50%; + top: -50%; + width: 200%; + height: 200%; + background-repeat: no-repeat; + background-size: 50% 50%, 50% 50%; + background-position: 0 0, 100% 0, 100% 100%, 0 100%; + background-image: linear-gradient(#19d4ae, #19d4ae), linear-gradient(#5ab1ef, #5ab1ef), linear-gradient(#fa6e86, #fa6e86), + linear-gradient(#ffb980, #ffb980); + animation: rotate 2s linear infinite; + } + &::after { + content: ''; + position: absolute; + z-index: -1; + left: 1px; + top: 1px; + width: calc(100% - 2px); + height: calc(100% - 2px); + border-radius: 100%; + } + .task-item-value { + text-align: center; + font-size: 14px; + font-weight: bold; + } + .task-item-label { + text-align: center; + } + } + .task1 { + &::after { + background: #5492be; + } + } + .task2 { + &::after { + background: #43a177; + } + } + .task3 { + &::after { + background: #a76077; + } + } + } + .task-first-item { + flex-direction: column; + text-align: center; + color: var(--el-color-primary); + .task-first { + font-size: 20px; + } + } + } + .progress { + color: var(--el-text-color-primary); + display: flex; + flex-direction: column; + flex: 1; + justify-content: space-between; + margin-top: 15px; + .progress-item { + height: 33.33%; + display: flex; + align-items: center; + .progress-box { + flex: 1; + width: 100%; + margin-left: 10px; + ::v-deep(.el-progress__text) { + color: var(--el-text-color-primary); + font-size: 12px !important; + text-align: right; + } + ::v-deep(.el-progress-bar__outer) { + background-color: rgba(0, 0, 0, 0.1) !important; + } + ::v-deep(.el-progress-bar) { + margin-right: -22px !important; + } + } + } + } + } + } + } + } + } +} diff --git a/src/views/chart/chart.ts b/src/views/chart/chart.ts new file mode 100644 index 0000000..6d10fd6 --- /dev/null +++ b/src/views/chart/chart.ts @@ -0,0 +1,59 @@ +/** + * sky 天气 + * @returns 返回模拟数据 + */ +export const skyList = [ + { + v1: '时间', + v2: '天气', + v3: '温度', + v5: '降水', + v7: '风力', + type: 'title', + }, + { + v1: '今天', + v2: 'ele-Sunny', + v3: '20°/26°', + v5: '50%', + v7: '13m/s', + }, + { + v1: '明天', + v2: 'ele-Lightning', + v3: '20°/26°', + v5: '50%', + v7: '13m/s', + }, +]; + +/** + * 当前设置状态 + * @returns 返回模拟数据 + */ +export const dBtnList = [ + { + v2: '阳光玫瑰种植', + v3: '126天', + v4: '设备在线', + }, +]; + +/** + * 当前设备监测 + * @returns 返回模拟数据 + */ +export const chartData4List = [ + { + label: '温度', + }, + { + label: '光照', + }, + { + label: '湿度', + }, + { + label: '风力', + }, +]; diff --git a/src/views/chart/head.vue b/src/views/chart/head.vue new file mode 100644 index 0000000..82842e8 --- /dev/null +++ b/src/views/chart/head.vue @@ -0,0 +1,107 @@ +<template> + <div class="big-data-up mb15"> + <div class="up-left"> + <i class="el-icon-time mr5"></i> + <span>{{ time.txt }}</span> + </div> + <div class="up-center"> + <span>智慧农业系统平台</span> + </div> + </div> +</template> + +<script lang="ts"> +import { reactive, toRefs, onBeforeMount, onUnmounted, defineComponent } from 'vue'; +import { formatDate } from '/@/utils/formatTime'; + +export default defineComponent({ + name: 'chartHead', + setup() { + const state = reactive({ + time: { + txt: '', + fun: 0, + }, + }); + // 初始化时间 + const initTime = () => { + state.time.txt = formatDate(new Date(), 'YYYY-mm-dd HH:MM:SS WWW QQQQ'); + state.time.fun = window.setInterval(() => { + state.time.txt = formatDate(new Date(), 'YYYY-mm-dd HH:MM:SS WWW QQQQ'); + }, 1000); + }; + // 页面加载前 + onBeforeMount(() => { + initTime(); + }); + // 页面卸载时 + onUnmounted(() => { + window.clearInterval(state.time.fun); + }); + return { + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.big-data-up { + height: 55px; + width: 100%; + display: flex; + align-items: center; + padding: 0 15px; + color: var(--el-color-primary); + overflow: hidden; + position: relative; + .up-left { + position: absolute; + } + .up-center { + width: 100%; + display: flex; + justify-content: center; + font-size: 18px; + letter-spacing: 5px; + background-image: -webkit-linear-gradient( + left, + var(--el-color-primary), + var(--el-color-primary-light-3) 25%, + var(--el-color-primary) 50%, + var(--el-color-primary-light-3) 75%, + var(--el-color-primary) + ); + -webkit-text-fill-color: transparent; + -webkit-background-clip: text; + background-clip: text; + background-size: 200% 100%; + -webkit-animation: masked-animation-data-v-b02d8052 4s linear infinite; + animation: masked-animation-data-v-b02d8052 4s linear infinite; + -webkit-box-reflect: below -2px -webkit-gradient(linear, left top, left bottom, from(transparent), to(hsla(0, 0%, 100%, 0.1))); + position: relative; + @keyframes masked-animation { + 0% { + background-position: 0 0; + } + 100% { + background-position: -100% 0; + } + } + position: relative; + &::after { + content: ''; + width: 250px; + position: absolute; + bottom: -15px; + left: 50%; + transform: translateX(-50%); + border: 1px transparent solid; + border-image: linear-gradient(to right, var(--el-color-primary-light-9), var(--el-color-primary)) 1 10; + } + span { + cursor: pointer; + } + } +} +</style> diff --git a/src/views/chart/index.vue b/src/views/chart/index.vue new file mode 100644 index 0000000..db3255e --- /dev/null +++ b/src/views/chart/index.vue @@ -0,0 +1,492 @@ +<template> + <div class="chart-scrollbar layout-view-bg-white" :style="{ height: `calc(100vh - ${initTagViewHeight}` }"> + <div class="chart-warp"> + <div class="chart-warp-top"> + <ChartHead /> + </div> + <div class="chart-warp-bottom"> + <!-- 左边 --> + <div class="big-data-down-left"> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <div class="flex-title">天气预报</div> + <div class="flex-content"> + <div class="sky"> + <SvgIcon name="ele-Sunny" class="sky-left" /> + <div class="sky-center"> + <div class="mb2"> + <span>多云转晴</span> + <span>东南风</span> + <span class="span ml5">良</span> + </div> + </div> + <div class="sky-right"> + <span>25</span> + <span>°C</span> + </div> + </div> + <div class="sky-dd"> + <div class="sky-dl" v-for="(v, k) in skyList" :key="k" :class="{ 'sky-dl-first': k === 1 }"> + <div>{{ v.v1 }}</div> + <div v-if="v.type === 'title'">{{ v.v2 }}</div> + <div v-else> + <SvgIcon :name="v.v2" /> + </div> + <div>{{ v.v3 }}</div> + <div class="tip">{{ v.v5 }}</div> + <div>{{ v.v7 }}</div> + </div> + </div> + </div> + </div> + </div> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <div class="flex-title">当前设备状态</div> + <div class="flex-content flex-content-overflow"> + <div class="d-states"> + <div class="d-states-item"> + <SvgIcon name="ele-Odometer" class="i-bg1" /> + <div class="d-states-flex"> + <div class="d-states-item-label">园区设备数</div> + <div class="d-states-item-value">99</div> + </div> + </div> + <div class="d-states-item"> + <SvgIcon name="ele-FirstAidKit" class="i-bg2" /> + <div class="d-states-flex"> + <div class="d-states-item-label">预警设备数</div> + <div class="d-states-item-value">10</div> + </div> + </div> + <div class="d-states-item"> + <SvgIcon name="ele-VideoPlay" class="i-bg3" /> + <div class="d-states-flex"> + <div class="d-states-item-label">运行设备数</div> + <div class="d-states-item-value">20</div> + </div> + </div> + </div> + <div class="d-btn"> + <div class="d-btn-item" v-for="(v, k) in dBtnList" :key="k"> + <i class="d-btn-item-left el-icon-money"></i> + <div class="d-btn-item-center"> + <div>{{ v.v2 }}|{{ v.v3 }}</div> + </div> + <div class="d-btn-item-eight">{{ v.v4 }}</div> + </div> + </div> + </div> + </div> + </div> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <div class="flex-title">近30天预警总数</div> + <div class="flex-content"> + <div style="height: 100%" ref="chartsWarningRef"></div> + </div> + </div> + </div> + </div> + + <!-- 中间 --> + <div class="big-data-down-center"> + <div class="big-data-down-center-one"> + <div class="big-data-down-center-one-content"> + <div style="height: 100%" ref="chartsCenterOneRef"></div> + </div> + </div> + <div class="big-data-down-center-two"> + <div class="flex-warp-item-box"> + <div class="flex-title"> + <span>当前设备监测</span> + <span class="flex-title-small">单位:次</span> + </div> + <div class="flex-content"> + <div class="flex-content-left"> + <div class="monitor-item" v-for="(v, k) in chartData4List" :key="k"> + <div class="monitor-wave"> + <div class="monitor-z-index"> + <div class="monitor-item-label">{{ v.label }}</div> + </div> + </div> + </div> + </div> + <div class="flex-content-right"> + <div style="height: 100%" ref="chartsMonitorRef"></div> + </div> + </div> + </div> + </div> + </div> + + <!-- 右边 --> + <div class="big-data-down-right"> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <div class="flex-title"> + <span>近7天产品追溯扫码统计</span> + <span class="flex-title-small">单位:次</span> + </div> + <div class="flex-content"> + <div style="height: 100%" ref="chartsSevenDaysRef"></div> + </div> + </div> + </div> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <div class="flex-title">当前任务统计</div> + <div class="flex-content"> + <div class="task"> + <div class="task-item task-first-item"> + <div class="task-item-value task-first">25</div> + <div class="task-item-label">待办任务</div> + </div> + <div class="task-item"> + <div class="task-item-box task1"> + <div class="task-item-value">12</div> + <div class="task-item-label">施肥</div> + </div> + </div> + <div class="task-item"> + <div class="task-item-box task2"> + <div class="task-item-value">3</div> + <div class="task-item-label">施药</div> + </div> + </div> + <div class="task-item"> + <div class="task-item-box task3"> + <div class="task-item-value">5</div> + <div class="task-item-label">农事</div> + </div> + </div> + </div> + <div class="progress"> + <div class="progress-item"> + <span>施肥率</span> + <div class="progress-box"> + <el-progress :percentage="70" color="#43bdf0"></el-progress> + </div> + </div> + <div class="progress-item"> + <span>施药率</span> + <div class="progress-box"> + <el-progress :percentage="36" color="#43bdf0"></el-progress> + </div> + </div> + <div class="progress-item"> + <span>农事率</span> + <div class="progress-box"> + <el-progress :percentage="91" color="#43bdf0"></el-progress> + </div> + </div> + </div> + </div> + </div> + </div> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <div class="flex-title"> + <span>近7天投入品记录</span> + <span class="flex-title-small">单位:件</span> + </div> + <div class="flex-content"> + <div style="height: 100%" ref="chartsInvestmentRef"></div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, computed, onMounted, getCurrentInstance, watch, nextTick, onActivated, defineComponent } from 'vue'; +import ChartHead from '/@/views/chart/head.vue'; +import * as echarts from 'echarts'; +import 'echarts-wordcloud'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; +import { skyList, dBtnList, chartData4List } from '/@/views/chart/chart'; + +export default defineComponent({ + name: 'chartIndex', + components: { ChartHead }, + setup() { + const { proxy } = <any>getCurrentInstance(); + const storesThemeConfig = useThemeConfig(); + const storesTagsViewRoutes = useTagsViewRoutes(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes); + const state = reactive({ + skyList, + dBtnList, + chartData4List, + myCharts: [], + }); + // 设置主内容的高度 + const initTagViewHeight = computed(() => { + let { isTagsview } = themeConfig.value; + if (isTagsViewCurrenFull.value) { + return `30px`; + } else { + if (isTagsview) return `114px`; + else return `80px`; + } + }); + // 初始化中间图表1 + const initChartsCenterOne = () => { + const myChart = echarts.init(proxy.$refs.chartsCenterOneRef); + const option = { + grid: { + top: 15, + right: 15, + bottom: 20, + left: 30, + }, + tooltip: {}, + series: [ + { + type: 'wordCloud', + sizeRange: [12, 40], + rotationRange: [0, 0], + rotationStep: 45, + gridSize: Math.random() * 20 + 5, + shape: 'circle', + width: '100%', + height: '100%', + textStyle: { + fontFamily: 'sans-serif', + fontWeight: 'bold', + color: function () { + return `rgb(${[Math.round(Math.random() * 160), Math.round(Math.random() * 160), Math.round(Math.random() * 160)].join(',')})`; + }, + }, + data: [ + { name: 'vue-next-admin', value: 520 }, + { name: 'lyt', value: 520 }, + { name: 'next-admin', value: 500 }, + { name: '更名', value: 420 }, + { name: '智慧农业', value: 520 }, + { name: '男神', value: 2.64 }, + { name: '好身材', value: 4.03 }, + { name: '校草', value: 24.95 }, + { name: '酷', value: 4.04 }, + { name: '时尚', value: 5.27 }, + { name: '阳光活力', value: 5.8 }, + { name: '初恋', value: 3.09 }, + { name: '英俊潇洒', value: 24.71 }, + { name: '霸气', value: 6.33 }, + { name: '腼腆', value: 2.55 }, + { name: '蠢萌', value: 3.88 }, + { name: '青春', value: 8.04 }, + { name: '网红', value: 5.87 }, + { name: '萌', value: 6.97 }, + { name: '认真', value: 2.53 }, + { name: '古典', value: 2.49 }, + { name: '温柔', value: 3.91 }, + { name: '有个性', value: 3.25 }, + { name: '可爱', value: 9.93 }, + { name: '幽默诙谐', value: 3.65 }, + ], + }, + ], + }; + myChart.setOption(option); + (<any>state.myCharts).push(myChart); + }; + // 初始化近7天产品追溯扫码统计 + const initChartsSevenDays = () => { + const myChart = echarts.init(proxy.$refs.chartsSevenDaysRef); + const option = { + grid: { + top: 15, + right: 15, + bottom: 20, + left: 30, + }, + tooltip: { + trigger: 'axis', + }, + xAxis: { + type: 'category', + boundaryGap: false, + data: ['1天', '2天', '3天', '4天', '5天', '6天', '7天'], + }, + yAxis: { + type: 'value', + }, + series: [ + { + name: '邮件营销', + type: 'line', + stack: '总量', + data: [12, 32, 11, 34, 90, 23, 21], + }, + { + name: '联盟广告', + type: 'line', + stack: '总量', + data: [22, 82, 91, 24, 90, 30, 30], + }, + { + name: '视频广告', + type: 'line', + stack: '总量', + data: [50, 32, 18, 14, 90, 30, 50], + }, + ], + }; + myChart.setOption(option); + (<any>state.myCharts).push(myChart); + }; + // 初始化近30天预警总数 + const initChartsWarning = () => { + const myChart = echarts.init(proxy.$refs.chartsWarningRef); + const option = { + grid: { + top: 50, + right: 20, + bottom: 30, + left: 30, + }, + tooltip: { + trigger: 'item', + }, + series: [ + { + name: '面积模式', + type: 'pie', + radius: [20, 50], + center: ['50%', '50%'], + roseType: 'area', + itemStyle: { + borderRadius: 8, + }, + data: [ + { value: 40, name: '监测设备预警' }, + { value: 38, name: '天气预警' }, + { value: 32, name: '任务预警' }, + { value: 30, name: '病虫害预警' }, + ], + }, + ], + }; + myChart.setOption(option); + (<any>state.myCharts).push(myChart); + }; + // 初始化当前设备监测 + const initChartsMonitor = () => { + const myChart = echarts.init(proxy.$refs.chartsMonitorRef); + const option = { + grid: { + top: 15, + right: 15, + bottom: 20, + left: 30, + }, + tooltip: { + trigger: 'axis', + }, + xAxis: { + type: 'category', + boundaryGap: false, + data: ['02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00'], + }, + yAxis: { + type: 'value', + }, + series: [ + { + itemStyle: { + color: '#289df5', + borderColor: '#289df5', + areaStyle: { + type: 'default', + opacity: 0.1, + }, + }, + data: [20, 32, 31, 34, 12, 13, 20], + type: 'line', + areaStyle: {}, + }, + ], + }; + myChart.setOption(option); + (<any>state.myCharts).push(myChart); + }; + // 初始化近7天投入品记录 + const initChartsInvestment = () => { + const myChart = echarts.init(proxy.$refs.chartsInvestmentRef); + const option = { + grid: { + top: 15, + right: 15, + bottom: 20, + left: 30, + }, + tooltip: { + trigger: 'axis', + }, + xAxis: { + type: 'category', + data: ['1天', '2天', '3天', '4天', '5天', '6天', '7天'], + }, + yAxis: { + type: 'value', + }, + series: [ + { + data: [10, 20, 15, 80, 70, 11, 30], + type: 'bar', + }, + ], + }; + myChart.setOption(option); + (<any>state.myCharts).push(myChart); + }; + // 批量设置 echarts resize + const initEchartsResizeFun = () => { + nextTick(() => { + for (let i = 0; i < state.myCharts.length; i++) { + (<any>state.myCharts[i]).resize(); + } + }); + }; + // 批量设置 echarts resize + const initEchartsResize = () => { + window.addEventListener('resize', initEchartsResizeFun); + }; + // 页面加载时 + onMounted(() => { + initChartsCenterOne(); + initChartsSevenDays(); + initChartsWarning(); + initChartsMonitor(); + initChartsInvestment(); + initEchartsResize(); + }); + // 由于页面缓存原因,keep-alive + onActivated(() => { + initEchartsResizeFun(); + }); + // 监听 vuex 中的 tagsview 开启全屏变化,重新 resize 图表,防止不出现/大小不变等 + watch( + () => isTagsViewCurrenFull.value, + () => { + initEchartsResizeFun(); + } + ); + return { + initTagViewHeight, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +@import './chart.scss'; +</style> diff --git a/src/views/dashboard/index.vue b/src/views/dashboard/index.vue new file mode 100644 index 0000000..6b27d59 --- /dev/null +++ b/src/views/dashboard/index.vue @@ -0,0 +1,35 @@ +<template> + <div> + <button @click="toLink">跳转</button> + </div> +</template> + +<script lang="ts"> + import {useRoute, useRouter} from "vue-router"; + + export default { + name: "index", + setup() { + const route = useRoute(); + const router = useRouter(); + const toLink = () => { + if (route.query?.redirect) { + router.push('/dashboard'); + // router.push({ + // path: <string>route.query?.redirect, + // query: Object.keys(<string>route.query?.params).length > 0 ? JSON.parse(<string>route.query?.params) : '', + // }); + } else { + router.push('/'); + } + }; + return { + toLink, + } + } + } +</script> + +<style scoped> + +</style> diff --git a/src/views/error/401.vue b/src/views/error/401.vue new file mode 100644 index 0000000..3ca649d --- /dev/null +++ b/src/views/error/401.vue @@ -0,0 +1,117 @@ +<template> + <div class="error layout-view-bg-white" :style="{ height: `calc(100vh - ${initTagViewHeight}` }"> + <div class="error-flex"> + <div class="left"> + <div class="left-item"> + <div class="left-item-animation left-item-num">401</div> + <div class="left-item-animation left-item-title">{{ $t('message.noAccess.accessTitle') }}</div> + <div class="left-item-animation left-item-msg">{{ $t('message.noAccess.accessMsg') }}</div> + <div class="left-item-animation left-item-btn"> + <el-button type="primary" round @click="onSetAuth">{{ $t('message.noAccess.accessBtn') }}</el-button> + </div> + </div> + </div> + <div class="right"> + <img + src="https://img-blog.csdnimg.cn/3333f265772a4fa89287993500ecbf96.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbHl0LXRvcA==,size_16,color_FFFFFF,t_70,g_se,x_16" + /> + </div> + </div> + </div> +</template> + +<script lang="ts"> +import { defineComponent, computed } from 'vue'; +import { useRouter } from 'vue-router'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; +import { Session } from '/@/utils/storage'; + +export default defineComponent({ + name: '401', + setup() { + const storesThemeConfig = useThemeConfig(); + const storesTagsViewRoutes = useTagsViewRoutes(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes); + const router = useRouter(); + const onSetAuth = () => { + Session.clear(); + router.push('/login'); + }; + // 设置主内容的高度 + const initTagViewHeight = computed(() => { + let { isTagsview } = themeConfig.value; + if (isTagsViewCurrenFull.value) { + return `30px`; + } else { + if (isTagsview) return `114px`; + else return `80px`; + } + }); + return { + onSetAuth, + initTagViewHeight, + }; + }, +}); +</script> + +<style scoped lang="scss"> +.error { + height: 100%; + background-color: var(--el-color-white); + display: flex; + .error-flex { + margin: auto; + display: flex; + height: 350px; + width: 900px; + .left { + flex: 1; + height: 100%; + align-items: center; + display: flex; + .left-item { + .left-item-animation { + opacity: 0; + animation-name: error-num; + animation-duration: 0.5s; + animation-fill-mode: forwards; + } + .left-item-num { + color: var(--el-color-info); + font-size: 55px; + } + .left-item-title { + font-size: 20px; + color: var(--el-text-color-primary); + margin: 15px 0 5px 0; + animation-delay: 0.1s; + } + .left-item-msg { + color: var(--el-text-color-secondary); + font-size: 12px; + margin-bottom: 30px; + animation-delay: 0.2s; + } + .left-item-btn { + animation-delay: 0.2s; + } + } + } + .right { + flex: 1; + opacity: 0; + animation-name: error-img; + animation-duration: 2s; + animation-fill-mode: forwards; + img { + width: 100%; + height: 100%; + } + } + } +} +</style> diff --git a/src/views/error/404.vue b/src/views/error/404.vue new file mode 100644 index 0000000..3a7ce22 --- /dev/null +++ b/src/views/error/404.vue @@ -0,0 +1,115 @@ +<template> + <div class="error layout-view-bg-white" :style="{ height: `calc(100vh - ${initTagViewHeight}` }"> + <div class="error-flex"> + <div class="left"> + <div class="left-item"> + <div class="left-item-animation left-item-num">404</div> + <div class="left-item-animation left-item-title">{{ $t('message.notFound.foundTitle') }}</div> + <div class="left-item-animation left-item-msg">{{ $t('message.notFound.foundMsg') }}</div> + <div class="left-item-animation left-item-btn"> + <el-button type="primary" round @click="onGoHome">{{ $t('message.notFound.foundBtn') }}</el-button> + </div> + </div> + </div> + <div class="right"> + <img + src="https://img-blog.csdnimg.cn/9eb1d85a417f4ed1ba7107f149ce3da1.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbHl0LXRvcA==,size_16,color_FFFFFF,t_70,g_se,x_16" + /> + </div> + </div> + </div> +</template> + +<script lang="ts"> +import { defineComponent, computed } from 'vue'; +import { useRouter } from 'vue-router'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; + +export default defineComponent({ + name: '404', + setup() { + const storesThemeConfig = useThemeConfig(); + const storesTagsViewRoutes = useTagsViewRoutes(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes); + const router = useRouter(); + const onGoHome = () => { + router.push('/'); + }; + // 设置主内容的高度 + const initTagViewHeight = computed(() => { + let { isTagsview } = themeConfig.value; + if (isTagsViewCurrenFull.value) { + return `30px`; + } else { + if (isTagsview) return `114px`; + else return `80px`; + } + }); + return { + onGoHome, + initTagViewHeight, + }; + }, +}); +</script> + +<style scoped lang="scss"> +.error { + height: 100%; + background-color: var(--el-color-white); + display: flex; + .error-flex { + margin: auto; + display: flex; + height: 350px; + width: 900px; + .left { + flex: 1; + height: 100%; + align-items: center; + display: flex; + .left-item { + .left-item-animation { + opacity: 0; + animation-name: error-num; + animation-duration: 0.5s; + animation-fill-mode: forwards; + } + .left-item-num { + color: var(--el-color-info); + font-size: 55px; + } + .left-item-title { + font-size: 20px; + color: var(--el-text-color-primary); + margin: 15px 0 5px 0; + animation-delay: 0.1s; + } + .left-item-msg { + color: var(--el-text-color-secondary); + font-size: 12px; + margin-bottom: 30px; + animation-delay: 0.2s; + } + .left-item-btn { + animation-delay: 0.2s; + } + } + } + .right { + flex: 1; + opacity: 0; + animation-name: error-img; + animation-duration: 2s; + animation-fill-mode: forwards; + img { + width: 100%; + height: 100%; + } + } + } +} +</style> diff --git a/src/views/home/index.vue b/src/views/home/index.vue new file mode 100644 index 0000000..2923664 --- /dev/null +++ b/src/views/home/index.vue @@ -0,0 +1,185 @@ +<template> + <div class="home-container"> + <el-row :gutter="15" class="home-card-one mb15"> + <el-col + :xs="24" + :sm="12" + :md="12" + :lg="6" + :xl="6" + v-for="(v, k) in homeOne" + :key="k" + :class="{ 'home-media home-media-lg': k > 1, 'home-media-sm': k === 1 }" + > + <div class="home-card-item flex" > + <el-button @click="renderMenu">{{v.name}}</el-button> + </div> + </el-col> + </el-row> + <el-row :gutter="15" class="home-card-two mb15"> + <el-col :xs="24" :sm="14" :md="14" :lg="16" :xl="16"> + <div class="home-card-item"> + <div style="height: 100%"></div> + </div> + </el-col> + <el-col :xs="24" :sm="10" :md="10" :lg="8" :xl="8" class="home-media"> + <div class="home-card-item"> + <div style="height: 100%"></div> + </div> + </el-col> + </el-row> + <el-row :gutter="15" class="home-card-three"> + <el-col :xs="24" :sm="10" :md="10" :lg="8" :xl="8"> + <div class="home-card-item"> + </div> + </el-col> + <el-col :xs="24" :sm="14" :md="14" :lg="16" :xl="16" class="home-media"> + <div class="home-card-item"> + <div style="height: 100%"></div> + </div> + </el-col> + </el-row> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent, onMounted, ref, watch, nextTick, onActivated } from 'vue'; +import * as echarts from 'echarts'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; +import { initBackEndControlRoutes } from '/@/router/backEnd'; +import {Session} from "/@/utils/storage"; + +let global: any = { + homeChartOne: null, + homeChartTwo: null, + homeCharThree: null, + dispose: [null, '', undefined], +}; + +interface stateType { + projectId:string, + homeOne: Array <type> +} +interface type { + id:number, + name: string +} +export default defineComponent({ + name: 'home', + setup() { + const homeLineRef = ref(); + const homePieRef = ref(); + const homeBarRef = ref(); + const storesTagsViewRoutes = useTagsViewRoutes(); + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes); + const state = reactive<stateType>({ + projectId:'', + homeOne:[{id:1,name:'系统1'},{id:2,name:'系统2'},{id:3,name:'系统4'},{id:4,name:'系统4'}], + }); + // 折线图 + const renderMenu = async() => { + state.projectId = '1' + Session.set('projectId','1') + await initBackEndControlRoutes(); + }; + return { + renderMenu, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +$homeNavLengh: 8; +.home-container { + overflow: hidden; + .home-card-one, + .home-card-two, + .home-card-three { + .home-card-item { + width: 100%; + height: 130px; + border-radius: 4px; + transition: all ease 0.3s; + padding: 20px; + overflow: hidden; + background: var(--el-color-white); + color: var(--el-text-color-primary); + border: 1px solid var(--next-border-color-light); + &:hover { + box-shadow: 0 2px 12px var(--next-color-dark-hover); + transition: all ease 0.3s; + } + &-icon { + width: 70px; + height: 70px; + border-radius: 100%; + flex-shrink: 1; + i { + color: var(--el-text-color-placeholder); + } + } + &-title { + font-size: 15px; + font-weight: bold; + height: 30px; + } + } + } + .home-card-one { + @for $i from 0 through 3 { + .home-one-animation#{$i} { + opacity: 0; + animation-name: error-num; + animation-duration: 0.5s; + animation-fill-mode: forwards; + animation-delay: calc($i/10) + s; + } + } + } + .home-card-two, + .home-card-three { + .home-card-item { + height: 400px; + width: 100%; + overflow: hidden; + .home-monitor { + height: 100%; + .flex-warp-item { + width: 25%; + height: 111px; + display: flex; + .flex-warp-item-box { + margin: auto; + text-align: center; + color: var(--el-text-color-primary); + display: flex; + border-radius: 5px; + background: var(--next-bg-color); + cursor: pointer; + transition: all 0.3s ease; + &:hover { + background: var(--el-color-primary-light-9); + transition: all 0.3s ease; + } + } + @for $i from 0 through $homeNavLengh { + .home-animation#{$i} { + opacity: 0; + animation-name: error-num; + animation-duration: 0.5s; + animation-fill-mode: forwards; + animation-delay: calc($i/10) + s; + } + } + } + } + } + } +} +</style> diff --git a/src/views/login/component/account.vue b/src/views/login/component/account.vue new file mode 100644 index 0000000..29b40dd --- /dev/null +++ b/src/views/login/component/account.vue @@ -0,0 +1,196 @@ +<template> + <el-form size="large" class="login-content-form"> + <el-form-item class="login-animation1"> + <el-input type="text" :placeholder="$t('message.account.accountPlaceholder1')" v-model="ruleForm.username" clearable autocomplete="off"> + <template #prefix> + <el-icon class="el-input__icon"><ele-User /></el-icon> + </template> + </el-input> + </el-form-item> + <el-form-item class="login-animation2"> + <el-input + :type="isShowPassword ? 'text' : 'password'" + :placeholder="$t('message.account.accountPlaceholder2')" + v-model="ruleForm.password" + autocomplete="off" + > + <template #prefix> + <el-icon class="el-input__icon"><ele-Unlock /></el-icon> + </template> + <template #suffix> + <i + class="iconfont el-input__icon login-content-password" + :class="isShowPassword ? 'icon-yincangmima' : 'icon-xianshimima'" + @click="isShowPassword = !isShowPassword" + > + </i> + </template> + </el-input> + </el-form-item> + <el-form-item class="login-animation3"> + <el-col :span="15"> + <el-input + type="text" + maxlength="4" + :placeholder="$t('message.account.accountPlaceholder3')" + v-model="ruleForm.code" + clearable + autocomplete="off" + > + <template #prefix> + <el-icon class="el-input__icon"><ele-Position /></el-icon> + </template> + </el-input> + </el-col> + <el-col :span="1"></el-col> + <el-col :span="8"> + <el-button class="login-content-code">1234</el-button> + </el-col> + </el-form-item> + <el-form-item class="login-animation4"> + <el-button type="primary" class="login-content-submit" round @click="onSignIn" :loading="loading.signIn"> + <span>{{ $t('message.account.accountBtnText') }}</span> + </el-button> + </el-form-item> + </el-form> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent, computed } from 'vue'; +import { useRoute, useRouter } from 'vue-router'; +import { ElMessage } from 'element-plus'; +import { useI18n } from 'vue-i18n'; +import Cookies from 'js-cookie'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { initFrontEndControlRoutes } from '/@/router/frontEnd'; +import { initBackEndControlRoutes } from '/@/router/backEnd'; +import { Session } from '/@/utils/storage'; +import { formatAxis } from '/@/utils/formatTime'; +import { NextLoading } from '/@/utils/loading'; +import { useLoginApi } from '/@/api/login'; +import {useUserInfo} from "/@/stores/userInfo"; + +export default defineComponent({ + name: 'loginAccount', + setup() { + const { t } = useI18n(); + const userInfo = useUserInfo() + const { userInfos } = storeToRefs(userInfo); + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const route = useRoute(); + const router = useRouter(); + const state = reactive({ + isShowPassword: false, + ruleForm: { + username: 'admin', + password: '123456', + }, + loading: { + signIn: false, + }, + }); + // 时间获取 + const currentTime = computed(() => { + return formatAxis(new Date()); + }); + // 登录 + const onSignIn = async () => { + state.loading.signIn = true; + // 存储 token 到浏览器缓存 + let res = await useLoginApi().signIn(state.ruleForm) + if(res.data.code === '200'){ + Session.set('ifMenu',false) + Session.set('projectId','') + Session.set('token', res.data.data.accessToken); + Session.set('sign',res.data.data.id) + await initFrontEndControlRoutes(); + signInSuccess(); + }else{ + state.loading.signIn = false + ElMessage({ + type:'warning', + message:res.data.msg + }) + } + // Session.set('token', Math.random().toString(36).substr(0)); + // // 模拟数据,对接接口时,记得删除多余代码及对应依赖的引入。用于 `/src/stores/userInfo.ts` 中不同用户登录判断(模拟数据) + // Cookies.set('userName', state.ruleForm.username); + // if (!themeConfig.value.isRequestRoutes) { + // // 前端控制路由,2、请注意执行顺序 + // await initFrontEndControlRoutes(); + // signInSuccess(); + // } else { + // // 模拟后端控制路由,isRequestRoutes 为 true,则开启后端控制路由 + // // 添加完动态路由,再进行 router 跳转,否则可能报错 No match found for location with path "/" + // await initBackEndControlRoutes(); + // // 执行完 initBackEndControlRoutes,再执行 signInSuccess + // signInSuccess(); + // } + }; + // 登录成功后的跳转 + const signInSuccess = async () => { + // 初始化登录成功时间问候语 + let currentTimeInfo = currentTime.value; + // 登录成功,跳到转首页 + // 如果是复制粘贴的路径,非首页/登录页,那么登录成功后重定向到对应的路径中 + if (route.query?.redirect) { + router.push('/'); + // router.push({ + // path: <string>route.query?.redirect, + // query: Object.keys(<string>route.query?.params).length > 0 ? JSON.parse(<string>route.query?.params) : '', + // }); + } else { + router.push('/login'); + } + state.loading.signIn = true; + const signInText = t('message.signInText'); + ElMessage.success(`${currentTimeInfo},${signInText}`); + // 登录成功提示 + // 关闭 loading + // 添加 loading,防止第一次进入界面时出现短暂空白 + // NextLoading.start(); + }; + return { + onSignIn, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.login-content-form { + margin-top: 20px; + @for $i from 1 through 4 { + .login-animation#{$i} { + opacity: 0; + animation-name: error-num; + animation-duration: 0.5s; + animation-fill-mode: forwards; + animation-delay: calc($i/10) + s; + } + } + .login-content-password { + display: inline-block; + width: 20px; + cursor: pointer; + &:hover { + color: #909399; + } + } + .login-content-code { + width: 100%; + padding: 0; + font-weight: bold; + letter-spacing: 5px; + } + .login-content-submit { + width: 100%; + letter-spacing: 2px; + font-weight: 300; + margin-top: 15px; + } +} +</style> diff --git a/src/views/login/index.vue b/src/views/login/index.vue new file mode 100644 index 0000000..3ded06e --- /dev/null +++ b/src/views/login/index.vue @@ -0,0 +1,190 @@ +<template> + <div class="login-container"> + <div class="login-icon-group"> + <img :src="loginIconTwo" class="login-icon-group-icon" /> + </div> + <div class="login-content"> + <div class="login-content-main"> + <h4 class="login-content-title ml15"></h4> + <div v-if="!isScan"> + <el-tabs v-model="tabsActiveName"> + <el-tab-pane :label="$t('message.label.one1')" name="account"> + <Account /> + </el-tab-pane> + </el-tabs> + </div> + <Scan v-if="isScan" /> + <div class="login-content-main-sacn" @click="isScan = !isScan"> + <div class="login-content-main-sacn-delta"></div> + </div> + </div> + </div> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, computed, defineComponent, onMounted } from 'vue'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import logoMini from '/@/assets/logo-mini.svg'; +import loginIconTwo from '/@/assets/login-icon-two.svg'; +import { NextLoading } from '/@/utils/loading'; +import Account from '/@/views/login/component/account.vue'; + +// 定义接口来定义对象的类型 +interface LoginState { + tabsActiveName: string; + isScan: boolean; +} + +export default defineComponent({ + name: 'loginIndex', + components: { Account, }, + setup() { + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const state = reactive<LoginState>({ + tabsActiveName: 'account', + isScan: false, + }); + // 获取布局配置信息 + const getThemeConfig = computed(() => { + return themeConfig.value; + }); + // 页面加载时 + onMounted(() => { + NextLoading.done(); + }); + return { + logoMini, + loginIconTwo, + getThemeConfig, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.login-container { + width: 100%; + height: 100%; + position: relative; + background: var(--el-color-white); + .login-icon-group { + width: 100%; + height: 100%; + position: relative; + .login-icon-group-title { + position: absolute; + top: 50px; + left: 80px; + display: flex; + align-items: center; + img { + width: 30px; + height: 30px; + } + &-text { + padding-left: 15px; + color: var(--el-color-primary); + } + } + &::before { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 60%; + overflow: hidden; + height: 80%; + -webkit-mask-box-image: url("data:image/svg+xml,%3Csvg width='1200' height='770' xmlns='http://www.w3.org/2000/svg' fill='none'%3E%3Cg%3E%3Cpath id='svg_1' d='M58.4 47.77C104.6 59.51 135.26 67.37 162.11 78.04C188.97 88.72 226.33 102.69 265.92 123.55C305.51 144.4 366.96 167.09 441.43 121.52C515.9 75.95 546.48 61.01 577.69 46.27C608.9 31.53 625.86 23.69 680.26 12.28C734.65 0.87 837.29 10.7 867.29 21.8C897.29 32.9 935.51 51.9 962.21 95.45C988.9 139.01 972.91 177.36 951.37 221.39C929.83 265.43 883.49 306 890.44 337.33C897.4 368.66 974.73 412.18 974.73 411.47C974.73 412.18 1066.36 457.62 1106.36 491.06C1146.36 524.5 1178.8 563.36 1184.03 579.63C1189.26 595.9 1200.4 622.49 1181.55 676.88C1162.71 731.26 1127.16 764.32 1115.31 778.64C1103.45 792.96 5.34 783.61 4.32 784.63C3.3 785.65 -172.34 2.38 1.13 35.04L58.4 47.77L58.4 47.77Z' fill='%23409eff'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"); + background: var(--el-color-primary-light-5); + transition: all 0.3s ease; + } + &::after { + content: ''; + width: 150px; + height: 300px; + position: absolute; + right: 0; + top: 0; + -webkit-mask-box-image: url("data:image/svg+xml,%3Csvg width='150' height='300' xmlns='http://www.w3.org/2000/svg' fill='none'%3E%3Cg%3E%3Cpath id='svg_1' d='M-0.56 -0.28C41.94 36.17 67.73 18.94 93.33 33.96C118.93 48.98 107.58 73.56 101.94 89.76C96.29 105.96 50.09 217.83 47.87 231.18C45.64 244.52 46.02 255.2 64.4 270.05C82.79 284.91 121.99 292.31 111.98 289.81C101.97 287.32 153.96 301.48 151.83 299.9C149.69 298.32 149.98 -1.36 149.71 -1.18C149.98 -1.36 -43.06 -36.74 -0.56 -0.28L-0.56 -0.28Z' fill='%23409eff'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"); + background: var(--el-color-primary-light-5); + transition: all 0.3s ease; + } + &-icon { + width: 60%; + height: 70%; + position: absolute; + left: 0; + bottom: 0; + } + } + .login-content { + width: 500px; + padding: 20px; + position: absolute; + right: 200px; + top: 50%; + transform: translateY(-50%) translate3d(0, 0, 0); + background-color: var(--el-color-white); + border: 5px solid var(--el-color-primary-light-8); + border-radius: 5px; + overflow: hidden; + z-index: 1; + height: 460px; + .login-content-main { + margin: 0 auto; + width: 80%; + .login-content-title { + color: var(--el-text-color-primary); + font-weight: 500; + font-size: 22px; + text-align: center; + letter-spacing: 4px; + margin: 15px 0 30px; + white-space: nowrap; + z-index: 5; + position: relative; + transition: all 0.3s ease; + } + } + .login-content-main-sacn { + position: absolute; + top: 0; + right: 0; + width: 50px; + height: 50px; + overflow: hidden; + cursor: pointer; + transition: all ease 0.3s; + color: var(--el-text-color-primary); + &-delta { + position: absolute; + width: 35px; + height: 70px; + z-index: 2; + top: 2px; + right: 21px; + background: var(--el-color-white); + transform: rotate(-45deg); + } + &:hover { + opacity: 1; + transition: all ease 0.3s; + color: var(--el-color-primary) !important; + } + i { + width: 47px; + height: 50px; + display: inline-block; + font-size: 48px; + position: absolute; + right: 2px; + top: -1px; + } + } + } +} +</style> diff --git a/src/views/make/noticeBar/index.vue b/src/views/make/noticeBar/index.vue new file mode 100644 index 0000000..2bb8730 --- /dev/null +++ b/src/views/make/noticeBar/index.vue @@ -0,0 +1,164 @@ +<template> + <div class="notice-bar-container"> + <el-card shadow="hover" header="滚动通知栏:默认"> + <NoticeBar + text="🎉🎉🔥基于vue3.x 、Typescript、vite、Element plus等,适配手机、平板、pc + 的后台开源免费模板库(vue2.x请切换vue-prev-admin分支),仓库地址:https://gitee.com/lyt-top/vue-next-admin" + /> + </el-card> + + <el-card shadow="hover" header="滚动通知栏:设置样式" class="mt15"> + <NoticeBar + text="🎉🎉🔥基于vue3.x 、Typescript、vite、Element plus等,适配手机、平板、pc + 的后台开源免费模板库(vue2.x请切换vue-prev-admin分支),仓库地址:https://gitee.com/lyt-top/vue-next-admin" + leftIcon="iconfont icon-tongzhi2" + rightIcon="ele-ArrowRight" + background="#ecf5ff" + color="#409eff" + /> + </el-card> + + <el-card shadow="hover" header="滚动通知栏:搭配 NoticeBar 和 Carousel 走马灯 组件可以实现垂直滚动的效果" class="mt15"> + <NoticeBar :scrollable="true"> + <el-carousel height="40px" direction="vertical" :autoplay="true" indicator-position="none" :interval="3000"> + <el-carousel-item v-for="v in noticeList" :key="v">{{ v }} </el-carousel-item> + </el-carousel> + </NoticeBar> + </el-card> + + <el-card shadow="hover" header="滚动通知栏:参数" class="mt15"> + <el-table :data="tableData" style="width: 100%"> + <el-table-column prop="a1" label="参数"> </el-table-column> + <el-table-column prop="a2" label="说明"> </el-table-column> + <el-table-column prop="a3" label="类型"> </el-table-column> + <el-table-column prop="a4" label="可选值"> </el-table-column> + <el-table-column prop="a5" label="默认值"> </el-table-column> + </el-table> + </el-card> + + <el-card shadow="hover" header="图标选择器(宽度自动):事件" class="mt15"> + <el-table :data="tableData1" style="width: 100%"> + <el-table-column prop="a1" label="事件名称"> </el-table-column> + <el-table-column prop="a2" label="说明"> </el-table-column> + <el-table-column prop="a3" label="类型"> </el-table-column> + <el-table-column prop="a4" label="回调参数"> </el-table-column> + </el-table> + </el-card> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent } from 'vue'; +import NoticeBar from '/@/components/noticeBar/index.vue'; + +export default defineComponent({ + name: 'makeNoticeBar', + components: { NoticeBar }, + setup() { + const state = reactive({ + noticeList: [ + '🎉🎉🔥基于vue3.x 、Typescript、vite、Element plus等', + '适配手机、平板、pc的后台开源免费模板库(vue2.x请切换vue-prev-admin分支)', + '仓库地址:https://gitee.com/lyt-top/vue-next-admin', + '演示地址:https://lyt-top.gitee.io/vue-next-admin-preview/#/login', + ], + tableData: [ + { + a1: 'mode', + a2: '通知栏模式,用于右侧 icon 图标点击', + a3: 'string', + a4: 'closeable / link', + a5: '', + }, + { + a1: 'text', + a2: '通知文本内容,scrollable 为 false 时生效', + a3: 'string', + a4: '', + a5: '', + }, + { + a1: 'color', + a2: '通知文本颜色', + a3: 'string', + a4: '', + a5: '#e6a23c', + }, + { + a1: 'background', + a2: '通知背景色', + a3: 'string', + a4: '', + a5: '#fdf6ec', + }, + { + a1: 'size', + a2: '字体大小,单位px', + a3: 'number / string', + a4: '', + a5: '14', + }, + { + a1: 'height', + a2: '通知栏高度,单位px', + a3: 'number / string', + a4: '', + a5: '40', + }, + { + a1: 'delay', + a2: '动画延迟时间 (s)', + a3: 'number / string', + a4: '', + a5: '1', + }, + { + a1: 'speed', + a2: '滚动速率 (px/s)', + a3: 'number / string', + a4: '', + a5: '100', + }, + { + a1: 'scrollable', + a2: '是否开启垂直滚动', + a3: 'boolean', + a4: 'true', + a5: 'false', + }, + { + a1: 'leftIcon', + a2: '自定义左侧图标', + a3: 'string', + a4: '', + a5: '', + }, + { + a1: 'rightIcon', + a2: '自定义右侧图标', + a3: 'string', + a4: '', + a5: '', + }, + ], + tableData1: [ + { + a1: 'close', + a2: '通知栏模式(mode)closeable 时回调事件', + a3: 'function', + a4: '', + }, + { + a1: 'link', + a2: '通知栏模式(mode)link 时回调事件', + a3: 'function', + a4: '', + }, + ], + }); + return { + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/make/selector/index.vue b/src/views/make/selector/index.vue new file mode 100644 index 0000000..db7c34a --- /dev/null +++ b/src/views/make/selector/index.vue @@ -0,0 +1,126 @@ +<template> + <div class="selector-container"> + <el-card shadow="hover" header="图标选择器(宽度自动):"> + <IconSelector @get="onGetIcon" @clear="onClearIcon" v-model="modelIcon" /> + </el-card> + + <el-card shadow="hover" header="图标选择器(宽度自动):参数" class="mt15"> + <el-table :data="tableData" style="width: 100%"> + <el-table-column prop="a1" label="参数"> </el-table-column> + <el-table-column prop="a2" label="说明"> </el-table-column> + <el-table-column prop="a3" label="类型"> </el-table-column> + <el-table-column prop="a4" label="可选值"> </el-table-column> + <el-table-column prop="a5" label="默认值"> </el-table-column> + </el-table> + </el-card> + + <el-card shadow="hover" header="图标选择器(宽度自动):事件" class="mt15"> + <el-table :data="tableData1" style="width: 100%"> + <el-table-column prop="a1" label="事件名称"> </el-table-column> + <el-table-column prop="a2" label="说明"> </el-table-column> + <el-table-column prop="a3" label="类型"> </el-table-column> + <el-table-column prop="a4" label="回调参数"> </el-table-column> + </el-table> + </el-card> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent } from 'vue'; +import IconSelector from '/@/components/iconSelector/index.vue'; + +export default defineComponent({ + name: 'makeSelector', + components: { IconSelector }, + setup() { + const state = reactive({ + modelIcon: '', + tableData: [ + { + a1: 'prepend', + a2: '输入框前置内容,只能字体图标', + a3: 'string', + a4: '', + a5: 'ele-Pointer', + }, + { + a1: 'placeholder', + a2: '输入框占位文本', + a3: 'string', + a4: '', + a5: '请输入内容搜索图标或者选择图标', + }, + { + a1: 'size', + a2: '尺寸', + a3: 'string', + a4: 'large / default / small', + a5: 'default', + }, + { + a1: 'title', + a2: '弹窗标题', + a3: 'string', + a4: '', + a5: '请选择图标', + }, + { + a1: 'type', + a2: 'icon 图标类型', + a3: 'string', + a4: 'ali / ele / awe / all', + a5: 'ele', + }, + { + a1: 'disabled', + a2: '禁用', + a3: 'boolean', + a4: 'true', + a5: 'false', + }, + { + a1: 'clearable', + a2: '是否可清空', + a3: 'boolean', + a4: 'false', + a5: 'true', + }, + { + a1: 'emptyDescription', + a2: '自定义空状态描述文字', + a3: 'String', + a4: '', + a5: '无相关图标', + }, + ], + tableData1: [ + { + a1: 'get', + a2: '获取当前点击的 icon 图标', + a3: 'function', + a4: '(icon: string)', + }, + { + a1: 'clear', + a2: '清空当前点击的 icon 图标', + a3: 'function', + a4: '(icon: string)', + }, + ], + }); + // 获取当前点击的 icon 图标 + const onGetIcon = (icon: string) => { + console.log(icon); + }; + // 清空当前点击的 icon 图标 + const onClearIcon = (icon: string) => { + console.log(icon); + }; + return { + onGetIcon, + onClearIcon, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/make/svgDemo/index.vue b/src/views/make/svgDemo/index.vue new file mode 100644 index 0000000..36fd320 --- /dev/null +++ b/src/views/make/svgDemo/index.vue @@ -0,0 +1,59 @@ +<template> + <div class="svg-demo-container"> + <el-card shadow="hover" header="svgIcon:演示(支持本地svg)"> + <SvgIcon name="iconfont icon-shuju1" color="red" :size="30" /> + <SvgIcon name="ele-Trophy" color="var(--el-color-primary)" :size="30" /> + <SvgIcon name="fa fa-flag-checkered" color="#09f" :size="30" /> + <SvgIcon :name="logoMini" color="#09f" :size="30" /> + </el-card> + <el-card shadow="hover" header="svgIcon:参数" class="mt15"> + <el-table :data="tableData" style="width: 100%"> + <el-table-column prop="a1" label="参数"> </el-table-column> + <el-table-column prop="a2" label="说明"> </el-table-column> + <el-table-column prop="a3" label="类型"> </el-table-column> + <el-table-column prop="a4" label="可选值"> </el-table-column> + <el-table-column prop="a5" label="默认值"> </el-table-column> + </el-table> + </el-card> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent } from 'vue'; +import logoMini from '/@/assets/logo-mini.svg'; + +export default defineComponent({ + name: 'makeSvgDemo', + setup() { + const state = reactive({ + tableData: [ + { + a1: 'name', + a2: 'svg 图标组件名字 / svg 路径 url', + a3: 'string', + a4: '', + a5: '', + }, + { + a1: 'size', + a2: 'svg 大小', + a3: 'number', + a4: '', + a5: 14, + }, + { + a1: 'color', + a2: 'svg 颜色', + a3: 'string', + a4: '', + a5: '', + }, + ], + }); + return { + logoMini, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/menu/menu1/menu11/index.vue b/src/views/menu/menu1/menu11/index.vue new file mode 100644 index 0000000..944beb8 --- /dev/null +++ b/src/views/menu/menu1/menu11/index.vue @@ -0,0 +1,21 @@ +<template> + <div> + <el-input v-model="val" placeholder="menu11:请输入内容测试路由缓存"></el-input> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent } from 'vue'; + +export default defineComponent({ + name: 'menu11', + setup() { + const state = reactive({ + val: '', + }); + return { + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/menu/menu1/menu12/menu121/index.vue b/src/views/menu/menu1/menu12/menu121/index.vue new file mode 100644 index 0000000..791130b --- /dev/null +++ b/src/views/menu/menu1/menu12/menu121/index.vue @@ -0,0 +1,21 @@ +<template> + <div> + <el-input v-model="val" placeholder="menu121:请输入内容测试路由缓存"></el-input> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent } from 'vue'; + +export default defineComponent({ + name: 'menu121', + setup() { + const state = reactive({ + val: '', + }); + return { + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/menu/menu1/menu12/menu122/index.vue b/src/views/menu/menu1/menu12/menu122/index.vue new file mode 100644 index 0000000..3db8096 --- /dev/null +++ b/src/views/menu/menu1/menu12/menu122/index.vue @@ -0,0 +1,21 @@ +<template> + <div> + <el-input v-model="val" placeholder="menu122:请输入内容测试路由缓存"></el-input> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent } from 'vue'; + +export default defineComponent({ + name: 'menu122', + setup() { + const state = reactive({ + val: '', + }); + return { + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/menu/menu1/menu13/index.vue b/src/views/menu/menu1/menu13/index.vue new file mode 100644 index 0000000..f984dcc --- /dev/null +++ b/src/views/menu/menu1/menu13/index.vue @@ -0,0 +1,27 @@ +<template> + <div> + <el-input v-model="val" placeholder="menu13:请输入内容测试路由缓存"></el-input> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, onActivated, onMounted, defineComponent } from 'vue'; + +export default defineComponent({ + name: 'menu13', + setup() { + const state = reactive({ + val: '', + }); + onMounted(() => { + console.log(2222); + }); + onActivated(() => { + console.log(1111); + }); + return { + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/menu/menu2/index.vue b/src/views/menu/menu2/index.vue new file mode 100644 index 0000000..0081506 --- /dev/null +++ b/src/views/menu/menu2/index.vue @@ -0,0 +1,21 @@ +<template> + <div> + <el-input v-model="val" placeholder="menu2:请输入内容测试路由缓存"></el-input> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent } from 'vue'; + +export default defineComponent({ + name: 'menu2', + setup() { + const state = reactive({ + val: '', + }); + return { + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/pages/awesome/index.vue b/src/views/pages/awesome/index.vue new file mode 100644 index 0000000..52b53bb --- /dev/null +++ b/src/views/pages/awesome/index.vue @@ -0,0 +1,87 @@ +<template> + <div class="awesome-container"> + <el-card shadow="hover" :header="`fontawesome 字体图标(自动载入):${sheetsIconList.length - 24}个`"> + <el-row class="iconfont-row"> + <el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="2" v-for="(v, k) in sheetsIconList" :key="k"> + <div class="iconfont-warp"> + <div class="flex-margin"> + <div class="iconfont-warp-value"> + <i :class="v" class="fa"></i> + </div> + <div class="iconfont-warp-label mt10">{{ v }}</div> + </div> + </div> + </el-col> + </el-row> + </el-card> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, onMounted, defineComponent } from 'vue'; +import initIconfont from '/@/utils/getStyleSheets'; + +export default defineComponent({ + name: 'pagesAwesome', + setup() { + const state = reactive({ + sheetsIconList: [], + }); + // 初始化获取 css 样式,这里使用fontawesome的图标(记得加上前缀 `fa`),其它第三方请自行做判断 + const initGetStyleSheets = () => { + initIconfont.awe().then((res: any) => (state.sheetsIconList = res)); + }; + // 页面加载时 + onMounted(() => { + initGetStyleSheets(); + }); + return { + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.awesome-container { + .iconfont-row { + border-top: 1px solid var(--next-border-color-light); + border-left: 1px solid var(--next-border-color-light); + .iconfont-warp { + text-align: center; + border-right: 1px solid var(--next-border-color-light); + border-bottom: 1px solid var(--next-border-color-light); + height: 120px; + overflow: hidden; + display: flex; + transition: all 0.3s ease; + &:hover { + box-shadow: 0 2px 12px var(--next-color-dark-hover); + cursor: pointer; + transition: all 0.3s ease; + .iconfont-warp-value { + i { + color: var(--el-color-primary); + transition: all 0.3s ease; + } + } + .iconfont-warp-label { + color: var(--el-color-primary); + transition: all 0.3s ease; + } + } + .iconfont-warp-value { + i { + color: #606266; + font-size: 32px; + transition: all 0.3s ease; + } + } + .iconfont-warp-label { + color: #99a9bf; + transition: all 0.3s ease; + } + } + } +} +</style> diff --git a/src/views/pages/drag/index.vue b/src/views/pages/drag/index.vue new file mode 100644 index 0000000..1b79498 --- /dev/null +++ b/src/views/pages/drag/index.vue @@ -0,0 +1,66 @@ +<template> + <div class="drag-container"> + <el-card shadow="hover" header="拖动指令效果(v-drag)作用于 Dialog 对话框"> + <el-button type="primary" @click="dialogVisible = true" size="default"> + <el-icon> + <ele-Pointer /> + </el-icon> + 点击打开 Dialog + </el-button> + </el-card> + + <el-card shadow="hover" header="自定义div" class="mt15"> + <div class="drag-dom"> + <div class="drag-header"> + <el-button type="success" size="default" v-drag="['.drag-container .drag-dom', '.drag-container .drag-header']"> + <el-icon> + <ele-Pointer /> + </el-icon> + 按住进行拖动测试 + </el-button> + </div> + </div> + </el-card> + + <el-dialog v-model="dialogVisible" width="769px"> + <template #header> + <div v-drag="['.drag-container .el-dialog', '.drag-container .el-dialog__header']">拖动指令效果(v-drag)</div> + </template> + <p>鼠标放标题头进行 Dialog 对话框拖动</p> + <template #footer> + <span class="dialog-footer"> + <el-button @click="dialogVisible = false" size="default">取 消</el-button> + <el-button type="primary" @click="dialogVisible = false" size="default">确 定</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent } from 'vue'; + +export default defineComponent({ + name: 'pagesDrag', + setup() { + const state = reactive({ + dialogVisible: false, + }); + return { + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.drag-container { + .drag-dom { + position: relative; + display: inline-block; + .drag-header { + display: inline-block; + } + } +} +</style> diff --git a/src/views/pages/dynamicForm/index.vue b/src/views/pages/dynamicForm/index.vue new file mode 100644 index 0000000..d6a7a68 --- /dev/null +++ b/src/views/pages/dynamicForm/index.vue @@ -0,0 +1,204 @@ +<template> + <div class="dynamic-form-container"> + <el-card shadow="hover" header="动态复杂表单"> + <el-form :model="form" ref="formRulesOneRef" size="default" label-width="100px" class="mt35"> + <el-row :gutter="35"> + <el-col + :xs="val.xs" + :sm="val.sm" + :md="val.md" + :lg="val.md" + :xl="val.xl" + class="mb20" + v-show="val.isShow" + v-for="(val, key) in formData" + :key="key" + > + <template v-if="val.type !== ''"> + <el-form-item + :label="val.label" + :prop="val.prop" + :rules="[{ required: val.required, message: `${val.label}不能为空`, trigger: val.type === 'input' ? 'blur' : 'change' }]" + v-if="val.type !== ''" + > + <el-input + v-model="form[val.prop]" + :placeholder="val.placeholder" + clearable + v-if="val.type === 'input'" + style="width: 100%" + :disabled="val.disabled" + ></el-input> + <el-date-picker + v-model="form[val.prop]" + type="date" + :placeholder="val.placeholder" + v-else-if="val.type === 'date'" + style="width: 100%" + :disabled="val.disabled" + > + </el-date-picker> + <el-select + v-model="form[val.prop]" + :placeholder="val.placeholder" + v-else-if="val.type === 'select'" + style="width: 100%" + :disabled="val.disabled" + > + <el-option v-for="item in val.options" :key="item.value" :label="item.label" :value="item.value"> </el-option> + </el-select> + <el-input + type="textarea" + v-model="form[val.prop]" + :placeholder="val.placeholder" + clearable + v-if="val.type === 'textarea'" + style="width: 100%" + :disabled="val.disabled" + ></el-input> + </el-form-item> + </template> + <template v-else> + <el-row :gutter="35" v-for="(v, k) in form.list" :key="k"> + <el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="6" class="mb20"> + <el-form-item label="年度" :prop="`list[${k}].year`" :rules="[{ required: true, message: `年度不能为空`, trigger: 'blur' }]"> + <template #label> + <el-button type="primary" circle size="small" @click="onAddRow" v-if="k === 0"> + <el-icon> + <ele-Plus /> + </el-icon> + </el-button> + <el-button type="danger" circle size="small" @click="onDelRow(k)" v-else> + <el-icon> + <ele-Delete /> + </el-icon> + </el-button> + <span class="ml10">年度</span> + </template> + <el-input v-model="form.list[k].year" style="width: 100%" placeholder="请输入"> </el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="6" class="mb20"> + <el-form-item label="月度" :prop="`list[${k}].month`" :rules="[{ required: true, message: `月度不能为空`, trigger: 'blur' }]"> + <el-input v-model="form.list[k].month" style="width: 100%" placeholder="请输入"> </el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="6" class="mb20"> + <el-form-item label="日度" :prop="`list[${k}].day`" :rules="[{ required: true, message: `日度不能为空`, trigger: 'blur' }]"> + <el-input v-model="form.list[k].day" style="width: 100%" placeholder="请输入"> </el-input> + </el-form-item> + </el-col> + </el-row> + </template> + </el-col> + </el-row> + </el-form> + </el-card> + <el-row class="flex mt15"> + <div class="flex-margin"> + <el-button size="default" @click="onResetForm"> + <el-icon> + <ele-RefreshRight /> + </el-icon> + 重置表单 + </el-button> + <el-button size="default" type="primary" @click="onSubmitForm"> + <SvgIcon name="iconfont icon-shuxing" /> + 验证表单 + </el-button> + </div> + </el-row> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, onMounted, getCurrentInstance, defineComponent } from 'vue'; +import { formData } from './mock'; + +// 定义接口来定义对象的类型 +interface FormDataOptions { + label: string; + value: string; +} +interface FormDataState { + label: string; + prop: string; + placeholder: string; + clearable: boolean; + disabled: boolean; + required: boolean; + type: string; + i18n: boolean; + i18nText: string; + isShow: boolean; + xs: number; + sm: number; + md: number; + lg: number; + xl: number; + options?: FormDataOptions[]; +} +interface DynamicFormState { + formData: FormDataState[]; + form: any; +} + +export default defineComponent({ + name: 'pagesDynamicForm', + setup() { + const { proxy } = <any>getCurrentInstance(); + const state = reactive<DynamicFormState>({ + formData, + form: { + name: '', + email: '', + autograph: '', + occupation: '', + list: [ + { + year: '', + month: '', + day: '', + }, + ], + remarks: '', + }, + }); + // 新增行 + const onAddRow = () => { + state.form.list.push({ + year: '', + month: '', + day: '', + }); + }; + // 删除行 + const onDelRow = (k: number) => { + state.form.list.splice(k, 1); + }; + // 表单验证 + const onSubmitForm = () => { + proxy.$refs.formRulesOneRef.validate((valid: boolean) => { + if (valid) { + proxy.$message.success('验证成功'); + } else { + return false; + } + }); + }; + // 重置表单 + const onResetForm = () => { + proxy.$refs.formRulesOneRef.resetFields(); + }; + // 页面加载时 + onMounted(() => {}); + return { + onAddRow, + onDelRow, + onSubmitForm, + onResetForm, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/pages/dynamicForm/mock.ts b/src/views/pages/dynamicForm/mock.ts new file mode 100644 index 0000000..2293fe9 --- /dev/null +++ b/src/views/pages/dynamicForm/mock.ts @@ -0,0 +1,119 @@ +// 表单数据选项(自行扩展) +export const formData = [ + { + label: '姓名', + prop: 'name', + placeholder: '请输入姓名', + clearable: true, + disabled: false, + required: true, + type: 'input', + i18n: false, + i18nText: '', + isShow: true, + xs: 24, + sm: 12, + md: 8, + lg: 6, + xl: 4, + }, + { + label: '邮箱', + prop: 'email', + placeholder: '请输入用户邮箱', + clearable: true, + disabled: false, + required: true, + type: 'input', + i18n: false, + i18nText: '', + isShow: true, + xs: 24, + sm: 12, + md: 8, + lg: 6, + xl: 4, + }, + { + label: '登陆时间', + prop: 'autograph', + placeholder: '选择时间', + clearable: true, + disabled: false, + required: true, + type: 'date', + i18n: false, + i18nText: '', + isShow: true, + xs: 24, + sm: 12, + md: 8, + lg: 6, + xl: 4, + }, + { + label: '职务', + prop: 'occupation', + placeholder: '请选择职务', + clearable: true, + disabled: false, + required: true, + type: 'select', + i18n: false, + i18nText: '', + options: [ + { + label: '计算机 / 互联网 / 通信', + value: '1', + }, + { + label: '生产 / 工艺 / 制造', + value: '2', + }, + { + label: '医疗 / 护理 / 制药', + value: '3', + }, + ], + isShow: true, + xs: 24, + sm: 12, + md: 8, + lg: 6, + xl: 4, + }, + { + label: '', + prop: '', + placeholder: '', + clearable: true, + disabled: false, + required: true, + type: '', + i18n: false, + i18nText: '', + isShow: true, + xs: 24, + sm: 24, + md: 24, + lg: 24, + xl: 24, + }, + { + label: '备注', + prop: 'remarks', + placeholder: '请输入', + clearable: true, + disabled: false, + required: true, + type: 'textarea', + i18n: false, + i18nText: '', + isShow: true, + xs: 24, + sm: 24, + md: 24, + lg: 24, + xl: 24, + }, +]; diff --git a/src/views/pages/element/index.vue b/src/views/pages/element/index.vue new file mode 100644 index 0000000..0bb2454 --- /dev/null +++ b/src/views/pages/element/index.vue @@ -0,0 +1,89 @@ +<template> + <div class="element-container"> + <el-card shadow="hover" :header="`element plus 字体图标(自动载入,增加了 ele- 前缀,使用时:ele-Aim):${sheetsIconList.length}个`"> + <el-row class="iconfont-row"> + <el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="2" v-for="(v, k) in sheetsIconList" :key="k"> + <div class="iconfont-warp"> + <div class="flex-margin"> + <div class="iconfont-warp-value"> + <SvgIcon :name="v" :size="30" /> + </div> + <div class="iconfont-warp-label mt10">{{ v }}</div> + </div> + </div> + </el-col> + </el-row> + </el-card> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, onMounted, defineComponent } from 'vue'; +import initIconfont from '/@/utils/getStyleSheets'; + +export default defineComponent({ + name: 'pagesElement', + setup() { + const state = reactive({ + sheetsIconList: [], + }); + // 初始化获取 css 样式,获取 element plus 自带 svg 图标,增加了 ele- 前缀,使用时:ele-Aim + const initGetStyleSheets = () => { + initIconfont.ele().then((res: any) => { + state.sheetsIconList = res; + }); + }; + // 页面加载时 + onMounted(() => { + initGetStyleSheets(); + }); + return { + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.element-container { + .iconfont-row { + border-top: 1px solid var(--next-border-color-light); + border-left: 1px solid var(--next-border-color-light); + .iconfont-warp { + text-align: center; + border-right: 1px solid var(--next-border-color-light); + border-bottom: 1px solid var(--next-border-color-light); + height: 120px; + overflow: hidden; + display: flex; + transition: all 0.3s ease; + &:hover { + box-shadow: 0 2px 12px var(--next-color-dark-hover); + cursor: pointer; + transition: all 0.3s ease; + .iconfont-warp-value { + i { + color: var(--el-color-primary); + transition: all 0.3s ease; + } + } + .iconfont-warp-label { + color: var(--el-color-primary); + transition: all 0.3s ease; + } + } + .iconfont-warp-value { + i { + color: #606266; + font-size: 32px; + transition: all 0.3s ease; + } + } + .iconfont-warp-label { + color: #99a9bf; + transition: all 0.3s ease; + } + } + } +} +</style> diff --git a/src/views/pages/filtering/details.vue b/src/views/pages/filtering/details.vue new file mode 100644 index 0000000..a2e5417 --- /dev/null +++ b/src/views/pages/filtering/details.vue @@ -0,0 +1,39 @@ +<template> + <div :style="{ height: `calc(100vh - ${initTagViewHeight}` }"> + <div class="layout-view-bg-white"> + <div class="w100 h100 flex"> + <div class="flex-margin color-primary">filtering-details 测试界面</div> + </div> + </div> + </div> +</template> + +<script lang="ts"> +import { computed, defineComponent } from 'vue'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; + +export default defineComponent({ + name: 'pagesFilteringDetails', + setup() { + const storesTagsViewRoutes = useTagsViewRoutes(); + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes); + // 设置主内容的高度 + const initTagViewHeight = computed(() => { + let { isTagsview } = themeConfig.value; + if (isTagsViewCurrenFull.value) { + return `30px`; + } else { + if (isTagsview) return `114px`; + else return `80px`; + } + }); + return { + initTagViewHeight, + }; + }, +}); +</script> diff --git a/src/views/pages/filtering/details1.vue b/src/views/pages/filtering/details1.vue new file mode 100644 index 0000000..2fde1b4 --- /dev/null +++ b/src/views/pages/filtering/details1.vue @@ -0,0 +1,39 @@ +<template> + <div :style="{ height: `calc(100vh - ${initTagViewHeight}` }"> + <div class="layout-view-bg-white"> + <div class="w100 h100 flex"> + <div class="flex-margin color-primary">测试界面</div> + </div> + </div> + </div> +</template> + +<script lang="ts"> +import { computed, defineComponent } from 'vue'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; + +export default defineComponent({ + name: 'pagesFilteringDetails1', + setup() { + const storesTagsViewRoutes = useTagsViewRoutes(); + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes); + // 设置主内容的高度 + const initTagViewHeight = computed(() => { + let { isTagsview } = themeConfig.value; + if (isTagsViewCurrenFull.value) { + return `30px`; + } else { + if (isTagsview) return `114px`; + else return `80px`; + } + }); + return { + initTagViewHeight, + }; + }, +}); +</script> diff --git a/src/views/pages/filtering/index.vue b/src/views/pages/filtering/index.vue new file mode 100644 index 0000000..7cb7ff5 --- /dev/null +++ b/src/views/pages/filtering/index.vue @@ -0,0 +1,355 @@ +<template> + <div class="filtering"> + <el-card + shadow="hover" + class="filtering-list br-top-no" + v-loading="tableData.loading" + element-loading-text="加载中..." + element-loading-background="rgba(255, 255, 255, 0.1)" + :class="{ 'min-h-360': tableData.data.length <= 0 }" + > + <div + v-for="(val, key) in filtering" + :key="key" + :ref=" + (el) => { + if (el) dlRefs[key] = el; + } + " + class="filtering-list-flex" + > + <div class="filtering-list-title">{{ val.title }}</div> + <div class="filtering-list-item" :style="{ height: val.isMore ? 'auto' : '50px' }"> + <span class="span" :class="v.active ? 'dd-active' : ''" v-for="(v, k) in val.children" :key="k" @click="onSelItem(val, v)">{{ + v.label + }}</span> + <div class="dd-more" v-if="val.isShowMore" @click="val.isMore = !val.isMore"> + <span>{{ val.isMore ? '收起' : '展开' }}</span> + <i :class="val.isMore ? 'el-icon-arrow-down' : 'el-icon-arrow-right'"></i> + </div> + </div> + </div> + <div class="flex-warp mt15 mb15" v-if="tableData.data.length > 0"> + <el-row :gutter="15"> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb15" v-for="(v, k) in tableData.data" :key="k" @click="onTableItemClick(v)"> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <div class="item-img"> + <img :src="v.img" /> + </div> + <div class="item-txt"> + <div class="item-txt-title">{{ v.title }}</div> + <div class="item-txt-other"> + <div style="width: 100%"> + <div class="item-txt-msg mb10"> + <span>评价 {{ v.evaluate }}</span> + <span class="ml10">收藏 {{ v.collection }}</span> + </div> + <div class="item-txt-msg item-txt-price"> + <span class="font-price"> + <span>¥</span> + <span class="font">{{ v.price }}</span> + </span> + <span>月销{{ v.monSales }}笔</span> + </div> + </div> + </div> + </div> + </div> + </div> + </el-col> + </el-row> + </div> + <div v-else class="filtering-no-data"> + <div class="no-data-box"> + <i class="el-icon-search"></i> + <div class="no-txt">暂无数据</div> + </div> + </div> + <template v-if="tableData.data.length > 0"> + <el-pagination + style="text-align: right" + background + @size-change="onHandleSizeChange" + @current-change="onHandleCurrentChange" + :page-sizes="[10, 20, 30]" + :current-page="tableData.param.pageNum" + :page-size="tableData.param.pageSize" + layout="total, sizes, prev, pager, next, jumper" + :total="tableData.total" + > + </el-pagination> + </template> + </el-card> + </div> +</template> + +<script lang="ts"> +import { ref, toRefs, reactive, onMounted, nextTick, defineComponent } from 'vue'; +import { useRouter } from 'vue-router'; +import { filtering, filterList } from './mock'; + +export default defineComponent({ + name: 'pagesFiltering', + setup() { + const dlRefs: any = ref([]); + const router = useRouter(); + const state = reactive({ + filtering, + tableData: { + data: filterList, + total: 99, + loading: false, + param: { + pageNum: 1, + pageSize: 10, + }, + }, + }); + // 页面加载时 + onMounted(() => { + initBtnToggle(); + window.onresize = () => { + initBtnToggle(); + }; + }); + // 初始化 `收起、展开` 按钮 + const initBtnToggle = () => { + nextTick(() => { + const els = dlRefs.value; + els.map((v: any, k: number) => { + v.scrollHeight < v.lastChild.scrollHeight ? (state.filtering[k].isShowMore = true) : (state.filtering[k].isShowMore = false); + }); + }); + }; + // 过滤当前选中的数据 + const onSelItem = (val: any, v: any) => { + val.children.map((v: any) => (v.active = false)); + v.active = true; + let arr = []; + state.filtering.map((item: any) => { + item.children.map((chil: any) => { + if (chil.active) { + arr.push({ + ...item, + children: [{ ...chil }], + }); + } + }); + }); + state.tableData.loading = true; + setTimeout(() => { + state.tableData.loading = false; + }, 500); + }; + // 当前列表项点击 + const onTableItemClick = (v: any) => { + if (v.id === 1) { + router.push({ + path: '/pages/filtering/details', + query: { id: v.id }, + }); + } else { + router.push({ + path: '/pages/filtering/details1', + query: { id: v.id }, + }); + } + }; + // 分页点击 + const onHandleSizeChange = (val: number) => { + state.tableData.param.pageSize = val; + }; + // 分页点击 + const onHandleCurrentChange = (val: number) => { + state.tableData.param.pageNum = val; + }; + return { + dlRefs, + onSelItem, + onTableItemClick, + onHandleSizeChange, + onHandleCurrentChange, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.filtering { + .filtering-list { + overflow: hidden; + border-bottom: none !important; + .filtering-list-flex { + &:last-of-type { + .filtering-list-item { + border-bottom: none !important; + } + } + .filtering-list-title { + float: left; + width: 64px; + font-weight: 700; + position: relative; + color: #909399; + margin: 15px 0; + &:after { + content: ''; + position: absolute; + border: 1px solid #909399; + border-width: 0 1px 1px 0; + width: 4px; + height: 4px; + transform: rotate(-45deg) translateY(-50%); + right: 10px; + top: 50%; + } + } + .filtering-list-item { + border-bottom: 1px dotted var(--next-border-color-light); + margin-left: 64px; + overflow: hidden; + position: relative; + .span { + color: #8d8d91; + font-size: 14px; + float: left; + padding: 0 15px; + margin: 15px 0; + &:hover { + color: var(--el-color-primary); + cursor: pointer; + } + } + .dd-active { + color: var(--el-color-primary); + } + .dd-more { + font-size: 12px; + position: absolute; + right: 0; + top: 16px; + color: #a5a5a5; + &:hover { + cursor: pointer; + color: #8d8d91; + } + } + } + } + } + .br-top-no { + border-top: none; + .flex-warp { + display: flex; + flex-wrap: wrap; + align-content: flex-start; + margin: 0 -5px; + .flex-warp-item { + padding: 5px; + width: 100%; + height: 360px; + .flex-warp-item-box { + border: 1px solid var(--next-border-color-light); + width: 100%; + height: 100%; + border-radius: 2px; + display: flex; + flex-direction: column; + transition: all 0.3s ease; + &:hover { + cursor: pointer; + border: 1px solid var(--el-color-primary); + transition: all 0.3s ease; + box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.03); + .item-txt-title { + color: var(--el-color-primary) !important; + transition: all 0.3s ease; + } + .item-img { + img { + transition: all 0.3s ease; + transform: translateZ(0) scale(1.05); + } + } + } + .item-img { + width: 100%; + height: 215px; + overflow: hidden; + img { + transition: all 0.3s ease; + width: 100%; + height: 100%; + } + } + .item-txt { + flex: 1; + padding: 15px; + display: flex; + flex-direction: column; + overflow: hidden; + .item-txt-title { + text-overflow: ellipsis; + overflow: hidden; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + display: -webkit-box; + color: #666666; + transition: all 0.3s ease; + &:hover { + color: var(--el-color-primary); + text-decoration: underline; + transition: all 0.3s ease; + } + } + .item-txt-other { + flex: 1; + align-items: flex-end; + display: flex; + .item-txt-msg { + font-size: 12px; + color: #8d8d91; + } + .item-txt-price { + display: flex; + justify-content: space-between; + align-items: center; + .font-price { + color: #ff5000; + .font { + font-size: 22px; + } + } + } + } + } + } + } + } + ::v-deep(.el-card__body) { + height: 100%; + .filtering-no-data { + display: flex; + height: 100%; + .no-data-box { + color: #cccccc; + margin: auto; + i { + font-size: 70px; + } + .no-txt { + font-size: 14px; + text-align: center; + margin-top: 15px; + } + } + } + } + } + .min-h-360 { + height: 360px; + } +} +</style> diff --git a/src/views/pages/filtering/mock.ts b/src/views/pages/filtering/mock.ts new file mode 100644 index 0000000..22e0f38 --- /dev/null +++ b/src/views/pages/filtering/mock.ts @@ -0,0 +1,201 @@ +// 导航数据 +export const filtering = [ + { + title: '权限', + isMore: false, + isShowMore: false, + id: 0, + children: [ + { + id: '01', + label: '全部', + active: true, + }, + { + id: '02', + label: '普通用户', + active: false, + }, + { + id: '03', + label: '管理员', + active: false, + }, + ], + }, + { + title: '布局', + isMore: false, + isShowMore: false, + id: 1, + children: [ + { + id: 11, + label: '全部', + active: true, + }, + { + id: 12, + label: '默认', + active: false, + }, + { + id: 13, + label: '经典', + active: false, + }, + { + id: 14, + label: '横向', + active: false, + }, + { + id: 15, + label: '分栏', + active: false, + }, + ], + }, + { + title: '配置', + isMore: false, + isShowMore: false, + id: 2, + children: [ + { + id: 21, + label: '全部', + active: true, + }, + { + id: 22, + label: '开启 Breadcrumb', + active: false, + }, + { + id: 23, + label: '开启 Tags-View', + active: false, + }, + { + id: 24, + label: '固定 Header', + active: false, + }, + { + id: 25, + label: '侧边栏 Logo', + active: false, + }, + { + id: 26, + label: '开启折叠 NavMenu', + active: false, + }, + { + id: 27, + label: '开启一个 NavMenu 展开', + active: false, + }, + { + id: 28, + label: '登录用户头像', + active: false, + }, + ], + }, +]; + +// 列表数据 +export const filterList = [ + { + img: 'http://news.sznews.com/pic/2020-08/14/9d9c9a60-f0af-41aa-b617-683b07c87642.jpg', + title: '嘉陵江2020年第1号洪水”在嘉陵江支流涪江形成', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 1, + }, + { + img: 'http://www.sznews.com/news/pic/2020-08/13/0ea47d3c-feb9-4bd7-8597-a8a373aa6340c6ec12c7-3b33-4528-91a6-85ec8ca1df67_watermark.png', + title: '让《民法典》走近群众 盐田街道开展人民调解宣传活动', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 2, + }, + { + img: 'http://www.sznews.com/photo/pic/2020-08/12/a08d6eb0-1d53-4f76-a313-ad3e5d701f98.jpg', + title: '记者手记:可可西里,“挪”向“藏羚羊大产房”的14个半小时', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 3, + }, + { + img: 'http://www.sznews.com/photo/pic/2020-08/11/43cc0e14-9bca-45b9-9a8b-342e09d6a4c7.jpg', + title: '以优异成绩庆祝深圳经济特区建立40周年', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 4, + }, + { + img: 'http://www.sznews.com/photo/pic/2020-08/11/a4dc322b-68ec-40e6-8906-3124142c3e49.jpg', + title: '草原上的“太阳姑娘”', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 5, + }, + { + img: 'http://www.sznews.com/zhuanti/pic/2020-08/07/57f087b4-4812-46cc-adb9-ead73621284e.png', + title: '奇观天下|带你走进非洲野生动物观光第一目的地', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 6, + }, + { + img: 'http://news.sznews.com/pic/2020-09/02/t2_(101X54X600X335)7cd39301-d9cf-45f1-91c3-9575b1e5ce0e.jpg.2', + title: '五角大楼发布“中国军力报告” 华春莹: 罔顾事实,充满偏见', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 7, + }, + { + img: 'http://news.sznews.com/pic/2020-09/02/b8b41d9c-0508-4498-8d37-6e597493769f.jpg', + title: '最新地铁消息汇总:4号线北延、2号线三期、8号线一期等今年通车', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 8, + }, + { + img: 'http://www.sznews.com/photo/pic/2020-08/10/1635374c-f4d6-475c-ac47-1334176f365d.png', + title: '9月1日深圳新增5例无症状感染者!钟南山这段话冲上热搜!', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 9, + }, + { + img: 'http://www.sznews.com/news/pic/2020-08/13/646e5458-92b7-4636-9940-9b0799babfe1.png', + title: '全能“小福宝” 为文明社区建设添砖加瓦', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 10, + }, +]; diff --git a/src/views/pages/formAdapt/index.vue b/src/views/pages/formAdapt/index.vue new file mode 100644 index 0000000..3bbfe04 --- /dev/null +++ b/src/views/pages/formAdapt/index.vue @@ -0,0 +1,114 @@ +<template> + <div class="form-adapt-container"> + <el-card shadow="hover" header="表单自适应演示(改变窗口查看效果)"> + <el-form :model="form" size="default" label-width="100px" class="mt35 mb35"> + <el-row :gutter="35"> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="姓名"> + <el-input v-model="form.name" placeholder="请输入姓名" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="用户归属部门"> + <el-input v-model="form.email" placeholder="请输入用户归属部门" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="登陆账户名"> + <el-input v-model="form.autograph" placeholder="请输入登陆账户名" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="职务"> + <el-select v-model="form.occupation" placeholder="请选择职务" clearable class="w100"> + <el-option label="计算机 / 互联网 / 通信" value="1"></el-option> + <el-option label="生产 / 工艺 / 制造" value="2"></el-option> + <el-option label="医疗 / 护理 / 制药" value="3"></el-option> + </el-select> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="手机"> + <el-input v-model="form.phone" placeholder="请输入手机" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="性别"> + <el-select v-model="form.sex" placeholder="请选择性别" clearable class="w100"> + <el-option label="男" value="1"></el-option> + <el-option label="女" value="2"></el-option> + </el-select> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="登录密码"> + <el-input v-model="form.phone1" placeholder="请输入登录密码" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="权限角色"> + <el-input v-model="form.phone2" placeholder="请输入权限角色" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="创建用户"> + <el-input v-model="form.phone3" placeholder="请输入创建用户" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="修改用户"> + <el-input v-model="form.phone4" placeholder="请输入修改用户" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="所属用户"> + <el-input v-model="form.phone5" placeholder="请输入所属用户" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="所属部门"> + <el-input v-model="form.phone6" placeholder="请输入所属部门" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24"> + <el-form-item> + <el-button type="primary"> + <SvgIcon name="iconfont icon-biaodan" /> + 更新个人信息 + </el-button> + </el-form-item> + </el-col> + </el-row> + </el-form> + </el-card> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent } from 'vue'; + +export default defineComponent({ + name: 'pagesFormAdapt', + setup() { + const state = reactive({ + form: { + name: '', + email: '', + autograph: '', + occupation: '', + phone: '', + sex: '', + phone1: '', + phone2: '', + phone3: '', + phone4: '', + phone5: '', + phone6: '', + }, + }); + return { + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/pages/formI18n/index.vue b/src/views/pages/formI18n/index.vue new file mode 100644 index 0000000..b9fe6b8 --- /dev/null +++ b/src/views/pages/formI18n/index.vue @@ -0,0 +1,59 @@ +<template> + <div class="form-i18n-container"> + <el-card shadow="hover" header="表单国际化演示(不适用于动态项 form-item)"> + <div style="text-align: center; margin-top: 15px"> + <el-radio-group v-model="radio" size="default" @change="onRadioChange"> + <el-radio-button label="zh-cn">中文简体</el-radio-button> + <el-radio-button label="en">英文</el-radio-button> + <el-radio-button label="zh-tw">中文繁体</el-radio-button> + </el-radio-group> + </div> + <el-form :model="form" size="default" label-width="100px" class="mt35 mb35"> + <el-row :gutter="35"> + <el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8" class="mb20"> + <el-form-item :label="$t('message.formI18nLabel.name')"> + <el-input v-model="form.name" :placeholder="$t('message.formI18nPlaceholder.name')" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8" class="mb20"> + <el-form-item :label="$t('message.formI18nLabel.email')"> + <el-input v-model="form.email" :placeholder="$t('message.formI18nPlaceholder.email')" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8" class="mb20"> + <el-form-item :label="$t('message.formI18nLabel.autograph')"> + <el-input v-model="form.autograph" :placeholder="$t('message.formI18nPlaceholder.autograph')" clearable></el-input> + </el-form-item> + </el-col> + </el-row> + </el-form> + </el-card> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent, getCurrentInstance } from 'vue'; + +export default defineComponent({ + name: 'pagesFormI18n', + setup() { + const { proxy } = <any>getCurrentInstance(); + const state = reactive({ + radio: 'zh-cn', + form: { + name: '', + email: '', + autograph: '', + }, + }); + // 单选框改变时 + const onRadioChange = () => { + proxy.$i18n.locale = state.radio; + }; + return { + onRadioChange, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/pages/formRules/component/formRulesOne.vue b/src/views/pages/formRules/component/formRulesOne.vue new file mode 100644 index 0000000..ff9e568 --- /dev/null +++ b/src/views/pages/formRules/component/formRulesOne.vue @@ -0,0 +1,68 @@ +<template> + <div class="form-rules-one-container"> + <el-form :model="form" :rules="rules" ref="formRulesOneRef" size="default" label-width="100px" class="mt35"> + <el-row :gutter="35"> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="姓名" prop="name"> + <el-input v-model="form.name" placeholder="请输入姓名" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="邮箱" prop="email"> + <el-input v-model="form.email" placeholder="请输入用户邮箱" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="登陆账户名" prop="autograph"> + <el-input v-model="form.autograph" placeholder="请输入登陆账户名" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="职务" prop="occupation"> + <el-select v-model="form.occupation" placeholder="请选择职务" clearable class="w100"> + <el-option label="计算机 / 互联网 / 通信" value="1"></el-option> + <el-option label="生产 / 工艺 / 制造" value="2"></el-option> + <el-option label="医疗 / 护理 / 制药" value="3"></el-option> + </el-select> + </el-form-item> + </el-col> + </el-row> + </el-form> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, onMounted, defineComponent } from 'vue'; + +export default defineComponent({ + name: 'pagesFormRulesOne', + props: { + data: { + type: Object, + default: () => {}, + }, + }, + setup(props) { + const state = reactive({ + form: { name: '', email: '', autograph: '', occupation: '' }, + rules: { + name: { required: true, message: '请输入姓名', trigger: 'blur' }, + email: { required: true, message: '请输入用户邮箱', trigger: 'blur' }, + autograph: { required: true, message: '请输入登陆账户名', trigger: 'blur' }, + occupation: { required: true, message: '请选择职务', trigger: 'change' }, + }, + }); + // 赋值回显 + const initForm = () => { + state.form = <any>props.data; + }; + // 页面加载时 + onMounted(() => { + initForm(); + }); + return { + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/pages/formRules/component/formRulesThree.vue b/src/views/pages/formRules/component/formRulesThree.vue new file mode 100644 index 0000000..145aed4 --- /dev/null +++ b/src/views/pages/formRules/component/formRulesThree.vue @@ -0,0 +1,50 @@ +<template> + <div class="form-rules-three-container"> + <el-form :model="form" :rules="rules" ref="formRulesThreeRef" size="default" label-width="100px" class="mt35"> + <el-row :gutter="35"> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="创建用户" prop="createUser"> + <el-input v-model="form.createUser" placeholder="请输入创建用户" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="修改用户" prop="editUser"> + <el-input v-model="form.editUser" placeholder="请输入修改用户" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="所属用户" prop="user"> + <el-input v-model="form.user" placeholder="请输入所属用户" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="所属部门" prop="department"> + <el-input v-model="form.department" placeholder="请输入所属部门" clearable></el-input> + </el-form-item> + </el-col> + </el-row> + </el-form> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent } from 'vue'; + +export default defineComponent({ + name: 'pagesFormRulesThree', + setup() { + const state = reactive({ + form: { createUser: '', editUser: '', user: '', department: '' }, + rules: { + createUser: { required: true, message: '请输入创建用户', trigger: 'blur' }, + editUser: { required: true, message: '请输入修改用户', trigger: 'blur' }, + user: { required: true, message: '请输入所属用户', trigger: 'blur' }, + department: { required: true, message: '请输入所属部门', trigger: 'blur' }, + }, + }); + return { + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/pages/formRules/component/formRulesTwo.vue b/src/views/pages/formRules/component/formRulesTwo.vue new file mode 100644 index 0000000..fcb0604 --- /dev/null +++ b/src/views/pages/formRules/component/formRulesTwo.vue @@ -0,0 +1,52 @@ +<template> + <div class="form-rules-two-container"> + <el-form :model="form" :rules="rules" ref="formRulesTwoRef" size="default" label-width="100px" class="mt35"> + <el-row :gutter="35"> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="手机" prop="phone"> + <el-input v-model="form.phone" placeholder="请输入手机" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="性别"> + <el-select v-model="form.sex" placeholder="请选择性别" clearable class="w100"> + <el-option label="男" value="1"></el-option> + <el-option label="女" value="2"></el-option> + </el-select> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="登录密码" prop="password"> + <el-input v-model="form.password" placeholder="请输入登录密码" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="权限角色" prop="auth"> + <el-input v-model="form.auth" placeholder="请输入权限角色" clearable></el-input> + </el-form-item> + </el-col> + </el-row> + </el-form> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent } from 'vue'; + +export default defineComponent({ + name: 'pagesFormRulesTwo', + setup() { + const state = reactive({ + form: { phone: '', sex: '', password: '', auth: '' }, + rules: { + phone: { required: true, message: '请输入手机', trigger: 'blur' }, + password: { required: true, message: '请输入登录密码', trigger: 'blur' }, + auth: { required: true, message: '请输入权限角色', trigger: 'blur' }, + }, + }); + return { + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/pages/formRules/index.vue b/src/views/pages/formRules/index.vue new file mode 100644 index 0000000..9c24343 --- /dev/null +++ b/src/views/pages/formRules/index.vue @@ -0,0 +1,80 @@ +<template> + <div class="form-rules-container"> + <el-card shadow="hover" header="表单组件1"> <FormRulesOne :data="formRulesOneData" ref="pagesFormRulesOneRef" /></el-card> + <el-card shadow="hover" header="表单组件2" class="mt15"><FormRulesTwo ref="pagesFormRulesTwoRef" /> </el-card> + <el-card shadow="hover" header="表单组件3" class="mt15"> <FormRulesThree ref="pagesFormRulesThreeRef" /></el-card> + <el-row class="flex mt15"> + <div class="flex-margin"> + <el-button size="default" @click="onResetForm"> + <SvgIcon name="ele-RefreshRight" /> + 重置表单 + </el-button> + <el-button size="default" type="primary" @click="onSubmitForm"> + <SvgIcon name="iconfont icon-shuxing" /> + 验证表单 + </el-button> + </div> + </el-row> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent, getCurrentInstance } from 'vue'; +import { ElMessage } from 'element-plus'; +import FormRulesOne from '/@/views/pages/formRules/component/formRulesOne.vue'; +import FormRulesTwo from '/@/views/pages/formRules/component/formRulesTwo.vue'; +import FormRulesThree from '/@/views/pages/formRules/component/formRulesThree.vue'; + +export default defineComponent({ + name: 'pagesFormRules', + components: { + FormRulesOne, + FormRulesTwo, + FormRulesThree, + }, + setup() { + const { proxy } = <any>getCurrentInstance(); + const state = reactive({ + formRulesOneData: { + name: 'lyt', + email: 'lyt123@.com', + autograph: 'lyt123456', + occupation: '1', + }, + }); + // 表单组件验证 + const formRulesValidate = (pageRef: string, sonRef: string) => { + return new Promise((resolve) => { + proxy.$refs[pageRef].$refs[sonRef].validate((valid: boolean) => { + if (valid) resolve(valid); + }); + }); + }; + // 表单组件重置 + const formRulesResetFields = () => { + proxy.$refs.pagesFormRulesOneRef.$refs.formRulesOneRef.resetFields(); + proxy.$refs.pagesFormRulesTwoRef.$refs.formRulesTwoRef.resetFields(); + proxy.$refs.pagesFormRulesThreeRef.$refs.formRulesThreeRef.resetFields(); + }; + // 验证表单 + const onSubmitForm = () => { + Promise.all([ + formRulesValidate('pagesFormRulesOneRef', 'formRulesOneRef'), + formRulesValidate('pagesFormRulesTwoRef', 'formRulesTwoRef'), + formRulesValidate('pagesFormRulesThreeRef', 'formRulesThreeRef'), + ]).then(() => { + ElMessage.success('表单全部验证成功'); + }); + }; + // 重置表单 + const onResetForm = () => { + formRulesResetFields(); + }; + return { + onSubmitForm, + onResetForm, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/pages/iocnfont/index.vue b/src/views/pages/iocnfont/index.vue new file mode 100644 index 0000000..48a44f9 --- /dev/null +++ b/src/views/pages/iocnfont/index.vue @@ -0,0 +1,87 @@ +<template> + <div class="iconfont-container"> + <el-card shadow="hover" :header="`iconfont 字体图标(自动载入):${sheetsIconList.length}个`"> + <el-row class="iconfont-row"> + <el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="2" v-for="(v, k) in sheetsIconList" :key="k"> + <div class="iconfont-warp"> + <div class="flex-margin"> + <div class="iconfont-warp-value"> + <i :class="v" class="iconfont"></i> + </div> + <div class="iconfont-warp-label mt10">{{ v }}</div> + </div> + </div> + </el-col> + </el-row> + </el-card> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, onMounted, defineComponent } from 'vue'; +import initIconfont from '/@/utils/getStyleSheets'; + +export default defineComponent({ + name: 'pagesIocnfont', + setup() { + const state = reactive({ + sheetsIconList: [], + }); + // 初始化获取 css 样式,这里使用阿里的图标(记得加上前缀 `iconfont`),其它第三方请自行做判断 + const initGetStyleSheets = () => { + initIconfont.ali().then((res: any) => (state.sheetsIconList = res)); + }; + // 页面加载时 + onMounted(() => { + initGetStyleSheets(); + }); + return { + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.iconfont-container { + .iconfont-row { + border-top: 1px solid var(--next-border-color-light); + border-left: 1px solid var(--next-border-color-light); + .iconfont-warp { + text-align: center; + border-right: 1px solid var(--next-border-color-light); + border-bottom: 1px solid var(--next-border-color-light); + height: 120px; + overflow: hidden; + display: flex; + transition: all 0.3s ease; + &:hover { + box-shadow: 0 2px 12px var(--next-color-dark-hover); + cursor: pointer; + transition: all 0.3s ease; + .iconfont-warp-value { + i { + color: var(--el-color-primary); + transition: all 0.3s ease; + } + } + .iconfont-warp-label { + color: var(--el-color-primary); + transition: all 0.3s ease; + } + } + .iconfont-warp-value { + i { + color: #606266; + font-size: 32px; + transition: all 0.3s ease; + } + } + .iconfont-warp-label { + color: #99a9bf; + transition: all 0.3s ease; + } + } + } +} +</style> diff --git a/src/views/pages/lazyImg/index.vue b/src/views/pages/lazyImg/index.vue new file mode 100644 index 0000000..ad63f8a --- /dev/null +++ b/src/views/pages/lazyImg/index.vue @@ -0,0 +1,194 @@ +<template> + <div class="lazy-img-container"> + <el-card shadow="hover" header="图片懒加载演示(F12 切换到 Network Img下进行图片加载查看)"> + <div class="flex-warp" v-if="tableData.data.length > 0"> + <el-row :gutter="15"> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb15" v-for="(v, k) in tableData.data" :key="k" @click="onTableItemClick(v)"> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <div class="item-img" v-loading="v.loading"> + <img :data-img="v.img" :data-key="k" :data-lazy-img-list="k" /> + </div> + <div class="item-txt"> + <div class="item-txt-title">{{ v.title }}</div> + <div class="item-txt-other"> + <div style="width: 100%"> + <div class="item-txt-msg mb10"> + <span>评价 {{ v.evaluate }}</span> + <span class="ml10">收藏 {{ v.collection }}</span> + </div> + <div class="item-txt-msg item-txt-price"> + <span class="font-price"> + <span>¥</span> + <span class="font">{{ v.price }}</span> + </span> + <span>月销{{ v.monSales }}笔</span> + </div> + </div> + </div> + </div> + </div> + </div> + </el-col> + </el-row> + </div> + <el-empty v-else description="暂无数据"></el-empty> + <template v-if="tableData.data.length > 0"> + <el-pagination + style="text-align: right" + background + @size-change="onHandleSizeChange" + @current-change="onHandleCurrentChange" + :page-sizes="[10, 20, 30]" + :current-page="tableData.param.pageNum" + :page-size="tableData.param.pageSize" + layout="total, sizes, prev, pager, next, jumper" + :total="tableData.total" + > + </el-pagination> + </template> + </el-card> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, onMounted, defineComponent } from 'vue'; +import { useRouter } from 'vue-router'; +import other from '/@/utils/other'; +import { filterList } from './mock'; + +export default defineComponent({ + name: 'pagesListAdapt', + setup() { + const router = useRouter(); + const state = reactive({ + tableData: { + data: filterList, + total: 99, + loading: false, + param: { + pageNum: 1, + pageSize: 10, + }, + }, + }); + // 当前列表项点击 + const onTableItemClick = (v: any) => { + router.push({ + path: '/pages/filteringDetails', + query: { id: v.id }, + }); + }; + // 分页点击 + const onHandleSizeChange = (val: number) => { + state.tableData.param.pageSize = val; + }; + // 分页点击 + const onHandleCurrentChange = (val: number) => { + state.tableData.param.pageNum = val; + }; + // 页面加载时 + onMounted(() => { + other.lazyImg('[data-lazy-img-list]', state.tableData.data); + }); + return { + onTableItemClick, + onHandleSizeChange, + onHandleCurrentChange, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.lazy-img-container { + .flex-warp { + display: flex; + flex-wrap: wrap; + align-content: flex-start; + margin: 0 -5px; + .flex-warp-item { + padding: 5px; + width: 100%; + height: 360px; + .flex-warp-item-box { + border: 1px solid var(--next-border-color-light); + width: 100%; + height: 100%; + border-radius: 2px; + display: flex; + flex-direction: column; + transition: all 0.3s ease; + &:hover { + cursor: pointer; + border: 1px solid var(--el-color-primary); + transition: all 0.3s ease; + box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.03); + .item-txt-title { + color: var(--el-color-primary) !important; + transition: all 0.3s ease; + } + .item-img { + img { + transition: all 0.3s ease; + transform: translateZ(0) scale(1.05); + } + } + } + .item-img { + width: 100%; + height: 215px; + overflow: hidden; + img { + transition: all 0.3s ease; + width: 100%; + height: 100%; + } + } + .item-txt { + flex: 1; + padding: 15px; + display: flex; + flex-direction: column; + overflow: hidden; + .item-txt-title { + text-overflow: ellipsis; + overflow: hidden; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + display: -webkit-box; + color: #666666; + transition: all 0.3s ease; + &:hover { + color: var(--el-color-primary); + text-decoration: underline; + transition: all 0.3s ease; + } + } + .item-txt-other { + flex: 1; + align-items: flex-end; + display: flex; + .item-txt-msg { + font-size: 12px; + color: #8d8d91; + } + .item-txt-price { + display: flex; + justify-content: space-between; + align-items: center; + .font-price { + color: #ff5000; + .font { + font-size: 22px; + } + } + } + } + } + } + } + } +} +</style> diff --git a/src/views/pages/lazyImg/mock.ts b/src/views/pages/lazyImg/mock.ts new file mode 100644 index 0000000..4eb3d29 --- /dev/null +++ b/src/views/pages/lazyImg/mock.ts @@ -0,0 +1,313 @@ +// 列表数据 +export const filterList = [ + { + img: 'https://news.sznews.com/pic/2021-03/09/e37326cc-4583-48f3-aa00-ecc2392d319d.jpg', + title: '36分钟,深圳平均通勤时间出炉!GDP10强城市中仅输杭州', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 1, + loading: true, + }, + { + img: 'http://news.sznews.com/pic/2021-03/09/78cf72b6-e2d9-459d-a368-470414a027f4679cf4ea-26fa-48c8-9fee-c2d092a91400.png', + title: '为爱而动,“红色鹊桥”三八妇女节交友联谊活动助力深圳女孩脱单', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 2, + loading: true, + }, + { + img: 'http://news.sznews.com/pic/2021-03/09/1faf3c6e-1250-4e6b-b072-4a331553e027.jpg', + title: '粤桂协作“背水一战” 解决广西大化县3.7万人饮水难题', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 3, + loading: true, + }, + { + img: 'https://news.sznews.com/pic/2021-03/09/9fcf6dd4-1e80-4497-bdc9-83dc7246d170.jpg.2', + title: '城镇就业女性平均薪酬6847元 女性职场渗透率提升', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 4, + loading: true, + }, + { + img: 'https://news.sznews.com/pic/2021-03/09/1bd78227-4126-4a43-bdf6-48ead6edd1bf.jpg.2', + title: '深圳:实现“从0到1”源头创新,推进大湾区综合性国家科学中心建设!', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 5, + loading: true, + }, + { + img: 'http://news.sznews.com/pic/2021-03/08/9ea943a3-3ae8-4f49-8296-711ec36ef8c6_watermark.png', + title: '煖声音第126期|愿你有诗酒趁年华的洒脱,也有岁月沉淀后的坚定从容', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 6, + loading: true, + }, + { + img: 'https://news.sznews.com/pic/2021-03/08/a95ba232-1422-4f7e-b85f-c61d486c8659.jpg.2', + title: '姐妹们一起来吐槽,最不能接受男人的缺点!', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 7, + loading: true, + }, + { + img: 'http://news.sznews.com/pic/2021-03/08/76816bf0-3899-4c7e-bc6e-079b5ba8725e.jpg', + title: '民生小事 | 手机遗落出租车 热心民警帮找回', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 8, + loading: true, + }, + { + img: 'https://news.sznews.com/pic/2021-03/08/28ed70d4-71f5-4abb-bf7b-0294bece9e43.jpg.2', + title: '“十三五”:深圳交上靓丽答卷 发展动力加快转换', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 9, + loading: true, + }, + { + img: 'http://news.sznews.com/pic/2021-03/05/d13ae31f-fd45-431a-b48e-c5895bbc193e.png', + title: '深圳湾公园一女子落水,三名男子接力及时施救', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 10, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210704/653/w930h523/20210704/d5d2-krwipas6444058.jpg', + title: '36分钟,深圳平均通勤时间出炉!GDP10强城市中仅输杭州', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 1, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210704/766/w930h636/20210704/b1ae-krwipas6332914.jpg', + title: '为爱而动,“红色鹊桥”三八妇女节交友联谊活动助力深圳女孩脱单', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 2, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210704/750/w930h620/20210704/2886-krwipas6264821.jpg', + title: '粤桂协作“背水一战” 解决广西大化县3.7万人饮水难题', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 3, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210704/750/w930h620/20210704/767c-krwipas6387862.jpg', + title: '城镇就业女性平均薪酬6847元 女性职场渗透率提升', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 4, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210704/111/w1024h687/20210704/1f65-krwipas5871436.jpg', + title: '盛夏的那考河湿地公园!', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 5, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210704/657/w930h527/20210704/7eae-krwipas5866609.jpg', + title: '煖声音第126期|愿你有诗酒趁年华的洒脱,也有岁月沉淀后的坚定从容', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 6, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210703/760/w930h630/20210703/124e-krwipas5596390.jpg', + title: '姐妹们一起来吐槽,最不能接受男人的缺点!', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 7, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210703/27/w930h697/20210703/9630-krwipas5514972.jpg', + title: '民生小事 | 手机遗落出租车 热心民警帮找回', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 8, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210703/750/w930h620/20210703/2fe3-krwipas5388050.jpg', + title: '“十三五”:深圳交上靓丽答卷 发展动力加快转换', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 9, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210703/724/w930h594/20210703/98b6-krwipas5234060.jpg', + title: '深圳湾公园一女子落水,三名男子接力及时施救', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 10, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210703/750/w930h620/20210703/f765-krwipas5194727.jpg', + title: '36分钟,深圳平均通勤时间出炉!GDP10强城市中仅输杭州', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 1, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210702/750/w930h620/20210702/5dde-krwipas4724976.jpg', + title: '为爱而动,“红色鹊桥”三八妇女节交友联谊活动助力深圳女孩脱单', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 2, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210702/750/w930h620/20210702/f45e-krwipas4566804.jpg', + title: '粤桂协作“背水一战” 解决广西大化县3.7万人饮水难题', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 3, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210702/750/w930h620/20210702/5579-krwipas4551382.jpg', + title: '城镇就业女性平均薪酬6847元 女性职场渗透率提升', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 4, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210702/750/w930h620/20210702/7c75-krwipas4543661.jpg', + title: '深圳:实现“从0到1”源头创新,推进大湾区综合性国家科学中心建设!', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 5, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210702/653/w930h523/20210702/ece2-krwipas4411140.jpg', + title: '煖声音第126期|愿你有诗酒趁年华的洒脱,也有岁月沉淀后的坚定从容', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 6, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210702/750/w930h620/20210702/f5c2-krwipas4215211.jpg', + title: '姐妹们一起来吐槽,最不能接受男人的缺点!', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 7, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210701/720/w930h590/20210701/eabc-krwipas3509204.jpg', + title: '民生小事 | 手机遗落出租车 热心民警帮找回', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 8, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210701/797/w930h667/20210701/4667-krwipas3365057.jpg', + title: '“十三五”:深圳交上靓丽答卷 发展动力加快转换', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 9, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210701/750/w930h620/20210701/baea-krwipas2976622.jpg', + title: '民众前往中共一大纪念馆参观', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 10, + loading: true, + }, + { + img: 'http://z0.sinaimg.cn/auto/resize?size=235_156&img=http://n.sinaimg.cn/spider20210630/617/w850h567/20210630/5c96-krwipas1819108.jpg', + title: '延吉灯光秀美轮美奂 市民徜徉璀璨夜景', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 10, + loading: true, + }, +]; diff --git a/src/views/pages/listAdapt/index.vue b/src/views/pages/listAdapt/index.vue new file mode 100644 index 0000000..15e27bc --- /dev/null +++ b/src/views/pages/listAdapt/index.vue @@ -0,0 +1,209 @@ +<template> + <div class="list-adapt-container"> + <el-card shadow="hover" header="列表自适应演示(改变窗口查看效果)"> + <div class="flex-warp" v-if="tableData.data.length > 0"> + <el-row :gutter="15"> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb15" v-for="(v, k) in tableData.data" :key="k" @click="onTableItemClick(v)"> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <div class="item-img"> + <img :src="v.img" /> + </div> + <div class="item-txt"> + <div class="item-txt-title">{{ v.title }}</div> + <div class="item-txt-other"> + <div style="width: 100%"> + <div class="item-txt-msg mb10"> + <span>评价 {{ v.evaluate }}</span> + <span class="ml10">收藏 {{ v.collection }}</span> + </div> + <div class="item-txt-msg item-txt-price"> + <span class="font-price"> + <span>¥</span> + <span class="font">{{ v.price }}</span> + </span> + <span>月销{{ v.monSales }}笔</span> + </div> + </div> + </div> + </div> + </div> + </div> + </el-col> + </el-row> + </div> + <el-empty v-else description="暂无数据"></el-empty> + <template v-if="tableData.data.length > 0"> + <el-pagination + style="text-align: right" + background + @size-change="onHandleSizeChange" + @current-change="onHandleCurrentChange" + :page-sizes="[10, 20, 30]" + :current-page="tableData.param.pageNum" + :page-size="tableData.param.pageSize" + layout="total, sizes, prev, pager, next, jumper" + :total="tableData.total" + > + </el-pagination> + </template> + </el-card> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent } from 'vue'; +import { useRouter } from 'vue-router'; +import { filterList } from './mock'; + +// 定义接口来定义对象的类型 +interface ListAdaptRow { + img: string; + title: string; + evaluate: string; + collection: string; + price: string; + monSales: string; + id: number; +} +interface TableDataState { + tableData: { + data: Array<ListAdaptRow>; + total: number; + loading: boolean; + param: { + pageNum: number; + pageSize: number; + }; + }; +} + +export default defineComponent({ + name: 'pagesListAdapt', + setup() { + const router = useRouter(); + const state = reactive<TableDataState>({ + tableData: { + data: filterList, + total: 99, + loading: false, + param: { + pageNum: 1, + pageSize: 10, + }, + }, + }); + // 当前列表项点击 + const onTableItemClick = (v: ListAdaptRow) => { + router.push({ + path: '/pages/filteringDetails', + query: { id: v.id }, + }); + }; + // 分页点击 + const onHandleSizeChange = (val: number) => { + state.tableData.param.pageSize = val; + }; + // 分页点击 + const onHandleCurrentChange = (val: number) => { + state.tableData.param.pageNum = val; + }; + return { + onTableItemClick, + onHandleSizeChange, + onHandleCurrentChange, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.flex-warp { + display: flex; + flex-wrap: wrap; + align-content: flex-start; + margin: 0 -5px; + .flex-warp-item { + padding: 5px; + width: 100%; + height: 360px; + .flex-warp-item-box { + border: 1px solid var(--next-border-color-light); + width: 100%; + height: 100%; + border-radius: 2px; + display: flex; + flex-direction: column; + transition: all 0.3s ease; + &:hover { + cursor: pointer; + border: 1px solid var(--el-color-primary); + transition: all 0.3s ease; + box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.03); + .item-txt-title { + color: var(--el-color-primary) !important; + transition: all 0.3s ease; + } + .item-img { + img { + transition: all 0.3s ease; + transform: translateZ(0) scale(1.05); + } + } + } + .item-img { + width: 100%; + height: 215px; + overflow: hidden; + img { + transition: all 0.3s ease; + width: 100%; + height: 100%; + } + } + .item-txt { + flex: 1; + padding: 15px; + display: flex; + flex-direction: column; + overflow: hidden; + .item-txt-title { + text-overflow: ellipsis; + overflow: hidden; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + display: -webkit-box; + color: #666666; + transition: all 0.3s ease; + &:hover { + color: var(--el-color-primary); + text-decoration: underline; + transition: all 0.3s ease; + } + } + .item-txt-other { + flex: 1; + align-items: flex-end; + display: flex; + .item-txt-msg { + font-size: 12px; + color: #8d8d91; + } + .item-txt-price { + display: flex; + justify-content: space-between; + align-items: center; + .font-price { + color: #ff5000; + .font { + font-size: 22px; + } + } + } + } + } + } + } +} +</style> diff --git a/src/views/pages/listAdapt/mock.ts b/src/views/pages/listAdapt/mock.ts new file mode 100644 index 0000000..a31e9e3 --- /dev/null +++ b/src/views/pages/listAdapt/mock.ts @@ -0,0 +1,93 @@ +// 列表数据 +export const filterList = [ + { + img: 'https://news.sznews.com/pic/2021-03/09/e37326cc-4583-48f3-aa00-ecc2392d319d.jpg', + title: '36分钟,深圳平均通勤时间出炉!GDP10强城市中仅输杭州', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 1, + }, + { + img: 'http://news.sznews.com/pic/2021-03/09/78cf72b6-e2d9-459d-a368-470414a027f4679cf4ea-26fa-48c8-9fee-c2d092a91400.png', + title: '为爱而动,“红色鹊桥”三八妇女节交友联谊活动助力深圳女孩脱单', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 2, + }, + { + img: 'http://news.sznews.com/pic/2021-03/09/1faf3c6e-1250-4e6b-b072-4a331553e027.jpg', + title: '粤桂协作“背水一战” 解决广西大化县3.7万人饮水难题', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 3, + }, + { + img: 'https://news.sznews.com/pic/2021-03/09/9fcf6dd4-1e80-4497-bdc9-83dc7246d170.jpg.2', + title: '城镇就业女性平均薪酬6847元 女性职场渗透率提升', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 4, + }, + { + img: 'https://news.sznews.com/pic/2021-03/09/1bd78227-4126-4a43-bdf6-48ead6edd1bf.jpg.2', + title: '深圳:实现“从0到1”源头创新,推进大湾区综合性国家科学中心建设!', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 5, + }, + { + img: 'http://news.sznews.com/pic/2021-03/08/9ea943a3-3ae8-4f49-8296-711ec36ef8c6_watermark.png', + title: '煖声音第126期|愿你有诗酒趁年华的洒脱,也有岁月沉淀后的坚定从容', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 6, + }, + { + img: 'https://news.sznews.com/pic/2021-03/08/a95ba232-1422-4f7e-b85f-c61d486c8659.jpg.2', + title: '姐妹们一起来吐槽,最不能接受男人的缺点!', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 7, + }, + { + img: 'http://news.sznews.com/pic/2021-03/08/76816bf0-3899-4c7e-bc6e-079b5ba8725e.jpg', + title: '民生小事 | 手机遗落出租车 热心民警帮找回', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 8, + }, + { + img: 'https://news.sznews.com/pic/2021-03/08/28ed70d4-71f5-4abb-bf7b-0294bece9e43.jpg.2', + title: '“十三五”:深圳交上靓丽答卷 发展动力加快转换', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 9, + }, + { + img: 'http://news.sznews.com/pic/2021-03/05/d13ae31f-fd45-431a-b48e-c5895bbc193e.png', + title: '深圳湾公园一女子落水,三名男子接力及时施救', + evaluate: (Math.random() * 10).toFixed(2), + collection: (Math.random() * 100).toFixed(2), + price: (Math.random() * 10).toFixed(2), + monSales: (Math.random() * 20).toFixed(2), + id: 10, + }, +]; diff --git a/src/views/pages/preview/index.vue b/src/views/pages/preview/index.vue new file mode 100644 index 0000000..ce3a771 --- /dev/null +++ b/src/views/pages/preview/index.vue @@ -0,0 +1,28 @@ +<template> + <div class="preview-container"> + <el-card shadow="hover" header="element-plus 大图预览"> + <el-image style="width: 100px; height: 100px; border-radius: 5px" :src="url" :preview-src-list="srcList" title="点击查看大图预览"> </el-image> + </el-card> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent } from 'vue'; + +export default defineComponent({ + name: 'pagesPreview', + setup() { + const state = reactive({ + url: 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1813762643,1914315241&fm=26&gp=0.jpg', + srcList: [ + 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1813762643,1914315241&fm=26&gp=0.jpg', + 'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=317673774,2961727727&fm=26&gp=0.jpg', + 'https://fuss10.elemecdn.com/1/8e/aeffeb4de74e2fde4bd74fc7b4486jpeg.jpeg', + ], + }); + return { + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/pages/steps/index.vue b/src/views/pages/steps/index.vue new file mode 100644 index 0000000..becc196 --- /dev/null +++ b/src/views/pages/steps/index.vue @@ -0,0 +1,51 @@ +<template> + <div class="steps-container"> + <el-card shadow="hover" header="element-plus 步骤条"> + <el-steps :active="stepsActive"> + <el-step title="第一步"> + <template #icon> + <SvgIcon name="iconfont icon-0_round_solid" :size="20" /> + </template> + </el-step> + <el-step title="第二步"> + <template #icon> + <SvgIcon name="iconfont icon-2_round_solid" :size="20" /> + </template> + </el-step> + <el-step title="第三步"> + <template #icon> + <SvgIcon name="iconfont icon-3_round_solid" :size="20" /> + </template> + </el-step> + </el-steps> + <el-result icon="success" title="成功提示" subTitle="请根据提示进行操作" v-if="stepsActive === 1"> </el-result> + <el-result icon="warning" title="警告提示" subTitle="请根据提示进行操作" v-else-if="stepsActive === 2"> </el-result> + <el-result icon="error" title="错误提示" subTitle="请根据提示进行操作" v-else-if="stepsActive === 3"> </el-result> + <el-button @click="onNextSteps" size="default" class="mt15" type="primary"> + <SvgIcon name="iconfont icon-step" /> + 下一步 + </el-button> + </el-card> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent } from 'vue'; + +export default defineComponent({ + name: 'pagesSteps', + setup() { + const state = reactive({ + stepsActive: 1, + }); + // 下一步点击 + const onNextSteps = () => { + if (state.stepsActive++ > 2) state.stepsActive = 1; + }; + return { + onNextSteps, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/pages/tableRules/index.vue b/src/views/pages/tableRules/index.vue new file mode 100644 index 0000000..2e17cde --- /dev/null +++ b/src/views/pages/tableRules/index.vue @@ -0,0 +1,129 @@ +<template> + <el-card shadow="hover" header="表单表格验证"> + <el-form ref="tableRulesRef" :model="tableData" size="default"> + <el-table :data="tableData.data" border class="module-table-uncollected"> + <el-table-column + v-for="(item, index) in tableData.header" + :key="index" + show-overflow-tooltip + :prop="item.prop" + :width="item.width" + :label="item.label" + > + <template v-slot:header> + <span v-if="item.isRequired" class="color-danger">*</span> + <span class="pl5">{{ item.label }}</span> + <el-tooltip v-if="item.isTooltip" effect="dark" content="这是tooltip" placement="top"> + <i class="iconfont icon-quanxian" /> + </el-tooltip> + </template> + <template v-slot="scope"> + <el-form-item + :prop="`data.${scope.$index}.${item.prop}`" + :rules="[{ required: item.isRequired, message: '不能为空', trigger: `${item.type}` == 'input' ? 'blur' : 'change' }]" + > + <el-select v-if="item.type === 'select'" v-model="scope.row[item.prop]" placeholder="请选择"> + <el-option v-for="sel in tableData.option" :key="sel.id" :label="sel.label" :value="sel.value" /> + </el-select> + <el-date-picker + v-else-if="item.type === 'date'" + v-model="scope.row[item.prop]" + type="date" + placeholder="选择日期" + style="width: 100%" + /> + <el-input v-else-if="item.type === 'input'" v-model="scope.row[item.prop]" placeholder="请输入内容" /> + <el-input v-else-if="item.type === 'dialog'" v-model="scope.row[item.prop]" readonly placeholder="请输入内容"> + <template v-slot:suffix> + <i class="iconfont icon-shouye_dongtaihui" /> + </template> + </el-input> + </el-form-item> + </template> + </el-table-column> + </el-table> + </el-form> + <el-row class="flex mt15"> + <div class="flex-margin"> + <el-button size="default" type="success" @click="onValidate">表格验证</el-button> + <el-button size="default" type="primary" @click="onAddRow">新增一行</el-button> + </div> + </el-row> + </el-card> +</template> + +<script lang="ts"> +import { defineComponent, toRefs, reactive, ref } from 'vue'; +import { ElMessage } from 'element-plus'; + +// 定义接口来定义对象的类型 +interface TableHeader { + prop: string; + width: string | number; + label: string; + isRequired?: boolean; + isTooltip?: boolean; + type: string; +} +interface TableRulesState { + tableData: { + data: any[]; + header: TableHeader[]; + option: any[]; + }; +} + +export default defineComponent({ + name: 'pagesTableRules', + setup() { + const tableRulesRef = ref(); + const state = reactive<TableRulesState>({ + tableData: { + data: [], + header: [ + { prop: 'a1', width: '', label: '一级分类', isRequired: true, type: 'select' }, + { prop: 'a2', width: '', label: '二级分类', isRequired: true, type: 'select' }, + { prop: 'a3', width: '', label: '三级分类', isRequired: true, type: 'select' }, + { prop: 'a4', width: '', label: '四级分类', isRequired: true, type: 'date' }, + { prop: 'a5', width: '', label: '五级分类', isRequired: true, type: 'input' }, + { prop: 'a6', width: '', label: '六级分类', isTooltip: true, type: 'dialog' }, + { prop: 'a7', width: '', label: '演示级分类', type: 'input' }, + { prop: 'a8', width: '', label: '颜色是分类', type: 'input' }, + ], + option: [ + { value: '选项1', label: '黄金糕' }, + { value: '选项2', label: '双皮奶' }, + { value: '选项3', label: '蚵仔煎' }, + ], + }, + }); + // 表格验证 + const onValidate = () => { + if (state.tableData.data.length <= 0) return ElMessage.warning('请先点击增加一行'); + tableRulesRef.value.validate((valid: any) => { + if (!valid) return ElMessage.warning('表格项必填未填'); + ElMessage.success('全部验证通过'); + }); + }; + // 新增一行 + const onAddRow = () => { + state.tableData.data.push({ + a1: '', + a2: '', + a3: '', + a4: '', + a5: '', + a6: '', + a7: '', + a8: '', + }); + }; + return { + onValidate, + onAddRow, + tableRulesRef, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/pages/tree/index.vue b/src/views/pages/tree/index.vue new file mode 100644 index 0000000..afcc752 --- /dev/null +++ b/src/views/pages/tree/index.vue @@ -0,0 +1,258 @@ +<template> + <div class="tree-container"> + <el-card shadow="hover" header="element plus Tree 树形控件改成表格"> + <div v-loading="treeLoading"> + <div class="tree-head"> + <div class="tree-head-check"><el-checkbox v-model="treeCheckAll" @change="onCheckAllChange"></el-checkbox></div> + <div class="tree-head-one">商品 ID</div> + <div style="flex: 1; display: flex"> + <div class="tree-head-two">商品名称</div> + <div class="tree-head-three">描述</div> + </div> + </div> + <el-tree :data="treeTableData" show-checkbox node-key="id" ref="treeTable" :props="treeDefaultProps" @check="onCheckTree"> + <template #default="{ node, data }"> + <span class="tree-custom-node"> + <span style="flex: 1">{{ node.label }}</span> + <span v-if="data.isShow" style="flex: 1; display: flex"> + <span type="text" size="default" style="flex: 1">{{ data.label1 }}</span> + <span type="text" size="default" style="flex: 1">{{ data.label2 }}</span> + </span> + </span> + </template> + </el-tree> + </div> + <el-button @click="onSelect" class="mt15" size="default" type="primary"> + <SvgIcon name="iconfont icon-shuxingtu" /> + 选择元素 + </el-button> + </el-card> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, onBeforeMount, getCurrentInstance, defineComponent } from 'vue'; +import { ElMessage } from 'element-plus'; + +// 定义接口来定义对象的类型 +interface TreeDataState { + id: number; + label: string; + label1: string; + label2: string; + isShow: boolean; + children?: TreeDataState[]; +} +interface TreeSate { + treeCheckAll: boolean; + treeLoading: boolean; + treeTableData: TreeDataState[]; + treeDefaultProps: { + children: string; + label: string; + }; + treeSelArr: TreeDataState[]; + treeLength: number; +} + +export default defineComponent({ + name: 'pagesTree', + setup() { + const { proxy } = <any>getCurrentInstance(); + const state = reactive<TreeSate>({ + treeCheckAll: false, + treeLoading: false, + treeTableData: [], + treeDefaultProps: { + children: 'children', + label: 'label', + }, + treeSelArr: [], + treeLength: 0, + }); + // 初始化树的长度 + const initTreeLengh = (arr: TreeDataState[]) => { + let count = 0; + arr.map((item) => { + if (item.children) { + count += item.children.length; + } + }); + state.treeLength = count + arr.length; + }; + // 全选改变时 + const onCheckAllChange = () => { + if (state.treeCheckAll) { + proxy.$refs.treeTable.setCheckedNodes(state.treeTableData); + } else { + proxy.$refs.treeTable.setCheckedKeys([]); + } + }; + // 节点选中状态发生变化时的回调 + const onCheckTree = () => { + state.treeSelArr = []; + state.treeSelArr = proxy.$refs.treeTable.getCheckedNodes(); + state.treeSelArr.length == state.treeLength ? (state.treeCheckAll = true) : (state.treeCheckAll = false); + }; + // 选择元素按钮 + const onSelect = () => { + let treeArr = proxy.$refs.treeTable.getCheckedNodes(); + if (treeArr.length <= 0) { + ElMessage.warning('请选择元素'); + return; + } else { + // console.log(proxy.$refs.treeTable.getCheckedNodes()); + } + }; + // 初始化树模拟数据 + const getTreeData = () => { + state.treeTableData = [ + { + id: 1, + label: '12987121', + label1: '好滋好味鸡蛋仔', + label2: '荷兰优质淡奶,奶香浓而不腻', + isShow: true, + children: [ + { + id: 11, + label: '一级 1-1', + label1: '好滋好味鸡蛋仔', + label2: '荷兰优质淡奶,奶香浓而不腻', + isShow: false, + }, + { + id: 12, + label: '一级 1-2', + label1: '好滋好味鸡蛋仔', + label2: '荷兰优质淡奶,奶香浓而不腻', + isShow: false, + }, + ], + }, + { + id: 2, + label: '12987122', + label1: '好滋好味鸡蛋仔', + label2: '荷兰优质淡奶,奶香浓而不腻', + isShow: true, + children: [ + { + id: 21, + label: '二级 2-1', + label1: '好滋好味鸡蛋仔', + label2: '荷兰优质淡奶,奶香浓而不腻', + isShow: false, + }, + { + id: 22, + label: '二级 2-2', + label1: '好滋好味鸡蛋仔', + label2: '荷兰优质淡奶,奶香浓而不腻', + isShow: false, + }, + ], + }, + { + id: 3, + label: '12987123', + label1: '好滋好味鸡蛋仔', + label2: '荷兰优质淡奶,奶香浓而不腻', + isShow: true, + children: [ + { + id: 31, + label: '二级 3-1', + label1: '好滋好味鸡蛋仔', + label2: '荷兰优质淡奶,奶香浓而不腻', + isShow: false, + }, + { + id: 32, + label: '二级 3-2', + label1: '好滋好味鸡蛋仔', + label2: '荷兰优质淡奶,奶香浓而不腻', + isShow: false, + }, + { + id: 33, + label: '二级 3-3', + label1: '好滋好味鸡蛋仔', + label2: '荷兰优质淡奶,奶香浓而不腻', + isShow: false, + }, + ], + }, + ]; + initTreeLengh(state.treeTableData); + }; + // 页面加载前 + onBeforeMount(() => { + getTreeData(); + }); + return { + getTreeData, + onCheckAllChange, + onCheckTree, + onSelect, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.tree-container { + .tree-head { + height: 48px; + line-height: 48px; + border: 1px solid var(--next-border-color-light); + border-bottom: none; + display: flex; + padding-right: 8px; + font-weight: bold; + color: #909399; + .tree-head-check { + width: 38px; + text-align: right; + } + .tree-head-one, + .tree-head-two, + .tree-head-three { + flex: 1; + } + .tree-head-one { + padding-left: 8px; + } + } + .el-tree { + overflow: hidden; + border-bottom: 1px solid var(--next-border-color-light); + .tree-custom-node { + flex: 1; + display: flex; + align-items: center; + justify-content: space-between; + padding-right: 8px; + width: 100%; + } + &::v-deep(.el-tree-node) { + border: 1px solid var(--next-border-color-light); + border-bottom: none; + color: #606266; + .el-tree-node__content { + line-height: 57px !important; + height: 57px !important; + } + .el-tree-node__children { + .el-tree-node { + border: none; + } + .el-tree-node__content { + border-top: 1px solid var(--next-border-color-light); + } + } + } + } +} +</style> diff --git a/src/views/pages/waterfall/index.vue b/src/views/pages/waterfall/index.vue new file mode 100644 index 0000000..48b48ea --- /dev/null +++ b/src/views/pages/waterfall/index.vue @@ -0,0 +1,174 @@ +<template> + <div class="waterfall-container"> + <el-card shadow="hover" header="瀑布屏(布局一)" class="mb15"> + <div class="waterfall-first"> + <div class="waterfall-first-item" v-for="v in 30" :key="v" v-waves> + <div class="w100 h100 flex"> + <span class="flex-margin">{{ v }}</span> + </div> + </div> + </div> + </el-card> + <el-card shadow="hover" header="瀑布屏(布局二)"> + <div class="waterfall-last"> + <div class="waterfall-last-item" v-for="v in 30" :key="v" v-waves="'light'"> + <div class="w100 h100 flex"> + <span class="flex-margin">{{ v }}</span> + </div> + </div> + </div> + </el-card> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent } from 'vue'; + +export default defineComponent({ + name: 'pagesWaterfall', + setup() { + const state = reactive({}); + return { + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.waterfall-container { + .waterfall-first { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(188px, 1fr)); + grid-gap: 0.25em; + grid-auto-flow: row dense; + grid-auto-rows: 20px; + .waterfall-first-item { + width: 100%; + background: var(--el-color-primary); + color: var(--el-color-white); + transition: all 0.3s ease; + border-radius: 3px; + &:nth-of-type(3n + 1) { + grid-row: auto / span 5; + } + &:nth-of-type(3n + 2) { + grid-row: auto / span 6; + } + &:nth-of-type(3n + 3) { + grid-row: auto / span 8; + } + &:hover { + box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%); + transition: all 0.3s ease; + cursor: pointer; + } + } + } + .waterfall-last { + display: grid; + grid-gap: 0.25em; + grid-auto-flow: row dense; + grid-auto-rows: minmax(188px, 20vmin); + grid-template-columns: 1fr; + .waterfall-last-item { + height: 100%; + background: var(--el-color-primary); + color: var(--el-color-white); + transition: all 0.3s ease; + border-radius: 3px; + &:hover { + box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%); + transition: all 0.3s ease; + cursor: pointer; + } + } + } + @media (min-width: 576px) { + .waterfall-last { + grid-template-columns: repeat(7, 1fr); + .waterfall-last-item { + &:nth-of-type(9n + 9) { + grid-column: auto / span 2; + } + &:nth-of-type(9n + 8) { + grid-column: auto / span 2; + } + &:nth-of-type(9n + 7) { + grid-column: auto / span 3; + } + &:nth-of-type(9n + 6) { + grid-column: auto / span 2; + } + &:nth-of-type(9n + 5) { + grid-column: auto / span 3; + } + &:nth-of-type(9n + 4) { + grid-column: auto / span 2; + } + &:nth-of-type(9n + 3) { + grid-column: auto / span 3; + } + &:nth-of-type(9n + 2) { + grid-column: auto / span 2; + } + &:nth-of-type(9n + 1) { + grid-column: auto / span 2; + } + } + } + } + @media (min-width: 576px) and (min-width: 1024px) { + .waterfall-last { + grid-template-columns: repeat(14, 1fr); + .waterfall-last-item { + &:nth-of-type(15n + 15) { + grid-column: auto / span 3; + } + &:nth-of-type(15n + 14) { + grid-column: auto / span 3; + } + &:nth-of-type(15n + 13) { + grid-column: auto / span 2; + } + &:nth-of-type(15n + 12) { + grid-column: auto / span 3; + } + &:nth-of-type(15n + 11) { + grid-column: auto / span 3; + } + &:nth-of-type(15n + 10) { + grid-column: auto / span 2; + } + &:nth-of-type(15n + 9) { + grid-column: auto / span 3; + } + &:nth-of-type(15n + 8) { + grid-column: auto / span 3; + } + &:nth-of-type(15n + 7) { + grid-column: auto / span 3; + } + &:nth-of-type(15n + 6) { + grid-column: auto / span 3; + } + &:nth-of-type(15n + 5) { + grid-column: auto / span 3; + } + &:nth-of-type(15n + 4) { + grid-column: auto / span 3; + } + &:nth-of-type(15n + 3) { + grid-column: auto / span 3; + } + &:nth-of-type(15n + 2) { + grid-column: auto / span 3; + } + &:nth-of-type(15n + 1) { + grid-column: auto / span 2; + } + } + } + } +} +</style> diff --git a/src/views/pages/waves/index.vue b/src/views/pages/waves/index.vue new file mode 100644 index 0000000..405c71a --- /dev/null +++ b/src/views/pages/waves/index.vue @@ -0,0 +1,134 @@ +<template> + <div class="preview-container"> + <el-card shadow="hover" header="波浪指令效果(v-waves)作用于 btn"> + <el-row class="mb10" style="color: #808080">可选参数 v-waves=" |light|red|orange|purple|green|teal"</el-row> + <div class="flex-warp"> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <el-button size="default" v-waves> + <SvgIcon name="iconfont icon-bolangnengshiyanchang" /> + 默认效果 + </el-button> + </div> + </div> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <el-button type="primary" size="default" v-waves="'light'"> + <SvgIcon name="iconfont icon-bolangnengshiyanchang" /> + light 效果 + </el-button> + </div> + </div> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <el-button type="success" size="default" v-waves="'red'"> + <SvgIcon name="iconfont icon-bolangnengshiyanchang" /> + red 效果 + </el-button> + </div> + </div> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <el-button type="info" size="default" v-waves="'orange'"> + <SvgIcon name="iconfont icon-bolangnengshiyanchang" /> + orange 效果 + </el-button> + </div> + </div> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <el-button type="warning" size="default" v-waves="'purple'"> + <SvgIcon name="iconfont icon-bolangnengshiyanchang" /> + purple 效果 + </el-button> + </div> + </div> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <el-button type="danger" size="default" v-waves="'green'"> + <SvgIcon name="iconfont icon-bolangnengshiyanchang" /> + green 效果 + </el-button> + </div> + </div> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <el-button type="primary" size="default" v-waves="'teal'"> + <SvgIcon name="iconfont icon-bolangnengshiyanchang" /> + teal 效果 + </el-button> + </div> + </div> + </div> + </el-card> + <el-card shadow="hover" header="波浪指令效果(v-waves)作用于 div" class="mt15"> + <div class="waterfall-first"> + <div class="waterfall-first-item" v-for="v in 12" :key="v" v-waves> + <div class="w100 h100 flex"> + <span class="flex-margin">{{ v }}</span> + </div> + </div> + </div> + </el-card> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, defineComponent } from 'vue'; + +export default defineComponent({ + name: 'pagesWaves', + setup() { + const state = reactive({}); + return { + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.preview-container { + .flex-warp { + display: flex; + flex-wrap: wrap; + align-content: flex-start; + margin: 0 -5px; + .flex-warp-item { + padding: 5px; + .flex-warp-item-box { + width: 100%; + height: 100%; + } + } + } + .waterfall-first { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(188px, 1fr)); + grid-gap: 0.25em; + grid-auto-flow: row dense; + grid-auto-rows: 20px; + .waterfall-first-item { + width: 100%; + background: var(--el-color-primary); + color: var(--el-color-white); + transition: all 0.3s ease; + border-radius: 3px; + &:nth-of-type(3n + 1) { + grid-row: auto / span 5; + } + &:nth-of-type(3n + 2) { + grid-row: auto / span 6; + } + &:nth-of-type(3n + 3) { + grid-row: auto / span 8; + } + &:hover { + box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%); + transition: all 0.3s ease; + cursor: pointer; + } + } + } +} +</style> diff --git a/src/views/pages/workflow/component/contextmenu/index.vue b/src/views/pages/workflow/component/contextmenu/index.vue new file mode 100644 index 0000000..f55e06f --- /dev/null +++ b/src/views/pages/workflow/component/contextmenu/index.vue @@ -0,0 +1,107 @@ +<template> + <transition name="el-zoom-in-center"> + <div + aria-hidden="true" + class="el-dropdown__popper el-popper is-light is-pure custom-contextmenu" + role="tooltip" + data-popper-placement="bottom" + :style="`top: ${dropdowns.y + 5}px;left: ${dropdowns.x}px;`" + :key="Math.random()" + v-show="isShow" + > + <ul class="el-dropdown-menu"> + <li + v-for="(v, k) in dropdownList" + class="el-dropdown-menu__item" + aria-disabled="false" + tabindex="-1" + :key="k" + @click="onCurrentClick(v.contextMenuClickId)" + > + <SvgIcon :name="v.icon" /> + <span>{{ v.txt }}{{ item.type === 'line' ? '线' : '节点' }}</span> + </li> + </ul> + <div class="el-popper__arrow" style="left: 10px"></div> + </div> + </transition> +</template> + +<script lang="ts"> +import { computed, defineComponent, reactive, toRefs, onMounted, onUnmounted } from 'vue'; + +export default defineComponent({ + name: 'pagesWorkflowContextmenu', + props: { + dropdown: { + type: Object, + }, + }, + setup(props, { emit }) { + const state = reactive({ + isShow: false, + dropdownList: [ + { contextMenuClickId: 0, txt: '删除', icon: 'ele-Delete' }, + { contextMenuClickId: 1, txt: '编辑', icon: 'ele-Edit' }, + ], + item: { + type: 'node', + }, + conn: {}, + }); + // 父级传过来的坐标 x,y 值 + const dropdowns = computed(() => { + return <any>props.dropdown; + }); + // 当前项菜单点击 + const onCurrentClick = (contextMenuClickId: number) => { + emit('current', Object.assign({}, { contextMenuClickId }, state.item), state.conn); + }; + // 打开右键菜单:判断是否固定,固定则不显示关闭按钮 + const openContextmenu = (item: any, conn = {}) => { + state.item = item; + state.conn = conn; + closeContextmenu(); + setTimeout(() => { + state.isShow = true; + }, 10); + }; + // 关闭右键菜单 + const closeContextmenu = () => { + state.isShow = false; + }; + // 监听页面监听进行右键菜单的关闭 + onMounted(() => { + document.body.addEventListener('click', closeContextmenu); + document.body.addEventListener('contextmenu', closeContextmenu); + }); + // 页面卸载时,移除右键菜单监听事件 + onUnmounted(() => { + document.body.removeEventListener('click', closeContextmenu); + document.body.removeEventListener('contextmenu', closeContextmenu); + }); + return { + dropdowns, + openContextmenu, + closeContextmenu, + onCurrentClick, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.custom-contextmenu { + transform-origin: center top; + z-index: 2190; + position: fixed; + .el-dropdown-menu__item { + font-size: 12px !important; + white-space: nowrap; + i { + font-size: 12px !important; + } + } +} +</style> diff --git a/src/views/pages/workflow/component/drawer/index.vue b/src/views/pages/workflow/component/drawer/index.vue new file mode 100644 index 0000000..74478a2 --- /dev/null +++ b/src/views/pages/workflow/component/drawer/index.vue @@ -0,0 +1,73 @@ +<template> + <div> + <el-drawer :title="`${nodeData.type === 'line' ? '线' : '节点'}操作`" v-model="isOpen" size="320px"> + <el-scrollbar> + <Line v-if="nodeData.type === 'line'" @change="onLineChange" @close="close" ref="lineRef" /> + <Node v-else @submit="onNodeSubmit" @close="close" ref="nodeRef" /> + </el-scrollbar> + </el-drawer> + </div> +</template> + +<script lang="ts"> +import { defineComponent, reactive, toRefs, ref, nextTick } from 'vue'; +import Line from './line.vue'; +import Node from './node.vue'; + +// 定义接口来定义对象的类型 +interface WorkflowDrawerState { + isOpen: boolean; + nodeData: { + type: string; + }; + jsplumbConn: any; +} + +export default defineComponent({ + name: 'pagesWorkflowDrawer', + components: { Line, Node }, + setup(props, { emit }) { + const lineRef = ref(); + const nodeRef = ref(); + const state = reactive<WorkflowDrawerState>({ + isOpen: false, + nodeData: { + type: 'node', + }, + jsplumbConn: {}, + }); + // 打开抽屉 + const open = (item: any, conn: any) => { + state.isOpen = true; + state.jsplumbConn = conn; + state.nodeData = item; + nextTick(() => { + if (item.type === 'line') lineRef.value.getParentData(item); + else nodeRef.value.getParentData(item); + }); + }; + // 关闭 + const close = () => { + state.isOpen = false; + }; + // 线 label 内容改变时 + const onLineChange = (label: any) => { + state.jsplumbConn.label = label; + emit('label', state.jsplumbConn); + }; + // 节点内容改变时 + const onNodeSubmit = (data: object) => { + emit('node', data); + }; + return { + lineRef, + nodeRef, + open, + close, + onLineChange, + onNodeSubmit, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/pages/workflow/component/drawer/line.vue b/src/views/pages/workflow/component/drawer/line.vue new file mode 100644 index 0000000..a19c92a --- /dev/null +++ b/src/views/pages/workflow/component/drawer/line.vue @@ -0,0 +1,62 @@ +<template> + <div class="pt15 pr15 pb15 pl15"> + <el-form :model="line" size="default" label-width="50px"> + <el-form-item label="来往"> + <el-input v-model="line.contact" placeholder="来往" clearable disabled></el-input> + </el-form-item> + <el-form-item label="类型"> + <el-input v-model="line.type" placeholder="类型" clearable disabled></el-input> + </el-form-item> + <el-form-item label="label"> + <el-input v-model="line.label" placeholder="请输入label内容" clearable></el-input> + </el-form-item> + <el-form-item> + <el-button @click="onLineTextReset"> + <SvgIcon name="ele-RefreshRight" /> + 重置 + </el-button> + <el-button @click="onLineTextChange" type="primary"> + <SvgIcon name="ele-Check" /> + 保存 + </el-button> + </el-form-item> + </el-form> + </div> +</template> + +<script lang="ts"> +import { defineComponent, reactive, toRefs } from 'vue'; + +// 定义接口来定义对象的类型 +interface WorkflowDrawerLineState { + line: any; +} + +export default defineComponent({ + name: 'pagesWorkflowDrawerLine', + setup(props, { emit }) { + const state = reactive<WorkflowDrawerLineState>({ + line: {}, + }); + // 获取父组件数据 + const getParentData = (data: object) => { + state.line = data; + }; + // 重置 + const onLineTextReset = () => { + state.line.label = ''; + }; + // 保存 + const onLineTextChange = () => { + emit('change', state.line.label); + emit('close'); + }; + return { + getParentData, + onLineTextReset, + onLineTextChange, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/pages/workflow/component/drawer/node.vue b/src/views/pages/workflow/component/drawer/node.vue new file mode 100644 index 0000000..b68ccde --- /dev/null +++ b/src/views/pages/workflow/component/drawer/node.vue @@ -0,0 +1,272 @@ +<template> + <div class="workflow-drawer-node"> + <el-tabs type="border-card" v-model="tabsActive"> + <!-- 节点编辑 --> + <el-tab-pane label="节点编辑" name="1"> + <el-scrollbar> + <el-form :model="node" :rules="nodeRules" ref="nodeFormRef" size="default" label-width="80px" class="pt15 pr15 pb15 pl15"> + <el-form-item label="数据id" prop="id"> + <el-input v-model="node.id" placeholder="请输入数据id" clearable disabled></el-input> + </el-form-item> + <el-form-item label="节点id" prop="nodeId"> + <el-input v-model="node.nodeId" placeholder="请输入节点id" clearable disabled></el-input> + </el-form-item> + <el-form-item label="类型" prop="type"> + <el-input v-model="node.type" placeholder="请输入类型" clearable disabled></el-input> + </el-form-item> + <el-form-item label="left坐标" prop="left"> + <el-input v-model="node.left" placeholder="请输入left坐标" clearable disabled></el-input> + </el-form-item> + <el-form-item label="top坐标" prop="top"> + <el-input v-model="node.top" placeholder="请输入top坐标" clearable disabled></el-input> + </el-form-item> + <el-form-item label="icon图标" prop="icon"> + <el-input v-model="node.icon" placeholder="请输入icon图标" clearable></el-input> + </el-form-item> + <el-form-item label="名称" prop="name"> + <el-input v-model="node.name" placeholder="请输入名称" clearable></el-input> + </el-form-item> + <el-form-item> + <el-button class="mb15" @click="onNodeRefresh"> + <SvgIcon name="ele-RefreshRight" /> + 重置 + </el-button> + <el-button type="primary" class="mb15" @click="onNodeSubmit"> + <SvgIcon name="ele-Check" /> + 保存 + </el-button> + </el-form-item> + </el-form> + </el-scrollbar> + </el-tab-pane> + + <!-- 扩展表单 --> + <el-tab-pane label="扩展表单" name="2"> + <el-scrollbar> + <el-form :model="form" ref="extendFormRef" size="default" label-width="80px" class="pt15 pr15 pb15 pl15"> + <el-form-item + :label="val.label" + :prop="val.prop" + v-for="(val, key) in node.from" + :key="key" + :rules="[{ required: val.required, message: `${val.label}不能为空`, trigger: 'blur' }]" + > + <el-input + v-model="form[val.prop]" + :placeholder="val.placeholder" + clearable + v-if="val.type === 'input'" + :disabled="val.disabled" + ></el-input> + <el-select v-model="form[val.prop]" placeholder="请选择" v-if="val.type === 'select'" clearable :disabled="val.disabled"> + <el-option v-for="item in val.options" :key="item.value" :label="item.label" :value="item.value"> </el-option> + </el-select> + <el-checkbox-group v-model="form[val.prop]" v-if="val.type === 'checkbox'" :disabled="val.disabled"> + <el-checkbox label="美食推荐" name="type"></el-checkbox> + <el-checkbox label="统计分析" name="type"></el-checkbox> + </el-checkbox-group> + </el-form-item> + <el-form-item> + <el-button class="mb15" @click="onExtendRefresh"> + <SvgIcon name="ele-RefreshRight" /> + 重置 + </el-button> + <el-button type="primary" class="mb15" @click="onExtendSubmit" :loading="loading.extend"> + <SvgIcon name="ele-Check" /> + 保存 + </el-button> + </el-form-item> + </el-form> + </el-scrollbar> + </el-tab-pane> + + <!-- 图表可视化 --> + <el-tab-pane label="图表可视化" name="3"> + <el-scrollbar> + <div class="flex-content-right"> + <div style="height: 200px; width: 320px" ref="chartsMonitorRef"></div> + </div> + </el-scrollbar> + </el-tab-pane> + </el-tabs> + </div> +</template> + +<script lang="ts"> +import { defineComponent, reactive, toRefs, ref, nextTick, getCurrentInstance } from 'vue'; +import { ElMessage } from 'element-plus'; +import * as echarts from 'echarts'; + +// 定义接口来定义对象的类型 +interface WorkflowDrawerNodeState { + node: { [key: string]: any }; + nodeRules: any; + form: any; + tabsActive: string; + loading: { + extend: boolean; + }; +} + +export default defineComponent({ + name: 'pagesWorkflowDrawerNode', + setup(props, { emit }) { + const { proxy } = <any>getCurrentInstance(); + const nodeFormRef = ref(); + const extendFormRef = ref(); + const chartsMonitorRef = ref(); + const state = reactive<WorkflowDrawerNodeState>({ + node: {}, + nodeRules: { + id: [{ required: true, message: '请输入数据id', trigger: 'blur' }], + nodeId: [{ required: true, message: '请输入节点id', trigger: 'blur' }], + type: [{ required: true, message: '请输入类型', trigger: 'blur' }], + left: [{ required: true, message: '请输入left坐标', trigger: 'blur' }], + top: [{ required: true, message: '请输入top坐标', trigger: 'blur' }], + icon: [{ required: true, message: '请输入icon图标', trigger: 'blur' }], + name: [{ required: true, message: '请输入名称', trigger: 'blur' }], + }, + form: { + module: [], + }, + tabsActive: '1', + loading: { + extend: false, + }, + }); + // 获取父组件数据 + const getParentData = (data: object) => { + state.tabsActive = '1'; + state.node = data; + initChartsMonitor(); + }; + // 节点编辑-重置 + const onNodeRefresh = () => { + state.node.icon = ''; + state.node.name = ''; + }; + // 节点编辑-保存 + const onNodeSubmit = () => { + nodeFormRef.value.validate((valid: boolean) => { + if (valid) { + emit('submit', state.node); + emit('close'); + } else { + return false; + } + }); + }; + // 扩展表单-重置 + const onExtendRefresh = () => { + extendFormRef.value.resetFields(); + }; + // 扩展表单-保存 + const onExtendSubmit = () => { + extendFormRef.value.validate((valid: boolean) => { + if (valid) { + state.loading.extend = true; + setTimeout(() => { + state.loading.extend = false; + ElMessage.success('保存成功'); + emit('close'); + }, 1000); + } else { + return false; + } + }); + }; + // 图表可视化-初始化 + const initChartsMonitor = () => { + const myChart = echarts.init(proxy.$refs.chartsMonitorRef); + const numsOne = []; + const numsTwo = []; + for (let i = 0; i < 7; i++) { + numsOne.push(`${Math.floor(Math.random() * 52 + 10)}:${Math.floor(Math.random() * 52 + 1)}`); + numsTwo.push(Math.floor(Math.random() * 52 + 1)); + } + const option = { + grid: { + top: 50, + right: 30, + bottom: 30, + left: 50, + }, + tooltip: { + trigger: 'axis', + }, + xAxis: { + type: 'category', + boundaryGap: false, + data: numsOne, + }, + yAxis: { + type: 'value', + }, + series: [ + { + itemStyle: { + color: '#289df5', + borderColor: '#289df5', + areaStyle: { + type: 'default', + opacity: 0.1, + }, + }, + data: numsTwo, + type: 'line', + areaStyle: {}, + }, + ], + }; + myChart.setOption(option); + nextTick(() => { + myChart.resize(); + }); + }; + return { + nodeFormRef, + extendFormRef, + chartsMonitorRef, + getParentData, + onNodeRefresh, + onNodeSubmit, + onExtendRefresh, + onExtendSubmit, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.workflow-drawer-node { + ::v-deep { + .el-tabs { + box-shadow: unset; + border: unset; + .el-tabs__nav { + display: flex; + width: 100%; + .el-tabs__item { + flex: 1; + padding: unset; + text-align: center; + &:first-of-type.is-active { + border-left-color: transparent; + } + &:last-of-type.is-active { + border-right-color: transparent; + } + } + } + .el-tabs__content { + padding: 0; + height: calc(100vh - 90px); + .el-tab-pane { + height: 100%; + } + } + } + } +} +</style> diff --git a/src/views/pages/workflow/component/tool/help.vue b/src/views/pages/workflow/component/tool/help.vue new file mode 100644 index 0000000..09198b5 --- /dev/null +++ b/src/views/pages/workflow/component/tool/help.vue @@ -0,0 +1,39 @@ +<template> + <div class="workflow-tool-help"> + <el-dialog v-model="isShow" width="769px"> + <template #header> + <div v-drag="['.workflow-tool-help .el-dialog', '.workflow-tool-help .el-dialog__header']">使用帮助</div> + </template> + <div>1、拖入:鼠标移入左侧导航中,鼠标形状改变时拖动到右侧网格状的视图中。</div> + <div class="mt10">2、移动:鼠标移入到视图中的某个节点元素,鼠标形状改变时拖动改变位置。</div> + <div class="mt10">3、连线:鼠标移入到视图中的某个节点元素的icon(图标),鼠标形状改变(变成"+"),按下鼠标左键进行拖线连接。</div> + <div class="mt10">4、节点:鼠标移入到视图中的某个节点元素,点击鼠标右键可进行删除、编辑节点。</div> + <div class="mt10 mb10">5、线条:鼠标移入到视图中的某个线条,线条颜色改变时,点击鼠标右键可进行删除、编辑线条。</div> + </el-dialog> + </div> +</template> + +<script lang="ts"> +import { defineComponent, reactive, toRefs } from 'vue'; +export default defineComponent({ + name: 'pagesWorkflowToolHelp', + setup() { + const state = reactive({ + isShow: false, + }); + // 打开弹窗 + const open = () => { + state.isShow = true; + }; + // 关闭弹窗 + const close = () => { + state.isShow = false; + }; + return { + open, + close, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/pages/workflow/component/tool/index.vue b/src/views/pages/workflow/component/tool/index.vue new file mode 100644 index 0000000..2cb9940 --- /dev/null +++ b/src/views/pages/workflow/component/tool/index.vue @@ -0,0 +1,79 @@ +<template> + <div class="workflow-tool"> + <div class="pl15">{{ setToolTitle }}</div> + <div class="workflow-tool-right"> + <div class="workflow-tool-icon" v-for="(v, k) in toolList" :key="k" :title="v.title" @click="onToolClick(v.fnName)"> + <SvgIcon :name="v.icon" /> + </div> + </div> + </div> +</template> + +<script lang="ts"> +import { defineComponent, computed, reactive, toRefs } from 'vue'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; + +export default defineComponent({ + name: 'pagesWorkflowTool', + setup(props, { emit }) { + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const state = reactive({ + toolList: [ + { icon: 'ele-Help', title: '帮助', fnName: 'help' }, + { icon: 'ele-Download', title: '下载', fnName: 'download' }, + { icon: 'ele-Check', title: '提交', fnName: 'submit' }, + { icon: 'ele-DocumentCopy', title: '复制', fnName: 'copy' }, + { icon: 'ele-Delete', title: '删除', fnName: 'del' }, + { icon: 'ele-FullScreen', title: '全屏', fnName: 'fullscreen' }, + ], + }); + // 设置 tool 标题 + const setToolTitle = computed(() => { + let { globalTitle } = themeConfig.value; + return `${globalTitle}工作流`; + }); + // 顶部工具栏 + const onToolClick = (fnName: string) => { + emit('tool', fnName); + }; + return { + setToolTitle, + onToolClick, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.workflow-tool { + height: 35px; + display: flex; + align-items: center; + border-bottom: 1px solid var(--el-border-color-light, #ebeef5); + color: var(--el-text-color-primary); + .workflow-tool-right { + flex: 1; + display: flex; + justify-content: flex-end; + } + &-icon { + padding: 0 10px; + cursor: pointer; + color: var(--next-bg-topBarColor); + height: 35px; + line-height: 35px; + display: flex; + align-items: center; + &:hover { + background: rgba(0, 0, 0, 0.04); + i { + display: inline-block; + animation: logoAnimation 0.3s ease-in-out; + } + } + } +} +</style> diff --git a/src/views/pages/workflow/index.vue b/src/views/pages/workflow/index.vue new file mode 100644 index 0000000..a84e496 --- /dev/null +++ b/src/views/pages/workflow/index.vue @@ -0,0 +1,693 @@ +<template> + <div class="workflow-container"> + <div class="workflow-mask" v-if="isShow"></div> + <div class="layout-view-bg-white flex" :style="{ height: `calc(100vh - ${setViewHeight}` }"> + <div class="workflow"> + <!-- 顶部工具栏 --> + <Tool @tool="onToolClick" /> + + <!-- 左侧导航区 --> + <div class="workflow-content"> + <div class="workflow-left"> + <el-scrollbar> + <div + ref="leftNavRefs" + v-for="(val, key) in leftNavList" + :key="val.id" + :style="{ height: val.isOpen ? 'auto' : '50px', overflow: 'hidden' }" + class="workflow-left-id" + > + <div class="workflow-left-title" @click="onTitleClick(val)"> + <span>{{ val.title }}</span> + <SvgIcon :name="val.isOpen ? 'ele-ArrowDown' : 'ele-ArrowRight'" /> + </div> + <div class="workflow-left-item" v-for="(v, k) in val.children" :key="k" :data-name="v.name" :data-icon="v.icon" :data-id="v.id"> + <div class="workflow-left-item-icon"> + <SvgIcon :name="v.icon" class="workflow-icon-drag" /> + <div class="font10 pl5 name">{{ v.name }}</div> + </div> + </div> + </div> + </el-scrollbar> + </div> + + <!-- 右侧绘画区 --> + <div class="workflow-right" ref="workflowRightRef"> + <div + v-for="(v, k) in jsplumbData.nodeList" + :key="v.nodeId" + :id="v.nodeId" + :data-node-id="v.nodeId" + :class="v.class" + :style="{ left: v.left, top: v.top }" + @click="onItemCloneClick(k)" + @contextmenu.prevent="onContextmenu(v, k, $event)" + > + <div class="workflow-right-box" :class="{ 'workflow-right-active': jsPlumbNodeIndex === k }"> + <div class="workflow-left-item-icon"> + <SvgIcon :name="v.icon" class="workflow-icon-drag" /> + <div class="font10 pl5 name">{{ v.name }}</div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + + <!-- 节点右键菜单 --> + <Contextmenu :dropdown="dropdownNode" ref="contextmenuNodeRef" @current="onCurrentNodeClick" /> + <!-- 线右键菜单 --> + <Contextmenu :dropdown="dropdownLine" ref="contextmenuLineRef" @current="onCurrentLineClick" /> + <!-- 抽屉表单、线 --> + <Drawer ref="drawerRef" @label="setLineLabel" @node="setNodeContent" /> + + <!-- 顶部工具栏-帮助弹窗 --> + <Help ref="helpRef" /> + </div> +</template> + +<script lang="ts"> +import { defineComponent, toRefs, reactive, computed, onMounted, onUnmounted, nextTick, ref } from 'vue'; +import { ElMessage, ElMessageBox } from 'element-plus'; +import { jsPlumb } from 'jsplumb'; +import Sortable from 'sortablejs'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; +import Tool from './component/tool/index.vue'; +import Help from './component/tool/help.vue'; +import Contextmenu from './component/contextmenu/index.vue'; +import Drawer from './component/drawer/index.vue'; +import commonFunction from '/@/utils/commonFunction'; +import { leftNavList } from './js/mock'; +import { jsplumbDefaults, jsplumbMakeSource, jsplumbMakeTarget, jsplumbConnect } from './js/config'; + +// 定义接口来定义对象的类型 +interface NodeListState { + id: string | number; + nodeId: string | undefined; + class: HTMLElement | string; + left: number | string; + top: number | string; + icon: string; + name: string; +} +interface LineListState { + sourceId: string; + targetId: string; + label: string; +} +interface XyState { + x: string | number; + y: string | number; +} +interface WorkflowState { + workflowRightRef: HTMLDivElement | null; + leftNavRefs: any[]; + leftNavList: any[]; + dropdownNode: XyState; + dropdownLine: XyState; + isShow: boolean; + jsPlumb: any; + jsPlumbNodeIndex: null | number; + jsplumbDefaults: any; + jsplumbMakeSource: any; + jsplumbMakeTarget: any; + jsplumbConnect: any; + jsplumbData: { + nodeList: Array<NodeListState>; + lineList: Array<LineListState>; + }; +} + +export default defineComponent({ + name: 'pagesWorkflow', + components: { Tool, Contextmenu, Drawer, Help }, + setup() { + const contextmenuNodeRef = ref(); + const contextmenuLineRef = ref(); + const drawerRef = ref(); + const helpRef = ref(); + const stores = useTagsViewRoutes(); + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const { isTagsViewCurrenFull } = storeToRefs(stores); + const { copyText } = commonFunction(); + const state = reactive<WorkflowState>({ + workflowRightRef: null as HTMLDivElement | null, + leftNavRefs: [], + leftNavList: [], + dropdownNode: { x: '', y: '' }, + dropdownLine: { x: '', y: '' }, + isShow: false, + jsPlumb: null, + jsPlumbNodeIndex: null, + jsplumbDefaults, + jsplumbMakeSource, + jsplumbMakeTarget, + jsplumbConnect, + jsplumbData: { + nodeList: [], + lineList: [], + }, + }); + // 设置 view 的高度 + const setViewHeight = computed(() => { + let { isTagsview } = themeConfig.value; + if (isTagsViewCurrenFull.value) { + return `30px`; + } else { + if (isTagsview) return `114px`; + else return `80px`; + } + }); + // 设置 宽度小于 768,不支持操 + const setClientWidth = () => { + const clientWidth = document.body.clientWidth; + clientWidth < 768 ? (state.isShow = true) : (state.isShow = false); + }; + // 左侧导航-数据初始化 + const initLeftNavList = () => { + state.leftNavList = leftNavList; + state.jsplumbData = { + nodeList: [ + { nodeId: 'huej738hbji', left: '148px', top: '93px', class: 'workflow-right-clone', icon: 'iconfont icon-gongju', name: '引擎', id: '11' }, + { + nodeId: '52kcszzyxrd', + left: '458px', + top: '203px', + class: 'workflow-right-clone', + icon: 'iconfont icon-shouye_dongtaihui', + name: '模版', + id: '12', + }, + { + nodeId: 'nltskl6k4me', + left: '164px', + top: '350px', + class: 'workflow-right-clone', + icon: 'iconfont icon-zhongduancanshuchaxun', + name: '名称', + id: '13', + }, + ], + lineList: [ + { sourceId: 'huej738hbji', targetId: '52kcszzyxrd', label: '传送' }, + { sourceId: 'huej738hbji', targetId: 'nltskl6k4me', label: '' }, + ], + }; + }; + // 左侧导航-初始化拖动 + const initSortable = () => { + state.leftNavRefs.forEach(v => { + Sortable.create(v as HTMLDivElement, { + group: { + name: 'vue-next-admin-1', + pull: 'clone', + put: false, + }, + animation: 0, + sort: false, + draggable: '.workflow-left-item', + forceFallback: true, + onEnd: function (evt: any) { + const { name, icon, id } = evt.clone.dataset; + const { layerX, layerY, clientX, clientY } = evt.originalEvent; + const el = state.workflowRightRef!; + const { x, y, width, height } = el.getBoundingClientRect(); + if (clientX < x || clientX > width + x || clientY < y || y > y + height) { + ElMessage.warning('请把节点拖入到画布中'); + } else { + // 节点id(唯一) + const nodeId = Math.random().toString(36).substr(2, 12); + // 处理节点数据 + const node = { + nodeId, + left: `${layerX - 40}px`, + top: `${layerY - 15}px`, + class: 'workflow-right-clone', + name, + icon, + id, + }; + // 右侧视图内容数组 + state.jsplumbData.nodeList.push(node); + // 元素加载完毕时 + nextTick(() => { + // 整个节点作为source或者target + state.jsPlumb.makeSource(nodeId, state.jsplumbMakeSource); + // // 整个节点作为source或者target + state.jsPlumb.makeTarget(nodeId, state.jsplumbMakeTarget, jsplumbConnect); + // 设置节点可以拖拽(此处为id值,非class) + state.jsPlumb.draggable(nodeId, { + containment: 'parent', + stop: (el: any) => { + state.jsplumbData.nodeList.forEach((v) => { + if (v.nodeId === el.el.id) { + // 节点x, y重新赋值,防止再次从左侧导航中拖拽节点时,x, y恢复默认 + v.left = `${el.pos[0]}px`; + v.top = `${el.pos[1]}px`; + } + }); + }, + }); + }); + } + }, + }); + }); + }; + // 初始化 jsPlumb + const initJsPlumb = () => { + (<any>jsPlumb).ready(() => { + state.jsPlumb = (<any>jsPlumb).getInstance({ + detachable: false, + Container: 'workflow-right', + }); + state.jsPlumb.fire('jsPlumbDemoLoaded', state.jsPlumb); + // 导入默认配置 + state.jsPlumb.importDefaults(state.jsplumbDefaults); + // 会使整个jsPlumb立即重绘。 + state.jsPlumb.setSuspendDrawing(false, true); + // 初始化节点、线的链接 + initJsPlumbConnection(); + // 点击线弹出右键菜单 + state.jsPlumb.bind('contextmenu', (conn: any, originalEvent: MouseEvent) => { + originalEvent.preventDefault(); + const { sourceId, targetId } = conn; + const { clientX, clientY } = originalEvent; + state.dropdownLine.x = clientX; + state.dropdownLine.y = clientY; + const v: any = state.jsplumbData.nodeList.find((v) => v.nodeId === targetId); + const line: any = state.jsplumbData.lineList.find((v) => v.sourceId === sourceId && v.targetId === targetId); + v.type = 'line'; + v.label = line.label; + contextmenuLineRef.value.openContextmenu(v, conn); + }); + // 连线之前 + state.jsPlumb.bind('beforeDrop', (conn: any) => { + const { sourceId, targetId } = conn; + const item = state.jsplumbData.lineList.find((v) => v.sourceId === sourceId && v.targetId === targetId); + if (item) { + ElMessage.warning('关系已存在,不可重复连接'); + return false; + } else { + return true; + } + }); + // 连线时 + state.jsPlumb.bind('connection', (conn: any) => { + const { sourceId, targetId } = conn; + state.jsplumbData.lineList.push({ + sourceId, + targetId, + label: '', + }); + }); + // 删除连线时回调函数 + state.jsPlumb.bind('connectionDetached', (conn: any) => { + const { sourceId, targetId } = conn; + state.jsplumbData.lineList = state.jsplumbData.lineList.filter((line) => { + if (line.sourceId == sourceId && line.targetId == targetId) { + return false; + } + return true; + }); + }); + }); + }; + // 初始化节点、线的链接 + const initJsPlumbConnection = () => { + // 节点 + state.jsplumbData.nodeList.forEach((v) => { + // 整个节点作为source或者target + state.jsPlumb.makeSource(v.nodeId, state.jsplumbMakeSource); + // 整个节点作为source或者target + state.jsPlumb.makeTarget(v.nodeId, state.jsplumbMakeTarget, jsplumbConnect); + // 设置节点可以拖拽(此处为id值,非class) + state.jsPlumb.draggable(v.nodeId, { + containment: 'parent', + stop: (el: any) => { + state.jsplumbData.nodeList.forEach((v) => { + if (v.nodeId === el.el.id) { + // 节点x, y重新赋值,防止再次从左侧导航中拖拽节点时,x, y恢复默认 + v.left = `${el.pos[0]}px`; + v.top = `${el.pos[1]}px`; + } + }); + }, + }); + }); + // 线 + state.jsplumbData.lineList.forEach((v) => { + state.jsPlumb.connect( + { + source: v.sourceId, + target: v.targetId, + label: v.label, + }, + state.jsplumbConnect + ); + }); + }; + // 左侧导航-菜单标题点击 + const onTitleClick = (val: any) => { + val.isOpen = !val.isOpen; + }; + // 右侧内容区-当前项点击 + const onItemCloneClick = (k: number) => { + state.jsPlumbNodeIndex = k; + }; + // 右侧内容区-当前项右键菜单点击 + const onContextmenu = (v: any, k: number, e: MouseEvent) => { + state.jsPlumbNodeIndex = k; + const { clientX, clientY } = e; + state.dropdownNode.x = clientX; + state.dropdownNode.y = clientY; + v.type = 'node'; + v.label = ''; + let item: any = {}; + state.leftNavList.forEach((l) => { + if (l.children) if (l.children.find((c: any) => c.id === v.id)) item = l.children.find((c: any) => c.id === v.id); + }); + v.from = item.form; + contextmenuNodeRef.value.openContextmenu(v); + }; + // 右侧内容区-当前项右键菜单点击回调(节点) + const onCurrentNodeClick = (item: any) => { + const { contextMenuClickId, nodeId } = item; + if (contextMenuClickId === 0) { + const nodeIndex = state.jsplumbData.nodeList.findIndex((item) => item.nodeId === nodeId); + state.jsplumbData.nodeList.splice(nodeIndex, 1); + state.jsPlumb.removeAllEndpoints(nodeId); + state.jsPlumbNodeIndex = null; + } else if (contextMenuClickId === 1) { + drawerRef.value.open(item); + } + }; + // 右侧内容区-当前项右键菜单点击回调(线) + const onCurrentLineClick = (item: any, conn: any) => { + const { contextMenuClickId } = item; + const { endpoints } = conn; + const intercourse: any = []; + endpoints.forEach((v: any) => { + intercourse.push({ + id: v.element.id, + innerText: v.element.innerText, + }); + }); + item.contact = `${intercourse[0].innerText}(${intercourse[0].id}) => ${intercourse[1].innerText}(${intercourse[1].id})`; + if (contextMenuClickId === 0) state.jsPlumb.deleteConnection(conn); + else if (contextMenuClickId === 1) drawerRef.value.open(item, conn); + }; + // 设置线的 label + const setLineLabel = (obj: any) => { + const { sourceId, targetId, label } = obj; + const conn = state.jsPlumb.getConnections({ + source: sourceId, + target: targetId, + })[0]; + conn.setLabel(label); + if (!label || label === '') { + conn.addClass('workflow-right-empty-label'); + } else { + conn.removeClass('workflow-right-empty-label'); + conn.addClass('workflow-right-label'); + } + state.jsplumbData.lineList.forEach((v) => { + if (v.sourceId === sourceId && v.targetId === targetId) v.label = label; + }); + }; + // 设置节点内容 + const setNodeContent = (obj: any) => { + const { nodeId, name, icon } = obj; + // 设置节点 name 与 icon + state.jsplumbData.nodeList.forEach((v) => { + if (v.nodeId === nodeId) { + v.name = name; + v.icon = icon; + } + }); + // 重绘 + nextTick(() => { + state.jsPlumb.setSuspendDrawing(false, true); + }); + }; + // 顶部工具栏-当前项点击 + const onToolClick = (fnName: String) => { + switch (fnName) { + case 'help': + onToolHelp(); + break; + case 'download': + onToolDownload(); + break; + case 'submit': + onToolSubmit(); + break; + case 'copy': + onToolCopy(); + break; + case 'del': + onToolDel(); + break; + case 'fullscreen': + onToolFullscreen(); + break; + } + }; + // 顶部工具栏-帮助 + const onToolHelp = () => { + nextTick(() => { + helpRef.value.open(); + }); + }; + // 顶部工具栏-下载 + const onToolDownload = () => { + const { globalTitle } = themeConfig.value; + const href = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(state.jsplumbData, null, '\t')); + const aLink = document.createElement('a'); + aLink.setAttribute('href', href); + aLink.setAttribute('download', `${globalTitle}工作流.json`); + aLink.click(); + aLink.remove(); + ElMessage.success('下载成功'); + }; + // 顶部工具栏-提交 + const onToolSubmit = () => { + // console.log(state.jsplumbData); + ElMessage.success('数据提交成功'); + }; + // 顶部工具栏-复制 + const onToolCopy = () => { + copyText(JSON.stringify(state.jsplumbData)); + }; + // 顶部工具栏-删除 + const onToolDel = () => { + ElMessageBox.confirm('此操作将清空画布,是否继续?', '提示', { + confirmButtonText: '清空', + cancelButtonText: '取消', + }) + .then(() => { + state.jsplumbData.nodeList.forEach((v) => { + state.jsPlumb.removeAllEndpoints(v.nodeId); + }); + nextTick(() => { + state.jsplumbData = { + nodeList: [], + lineList: [], + }; + ElMessage.success('清空画布成功'); + }); + }) + .catch(() => {}); + }; + // 顶部工具栏-全屏 + const onToolFullscreen = () => { + stores.setCurrenFullscreen(true); + }; + // 页面加载时 + onMounted(async () => { + await initLeftNavList(); + initSortable(); + initJsPlumb(); + setClientWidth(); + window.addEventListener('resize', setClientWidth); + }); + // 页面卸载时 + onUnmounted(() => { + window.removeEventListener('resize', setClientWidth); + }); + return { + setViewHeight, + setClientWidth, + setLineLabel, + setNodeContent, + onTitleClick, + onItemCloneClick, + onContextmenu, + onCurrentNodeClick, + onCurrentLineClick, + contextmenuNodeRef, + contextmenuLineRef, + drawerRef, + helpRef, + onToolClick, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.workflow-container { + position: relative; + .workflow { + display: flex; + height: 100%; + width: 100%; + flex-direction: column; + .workflow-content { + display: flex; + height: calc(100% - 35px); + .workflow-left { + width: 220px; + height: 100%; + border-right: 1px solid var(--el-border-color-light, #ebeef5); + ::v-deep(.el-collapse-item__content) { + padding-bottom: 0; + } + .workflow-left-title { + height: 50px; + display: flex; + align-items: center; + padding: 0 10px; + border-top: 1px solid var(--el-border-color-light, #ebeef5); + color: var(--el-text-color-primary); + cursor: default; + span { + flex: 1; + } + } + .workflow-left-item { + display: inline-block; + width: calc(50% - 15px); + position: relative; + cursor: move; + margin: 0 0 10px 10px; + .workflow-left-item-icon { + height: 35px; + display: flex; + align-items: center; + transition: all 0.3s ease; + padding: 5px 10px; + border: 1px dashed transparent; + background: var(--next-bg-color); + border-radius: 3px; + i, + .name { + color: var(--el-text-color-secondary); + transition: all 0.3s ease; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + } + &:hover { + transition: all 0.3s ease; + border: 1px dashed var(--el-color-primary); + background: var(--el-color-primary-light-9); + border-radius: 5px; + i, + .name { + transition: all 0.3s ease; + color: var(--el-color-primary); + } + } + } + } + & .workflow-left-id:first-of-type { + .workflow-left-title { + border-top: none; + } + } + } + .workflow-right { + flex: 1; + position: relative; + overflow: hidden; + height: 100%; + background-image: linear-gradient(90deg, rgb(156 214 255 / 15%) 10%, rgba(0, 0, 0, 0) 10%), + linear-gradient(rgb(156 214 255 / 15%) 10%, rgba(0, 0, 0, 0) 10%); + background-size: 10px 10px; + .workflow-right-clone { + position: absolute; + .workflow-right-box { + height: 35px; + align-items: center; + color: var(--el-text-color-secondary); + padding: 0 10px; + border-radius: 3px; + cursor: move; + transition: all 0.3s ease; + min-width: 94.5px; + background: var(--el-color-white); + border: 1px solid var(--el-border-color-light, #ebeef5); + .workflow-left-item-icon { + display: flex; + align-items: center; + height: 35px; + } + &:hover { + border: 1px dashed var(--el-color-primary); + background: var(--el-color-primary-light-9); + transition: all 0.3s ease; + color: var(--el-color-primary); + i { + cursor: Crosshair; + } + } + } + .workflow-right-active { + border: 1px dashed var(--el-color-primary); + background: var(--el-color-primary-light-9); + color: var(--el-color-primary); + } + } + ::v-deep(.jtk-overlay):not(.aLabel) { + padding: 4px 10px; + border: 1px solid var(--el-border-color-light, #ebeef5) !important; + color: var(--el-text-color-secondary) !important; + background: var(--el-color-white) !important; + border-radius: 3px; + font-size: 10px; + } + ::v-deep(.jtk-overlay.workflow-right-empty-label) { + display: none; + } + } + } + } + .workflow-mask { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + &::after { + content: '手机版不支持 jsPlumb 操作'; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1; + background: rgba(255, 255, 255, 0.9); + color: #666666; + display: flex; + align-items: center; + justify-content: center; + } + } +} +</style> diff --git a/src/views/pages/workflow/js/config.ts b/src/views/pages/workflow/js/config.ts new file mode 100644 index 0000000..3784c02 --- /dev/null +++ b/src/views/pages/workflow/js/config.ts @@ -0,0 +1,99 @@ +// jsplumb 默认配置 +export const jsplumbDefaults = { + // 多个锚点 [源锚点,目标锚点] + Anchors: [ + 'Top', + 'TopCenter', + 'TopRight', + 'TopLeft', + 'Right', + 'RightMiddle', + 'Bottom', + 'BottomCenter', + 'BottomRight', + 'BottomLeft', + 'Left', + 'LeftMiddle', + ], + // 连线的容器id + Container: 'workflow-right', + // 设置链接线的形状,如直线或者曲线之类的。anchor可以去设置锚点的位置。可选值"<Bezier|Flowchart|StateMachine|Straight>" + Connector: ['Bezier', { curviness: 100 }], + // 节点是否可以用鼠标拖动使其断开,默认为true。即用鼠标链接上的连线,也可以使用鼠标拖动让其断开。设置成false,可以让其拖动也不会自动断开 + ConnectionsDetachable: false, + // 删除线的时候节点不删除 + DeleteEndpointsOnDetach: false, + // 每当添加或以其他方式创建 Endpoint 并且 jsPlumb 尚未给出任何明确的 Endpoint 定义时将使用 + Endpoint: ['Blank', { Overlays: '' }], + // 连接中源和目标端点的默认外观 + EndpointStyle: { fill: '#1879ffa1', outlineWidth: 1 }, + // jsPlumb 的内部日志记录是否打开 + LogEnabled: true, + // 连接器的默认外观 + PaintStyle: { + stroke: '#E0E3E7', + strokeWidth: 1, + outlineStroke: 'transparent', + outlineWidth: 10, + }, + // 用于配置任何可拖动元素的默认选项jsPlumb.draggable + DragOptions: { cursor: 'pointer', zIndex: 2000 }, + // 添加到连接器和端点的默认叠加层。已弃用:从 4.x 开始,将不支持此功能。并非所有叠加层都可以连接到连接器和端点。 + Overlays: [ + [ + 'Arrow', + { + width: 10, // 箭头尾部的宽度 + length: 8, // 从箭头的尾部到头部的距离 + location: 1, // 位置,建议使用0~1之间 + direction: 1, // 方向,默认值为1(表示向前),可选-1(表示向后) + foldback: 0.623, // 折回,也就是尾翼的角度,默认0.623,当为1时,为正三角 + }, + ], + [ + 'Label', + { + label: '', + location: 0.5, + cssClass: 'aLabel', + }, + ], + ], + // 默认渲染模式 svg、canvas + RenderMode: 'svg', + // 悬停状态下连接的默认外观 + HoverPaintStyle: { stroke: '#b0b2b5', strokeWidth: 1 }, + // 悬停状态下端点的默认外观 + EndpointHoverStyle: { fill: 'red' }, + // 端点和连接的默认范围。范围提供了对哪些端点可以连接到哪些其他端点的基本控制 + Scope: 'jsPlumb_DefaultScope', +}; + +// 整个节点作为source或者target +export const jsplumbMakeSource = { + // 设置可以拖拽的类名,只要鼠标移动到该类名上的DOM,就可以拖拽连线 + filter: '.workflow-icon-drag', + filterExclude: false, + anchor: 'Continuous', + // 是否允许自己连接自己 + allowLoopback: true, + maxConnections: -1, +}; + +// 整个节点作为source或者target +export const jsplumbMakeTarget = { + filter: '.workflow-icon-drag', + filterExclude: false, + // 是否允许自己连接自己 + anchor: 'Continuous', + allowLoopback: true, + dropOptions: { hoverClass: 'ef-drop-hover' }, +}; + +// 连线参数 +export const jsplumbConnect = { + isSource: true, + isTarget: true, + // 动态锚点、提供了4个方向 Continuous、AutoDefault + anchor: 'Continuous', +}; diff --git a/src/views/pages/workflow/js/mock.ts b/src/views/pages/workflow/js/mock.ts new file mode 100644 index 0000000..151c3ac --- /dev/null +++ b/src/views/pages/workflow/js/mock.ts @@ -0,0 +1,262 @@ +// 左侧菜单导航数据 +export const leftNavList = [ + { + title: '工作流', + icon: 'iconfont icon-shouye', + isOpen: true, + id: '1', + children: [ + { + icon: 'iconfont icon-gongju', + name: '引擎', + id: '11', + form: [ + { + type: 'input', + label: '客户姓名', + prop: 'name', + placeholder: '请输入客户姓名', + required: true, + disabled: false, + }, + { + type: 'select', + label: '性别', + prop: 'sex', + placeholder: '请选择性别', + required: true, + disabled: false, + options: [ + { + value: '0', + label: '女', + }, + { + value: '1', + label: '男', + }, + ], + }, + { + type: 'input', + label: '员工编号', + prop: 'number', + placeholder: '请输入员工编号', + required: true, + disabled: false, + }, + { + type: 'input', + label: '办公电话', + prop: 'mobile', + placeholder: '请输入办公电话', + required: true, + disabled: false, + }, + { + type: 'select', + label: '权限分配', + prop: 'role', + placeholder: '请选择性别', + required: true, + disabled: false, + options: [ + { + value: '0', + label: '编辑权限', + }, + { + value: '1', + label: '删除权限', + }, + ], + }, + { + type: 'checkbox', + label: '模块选择', + prop: 'module', + placeholder: '请选择模块', + required: true, + disabled: false, + }, + ], + }, + { + icon: 'iconfont icon-shouye_dongtaihui', + name: '模版', + id: '12', + form: [ + { + type: 'input', + label: '等级', + prop: 'grade', + placeholder: '请输入等级', + required: true, + disabled: false, + }, + { + type: 'input', + label: '登记密码', + prop: 'password', + placeholder: '请输入登记密码', + required: true, + disabled: false, + }, + ], + }, + { + icon: 'iconfont icon-zhongduancanshuchaxun', + name: '名称', + id: '13', + form: [ + { + type: 'input', + label: '数据表', + prop: 'dataSheet', + placeholder: '请输入数据表', + required: true, + disabled: false, + }, + { + type: 'input', + label: '字段配置', + prop: 'field', + placeholder: '请输入字段配置', + required: true, + disabled: false, + }, + ], + }, + { + icon: 'iconfont icon-zhongduancanshu', + name: '版本', + id: '14', + form: [ + { + type: 'input', + label: '发布模板', + prop: 'publish', + placeholder: '请输入发布模板', + required: true, + disabled: false, + }, + ], + }, + { + icon: 'iconfont icon-bolangnengshiyanchang', + name: '建模', + id: '15', + form: [ + { + type: 'input', + label: '内容模板', + prop: 'content', + placeholder: '请输入内容模板', + required: true, + disabled: false, + }, + ], + }, + { + icon: 'iconfont icon-xingqiu', + name: '节点', + id: '16', + form: [ + { + type: 'input', + label: '活动名称6', + prop: 'name16', + }, + ], + }, + ], + }, + { + title: '流程', + isOpen: true, + icon: 'iconfont icon-caijian', + id: '2', + children: [ + { + icon: 'iconfont icon-fuwenben', + name: '实例', + id: '21', + form: [ + { + type: 'input', + label: '活动名称7', + prop: 'name21', + }, + ], + }, + { + icon: 'iconfont icon-fuwenbenkuang', + name: '轨迹', + id: '22', + form: [ + { + type: 'input', + label: '活动名称8', + prop: 'name22', + }, + ], + }, + { + icon: 'iconfont icon-shangchuan', + name: '数据', + id: '23', + form: [ + { + type: 'input', + label: '活动名称9', + prop: 'name23', + }, + ], + }, + ], + }, + { + title: '任务', + isOpen: true, + icon: 'iconfont icon-shuju', + id: '3', + children: [ + { + icon: 'iconfont icon-icon-', + name: '参与人', + id: '31', + form: [ + { + type: 'input', + label: '活动名称1', + prop: 'name31', + }, + ], + }, + { + icon: 'iconfont icon-gerenzhongxin', + name: '执行人', + id: '32', + form: [ + { + type: 'input', + label: '活动名称2', + prop: 'name32', + }, + ], + }, + { + icon: 'iconfont icon-fangkuang', + name: '工单', + id: '33', + form: [ + { + type: 'input', + label: '活动名称3', + prop: 'name33', + }, + ], + }, + ], + }, +]; diff --git a/src/views/params/common/details.vue b/src/views/params/common/details.vue new file mode 100644 index 0000000..9ba885e --- /dev/null +++ b/src/views/params/common/details.vue @@ -0,0 +1,52 @@ +<template> + <div class="layout-view-bg-white flex" :style="{ height: `calc(100vh - ${setViewHeight}` }"> + <div class="flex-margin color-primary"> + <div>paramsCommonDetails</div> + <div class="mt10 mb10">路径:path: {{ params.path }}</div> + <div>参数:query: {{ params.query }}</div> + </div> + </div> +</template> + +<script lang="ts"> +import { defineComponent, toRefs, reactive, computed, onMounted } from 'vue'; +import { useRoute } from 'vue-router'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; + +export default defineComponent({ + name: 'paramsCommonDetails', + setup() { + const route = useRoute(); + const storesTagsViewRoutes = useTagsViewRoutes(); + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes); + const state = reactive({ + params: { + path: '', + query: '', + }, + }); + // 设置 view 的高度 + const setViewHeight = computed(() => { + let { isTagsview } = themeConfig.value; + if (isTagsViewCurrenFull.value) { + return `30px`; + } else { + if (isTagsview) return `114px`; + else return `80px`; + } + }); + // 页面加载时 + onMounted(() => { + state.params = <any>route; + }); + return { + setViewHeight, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/params/common/index.vue b/src/views/params/common/index.vue new file mode 100644 index 0000000..733156c --- /dev/null +++ b/src/views/params/common/index.vue @@ -0,0 +1,100 @@ +<template> + <div class="layout-view-bg-white flex" :style="{ height: `calc(100vh - ${setViewHeight}` }"> + <div class="flex-margin" style="width: 400px"> + <el-result icon="success" title="普通路由" subTitle="可 `开启 TagsView 共用` 进行单标签测试"> + <template #extra> + <el-alert type="success" :closable="false" class="mb30"> + <template #default> + <div>1、设置非国际化:格式:tagsViewName=xxx</div> + <br /> + <div>2、设置国际化:格式:tagsViewName=JSON.stringify({"zh-cn":"测试用","en":"test+page","zh-tw":"測試用"})</div> + <br /> + <div>3、设置国际化后,去顶栏切换语言查看演示效果</div> + <br /> + <div> + 4、 <a href="https://gitee.com/q7but" target="_black">感谢@q7but</a>、 + <a href="https://gitee.com/lyt-top/vue-next-admin/pulls/22/files" target="_black">!22 add 添加自定义 tagVIewName 拓展,支持国际化</a> + </div> + </template> + </el-alert> + <el-input v-model="tagsViewName" placeholder="请输入tagsView 名称" clearable class="mb15" style="width: 400px"></el-input> + <el-input v-model="value" placeholder="请输入路由参数 id 值" clearable style="width: 400px"></el-input> + <el-button type="primary" size="default" class="mt15" @click="onGoDetailsClick"> + <SvgIcon name="iconfont icon-putong" /> + 普通路由传参 + </el-button> + <el-button type="primary" size="default" class="mt15" @click="onChangeI18n"> + <SvgIcon name="iconfont icon-fuhao-zhongwen" /> + {{ tagsViewNameIsI18n ? '普通的演示' : '国际化演示' }} + </el-button> + </template> + </el-result> + </div> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, computed, defineComponent } from 'vue'; +import { useRouter } from 'vue-router'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; + +export default defineComponent({ + name: 'paramsCommon', + setup() { + const storesTagsViewRoutes = useTagsViewRoutes(); + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes); + const state = reactive({ + value: '', + tagsViewName: '', + tagsViewNameIsI18n: false, + }); + const router = useRouter(); + // 设置 view 的高度 + const setViewHeight = computed(() => { + let { isTagsview } = themeConfig.value; + if (isTagsViewCurrenFull.value) { + return `30px`; + } else { + if (isTagsview) return `114px`; + else return `80px`; + } + }); + // 跳转到详情 + /** + * 设置 tagsView 名称: + * 传不同的 tagsViewName 值 + */ + const onGoDetailsClick = () => { + const params: any = { id: state.value }; + if (state.tagsViewName) params.tagsViewName = state.tagsViewName; + router.push({ + path: '/params/common/details', + query: params, + }); + state.value = ''; + }; + const onChangeI18n = () => { + state.tagsViewNameIsI18n = !state.tagsViewNameIsI18n; + if (state.tagsViewNameIsI18n) { + state.tagsViewName = JSON.stringify({ + 'zh-cn': '测试用', + en: 'test page', + 'zh-tw': '測試用', + }); + } else { + state.tagsViewName = '我是普通路由测试tagsViewName(非国际化)'; + } + }; + return { + setViewHeight, + onGoDetailsClick, + onChangeI18n, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/params/dynamic/details.vue b/src/views/params/dynamic/details.vue new file mode 100644 index 0000000..7283ba1 --- /dev/null +++ b/src/views/params/dynamic/details.vue @@ -0,0 +1,52 @@ +<template> + <div class="layout-view-bg-white flex" :style="{ height: `calc(100vh - ${setViewHeight}` }"> + <div class="flex-margin color-primary"> + <div>paramsDynamicDetails</div> + <div class="mt10 mb10">路径:path: {{ params.path }}</div> + <div>参数:params: {{ params.params }}</div> + </div> + </div> +</template> + +<script lang="ts"> +import { defineComponent, toRefs, reactive, computed, onMounted } from 'vue'; +import { useRoute } from 'vue-router'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; + +export default defineComponent({ + name: 'paramsDynamicDetails', + setup() { + const storesTagsViewRoutes = useTagsViewRoutes(); + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes); + const route = useRoute(); + const state = reactive({ + params: { + path: '', + params: '', + }, + }); + // 设置 view 的高度 + const setViewHeight = computed(() => { + let { isTagsview } = themeConfig.value; + if (isTagsViewCurrenFull.value) { + return `30px`; + } else { + if (isTagsview) return `114px`; + else return `80px`; + } + }); + // 页面加载时 + onMounted(() => { + state.params = <any>route; + }); + return { + setViewHeight, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/params/dynamic/index.vue b/src/views/params/dynamic/index.vue new file mode 100644 index 0000000..5c39f5d --- /dev/null +++ b/src/views/params/dynamic/index.vue @@ -0,0 +1,102 @@ +<template> + <div class="layout-view-bg-white flex" :style="{ height: `calc(100vh - ${setViewHeight}` }"> + <div class="flex-margin" style="width: 400px"> + <el-result icon="warning" title="动态路由" subTitle="可 `开启 TagsView 共用` 进行单标签测试"> + <template #extra> + <el-alert type="success" :closable="false" class="mb30"> + <template #default> + <div>1、设置非国际化:格式:tagsViewName=xxx</div> + <br /> + <div>2、设置国际化:格式:tagsViewName=JSON.stringify({"zh-cn":"测试用","en":"test+page","zh-tw":"測試用"})</div> + <br /> + <div>3、设置国际化后,去顶栏切换语言查看演示效果</div> + <br /> + <div> + 4、 <a href="https://gitee.com/q7but" target="_black">感谢@q7but</a>、 + <a href="https://gitee.com/lyt-top/vue-next-admin/pulls/22/files" target="_black">!22 add 添加自定义 tagVIewName 拓展,支持国际化</a> + </div> + </template> + </el-alert> + <el-input v-model="tagsViewName" placeholder="请输入tagsView 名称" clearable class="mb15" style="width: 400px"></el-input> + <el-input v-model="value" placeholder="请输入路由参数id值" clearable style="width: 400px"></el-input> + <el-button type="primary" size="default" class="mt15" @click="onGoDetailsClick"> + <SvgIcon name="iconfont icon-dongtai" /> + 动态路由传参 + </el-button> + <el-button type="primary" size="default" class="mt15" @click="onChangeI18n"> + <SvgIcon name="iconfont icon-fuhao-zhongwen" /> + {{ tagsViewNameIsI18n ? '普通的演示' : '国际化演示' }} + </el-button> + </template> + </el-result> + </div> + </div> +</template> + +<script lang="ts"> +import { defineComponent, toRefs, reactive, computed } from 'vue'; +import { useRouter } from 'vue-router'; +import { ElMessage } from 'element-plus'; +import { storeToRefs } from 'pinia'; +import { useThemeConfig } from '/@/stores/themeConfig'; +import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; + +export default defineComponent({ + name: 'paramsDynamic', + setup() { + const storesTagsViewRoutes = useTagsViewRoutes(); + const storesThemeConfig = useThemeConfig(); + const { themeConfig } = storeToRefs(storesThemeConfig); + const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes); + const state = reactive({ + value: '', + tagsViewName: '', + tagsViewNameIsI18n: false, + }); + const router = useRouter(); + // 设置 view 的高度 + const setViewHeight = computed(() => { + let { isTagsview } = themeConfig.value; + if (isTagsViewCurrenFull.value) { + return `30px`; + } else { + if (isTagsview) return `114px`; + else return `80px`; + } + }); + // 跳转到详情 + const onGoDetailsClick = () => { + if (!state.tagsViewName) return ElMessage.warning('动态路由tagsViewName为必填,因为路由配置了'); + if (!state.value) return ElMessage.warning('路由参数id值为必填'); + // name 值为路由中的 name + router.push({ + name: 'paramsDynamicDetails', + params: { + t: 'vue-next-admin', + id: state.value, + tagsViewName: state.tagsViewName, + }, + }); + state.value = ''; + }; + const onChangeI18n = () => { + state.tagsViewNameIsI18n = !state.tagsViewNameIsI18n; + if (state.tagsViewNameIsI18n) { + state.tagsViewName = JSON.stringify({ + 'zh-cn': '我是动态路由', + en: 'Im dynamic routing', + 'zh-tw': '我是動態路由', + }); + } else { + state.tagsViewName = '我是动态路由测试tagsViewName(非国际化)'; + } + }; + return { + setViewHeight, + onGoDetailsClick, + onChangeI18n, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/personal/index.vue b/src/views/personal/index.vue new file mode 100644 index 0000000..5a29dc7 --- /dev/null +++ b/src/views/personal/index.vue @@ -0,0 +1,387 @@ +<template> + <div class="personal"> + <el-row> + <!-- 个人信息 --> + <el-col :xs="24" :sm="16"> + <el-card shadow="hover" header="个人信息"> + <div class="personal-user"> + <div class="personal-user-left"> + <el-upload class="h100 personal-user-left-upload" action="https://jsonplaceholder.typicode.com/posts/" multiple :limit="1"> + <img src="https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1813762643,1914315241&fm=26&gp=0.jpg" /> + </el-upload> + </div> + <div class="personal-user-right"> + <el-row> + <el-col :span="24" class="personal-title mb18">{{ currentTime }},admin,生活变的再糟糕,也不妨碍我变得更好! </el-col> + <el-col :span="24"> + <el-row> + <el-col :xs="24" :sm="8" class="personal-item mb6"> + <div class="personal-item-label">昵称:</div> + <div class="personal-item-value">小柒</div> + </el-col> + <el-col :xs="24" :sm="16" class="personal-item mb6"> + <div class="personal-item-label">身份:</div> + <div class="personal-item-value">超级管理</div> + </el-col> + </el-row> + </el-col> + <el-col :span="24"> + <el-row> + <el-col :xs="24" :sm="8" class="personal-item mb6"> + <div class="personal-item-label">登录IP:</div> + <div class="personal-item-value">192.168.1.1</div> + </el-col> + <el-col :xs="24" :sm="16" class="personal-item mb6"> + <div class="personal-item-label">登录时间:</div> + <div class="personal-item-value">2021-02-05 18:47:26</div> + </el-col> + </el-row> + </el-col> + </el-row> + </div> + </div> + </el-card> + </el-col> + + <!-- 消息通知 --> + <el-col :xs="24" :sm="8" class="pl15 personal-info"> + <el-card shadow="hover"> + <template #header> + <span>消息通知</span> + <span class="personal-info-more">更多</span> + </template> + <div class="personal-info-box"> + <ul class="personal-info-ul"> + <li v-for="(v, k) in newsInfoList" :key="k" class="personal-info-li"> + <a :href="v.link" target="_block" class="personal-info-li-title">{{ v.title }}</a> + </li> + </ul> + </div> + </el-card> + </el-col> + + <!-- 营销推荐 --> + <el-col :span="24"> + <el-card shadow="hover" class="mt15" header="营销推荐"> + <el-row :gutter="15" class="personal-recommend-row"> + <el-col :sm="6" v-for="(v, k) in recommendList" :key="k" class="personal-recommend-col"> + <div class="personal-recommend" :style="{ 'background-color': v.bg }"> + <SvgIcon :name="v.icon" :size="70" :style="{ color: v.iconColor }" /> + <div class="personal-recommend-auto"> + <div>{{ v.title }}</div> + <div class="personal-recommend-msg">{{ v.msg }}</div> + </div> + </div> + </el-col> + </el-row> + </el-card> + </el-col> + + <!-- 更新信息 --> + <el-col :span="24"> + <el-card shadow="hover" class="mt15 personal-edit" header="更新信息"> + <div class="personal-edit-title">基本信息</div> + <el-form :model="personalForm" size="default" label-width="40px" class="mt35 mb35"> + <el-row :gutter="35"> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="昵称"> + <el-input v-model="personalForm.name" placeholder="请输入昵称" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="邮箱"> + <el-input v-model="personalForm.email" placeholder="请输入邮箱" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="签名"> + <el-input v-model="personalForm.autograph" placeholder="请输入签名" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="职业"> + <el-select v-model="personalForm.occupation" placeholder="请选择职业" clearable class="w100"> + <el-option label="计算机 / 互联网 / 通信" value="1"></el-option> + <el-option label="生产 / 工艺 / 制造" value="2"></el-option> + <el-option label="医疗 / 护理 / 制药" value="3"></el-option> + </el-select> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="手机"> + <el-input v-model="personalForm.phone" placeholder="请输入手机" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20"> + <el-form-item label="性别"> + <el-select v-model="personalForm.sex" placeholder="请选择性别" clearable class="w100"> + <el-option label="男" value="1"></el-option> + <el-option label="女" value="2"></el-option> + </el-select> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24"> + <el-form-item> + <el-button type="primary"> + <el-icon> + <ele-Position /> + </el-icon> + 更新个人信息 + </el-button> + </el-form-item> + </el-col> + </el-row> + </el-form> + <div class="personal-edit-title mb15">账号安全</div> + <div class="personal-edit-safe-box"> + <div class="personal-edit-safe-item"> + <div class="personal-edit-safe-item-left"> + <div class="personal-edit-safe-item-left-label">账户密码</div> + <div class="personal-edit-safe-item-left-value">当前密码强度:强</div> + </div> + <div class="personal-edit-safe-item-right"> + <el-button text type="primary">立即修改</el-button> + </div> + </div> + </div> + <div class="personal-edit-safe-box"> + <div class="personal-edit-safe-item"> + <div class="personal-edit-safe-item-left"> + <div class="personal-edit-safe-item-left-label">密保手机</div> + <div class="personal-edit-safe-item-left-value">已绑定手机:132****4108</div> + </div> + <div class="personal-edit-safe-item-right"> + <el-button text type="primary">立即修改</el-button> + </div> + </div> + </div> + <div class="personal-edit-safe-box"> + <div class="personal-edit-safe-item"> + <div class="personal-edit-safe-item-left"> + <div class="personal-edit-safe-item-left-label">密保问题</div> + <div class="personal-edit-safe-item-left-value">已设置密保问题,账号安全大幅度提升</div> + </div> + <div class="personal-edit-safe-item-right"> + <el-button text type="primary">立即设置</el-button> + </div> + </div> + </div> + <div class="personal-edit-safe-box"> + <div class="personal-edit-safe-item"> + <div class="personal-edit-safe-item-left"> + <div class="personal-edit-safe-item-left-label">绑定QQ</div> + <div class="personal-edit-safe-item-left-value">已绑定QQ:110****566</div> + </div> + <div class="personal-edit-safe-item-right"> + <el-button text type="primary">立即设置</el-button> + </div> + </div> + </div> + </el-card> + </el-col> + </el-row> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, computed, defineComponent } from 'vue'; +import { formatAxis } from '/@/utils/formatTime'; +import { newsInfoList, recommendList } from './mock'; + +// 定义接口来定义对象的类型 +interface PersonalState { + newsInfoList: any; + recommendList: any; + personalForm: any; +} + +export default defineComponent({ + name: 'personal', + setup() { + const state = reactive<PersonalState>({ + newsInfoList, + recommendList, + personalForm: { + name: '', + email: '', + autograph: '', + occupation: '', + phone: '', + sex: '', + }, + }); + // 当前时间提示语 + const currentTime = computed(() => { + return formatAxis(new Date()); + }); + return { + currentTime, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +@import '../../theme/mixins/index.scss'; +.personal { + .personal-user { + height: 130px; + display: flex; + align-items: center; + .personal-user-left { + width: 100px; + height: 130px; + border-radius: 3px; + ::v-deep(.el-upload) { + height: 100%; + } + .personal-user-left-upload { + img { + width: 100%; + height: 100%; + border-radius: 3px; + } + &:hover { + img { + animation: logoAnimation 0.3s ease-in-out; + } + } + } + } + .personal-user-right { + flex: 1; + padding: 0 15px; + .personal-title { + font-size: 18px; + @include text-ellipsis(1); + } + .personal-item { + display: flex; + align-items: center; + font-size: 13px; + .personal-item-label { + color: var(--el-text-color-secondary); + @include text-ellipsis(1); + } + .personal-item-value { + @include text-ellipsis(1); + } + } + } + } + .personal-info { + .personal-info-more { + float: right; + color: var(--el-text-color-secondary); + font-size: 13px; + &:hover { + color: var(--el-color-primary); + cursor: pointer; + } + } + .personal-info-box { + height: 130px; + overflow: hidden; + .personal-info-ul { + list-style: none; + .personal-info-li { + font-size: 13px; + padding-bottom: 10px; + .personal-info-li-title { + display: inline-block; + @include text-ellipsis(1); + color: var(--el-text-color-secondary); + text-decoration: none; + } + & a:hover { + color: var(--el-color-primary); + cursor: pointer; + } + } + } + } + } + .personal-recommend-row { + .personal-recommend-col { + .personal-recommend { + position: relative; + height: 100px; + border-radius: 3px; + overflow: hidden; + cursor: pointer; + &:hover { + i { + right: 0px !important; + bottom: 0px !important; + transition: all ease 0.3s; + } + } + i { + position: absolute; + right: -10px; + bottom: -10px; + font-size: 70px; + transform: rotate(-30deg); + transition: all ease 0.3s; + } + .personal-recommend-auto { + padding: 15px; + position: absolute; + left: 0; + top: 5%; + color: var(--next-color-white); + .personal-recommend-msg { + font-size: 12px; + margin-top: 10px; + } + } + } + } + } + .personal-edit { + .personal-edit-title { + position: relative; + padding-left: 10px; + color: var(--el-text-color-regular); + &::after { + content: ''; + width: 2px; + height: 10px; + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + background: var(--el-color-primary); + } + } + .personal-edit-safe-box { + border-bottom: 1px solid var(--el-border-color-light, #ebeef5); + padding: 15px 0; + .personal-edit-safe-item { + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + .personal-edit-safe-item-left { + flex: 1; + overflow: hidden; + .personal-edit-safe-item-left-label { + color: var(--el-text-color-regular); + margin-bottom: 5px; + } + .personal-edit-safe-item-left-value { + color: var(--el-text-color-secondary); + @include text-ellipsis(1); + margin-right: 15px; + } + } + } + &:last-of-type { + padding-bottom: 0; + border-bottom: none; + } + } + } +} +</style> diff --git a/src/views/personal/mock.ts b/src/views/personal/mock.ts new file mode 100644 index 0000000..ff57575 --- /dev/null +++ b/src/views/personal/mock.ts @@ -0,0 +1,66 @@ +/** + * 消息通知 + * @returns 返回模拟数据 + */ +export const newsInfoList: Array<object> = [ + { + title: '[发布] 2021年02月28日发布基于 vue3.x + vite v1.0.0 版本', + date: '02/28', + link: 'https://gitee.com/lyt-top/vue-next-admin', + }, + { + title: '[发布] 2021年04月15日发布 vue2.x + webpack 重构版本', + date: '04/15', + link: 'https://gitee.com/lyt-top/vue-next-admin/tree/vue-prev-admin/', + }, + { + title: '[重构] 2021年04月10日 重构 vue2.x + webpack v1.0.0 版本', + date: '04/10', + link: 'https://gitee.com/lyt-top/vue-next-admin/tree/vue-prev-admin/', + }, + { + title: '[预览] 2020年12月08日,基于 vue3.x 版本后台模板的预览', + date: '12/08', + link: 'http://lyt-top.gitee.io/vue-next-admin-preview/#/login', + }, + { + title: '[预览] 2020年11月15日,基于 vue2.x 版本后台模板的预览', + date: '11/15', + link: 'https://lyt-top.gitee.io/vue-prev-admin-preview/#/login', + }, +]; + +/** + * 营销推荐 + * @returns 返回模拟数据 + */ +export const recommendList: Array<object> = [ + { + title: '优惠券', + msg: '现金券、折扣券、营销必备', + icon: 'ele-Food', + bg: '#48D18D', + iconColor: '#64d89d', + }, + { + title: '多人拼团', + msg: '社交电商、开辟流量', + icon: 'ele-ShoppingCart', + bg: '#F95959', + iconColor: '#F86C6B', + }, + { + title: '分销中心', + msg: '轻松招募分销员,成功推广奖励', + icon: 'ele-School', + bg: '#8595F4', + iconColor: '#92A1F4', + }, + { + title: '秒杀', + msg: '超低价抢购引导更多销量', + icon: 'ele-AlarmClock', + bg: '#FEBB50', + iconColor: '#FDC566', + }, +]; diff --git a/src/views/system/department/component/deptDialog.vue b/src/views/system/department/component/deptDialog.vue new file mode 100644 index 0000000..0477317 --- /dev/null +++ b/src/views/system/department/component/deptDialog.vue @@ -0,0 +1,161 @@ +<template> + <div class="system-add-dept-container"> + <el-dialog :title="title" v-model="isShowDialog" width="600px"> + <el-form :model="departmentForm" size="default" label-width="90px"> + <el-row :gutter="35"> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="上级部门"> + <el-cascader + :options="deptData" + :props="{ checkStrictly: true, value: 'id', label: 'name' }" + placeholder="请选择部门" + clearable + class="w100" + v-model="departmentForm.struct" + > + </el-cascader> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="部门名称"> + <el-input v-model="departmentForm.name" placeholder="请输入部门名称" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="部门描述"> + <el-input v-model="departmentForm.info" type="textarea" placeholder="请输入部门描述" maxlength="150"></el-input> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <span class="dialog-footer"> + <el-button @click="onCancel" size="default">取 消</el-button> + <el-button type="primary" @click="onSubmit" size="default">新 增</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script lang="ts"> +import { ElMessage } from 'element-plus'; +import { reactive, toRefs, onMounted, defineComponent } from 'vue'; +import { departmentApi } from "/@/api/department"; + +// 定义接口来定义对象的类型 +interface TableDataRow { + struct: Array<string>; + name:string, + info:string, + parentId:string, + id:number, +} +interface DeptSate { + title:string; + isShowDialog: boolean; + departmentForm: { + struct: Array<string>; + name:string, + info:string, + parentId:string + }; + deptData: Array<TableDataRow>; +} + +export default defineComponent({ + name: 'systemAddDept', + setup(prop,context) { + const state = reactive<DeptSate>({ + title:'', + isShowDialog: false, + departmentForm: { + name:'', + parentId:'', + info:'', + struct:[] + }, + deptData: [], // 部门数据 + }); + // 打开弹窗 + const openDialog = (type:string, value: any,departmentList: []) => { + state.isShowDialog = true; + state.deptData = JSON.parse(JSON.stringify(departmentList)) + if(type === '新增'){ + state.title = '新增部门' + state.departmentForm = { + name:'', + parentId:'', + info:'', + struct:[] + } + }else{ + state.title = '编辑部门' + } + }; + // 关闭弹窗 + const closeDialog = () => { + state.isShowDialog = false; + }; + // 取消 + const onCancel = () => { + closeDialog(); + }; + // 新增 + const onSubmit = async () => { + if(state.departmentForm.struct && state.departmentForm.struct !== []){ + let departmentId = JSON.parse(JSON.stringify(state.departmentForm.struct)) + state.departmentForm.parentId = departmentId[departmentId.length - 1] + } + if(state.title === '新增部门'){ + let res = await departmentApi().addDepartment(state.departmentForm) + if(res.data.code === '200'){ + ElMessage({ + type:'success', + message:'菜单新增成功', + duration:2000 + }) + closeDialog(); + context.emit('getMenuList') + }else{ + ElMessage({ + type:'warning', + message:res.data.msg + }) + } + }else{ + let res = await departmentApi().modDepartment(state.departmentForm) + if(res.data.code === '200'){ + ElMessage({ + type:'success', + message:'菜单修改成功', + duration:2000 + }) + closeDialog(); + context.emit('getMenuList') + }else{ + ElMessage({ + type:'warning', + message:res.data.msg + }) + } + } + }; + // 初始化部门数据 + const initTableData = () => { + + }; + // 页面加载时 + onMounted(() => { + initTableData(); + }); + return { + openDialog, + closeDialog, + onCancel, + onSubmit, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/system/department/component/editDept.vue b/src/views/system/department/component/editDept.vue new file mode 100644 index 0000000..7b16f44 --- /dev/null +++ b/src/views/system/department/component/editDept.vue @@ -0,0 +1,179 @@ +<template> + <div class="system-edit-dept-container"> + <el-dialog title="修改部门" v-model="isShowDialog" width="769px"> + <el-form :model="ruleForm" size="default" label-width="90px"> + <el-row :gutter="35"> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="上级部门"> + <el-cascader + :options="deptData" + :props="{ checkStrictly: true, value: 'deptName', label: 'deptName' }" + placeholder="请选择部门" + clearable + class="w100" + v-model="ruleForm.deptLevel" + > + <template #default="{ node, data }"> + <span>{{ data.deptName }}</span> + <span v-if="!node.isLeaf"> ({{ data.children.length }}) </span> + </template> + </el-cascader> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="部门名称"> + <el-input v-model="ruleForm.deptName" placeholder="请输入部门名称" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="负责人"> + <el-input v-model="ruleForm.person" placeholder="请输入负责人" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="手机号"> + <el-input v-model="ruleForm.phone" placeholder="请输入手机号" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="邮箱"> + <el-input v-model="ruleForm.email" placeholder="请输入" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="排序"> + <el-input-number v-model="ruleForm.sort" :min="0" :max="999" controls-position="right" placeholder="请输入排序" class="w100" /> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="部门状态"> + <el-switch v-model="ruleForm.status" inline-prompt active-text="启" inactive-text="禁"></el-switch> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="部门描述"> + <el-input v-model="ruleForm.describe" type="textarea" placeholder="请输入部门描述" maxlength="150"></el-input> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <span class="dialog-footer"> + <el-button @click="onCancel" size="default">取 消</el-button> + <el-button type="primary" @click="onSubmit" size="default">修 改</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script lang="ts"> +import { reactive, toRefs, onMounted, defineComponent } from 'vue'; + +// 定义接口来定义对象的类型 +interface TableDataRow { + deptName: string; + createTime: string; + status: boolean; + sort: number; + describe: string; + id: number; + children?: TableDataRow[]; +} +interface RuleFormState { + deptLevel: Array<string>; + deptName: string; + person: string; + phone: string | number; + email: string; + sort: number; + status: boolean; + describe: string; +} +interface DeptSate { + isShowDialog: boolean; + ruleForm: RuleFormState; + deptData: Array<TableDataRow>; +} + +export default defineComponent({ + name: 'systemEditDept', + setup() { + const state = reactive<DeptSate>({ + isShowDialog: false, + ruleForm: { + deptLevel: [], // 上级部门 + deptName: '', // 部门名称 + person: '', // 负责人 + phone: '', // 手机号 + email: '', // 邮箱 + sort: 0, // 排序 + status: true, // 部门状态 + describe: '', // 部门描述 + }, + deptData: [], // 部门数据 + }); + // 打开弹窗 + const openDialog = (row: RuleFormState) => { + row.deptLevel = ['vueNextAdmin']; + row.person = 'lyt'; + row.phone = '12345678910'; + row.email = 'vueNextAdmin@123.com'; + state.ruleForm = row; + state.isShowDialog = true; + }; + // 关闭弹窗 + const closeDialog = () => { + state.isShowDialog = false; + }; + // 取消 + const onCancel = () => { + closeDialog(); + }; + // 新增 + const onSubmit = () => { + closeDialog(); + }; + // 初始化部门数据 + const initTableData = () => { + state.deptData.push({ + deptName: 'vueNextAdmin', + createTime: new Date().toLocaleString(), + status: true, + sort: Math.random(), + describe: '顶级部门', + id: Math.random(), + children: [ + { + deptName: 'IT外包服务', + createTime: new Date().toLocaleString(), + status: true, + sort: Math.random(), + describe: '总部', + id: Math.random(), + }, + { + deptName: '资本控股', + createTime: new Date().toLocaleString(), + status: true, + sort: Math.random(), + describe: '分部', + id: Math.random(), + }, + ], + }); + }; + // 页面加载时 + onMounted(() => { + initTableData(); + }); + return { + openDialog, + closeDialog, + onCancel, + onSubmit, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/system/department/index.vue b/src/views/system/department/index.vue new file mode 100644 index 0000000..4f33400 --- /dev/null +++ b/src/views/system/department/index.vue @@ -0,0 +1,121 @@ +<template> + <div class="system-dept-container"> + <el-card shadow="hover"> + <div class="system-dept-search mb15"> + <el-input size="default" placeholder="请输入部门名称" style="max-width: 180px"> </el-input> + <el-button size="default" type="primary" class="ml10"> + <el-icon> + <ele-Search /> + </el-icon> + 查询 + </el-button> + <el-button size="default" type="success" class="ml10" @click="onOpenDeptDialog('新增','')"> + <el-icon> + <ele-FolderAdd /> + </el-icon> + 新增部门 + </el-button> + </div> + <el-table + :data="tableData.data" + style="width: 100%" + row-key="id" + default-expand-all + :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" + > + <el-table-column prop="name" label="部门名称" show-overflow-tooltip> </el-table-column> + <el-table-column prop="status" label="部门状态" show-overflow-tooltip> + <template #default="scope"> + <el-tag type="success" v-if="scope.row.status">启用</el-tag> + <el-tag type="info" v-else>禁用</el-tag> + </template> + </el-table-column> + <el-table-column prop="info" label="部门描述" show-overflow-tooltip></el-table-column> + <el-table-column label="操作" show-overflow-tooltip width="140"> + <template #default="scope"> + <el-button size="small" text type="primary" @click="onOpenDeptDialog('新增','')">新增</el-button> + <el-button size="small" text type="primary" @click="onOpenDeptDialog('修改',scope.row)">修改</el-button> + <el-button size="small" text type="primary" @click="onTabelRowDel(scope.row)">删除</el-button> + </template> + </el-table-column> + </el-table> + </el-card> + <deptDialog ref="deptDialog" /> + </div> +</template> + +<script lang="ts"> +import { ref, toRefs, reactive, onMounted, defineComponent } from 'vue'; +import { ElMessageBox, ElMessage } from 'element-plus'; +import deptDialog from '/@/views/system/department/component/deptDialog.vue'; +import {departmentApi} from "/@/api/department"; + +// 定义接口来定义对象的类型 +interface TableDataRow { + name: string; + status: boolean; + parentId: number; + info: string; + id: number; + children?: TableDataRow[]; +} +interface TableDataState { + tableData: { + data: Array<TableDataRow>; + total: number; + loading: boolean; + }; +} + +export default defineComponent({ + name: 'systemDept', + components: { deptDialog }, + setup() { + const deptDialog = ref(); + const state = reactive<TableDataState>({ + tableData: { + data: [], + total: 0, + loading: false, + }, + }); + // 初始化表格数据 + const initTableData = async () => { + let res = await departmentApi().getDepartmentList() + if(res.data.code === '200'){ + state.tableData.data = res.data.data + state.tableData.total = state.tableData.data.length; + }else{ + ElMessage({ + type:'warning', + message:res.data.msg + }) + } + }; + // 打开新增菜单弹窗 + const onOpenDeptDialog = (type: string,value: any) => { + deptDialog.value.openDialog(type,value,state.tableData.data); + }; + // 删除当前行 + const onTabelRowDel = (row: TableDataRow) => { + ElMessageBox.confirm(`此操作将永久删除部门:${row.id}, 是否继续?`, '提示', { + confirmButtonText: '删除', + cancelButtonText: '取消', + type: 'warning', + }).then(() => { + ElMessage.success('删除成功'); + }).catch(() => {}); + }; + // 页面加载时 + onMounted(() => { + initTableData(); + }); + return { + deptDialog, + onOpenDeptDialog, + onTabelRowDel, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/system/dic/component/addDic.vue b/src/views/system/dic/component/addDic.vue new file mode 100644 index 0000000..c964dd9 --- /dev/null +++ b/src/views/system/dic/component/addDic.vue @@ -0,0 +1,129 @@ +<template> + <div class="system-add-dic-container"> + <el-dialog title="新增字典" v-model="isShowDialog" width="769px"> + <el-alert title="半成品,交互过于复杂,请自行扩展!" type="warning" :closable="false" class="mb20"> </el-alert> + <el-form :model="ruleForm" size="default" label-width="90px"> + <el-row :gutter="35"> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="字典名称"> + <el-input v-model="ruleForm.dicName" placeholder="请输入字典名称" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="字段名"> + <el-input v-model="ruleForm.fieldName" placeholder="请输入字段名,拼接 ruleForm.list" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="字典状态"> + <el-switch v-model="ruleForm.status" inline-prompt active-text="启" inactive-text="禁"></el-switch> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-row :gutter="35" v-for="(v, k) in ruleForm.list" :key="k"> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item :prop="`list[${k}].label`"> + <template #label> + <el-button type="primary" circle size="small" @click="onAddRow" v-if="k === 0"> + <el-icon> + <ele-Plus /> + </el-icon> + </el-button> + <el-button type="danger" circle size="small" @click="onDelRow(k)" v-else> + <el-icon> + <ele-Delete /> + </el-icon> + </el-button> + <span class="ml10">字段</span> + </template> + <el-input v-model="v.label" style="width: 100%" placeholder="请输入字段名"> </el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="属性" :prop="`list[${k}].value`"> + <el-input v-model="v.value" style="width: 100%" placeholder="请输入属性值"> </el-input> + </el-form-item> + </el-col> + </el-row> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="字典描述"> + <el-input v-model="ruleForm.describe" type="textarea" placeholder="请输入字典描述" maxlength="150"></el-input> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <span class="dialog-footer"> + <el-button @click="onCancel" size="default">取 消</el-button> + <el-button type="primary" @click="onSubmit" size="default">新 增</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script lang="ts"> +import { reactive, toRefs, defineComponent } from 'vue'; + +export default defineComponent({ + name: 'systemAddDic', + setup() { + const state = reactive({ + isShowDialog: false, + ruleForm: { + dicName: '', // 字典名称 + fieldName: '', // 字段名 + status: true, // 字典状态 + list: [ + // 子集字段 + 属性值 + { + id: Math.random(), + label: '', + value: '', + }, + ], + describe: '', // 字典描述 + fieldNameList: [], // 字段名: [{子集字段 + 属性值}] + }, + }); + // 打开弹窗 + const openDialog = () => { + state.isShowDialog = true; + }; + // 关闭弹窗 + const closeDialog = () => { + state.isShowDialog = false; + }; + // 取消 + const onCancel = () => { + closeDialog(); + }; + // 新增 + const onSubmit = () => { + closeDialog(); + }; + // 新增行 + const onAddRow = () => { + state.ruleForm.list.push({ + id: Math.random(), + label: '', + value: '', + }); + }; + // 删除行 + const onDelRow = (k: number) => { + state.ruleForm.list.splice(k, 1); + }; + return { + openDialog, + closeDialog, + onCancel, + onSubmit, + onAddRow, + onDelRow, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/system/dic/component/editDic.vue b/src/views/system/dic/component/editDic.vue new file mode 100644 index 0000000..66b0365 --- /dev/null +++ b/src/views/system/dic/component/editDic.vue @@ -0,0 +1,162 @@ +<template> + <div class="system-edit-dic-container"> + <el-dialog title="修改字典" v-model="isShowDialog" width="769px"> + <el-alert title="半成品,交互过于复杂,请自行扩展!" type="warning" :closable="false" class="mb20"> </el-alert> + <el-form :model="ruleForm" size="default" label-width="90px"> + <el-row :gutter="35"> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="字典名称"> + <el-input v-model="ruleForm.dicName" placeholder="请输入字典名称" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="字段名"> + <el-input v-model="ruleForm.fieldName" placeholder="请输入字段名,拼接 ruleForm.list" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="字典状态"> + <el-switch v-model="ruleForm.status" inline-prompt active-text="启" inactive-text="禁"></el-switch> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-row :gutter="35" v-for="(v, k) in ruleForm.list" :key="k"> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item :prop="`list[${k}].label`"> + <template #label> + <el-button type="primary" circle size="small" @click="onAddRow" v-if="k === 0"> + <el-icon> + <ele-Plus /> + </el-icon> + </el-button> + <el-button type="danger" circle size="small" @click="onDelRow(k)" v-else> + <el-icon> + <ele-Delete /> + </el-icon> + </el-button> + <span class="ml10">字段</span> + </template> + <el-input v-model="v.label" style="width: 100%" placeholder="请输入字段名"> </el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="属性" :prop="`list[${k}].value`"> + <el-input v-model="v.value" style="width: 100%" placeholder="请输入属性值"> </el-input> + </el-form-item> + </el-col> + </el-row> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="字典描述"> + <el-input v-model="ruleForm.describe" type="textarea" placeholder="请输入字典描述" maxlength="150"></el-input> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <span class="dialog-footer"> + <el-button @click="onCancel" size="default">取 消</el-button> + <el-button type="primary" @click="onSubmit" size="default">修 改</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script lang="ts"> +import { reactive, toRefs, defineComponent } from 'vue'; + +// 定义接口来定义对象的类型 +interface RuleFormList { + id: number; + label: string; + value: string; +} +interface RuleFormState { + dicName: string; + fieldName: string; + status: boolean; + list: RuleFormList[]; + describe: string; + fieldNameList: Array<any>; +} +interface DicState { + isShowDialog: boolean; + ruleForm: RuleFormState; +} + +export default defineComponent({ + name: 'systemEditDic', + setup() { + const state = reactive<DicState>({ + isShowDialog: false, + ruleForm: { + dicName: '', // 字典名称 + fieldName: '', // 字段名 + status: true, // 字典状态 + list: [ + // 子集字段 + 属性值 + { + id: Math.random(), + label: '', + value: '', + }, + ], + describe: '', // 字典描述 + fieldNameList: [], // 字段名: [{子集字段 + 属性值}] + }, + }); + // 打开弹窗 + const openDialog = (row: RuleFormState) => { + if (row.fieldName === 'SYS_UERINFO') { + row.list = [ + { id: Math.random(), label: 'sex', value: '1' }, + { id: Math.random(), label: 'sex', value: '0' }, + ]; + } else { + row.list = [ + { id: Math.random(), label: 'role', value: 'admin' }, + { id: Math.random(), label: 'role', value: 'common' }, + { id: Math.random(), label: 'roleName', value: '超级管理员' }, + { id: Math.random(), label: 'roleName', value: '普通用户' }, + ]; + } + state.ruleForm = row; + state.isShowDialog = true; + }; + // 关闭弹窗 + const closeDialog = () => { + state.isShowDialog = false; + }; + // 取消 + const onCancel = () => { + closeDialog(); + }; + // 新增 + const onSubmit = () => { + closeDialog(); + }; + // 新增行 + const onAddRow = () => { + state.ruleForm.list.push({ + id: Math.random(), + label: '', + value: '', + }); + }; + // 删除行 + const onDelRow = (k: number) => { + state.ruleForm.list.splice(k, 1); + }; + return { + openDialog, + closeDialog, + onCancel, + onSubmit, + onAddRow, + onDelRow, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/system/dic/index.vue b/src/views/system/dic/index.vue new file mode 100644 index 0000000..034140c --- /dev/null +++ b/src/views/system/dic/index.vue @@ -0,0 +1,159 @@ +<template> + <div class="system-dic-container"> + <el-card shadow="hover"> + <div class="system-user-search mb15"> + <el-input size="default" placeholder="请输入字典名称" style="max-width: 180px"> </el-input> + <el-button size="default" type="primary" class="ml10"> + <el-icon> + <ele-Search /> + </el-icon> + 查询 + </el-button> + <el-button size="default" type="success" class="ml10" @click="onOpenAddDic"> + <el-icon> + <ele-FolderAdd /> + </el-icon> + 新增字典 + </el-button> + </div> + <el-table :data="tableData.data" style="width: 100%"> + <el-table-column type="index" label="序号" width="50" /> + <el-table-column prop="dicName" label="字典名称" show-overflow-tooltip></el-table-column> + <el-table-column prop="fieldName" label="字段名" show-overflow-tooltip></el-table-column> + <el-table-column prop="status" label="字典状态" show-overflow-tooltip> + <template #default="scope"> + <el-tag type="success" v-if="scope.row.status">启用</el-tag> + <el-tag type="info" v-else>禁用</el-tag> + </template> + </el-table-column> + <el-table-column prop="describe" label="字典描述" show-overflow-tooltip></el-table-column> + <el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column> + <el-table-column label="操作" width="100"> + <template #default="scope"> + <el-button size="small" text type="primary" @click="onOpenEditDic(scope.row)">修改</el-button> + <el-button size="small" text type="primary" @click="onRowDel(scope.row)">删除</el-button> + </template> + </el-table-column> + </el-table> + <el-pagination + @size-change="onHandleSizeChange" + @current-change="onHandleCurrentChange" + class="mt15" + :pager-count="5" + :page-sizes="[10, 20, 30]" + v-model:current-page="tableData.param.pageNum" + background + v-model:page-size="tableData.param.pageSize" + layout="total, sizes, prev, pager, next, jumper" + :total="tableData.total" + > + </el-pagination> + </el-card> + <AddDic ref="addDicRef" /> + <EditDic ref="editDicRef" /> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, onMounted, ref, defineComponent } from 'vue'; +import { ElMessageBox, ElMessage } from 'element-plus'; +import AddDic from '/@/views/system/dic/component/addDic.vue'; +import EditDic from '/@/views/system/dic/component/editDic.vue'; + +// 定义接口来定义对象的类型 +interface TableDataRow { + dicName: string; + fieldName: string; + describe: string; + status: boolean; + createTime: string; +} +interface TableDataState { + tableData: { + data: Array<TableDataRow>; + total: number; + loading: boolean; + param: { + pageNum: number; + pageSize: number; + }; + }; +} + +export default defineComponent({ + name: 'systemDic', + components: { AddDic, EditDic }, + setup() { + const addDicRef = ref(); + const editDicRef = ref(); + const state = reactive<TableDataState>({ + tableData: { + data: [], + total: 0, + loading: false, + param: { + pageNum: 1, + pageSize: 10, + }, + }, + }); + // 初始化表格数据 + const initTableData = () => { + const data: Array<TableDataRow> = []; + for (let i = 0; i < 2; i++) { + data.push({ + dicName: i === 0 ? '角色标识' : '用户性别', + fieldName: i === 0 ? 'SYS_ROLE' : 'SYS_UERINFO', + describe: i === 0 ? '这是角色字典' : '这是用户性别字典', + status: true, + createTime: new Date().toLocaleString(), + }); + } + state.tableData.data = data; + state.tableData.total = state.tableData.data.length; + }; + // 打开新增字典弹窗 + const onOpenAddDic = () => { + addDicRef.value.openDialog(); + }; + // 打开修改字典弹窗 + const onOpenEditDic = (row: TableDataRow) => { + editDicRef.value.openDialog(row); + }; + // 删除字典 + const onRowDel = (row: TableDataRow) => { + ElMessageBox.confirm(`此操作将永久删除字典名称:“${row.dicName}”,是否继续?`, '提示', { + confirmButtonText: '确认', + cancelButtonText: '取消', + type: 'warning', + }) + .then(() => { + ElMessage.success('删除成功'); + }) + .catch(() => {}); + }; + // 分页改变 + const onHandleSizeChange = (val: number) => { + state.tableData.param.pageSize = val; + }; + // 分页改变 + const onHandleCurrentChange = (val: number) => { + state.tableData.param.pageNum = val; + }; + // 页面加载时 + onMounted(() => { + initTableData(); + }); + return { + addDicRef, + editDicRef, + onOpenAddDic, + onOpenEditDic, + onRowDel, + onHandleSizeChange, + onHandleCurrentChange, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/system/menu/component/menuDialog.vue b/src/views/system/menu/component/menuDialog.vue new file mode 100644 index 0000000..ab33832 --- /dev/null +++ b/src/views/system/menu/component/menuDialog.vue @@ -0,0 +1,247 @@ +<template> + <div class="system-add-menu-container"> + <el-dialog :title="title" v-model="isShowDialog" width="769px"> + <el-form :model="ruleForm" size="default" label-width="80px"> + <el-row :gutter="35"> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="上级菜单"> + <el-cascader + :options="menuData" + :props="{ checkStrictly: true, value: 'id', label: 'title' }" + placeholder="请选择上级菜单" + clearable + class="w100" + v-model="ruleForm.menuSuperior" + > + </el-cascader> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="菜单名称"> + <el-input v-model="ruleForm.meta.title" placeholder="格式:message.router.xxx" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="路由名称"> + <el-input v-model="ruleForm.name" placeholder="路由中的 name 值" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="路由路径"> + <el-input v-model="ruleForm.path" placeholder="路由中的 path 值" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="重定向"> + <el-input v-model="ruleForm.redirect" placeholder="请输入路由重定向" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="菜单图标"> + <IconSelector placeholder="请输入菜单图标" v-model="ruleForm.meta.icon" type="all" /> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="组件路径"> + <el-input v-model="ruleForm.component" placeholder="组件路径" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="权限标识"> + <el-select v-model="ruleForm.meta.roles" multiple placeholder="取角色管理" clearable class="w100"> + <el-option label="admin" value="admin"></el-option> + <el-option label="common" value="common"></el-option> + </el-select> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="菜单排序"> + <el-input-number v-model="ruleForm.priority" controls-position="right" placeholder="请输入排序" class="w100"/> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="是否隐藏"> + <el-radio-group v-model="ruleForm.meta.isHide"> + <el-radio :label="true">隐藏</el-radio> + <el-radio :label="false">不隐藏</el-radio> + </el-radio-group> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <span class="dialog-footer"> + <el-button @click="onCancel" size="default">取 消</el-button> + <el-button type="primary" @click="onSubmit" size="default">{{ buttonName }}</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script lang="ts"> +import { reactive, toRefs, onMounted, defineComponent } from 'vue'; +import { storeToRefs } from 'pinia'; +import { useRoutesList } from '/@/stores/routesList'; +import { i18n } from '/@/i18n/index'; +import IconSelector from '/@/components/iconSelector/index.vue'; +import { useMenuApi } from '/@/api/menu/index' +import { ElMessageBox, ElMessage } from 'element-plus'; +import {Session} from "/@/utils/storage"; +// import { setBackEndControlRefreshRoutes } from "/@/router/backEnd"; + +export default defineComponent({ + name: 'systemAddMenu', + components: { IconSelector }, + setup(props,context) { + const stores = useRoutesList(); + const { routesList } = storeToRefs(stores); + const state = reactive({ + isShowDialog: false, + title:'', + buttonName:'', + // 参数请参考 `/src/router/route.ts` 中的 `dynamicRoutes` 路由菜单格式 + ruleForm: { + projectId:'', + parentId:0, + menuSuperior: [], // 上级菜单 + menuType: 'menu', // 菜单类型 + name: '', // 路由名称 + component: '', // 组件路径 + priority: 0, // 菜单排序 + path: '', // 路由路径 + redirect: '', // 路由重定向,有子集 children 时 + meta: { + title: '', // 菜单名称 + icon: '', // 菜单图标 + isHide: false, // 是否隐藏 + isKeepAlive: true, // 是否缓存 + isAffix: false, // 是否固定 + isLink: '', // 外链/内嵌时链接地址(http:xxx.com),开启外链条件,`1、isLink: 链接地址不为空` + isIframe: false, // 是否内嵌,开启条件,`1、isIframe:true 2、isLink:链接地址不为空` + roles: '', // 权限标识,取角色管理 + }, + btnPower: '', // 菜单类型为按钮时,权限标识 + }, + menuData: [], // 上级菜单数据 + }); + // 获取 vuex 中的路由 + const getMenuList = (routes: any) => { + const arr: any = []; + routes.map((val: any) => { + val['title'] = val.meta.title; + val['id'] = val.id + arr.push(val); + if (val.children) getMenuList(val.children); + }); + return arr; + }; + // 打开弹窗 + const openDialog = (type:string,value:any) => { + state.isShowDialog = true; + if(type === '新增'){ + state.buttonName = '新增' + state.title = '新增菜单' + state.ruleForm = { + projectId:Session.get('projectId'), + parentId:0, + menuSuperior: [], + menuType: 'menu', + name: '', + component: '', + priority: 0, + path: '', + redirect: '', + meta: { + title: '', + icon: '', + isHide: false, + isKeepAlive: true, + isAffix: false, + isLink: '', + isIframe: false, + roles: '', + }, + btnPower: '', + } + }else{ + state.buttonName = '修改' + state.title = '修改菜单' + state.ruleForm = JSON.parse(JSON.stringify(value)) + } + }; + // 关闭弹窗 + const closeDialog = () => { + state.isShowDialog = false; + }; + // 是否内嵌下拉改变 + // const onSelectIframeChange = () => { + // if (state.ruleForm.meta.isIframe) state.ruleForm.isLink = true; + // else state.ruleForm.isLink = false; + // }; + // 取消 + const onCancel = () => { + closeDialog(); + }; + // 新增 + const onSubmit = async () => { + if(state.ruleForm.menuSuperior && state.ruleForm.menuSuperior !== []){ + let menuId = JSON.parse(JSON.stringify(state.ruleForm.menuSuperior)) + state.ruleForm.parentId = menuId[menuId.length - 1] + } + if(state.title === '新增'){ + let res = await useMenuApi().addMenu(state.ruleForm) + if(res.data.code === '200'){ + ElMessage({ + type:'success', + message:'菜单新增成功', + duration:2000 + }) + closeDialog(); + context.emit('getMenuList') + }else{ + ElMessage({ + type:'warning', + message:res.data.msg + }) + } + }else{ + let res = await useMenuApi().modMenu(state.ruleForm) + if(res.data.code === '200'){ + ElMessage({ + type:'success', + message:'菜单修改成功', + duration:2000 + }) + closeDialog(); + context.emit('getMenuList') + }else{ + ElMessage({ + type:'warning', + message:res.data.msg + }) + } + } + + // closeDialog(); // 关闭弹窗 + // setBackEndControlRefreshRoutes() // 刷新菜单,未进行后端接口测试 + }; + + const show = () => { + console.log(JSON.parse(JSON.stringify(state.ruleForm.menuSuperior))); + } + // 页面加载时 + onMounted(async () => { + let res = await useMenuApi().getMenuAdmin(Session.get('projectId')) + state.menuData = JSON.parse(JSON.stringify(getMenuList(res.data.data))) + }); + return { + openDialog, + closeDialog, + onCancel, + onSubmit, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/system/menu/index.vue b/src/views/system/menu/index.vue new file mode 100644 index 0000000..2197f6a --- /dev/null +++ b/src/views/system/menu/index.vue @@ -0,0 +1,128 @@ +<template> + <div class="system-menu-container"> + <el-card shadow="hover"> + <div class="system-menu-search mb15"> + <el-input size="default" placeholder="请输入菜单名称" style="max-width: 180px"> </el-input> + <el-button size="default" type="primary" class="ml10"> + <el-icon> + <ele-Search /> + </el-icon> + 查询 + </el-button> + <el-button size="default" type="success" class="ml10" @click="onOpenMenuDialog('新增')"> + <el-icon> + <ele-FolderAdd /> + </el-icon> + 新增菜单 + </el-button> + </div> + <el-table :data="menuTableData" style="width: 100%" row-key="path" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"> + <el-table-column label="菜单名称" show-overflow-tooltip> + <template #default="scope"> + <SvgIcon :name="scope.row.meta.icon" /> + <span class="ml10">{{ scope.row.meta.title }}</span> + </template> + </el-table-column> + <el-table-column prop="path" label="路由路径" show-overflow-tooltip></el-table-column> + <el-table-column label="组件路径" show-overflow-tooltip> + <template #default="scope"> + <span>{{ scope.row.component }}</span> + </template> + </el-table-column> + <el-table-column label="权限标识" show-overflow-tooltip> + <template #default="scope"> + <span>{{ scope.row.meta.roles }}</span> + </template> + </el-table-column> + <el-table-column label="排序" show-overflow-tooltip width="80"> + <template #default="scope"> + {{ scope.$index }} + </template> + </el-table-column> + <el-table-column label="类型" show-overflow-tooltip width="80"> + <template #default="scope"> + <el-tag type="success" size="small">{{ scope.row.xx }}菜单</el-tag> + </template> + </el-table-column> + <el-table-column label="操作" show-overflow-tooltip width="140"> + <template #default="scope"> + <el-button size="small" text type="primary" @click="onOpenMenuDialog('新增')">新增</el-button> + <el-button size="small" text type="primary" @click="onOpenMenuDialog('修改',scope.row)">修改</el-button> + <el-button size="small" text type="primary" @click="onTabelRowDel(scope.row)">删除</el-button> + </template> + </el-table-column> + </el-table> + </el-card> + <menuDialog ref="menuDialog" @getMenuList="getMenuList"/> + </div> +</template> + +<script lang="ts"> +import { ref, toRefs, reactive, computed, onMounted, defineComponent } from 'vue'; +import { RouteRecordRaw } from 'vue-router'; +import { ElMessageBox, ElMessage } from 'element-plus'; +import { storeToRefs } from 'pinia'; +import { useRoutesList } from '/@/stores/routesList'; +import menuDialog from '/@/views/system/menu/component/menuDialog.vue'; +import {useMenuApi} from "/@/api/menu"; +import {Session} from "/@/utils/storage"; +import pinia from "/@/stores"; +import {dynamicRoutes} from "/@/router/route"; + +export default defineComponent({ + name: 'systemMenu', + components: { menuDialog }, + setup() { + const stores = useRoutesList(); + const { routesList } = storeToRefs(stores); + const menuDialog = ref(); + const state = reactive({ + menuData:[], + }); + // 获取 vuex 中的路由 + const menuTableData = computed(() => { + return routesList.value; + }); + // 打开新增菜单弹窗 + const onOpenMenuDialog = (type: string,value: any) => { + debugger + menuDialog.value.openDialog(type,value); + }; + // 打开编辑菜单弹窗 + // 删除当前行 + const onTabelRowDel = (row: RouteRecordRaw) => { + ElMessageBox.confirm(`此操作将永久删除路由:${row.path}, 是否继续?`, '提示', { + confirmButtonText: '删除', + cancelButtonText: '取消', + type: 'warning', + }).then(() => { + ElMessage.success('删除成功'); + }).catch(() => {}); + }; + const getMenuList = async () => { + let res = await useMenuApi().getMenuAdmin(Session.get('projectId')) + if(res.data.code === '200'){ + // state.menuData = res.data.data + const storesRoutesList = useRoutesList(pinia); + storesRoutesList.setRoutesList(res.data.data); + }else{ + ElMessage({ + type:'warning', + message:res.data.msg + }) + } + }; + onMounted( () => { + getMenuList() + }); + return { + getMenuList, + menuDialog, + onOpenMenuDialog, + menuTableData, + onTabelRowDel, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/system/role/component/addRole.vue b/src/views/system/role/component/addRole.vue new file mode 100644 index 0000000..adb0e83 --- /dev/null +++ b/src/views/system/role/component/addRole.vue @@ -0,0 +1,240 @@ +<template> + <div class="system-add-role-container"> + <el-dialog title="新增角色" v-model="isShowDialog" width="769px"> + <el-form :model="ruleForm" size="default" label-width="90px"> + <el-row :gutter="35"> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="角色名称"> + <el-input v-model="ruleForm.roleName" placeholder="请输入角色名称" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="角色标识"> + <template #label> + <el-tooltip effect="dark" content="用于 `router/route.ts` meta.roles" placement="top-start"> + <span>角色标识</span> + </el-tooltip> + </template> + <el-input v-model="ruleForm.roleSign" placeholder="请输入角色标识" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="排序"> + <el-input-number v-model="ruleForm.sort" :min="0" :max="999" controls-position="right" placeholder="请输入排序" class="w100" /> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="角色状态"> + <el-switch v-model="ruleForm.status" inline-prompt active-text="启" inactive-text="禁"></el-switch> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="角色描述"> + <el-input v-model="ruleForm.describe" type="textarea" placeholder="请输入角色描述" maxlength="150"></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="菜单权限"> + <el-tree :data="menuData" :props="menuProps" show-checkbox class="menu-data-tree" /> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <span class="dialog-footer"> + <el-button @click="onCancel" size="default">取 消</el-button> + <el-button type="primary" @click="onSubmit" size="default">新 增</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script lang="ts"> +import { reactive, toRefs, defineComponent } from 'vue'; + +// 定义接口来定义对象的类型 +interface MenuDataTree { + id: number; + label: string; + children?: MenuDataTree[]; +} +interface RoleState { + isShowDialog: boolean; + ruleForm: { + roleName: string; + roleSign: string; + sort: number; + status: boolean; + describe: string; + }; + menuData: Array<MenuDataTree>; + menuProps: { + children: string; + label: string; + }; +} + +export default defineComponent({ + name: 'systemAddRole', + setup() { + const state = reactive<RoleState>({ + isShowDialog: false, + ruleForm: { + roleName: '', // 角色名称 + roleSign: '', // 角色标识 + sort: 0, // 排序 + status: true, // 角色状态 + describe: '', // 角色描述 + }, + menuData: [], + menuProps: { + children: 'children', + label: 'label', + }, + }); + // 打开弹窗 + const openDialog = () => { + state.isShowDialog = true; + getMenuData(); + }; + // 关闭弹窗 + const closeDialog = () => { + state.isShowDialog = false; + }; + // 取消 + const onCancel = () => { + closeDialog(); + }; + // 新增 + const onSubmit = () => { + closeDialog(); + }; + // 获取菜单结构数据 + const getMenuData = () => { + state.menuData = [ + { + id: 1, + label: '系统管理', + children: [ + { + id: 11, + label: '菜单管理', + children: [ + { + id: 111, + label: '菜单新增', + }, + { + id: 112, + label: '菜单修改', + }, + { + id: 113, + label: '菜单删除', + }, + { + id: 114, + label: '菜单查询', + }, + ], + }, + { + id: 12, + label: '角色管理', + children: [ + { + id: 121, + label: '角色新增', + }, + { + id: 122, + label: '角色修改', + }, + { + id: 123, + label: '角色删除', + }, + { + id: 124, + label: '角色查询', + }, + ], + }, + { + id: 13, + label: '用户管理', + children: [ + { + id: 131, + label: '用户新增', + }, + { + id: 132, + label: '用户修改', + }, + { + id: 133, + label: '用户删除', + }, + { + id: 134, + label: '用户查询', + }, + ], + }, + ], + }, + { + id: 2, + label: '权限管理', + children: [ + { + id: 21, + label: '前端控制', + children: [ + { + id: 211, + label: '页面权限', + }, + { + id: 212, + label: '页面权限', + }, + ], + }, + { + id: 22, + label: '后端控制', + children: [ + { + id: 221, + label: '页面权限', + }, + ], + }, + ], + }, + ]; + }; + return { + openDialog, + closeDialog, + onCancel, + onSubmit, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.system-add-role-container { + .menu-data-tree { + width: 100%; + border: 1px solid var(--el-border-color); + border-radius: var(--el-input-border-radius, var(--el-border-radius-base)); + padding: 5px; + } +} +</style> diff --git a/src/views/system/role/component/editRole.vue b/src/views/system/role/component/editRole.vue new file mode 100644 index 0000000..fc6fe29 --- /dev/null +++ b/src/views/system/role/component/editRole.vue @@ -0,0 +1,242 @@ +<template> + <div class="system-edit-role-container"> + <el-dialog title="修改角色" v-model="isShowDialog" width="769px"> + <el-form :model="ruleForm" size="default" label-width="90px"> + <el-row :gutter="35"> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="角色名称"> + <el-input v-model="ruleForm.roleName" placeholder="请输入角色名称" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="角色标识"> + <template #label> + <el-tooltip effect="dark" content="用于 `router/route.ts` meta.roles" placement="top-start"> + <span>角色标识</span> + </el-tooltip> + </template> + <el-input v-model="ruleForm.roleSign" placeholder="请输入角色标识" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="排序"> + <el-input-number v-model="ruleForm.sort" :min="0" :max="999" controls-position="right" placeholder="请输入排序" class="w100" /> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="角色状态"> + <el-switch v-model="ruleForm.status" inline-prompt active-text="启" inactive-text="禁"></el-switch> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="角色描述"> + <el-input v-model="ruleForm.describe" type="textarea" placeholder="请输入角色描述" maxlength="150"></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="菜单权限"> + <el-tree :data="menuData" :props="menuProps" :default-checked-keys="[112, 113]" node-key="id" show-checkbox class="menu-data-tree" /> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <span class="dialog-footer"> + <el-button @click="onCancel" size="default">取 消</el-button> + <el-button type="primary" @click="onSubmit" size="default">修 改</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script lang="ts"> +import { reactive, toRefs, defineComponent } from 'vue'; + +// 定义接口来定义对象的类型 +interface MenuDataTree { + id: number; + label: string; + children?: MenuDataTree[]; +} +interface DialogRow { + roleName: string; + roleSign: string; + sort: number; + status: boolean; + describe: string; +} +interface RoleState { + isShowDialog: boolean; + ruleForm: DialogRow; + menuData: Array<MenuDataTree>; + menuProps: { + children: string; + label: string; + }; +} + +export default defineComponent({ + name: 'systemEditRole', + setup() { + const state = reactive<RoleState>({ + isShowDialog: false, + ruleForm: { + roleName: '', // 角色名称 + roleSign: '', // 角色标识 + sort: 0, // 排序 + status: true, // 角色状态 + describe: '', // 角色描述 + }, + menuData: [], + menuProps: { + children: 'children', + label: 'label', + }, + }); + // 打开弹窗 + const openDialog = (row: DialogRow) => { + state.ruleForm = row; + state.isShowDialog = true; + getMenuData(); + }; + // 关闭弹窗 + const closeDialog = () => { + state.isShowDialog = false; + }; + // 取消 + const onCancel = () => { + closeDialog(); + }; + // 新增 + const onSubmit = () => { + closeDialog(); + }; + // 获取菜单结构数据 + const getMenuData = () => { + state.menuData = [ + { + id: 1, + label: '系统管理', + children: [ + { + id: 11, + label: '菜单管理', + children: [ + { + id: 111, + label: '菜单新增', + }, + { + id: 112, + label: '菜单修改', + }, + { + id: 113, + label: '菜单删除', + }, + { + id: 114, + label: '菜单查询', + }, + ], + }, + { + id: 12, + label: '角色管理', + children: [ + { + id: 121, + label: '角色新增', + }, + { + id: 122, + label: '角色修改', + }, + { + id: 123, + label: '角色删除', + }, + { + id: 124, + label: '角色查询', + }, + ], + }, + { + id: 13, + label: '用户管理', + children: [ + { + id: 131, + label: '用户新增', + }, + { + id: 132, + label: '用户修改', + }, + { + id: 133, + label: '用户删除', + }, + { + id: 134, + label: '用户查询', + }, + ], + }, + ], + }, + { + id: 2, + label: '权限管理', + children: [ + { + id: 21, + label: '前端控制', + children: [ + { + id: 211, + label: '页面权限', + }, + { + id: 212, + label: '页面权限', + }, + ], + }, + { + id: 22, + label: '后端控制', + children: [ + { + id: 221, + label: '页面权限', + }, + ], + }, + ], + }, + ]; + }; + return { + openDialog, + closeDialog, + onCancel, + onSubmit, + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.system-edit-role-container { + .menu-data-tree { + width: 100%; + border: 1px solid var(--el-border-color); + border-radius: var(--el-input-border-radius, var(--el-border-radius-base)); + padding: 5px; + } +} +</style> diff --git a/src/views/system/role/index.vue b/src/views/system/role/index.vue new file mode 100644 index 0000000..7835197 --- /dev/null +++ b/src/views/system/role/index.vue @@ -0,0 +1,167 @@ +<template> + <div class="system-role-container"> + <el-card shadow="hover"> + <div class="system-user-search mb15"> + <el-input size="default" placeholder="请输入角色名称" style="max-width: 180px"> </el-input> + <el-button size="default" type="primary" class="ml10" @click="handleSearch"> + <el-icon> + <ele-Search /> + </el-icon> + 查询 + </el-button> + <el-button size="default" type="success" class="ml10" @click="onOpenAddRole"> + <el-icon> + <ele-FolderAdd /> + </el-icon> + 新增角色 + </el-button> + </div> + <el-table :data="tableData.data" style="width: 100%"> + <el-table-column type="index" label="序号" width="60" /> + <el-table-column prop="name" label="角色名称" show-overflow-tooltip></el-table-column> + <el-table-column prop="code" label="角色标识" show-overflow-tooltip></el-table-column> + <el-table-column prop="sort" label="排序" show-overflow-tooltip></el-table-column> + <el-table-column prop="status" label="角色状态" show-overflow-tooltip> + <template #default="scope"> + <el-tag type="success" v-if="scope.row.status">启用</el-tag> + <el-tag type="info" v-else>禁用</el-tag> + </template> + </el-table-column> + <el-table-column prop="info" label="角色描述" show-overflow-tooltip></el-table-column> + <el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column> + <el-table-column label="操作" width="100"> + <template #default="scope"> + <el-button :disabled="scope.row.roleName === '超级管理员'" size="small" text type="primary" @click="onOpenEditRole(scope.row)" + >修改</el-button + > + <el-button :disabled="scope.row.roleName === '超级管理员'" size="small" text type="primary" @click="onRowDel(scope.row)">删除</el-button> + </template> + </el-table-column> + </el-table> + <el-pagination + @size-change="onHandleSizeChange" + @current-change="onHandleCurrentChange" + class="mt15" + :pager-count="5" + :page-sizes="[10, 20, 30]" + v-model:current-page="tableData.param.pageNum" + background + v-model:page-size="tableData.param.pageSize" + layout="total, sizes, prev, pager, next, jumper" + :total="tableData.total" + > + </el-pagination> + </el-card> + <AddRole ref="addRoleRef" /> + <EditRole ref="editRoleRef" /> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, onMounted, ref, defineComponent } from 'vue'; +import { ElMessageBox, ElMessage } from 'element-plus'; +import AddRole from '/@/views/system/role/component/addRole.vue'; +import EditRole from '/@/views/system/role/component/editRole.vue'; +import {useRoleApi} from "/@/api/role"; + +// 定义接口来定义对象的类型 +interface TableData { + roleName: string; + roleSign: string; + describe: string; + sort: number; + status: boolean; + createTime: string; +} +interface TableDataState { + tableData: { + data: Array<TableData>; + total: number; + loading: boolean; + param: { + pageNum: number; + pageSize: number; + }; + }; +} + +export default defineComponent({ + name: 'systemRole', + components: { AddRole, EditRole }, + setup() { + const addRoleRef = ref(); + const editRoleRef = ref(); + const state = reactive<TableDataState>({ + tableData: { + data: [], + total: 0, + loading: false, + param: { + pageNum: 1, + pageSize: 10, + }, + }, + }); + // 初始化表格数据 + const initTableData = async () => { + let res = await useRoleApi().getRoleList() + if(res.data.code === '200'){ + state.tableData.data = res.data.data; + }else{ + ElMessage({ + type:'warning', + message:res.data.msg + }) + } + + }; + // 打开新增角色弹窗 + const onOpenAddRole = () => { + addRoleRef.value.openDialog(); + }; + // 打开修改角色弹窗 + const onOpenEditRole = (row: Object) => { + editRoleRef.value.openDialog(row); + }; + // 删除角色 + const onRowDel = (row: any) => { + ElMessageBox.confirm(`此操作将永久删除角色名称:“${row.roleName}”,是否继续?`, '提示', { + confirmButtonText: '确认', + cancelButtonText: '取消', + type: 'warning', + }) + .then(() => { + ElMessage.success('删除成功'); + }) + .catch(() => {}); + }; + const handleSearch = () => { + debugger + initTableData() + } + // 分页改变 + const onHandleSizeChange = (val: number) => { + state.tableData.param.pageSize = val; + }; + // 分页改变 + const onHandleCurrentChange = (val: number) => { + state.tableData.param.pageNum = val; + }; + // 页面加载时 + onMounted(() => { + initTableData(); + }); + return { + addRoleRef, + editRoleRef, + onOpenAddRole, + onOpenEditRole, + onRowDel, + onHandleSizeChange, + onHandleCurrentChange, + handleSearch, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/system/user/component/addUser.vue b/src/views/system/user/component/addUser.vue new file mode 100644 index 0000000..4a78153 --- /dev/null +++ b/src/views/system/user/component/addUser.vue @@ -0,0 +1,200 @@ +<template> + <div class="system-add-user-container"> + <el-dialog title="新增用户" v-model="isShowDialog" width="769px"> + <el-form :model="ruleForm" size="default" label-width="90px"> + <el-row :gutter="35"> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="账户名称"> + <el-input v-model="ruleForm.userName" placeholder="请输入账户名称" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="用户昵称"> + <el-input v-model="ruleForm.userNickname" placeholder="请输入用户昵称" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="关联角色"> + <el-select v-model="ruleForm.roleSign" placeholder="请选择" clearable class="w100"> + <el-option label="超级管理员" value="admin"></el-option> + <el-option label="普通用户" value="common"></el-option> + </el-select> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="部门"> + <el-cascader + :options="deptData" + :props="{ checkStrictly: true, value: 'deptName', label: 'deptName' }" + placeholder="请选择部门" + clearable + class="w100" + v-model="ruleForm.department" + > + <template #default="{ node, data }"> + <span>{{ data.deptName }}</span> + <span v-if="!node.isLeaf"> ({{ data.children.length }}) </span> + </template> + </el-cascader> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="手机号"> + <el-input v-model="ruleForm.phone" placeholder="请输入手机号" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="邮箱"> + <el-input v-model="ruleForm.email" placeholder="请输入" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="性别"> + <el-select v-model="ruleForm.sex" placeholder="请选择" clearable class="w100"> + <el-option label="男" value="男"></el-option> + <el-option label="女" value="女"></el-option> + </el-select> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="账户密码"> + <el-input v-model="ruleForm.password" placeholder="请输入" type="password" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="账户过期"> + <el-date-picker v-model="ruleForm.overdueTime" type="date" placeholder="请选择" class="w100"> </el-date-picker> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="用户状态"> + <el-switch v-model="ruleForm.status" inline-prompt active-text="启" inactive-text="禁"></el-switch> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="用户描述"> + <el-input v-model="ruleForm.describe" type="textarea" placeholder="请输入用户描述" maxlength="150"></el-input> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <span class="dialog-footer"> + <el-button @click="onCancel" size="default">取 消</el-button> + <el-button type="primary" @click="onSubmit" size="default">新 增</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script lang="ts"> +import { reactive, toRefs, onMounted, defineComponent } from 'vue'; + +// 定义接口来定义对象的类型 +interface DeptData { + deptName: string; + createTime: string; + status: boolean; + sort: number | string; + describe: string; + id: number; + children?: DeptData[]; +} +interface UserState { + isShowDialog: boolean; + ruleForm: { + userName: string; + userNickname: string; + roleSign: string; + department: any; + phone: string; + email: string; + sex: string; + password: string; + overdueTime: string; + status: boolean; + describe: string; + }; + deptData: Array<DeptData>; +} + +export default defineComponent({ + name: 'systemAddUser', + setup() { + const state = reactive<UserState>({ + isShowDialog: false, + ruleForm: { + userName: '', // 账户名称 + userNickname: '', // 用户昵称 + roleSign: '', // 关联角色 + department: [], // 部门 + phone: '', // 手机号 + email: '', // 邮箱 + sex: '', // 性别 + password: '', // 账户密码 + overdueTime: '', // 账户过期 + status: true, // 用户状态 + describe: '', // 用户描述 + }, + deptData: [], // 部门数据 + }); + // 打开弹窗 + const openDialog = () => { + state.isShowDialog = true; + }; + // 关闭弹窗 + const closeDialog = () => { + state.isShowDialog = false; + }; + // 取消 + const onCancel = () => { + closeDialog(); + }; + // 新增 + const onSubmit = () => { + closeDialog(); + }; + // 初始化部门数据 + const initTableData = () => { + state.deptData.push({ + deptName: 'vueNextAdmin', + createTime: new Date().toLocaleString(), + status: true, + sort: Math.random(), + describe: '顶级部门', + id: Math.random(), + children: [ + { + deptName: 'IT外包服务', + createTime: new Date().toLocaleString(), + status: true, + sort: Math.random(), + describe: '总部', + id: Math.random(), + }, + { + deptName: '资本控股', + createTime: new Date().toLocaleString(), + status: true, + sort: Math.random(), + describe: '分部', + id: Math.random(), + }, + ], + }); + }; + // 页面加载时 + onMounted(() => { + initTableData(); + }); + return { + openDialog, + closeDialog, + onCancel, + onSubmit, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/system/user/component/editUser.vue b/src/views/system/user/component/editUser.vue new file mode 100644 index 0000000..b7a0793 --- /dev/null +++ b/src/views/system/user/component/editUser.vue @@ -0,0 +1,202 @@ +<template> + <div class="system-edit-user-container"> + <el-dialog title="修改用户" v-model="isShowDialog" width="769px"> + <el-form :model="ruleForm" size="default" label-width="90px"> + <el-row :gutter="35"> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="账户名称"> + <el-input v-model="ruleForm.userName" placeholder="请输入账户名称" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="用户昵称"> + <el-input v-model="ruleForm.userNickname" placeholder="请输入用户昵称" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="关联角色"> + <el-select v-model="ruleForm.roleSign" placeholder="请选择" clearable class="w100"> + <el-option label="超级管理员" value="admin"></el-option> + <el-option label="普通用户" value="common"></el-option> + </el-select> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="部门"> + <el-cascader + :options="deptData" + :props="{ checkStrictly: true, value: 'deptName', label: 'deptName' }" + placeholder="请选择部门" + clearable + class="w100" + v-model="ruleForm.department" + > + <template #default="{ node, data }"> + <span>{{ data.deptName }}</span> + <span v-if="!node.isLeaf"> ({{ data.children.length }}) </span> + </template> + </el-cascader> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="手机号"> + <el-input v-model="ruleForm.phone" placeholder="请输入手机号" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="邮箱"> + <el-input v-model="ruleForm.email" placeholder="请输入" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="性别"> + <el-select v-model="ruleForm.sex" placeholder="请选择" clearable class="w100"> + <el-option label="男" value="男"></el-option> + <el-option label="女" value="女"></el-option> + </el-select> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="账户密码"> + <el-input v-model="ruleForm.password" placeholder="请输入" type="password" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="账户过期"> + <el-date-picker v-model="ruleForm.overdueTime" type="date" placeholder="请选择" class="w100"> </el-date-picker> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> + <el-form-item label="用户状态"> + <el-switch v-model="ruleForm.status" inline-prompt active-text="启" inactive-text="禁"></el-switch> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="用户描述"> + <el-input v-model="ruleForm.describe" type="textarea" placeholder="请输入用户描述" maxlength="150"></el-input> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <span class="dialog-footer"> + <el-button @click="onCancel" size="default">取 消</el-button> + <el-button type="primary" @click="onSubmit" size="default">修 改</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script lang="ts"> +import { reactive, toRefs, onMounted, defineComponent } from 'vue'; + +// 定义接口来定义对象的类型 +interface DeptData { + deptName: string; + createTime: string; + status: boolean; + sort: number | string; + describe: string; + id: number; + children?: DeptData[]; +} +interface RuleFormRow { + userName: string; + userNickname: string; + roleSign: string; + department: any; + phone: string; + email: string; + sex: string; + password: string; + overdueTime: string; + status: boolean; + describe: string; +} +interface UserState { + isShowDialog: boolean; + ruleForm: RuleFormRow; + deptData: Array<DeptData>; +} + +export default defineComponent({ + name: 'systemEditUser', + setup() { + const state = reactive<UserState>({ + isShowDialog: false, + ruleForm: { + userName: '', // 账户名称 + userNickname: '', // 用户昵称 + roleSign: '', // 关联角色 + department: [], // 部门 + phone: '', // 手机号 + email: '', // 邮箱 + sex: '', // 性别 + password: '', // 账户密码 + overdueTime: '', // 账户过期 + status: true, // 用户状态 + describe: '', // 用户描述 + }, + deptData: [], // 部门数据 + }); + // 打开弹窗 + const openDialog = (row: RuleFormRow) => { + state.ruleForm = row; + state.isShowDialog = true; + }; + // 关闭弹窗 + const closeDialog = () => { + state.isShowDialog = false; + }; + // 取消 + const onCancel = () => { + closeDialog(); + }; + // 新增 + const onSubmit = () => { + closeDialog(); + }; + // 初始化部门数据 + const initTableData = () => { + state.deptData.push({ + deptName: 'vueNextAdmin', + createTime: new Date().toLocaleString(), + status: true, + sort: Math.random(), + describe: '顶级部门', + id: Math.random(), + children: [ + { + deptName: 'IT外包服务', + createTime: new Date().toLocaleString(), + status: true, + sort: Math.random(), + describe: '总部', + id: Math.random(), + }, + { + deptName: '资本控股', + createTime: new Date().toLocaleString(), + status: true, + sort: Math.random(), + describe: '分部', + id: Math.random(), + }, + ], + }); + }; + // 页面加载时 + onMounted(() => { + initTableData(); + }); + return { + openDialog, + closeDialog, + onCancel, + onSubmit, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue new file mode 100644 index 0000000..a120c59 --- /dev/null +++ b/src/views/system/user/index.vue @@ -0,0 +1,177 @@ +<template> + <div class="system-user-container"> + <el-card shadow="hover"> + <div class="system-user-search mb15"> + <el-input size="default" placeholder="请输入用户名称" style="max-width: 180px"> </el-input> + <el-button size="default" type="primary" class="ml10"> + <el-icon> + <ele-Search /> + </el-icon> + 查询 + </el-button> + <el-button size="default" type="success" class="ml10" @click="onOpenAddUser"> + <el-icon> + <ele-FolderAdd /> + </el-icon> + 新增用户 + </el-button> + </div> + <el-table :data="tableData.data" style="width: 100%"> + <el-table-column type="index" label="序号" width="60" /> + <el-table-column prop="userName" label="账户名称" show-overflow-tooltip></el-table-column> + <el-table-column prop="userNickname" label="用户昵称" show-overflow-tooltip></el-table-column> + <el-table-column prop="roleSign" label="关联角色" show-overflow-tooltip></el-table-column> + <el-table-column prop="department" label="部门" show-overflow-tooltip></el-table-column> + <el-table-column prop="phone" label="手机号" show-overflow-tooltip></el-table-column> + <el-table-column prop="email" label="邮箱" show-overflow-tooltip></el-table-column> + <el-table-column prop="status" label="用户状态" show-overflow-tooltip> + <template #default="scope"> + <el-tag type="success" v-if="scope.row.status">启用</el-tag> + <el-tag type="info" v-else>禁用</el-tag> + </template> + </el-table-column> + <el-table-column prop="describe" label="用户描述" show-overflow-tooltip></el-table-column> + <el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column> + <el-table-column label="操作" width="100"> + <template #default="scope"> + <el-button :disabled="scope.row.userName === 'admin'" size="small" text type="primary" @click="onOpenEditUser(scope.row)">修改</el-button> + <el-button :disabled="scope.row.userName === 'admin'" size="small" text type="primary" @click="onRowDel(scope.row)">删除</el-button> + </template> + </el-table-column> + </el-table> + <el-pagination + @size-change="onHandleSizeChange" + @current-change="onHandleCurrentChange" + class="mt15" + :pager-count="5" + :page-sizes="[10, 20, 30]" + v-model:current-page="tableData.param.pageNum" + background + v-model:page-size="tableData.param.pageSize" + layout="total, sizes, prev, pager, next, jumper" + :total="tableData.total" + > + </el-pagination> + </el-card> + <AddUer ref="addUserRef" /> + <EditUser ref="editUserRef" /> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, onMounted, ref, defineComponent } from 'vue'; +import { ElMessageBox, ElMessage } from 'element-plus'; +import AddUer from '/@/views/system/user/component/addUser.vue'; +import EditUser from '/@/views/system/user/component/editUser.vue'; + +// 定义接口来定义对象的类型 +interface TableDataRow { + userName: string; + userNickname: string; + roleSign: string; + department: string[]; + phone: string; + email: string; + sex: string; + password: string; + overdueTime: Date; + status: boolean; + describe: string; + createTime: string; +} +interface TableDataState { + tableData: { + data: Array<TableDataRow>; + total: number; + loading: boolean; + param: { + pageNum: number; + pageSize: number; + }; + }; +} + +export default defineComponent({ + name: 'systemUser', + components: { AddUer, EditUser }, + setup() { + const addUserRef = ref(); + const editUserRef = ref(); + const state = reactive<TableDataState>({ + tableData: { + data: [], + total: 0, + loading: false, + param: { + pageNum: 1, + pageSize: 10, + }, + }, + }); + // 初始化表格数据 + const initTableData = () => { + const data: Array<TableDataRow> = []; + for (let i = 0; i < 2; i++) { + data.push({ + userName: i === 0 ? 'admin' : 'test', + userNickname: i === 0 ? '我是管理员' : '我是普通用户', + roleSign: i === 0 ? 'admin' : 'common', + department: i === 0 ? ['vueNextAdmin', 'IT外包服务'] : ['vueNextAdmin', '资本控股'], + phone: '12345678910', + email: 'vueNextAdmin@123.com', + sex: '女', + password: '123456', + overdueTime: new Date(), + status: true, + describe: i === 0 ? '不可删除' : '测试用户', + createTime: new Date().toLocaleString(), + }); + } + state.tableData.data = data; + state.tableData.total = state.tableData.data.length; + }; + // 打开新增用户弹窗 + const onOpenAddUser = () => { + addUserRef.value.openDialog(); + }; + // 打开修改用户弹窗 + const onOpenEditUser = (row: TableDataRow) => { + editUserRef.value.openDialog(row); + }; + // 删除用户 + const onRowDel = (row: TableDataRow) => { + ElMessageBox.confirm(`此操作将永久删除账户名称:“${row.userName}”,是否继续?`, '提示', { + confirmButtonText: '确认', + cancelButtonText: '取消', + type: 'warning', + }) + .then(() => { + ElMessage.success('删除成功'); + }) + .catch(() => {}); + }; + // 分页改变 + const onHandleSizeChange = (val: number) => { + state.tableData.param.pageSize = val; + }; + // 分页改变 + const onHandleCurrentChange = (val: number) => { + state.tableData.param.pageNum = val; + }; + // 页面加载时 + onMounted(() => { + initTableData(); + }); + return { + addUserRef, + editUserRef, + onOpenAddUser, + onOpenEditUser, + onRowDel, + onHandleSizeChange, + onHandleCurrentChange, + ...toRefs(state), + }; + }, +}); +</script> diff --git a/src/views/test/index.vue b/src/views/test/index.vue new file mode 100644 index 0000000..827727e --- /dev/null +++ b/src/views/test/index.vue @@ -0,0 +1,13 @@ +<template> + +</template> + +<script> + export default { + name: "index" + } +</script> + +<style scoped> + +</style> diff --git a/src/views/visualizing/demo1.vue b/src/views/visualizing/demo1.vue new file mode 100644 index 0000000..cfc6166 --- /dev/null +++ b/src/views/visualizing/demo1.vue @@ -0,0 +1,1278 @@ +<template> + <div class="visualizing-demo1"> + <!-- 地图 --> + <div ref="visualizingDemo1" style="height: 100%"></div> + <div class="visualizing-container"> + <!-- 头部 --> + <div class="visualizing-container-head"> + <div class="visualizing-container-head-left"> + <div class="visualizing-container-head-left-text"> + <div class="visualizing-container-head-left-text-box">{{ time.txt }}</div> + </div> + </div> + <div class="visualizing-container-head-center"> + <div class="visualizing-container-head-center-box"> + <div class="visualizing-container-head-center-maintitle">深圳市xxx软件科技有限公司</div> + <div class="visualizing-container-head-center-subtitle">旅游经济</div> + </div> + </div> + <div class="visualizing-container-head-right"> + <div class="visualizing-container-head-right-text"> + <div class="visualizing-container-head-right-text-box">🌤 多云转晴东南风 26~30℃</div> + </div> + </div> + </div> + + <!-- 图表左侧 --> + <div class="visualizing-container-content-left"> + <div class="visualizing-container-content-left-flex"> + <div class="visualizing-container-title"> + <i class="el-icon-s-shop"></i> + <span>产业概况</span> + </div> + <hr class="visualizing-container-title-colorful" /> + <div ref="visualizingContentLeftTop" style="height: 100%"></div> + </div> + <div class="visualizing-container-content-left-flex"> + <div class="visualizing-container-title"> + <i class="el-icon-s-promotion"></i> + <span>A级风景区对比</span> + </div> + <hr class="visualizing-container-title-colorful" /> + <div ref="visualizingContentLeftBottom" style="height: 100%"></div> + </div> + </div> + + <!-- 图表中间 --> + <div class="visualizing-container-content-center"> + <div class="visualizing-container-content-center-bottom"> + <div class="visualizing-container-content-center-bottom-flex"> + <div class="visualizing-container-title"> + <i class="el-icon-s-custom"></i> + <span>游客过夜情况</span> + </div> + <hr class="visualizing-container-title-colorful" /> + <div ref="visualizingContentCenterTop" style="height: 100%"></div> + </div> + <div class="visualizing-container-content-center-bottom-flex"> + <div class="visualizing-container-title"> + <i class="el-icon-s-flag"></i> + <span>游客驻留时长</span> + </div> + <hr class="visualizing-container-title-colorful" /> + <div ref="visualizingContentCenterBottom" style="height: 100%"></div> + </div> + </div> + </div> + + <!-- 图表右侧 --> + <div class="visualizing-container-content-right"> + <div class="visualizing-container-content-right-flex"> + <div class="visualizing-container-title"> + <i class="el-icon-s-marketing"></i> + <span>当日游客趋势分析</span> + </div> + <hr class="visualizing-container-title-colorful" /> + <div ref="visualizingContentRightTop" style="height: 100%"></div> + </div> + <div class="visualizing-container-content-right-flex"> + <div class="visualizing-container-title"> + <i class="el-icon-s-data"></i> + <span>当月游客趋势分析</span> + </div> + <hr class="visualizing-container-title-colorful" /> + <div ref="visualizingContentRightBottom" style="height: 100%"></div> + </div> + </div> + </div> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, onMounted, onUnmounted, getCurrentInstance, defineComponent } from 'vue'; +import * as echarts from 'echarts'; +import 'echarts/extension/bmap/bmap'; +import { formatDate } from '/@/utils/formatTime'; +import { NextLoading } from '/@/utils/loading'; +import { echartsMapList, echartsMapData, echartsMapImgs } from './mock/demo1'; + +// 定义接口来定义对象的类型 +interface Demo1State { + visualizingDemo1: any; + echartsMapList: any; + echartsMapData: any; + echartsMapImgs: any; + time: any; + myCharts: any[]; +} + +export default defineComponent({ + name: 'visualizingLinkDemo1', + setup() { + const { proxy } = <any>getCurrentInstance(); + const state = reactive<Demo1State>({ + visualizingDemo1: null, + echartsMapList, + echartsMapData, + echartsMapImgs, + time: { + txt: '', + fun: 0, + }, + myCharts: [], + }); + // 初始化时间 + const initTime = () => { + state.time.txt = formatDate(new Date(), 'YYYY-mm-dd HH:MM:SS WWW QQQQ ZZZ'); + state.time.fun = window.setInterval(() => { + state.time.txt = formatDate(new Date(), 'YYYY-mm-dd HH:MM:SS WWW QQQQ ZZZ'); + }, 1000); + }; + // echartsMap 将坐标信息和对应物理量的值合在一起 + const convertData = (data: any) => { + let res = []; + for (let i = 0; i < data.length; i++) { + let geoCoord = state.echartsMapData[data[i].name]; + if (geoCoord) { + res.push({ + name: data[i].name, + value: geoCoord.concat(data[i].value), + }); + } + } + return res; + }; + // 初始化 echartsMap(地图上的点) + const initEchartsMap = () => { + const myChart = echarts.init(<HTMLElement>state.visualizingDemo1); + const option = { + tooltip: { + trigger: 'item', + formatter(params: any) { + // 自定义鼠标放入样式 + let item = state.echartsMapImgs.find((v: any) => v.name === params.name); + let html = `<div style="width: 240px"> + <div style="display: flex; align-items: center"> + <img src="${item?.url}" style="width: 50px; height: 50px; border-radius: 100%; position: relative; border: 4px solid #ffffff; margin-left: -4px" /> + <div + style=" + background: #51c1ff; + width: 100%; + height: 32px; + margin-left: -14px; + display: flex; + align-items: center; + padding-left: 20px; + color: #fff; + " + > + ${item?.name} + </div> + </div> + <div style="margin-top: 10px; font-size: 12px"> + <div style="width: 61px"><i class="el-icon-location-information" style="margin-right: 5px"></i>地址:</div> + <div style="flex: 1; white-space: pre-wrap; word-break: break-all; margin-top: 5px; color: #333">${item?.add}</div> + </div> + <div style="margin-top: 10px; font-size: 12px"> + <div style="width: 61px"><i class="el-icon-chat-dot-round" style="margin-right: 5px"></i>概括:</div> + <div style="flex: 1; white-space: pre-wrap; word-break: break-all; margin-top: 5px; color: #333">${item?.dec}</div> + </div> + </div>`; + return html; + }, + }, + color: ['#ea7ccc'], + bmap: { + center: [114.064524, 22.549225], + zoom: 11, + roam: true, + mapStyle: {}, + }, + series: [ + { + name: '门票收入', + type: 'scatter', + coordinateSystem: 'bmap', + data: convertData(state.echartsMapList), + symbolSize: function (val: any) { + return val[2] / 10; + }, + encode: { + value: 2, + }, + label: { + formatter: '{b}', + position: 'right', + show: false, + }, + emphasis: { + label: { + show: true, + }, + }, + }, + { + name: '门票收入', + type: 'effectScatter', + coordinateSystem: 'bmap', + data: convertData( + state.echartsMapList + .sort(function (a: any, b: any) { + return b.value - a.value; + }) + .slice(0, 6) + ), + symbolSize: function (val: any) { + return val[2] / 10; + }, + encode: { + value: 2, + }, + showEffectOn: 'render', + rippleEffect: { + brushType: 'stroke', + }, + hoverAnimation: true, + label: { + formatter: '{b}', + position: 'right', + show: true, + }, + itemStyle: { + shadowBlur: 100, + shadowColor: '#333', + }, + zlevel: 1, + }, + ], + }; + myChart.setOption(option); + state.myCharts.push(myChart); + + // 地图 + const map = (<any>myChart).getModel().getComponent('bmap').getBMap(); + // BMAP_NORMAL_MAP :此地图类型展示普通街道视图 + // BMAP_PERSPECTIVE_MAP :此地图类型展示透视图像视图。(这个还不会用) + // BMAP_SATELLITE_MAP:卫星地图 (没有坐标, 绿绿的一片的卫星地图) + // BMAP_HYBRID_MAP:混合地图 (既有坐标,也是绿绿的一片的卫星地图) + // eslint-disable-next-line no-undef + map.setMapType(BMAP_SATELLITE_MAP); + // eslint-disable-next-line no-undef + let bdary = new BMap.Boundary(); + // 获取行政区域 + bdary.get('深圳', function (rs: any) { + // 行政区域的点有多少个 + let count = rs.boundaries.length; + for (let i = 0; i < count; i++) { + // eslint-disable-next-line no-undef + let ply = new BMap.Polygon(rs.boundaries[i], { + // 设置多边形边线线粗 + strokeWeight: 4, + // 设置多边形边线透明度0-1 + strokeOpacity: 1, + // 设置多边形边线样式为实线或虚线,取值 solid 或 dashed + StrokeStyle: 'dashed', + // 设置多边形边线颜色 + strokeColor: '#febb50', + // 设置多边形填充颜色 + fillColor: '', + }); + // 建立多边形覆盖物 + // 添加覆盖物 + map.addOverlay(ply); + // 调整视野 + map.setViewport(ply.getPath()); + } + // 初始化地图,设置中心点坐标和地图级别 + // new BMap.Point('深圳市', 11) + // eslint-disable-next-line no-undef + map.centerAndZoom(new BMap.Point(114.064524, 22.549225), 11); + }); + }; + // 产业概况 + const initVisualizingContentLeftTop = () => { + const myChart = echarts.init(proxy.$refs.visualizingContentLeftTop); + const option = { + grid: { + top: 50, + right: 0, + bottom: 50, + left: 30, + }, + tooltip: { + trigger: 'axis', + }, + xAxis: { + data: ['1月', '2月', '3月', '4月', '5月', '6月'], + axisLine: { + lineStyle: { + color: 'rgba(22, 207, 208, 0.1)', + width: 1, + }, + }, + axisTick: { + show: false, + }, + axisLabel: { + color: '#16cfd0', + }, + }, + yAxis: [ + { + type: 'value', + name: '价格', + axisLine: { + show: true, + lineStyle: { + color: 'rgba(22, 207, 208, 0.1)', + }, + }, + axisLabel: { + color: '#16cfd0', + }, + splitLine: { + show: true, + lineStyle: { + color: 'rgba(22, 207, 208, 0.3)', + }, + }, + splitArea: { + show: true, + areaStyle: { + color: 'rgba(22, 207, 208, 0.02)', + }, + }, + nameTextStyle: { + color: '#16cfd0', + }, + }, + ], + series: [ + { + name: '预购队列', + type: 'line', + data: [200, 85, 112, 275, 305, 415], + itemStyle: { + color: '#16cfd0', + }, + }, + { + name: '最新成交价', + type: 'line', + data: [50, 85, 22, 155, 170, 25], + itemStyle: { + color: '#febb50', + }, + }, + ], + }; + myChart.setOption(option); + state.myCharts.push(myChart); + }; + // A级风景区对比 + const initVisualizingContentLeftBottom = () => { + const myChart = echarts.init(proxy.$refs.visualizingContentLeftBottom); + const option = { + grid: { + top: 50, + right: 10, + bottom: 40, + left: 30, + }, + tooltip: { + trigger: 'axis', + }, + xAxis: { + type: 'category', + boundaryGap: false, + data: ['1月', '2月', '3月', '4月', '5月'], + axisLine: { + lineStyle: { + color: 'rgba(22, 207, 208, 0.1)', + width: 1, + }, + }, + axisTick: { + show: false, + }, + axisLabel: { + interval: 0, + color: '#16cfd0', + textStyle: { + fontSize: 10, + }, + }, + }, + yAxis: [ + { + type: 'value', + name: '销量', + axisLabel: { + color: '#16cfd0', + }, + splitLine: { + show: true, + lineStyle: { + color: 'rgba(22, 207, 208, 0.3)', + }, + }, + splitArea: { + show: true, + areaStyle: { + color: 'rgba(22, 207, 208, 0.02)', + }, + }, + nameTextStyle: { + color: '#16cfd0', + }, + }, + ], + series: [ + { + name: '客流', + type: 'line', + stack: '总量', + smooth: true, + lineStyle: { + width: 0, + }, + areaStyle: { + opacity: 0.8, + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { + offset: 0, + color: 'rgba(128, 255, 165)', + }, + { + offset: 1, + color: 'rgba(1, 191, 236)', + }, + ]), + }, + emphasis: { + focus: 'series', + }, + data: [140, 232, 101, 264, 90], + }, + { + name: '天数', + type: 'line', + stack: '总量', + smooth: true, + lineStyle: { + width: 0, + }, + areaStyle: { + opacity: 0.8, + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { + offset: 0, + color: 'rgba(0, 221, 255)', + }, + { + offset: 1, + color: 'rgba(77, 119, 255)', + }, + ]), + }, + emphasis: { + focus: 'series', + }, + data: [120, 282, 111, 234, 220], + }, + ], + }; + myChart.setOption(option); + state.myCharts.push(myChart); + }; + // 游客过夜情况 + const initVisualizingContentCenterTop = () => { + const myChart = echarts.init(proxy.$refs.visualizingContentCenterTop); + const min = 100; + const max = 1000; + const option = { + grid: { + top: 50, + right: 10, + bottom: 66, + left: 38, + }, + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'shadow', + }, + }, + xAxis: [ + { + type: 'category', + data: ['地区', '地区', '地区', '地区', '地区', '地区', '地区', '地区', '地区', '地区'], + axisLabel: { + color: '#16cfd0', + textStyle: { + fontSize: 9, + }, + interval: 0, + rotate: -45, + }, + axisLine: { + lineStyle: { + color: 'rgba(22, 207, 208, 0.1)', + width: 1, + }, + }, + axisTick: { + show: false, + }, + }, + ], + yAxis: [ + { + type: 'value', + name: '天数', + nameGap: 25, + axisLine: { + show: true, + lineStyle: { + color: 'rgba(22, 207, 208, 0.1)', + }, + }, + axisLabel: { + color: '#16cfd0', + }, + splitLine: { + show: true, + lineStyle: { + color: 'rgba(22, 207, 208, 0.3)', + }, + }, + splitArea: { + show: true, + areaStyle: { + color: 'rgba(22, 207, 208, 0.02)', + }, + }, + nameTextStyle: { + color: '#16cfd0', + }, + }, + ], + series: [ + { + type: 'bar', + barWidth: 15, + itemStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { + offset: 0, + color: '#de682e', + }, + { + offset: 1, + color: '#ecc232', + }, + ]), + }, + }, + label: { + normal: { + show: true, + position: 'top', + formatter: function (param: any) { + if (param.value == max || param.value == min) { + return ''; + } + return param.value; + }, + textStyle: { + color: 'rgba(22, 207, 208, 0.8)', + fontSize: 10, + }, + }, + }, + markPoint: { + symbolSize: 30, + label: { + normal: { + textStyle: { + color: '#ffffff', + fontSize: 10, + }, + }, + }, + data: [ + { name: '年最低', value: min, xAxis: 0, yAxis: 100 }, + { name: '年最高', value: max, xAxis: 9, yAxis: 1000 }, + ], + }, + data: [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000], + }, + ], + }; + myChart.setOption(option); + state.myCharts.push(myChart); + }; + // 游客驻留时长 + const initVisualizingContentCenterBottom = () => { + const myChart = echarts.init(proxy.$refs.visualizingContentCenterBottom); + const option = { + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'shadow', + }, + }, + grid: { + top: 26, + right: 10, + bottom: 66, + left: 45, + }, + xAxis: { + type: 'value', + axisLabel: { + color: '#16cfd0', + }, + splitLine: { + show: true, + lineStyle: { + color: 'rgba(22, 207, 208, 0.3)', + }, + }, + }, + yAxis: { + type: 'category', + axisLabel: { + color: '#16cfd0', + }, + }, + series: [ + { + name: '已完成', + type: 'bar', + stack: 'total', + label: { + show: true, + }, + emphasis: { + focus: 'series', + }, + barWidth: 12, + itemStyle: { + label: { + show: true, + }, + labelLine: { + show: false, + }, + color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [ + { offset: 0, color: 'rgba(7,165,255,0.2)' }, + { offset: 1, color: 'rgba(7,165,255,1)' }, + ]), + }, + }, + { + name: '进行中', + type: 'bar', + stack: 'total', + label: { + show: true, + }, + emphasis: { + focus: 'series', + }, + barWidth: 12, + itemStyle: { + label: { + show: true, + }, + labelLine: { + show: false, + }, + color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [ + { offset: 0, color: 'rgba(41,244,236,0)' }, + { offset: 1, color: 'rgba(41,244,236,1)' }, + ]), + }, + }, + ], + dataset: { + source: [ + { status: '已签收', value1: 33, value2: 93 }, + { status: '配送中', value1: 53, value2: 32 }, + { status: '已出库', value1: 78, value2: 65 }, + { status: '采购中', value1: 12, value2: 35 }, + { status: '接单中', value1: 90, value2: 52 }, + ], + }, + }; + myChart.setOption(option); + state.myCharts.push(myChart); + }; + // 当日游客趋势分析 + const initVisualizingContentRightTop = () => { + const myChart = echarts.init(proxy.$refs.visualizingContentRightTop); + const option = { + grid: { + top: 50, + right: 30, + bottom: 50, + left: 20, + }, + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'shadow', + }, + }, + xAxis: { + data: ['1月', '2月', '3月', '4月', '5月', '6月'], + axisLine: { + lineStyle: { + color: 'rgba(22, 207, 208, 0.5)', + width: 1, + }, + }, + axisTick: { + show: false, + }, + axisLabel: { + color: '#16cfd0', + }, + }, + yAxis: [ + { + type: 'value', + name: '亿元', + axisLine: { + show: true, + lineStyle: { + color: 'rgba(22, 207, 208, 0.1)', + }, + }, + axisLabel: { + color: '#16cfd0', + }, + splitLine: { + show: true, + lineStyle: { + color: 'rgba(22, 207, 208, 0.3)', + }, + }, + splitArea: { + show: true, + areaStyle: { + color: 'rgba(22, 207, 208, 0.02)', + }, + }, + nameTextStyle: { + color: '#16cfd0', + }, + }, + { + type: 'value', + name: '同比', + position: 'right', + axisLine: { + show: false, + }, + axisLabel: { + show: true, + formatter: '{value}%', + textStyle: { + color: '#16cfd0', + }, + }, + splitLine: { + show: false, + }, + axisTick: { + show: false, + }, + splitArea: { + show: true, + areaStyle: { + color: 'rgba(22, 207, 208, 0.02)', + }, + }, + nameTextStyle: { + color: '#16cfd0', + }, + }, + ], + series: [ + { + name: '销售水量', + type: 'line', + yAxisIndex: 1, + smooth: true, + showAllSymbol: true, + symbol: 'circle', + itemStyle: { + color: '#058cff', + }, + lineStyle: { + color: '#058cff', + }, + areaStyle: { + color: 'rgba(5,140,255, 0.2)', + }, + data: [4.2, 3.8, 4.8, 3.5, 2.9, 2.8], + }, + { + name: '主营业务', + type: 'bar', + barWidth: 15, + itemStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { + offset: 0, + color: '#00FFE3', + }, + { + offset: 1, + color: '#4693EC', + }, + ]), + }, + }, + data: [4.2, 3.8, 4.8, 3.5, 2.9, 2.8], + }, + ], + }; + myChart.setOption(option); + state.myCharts.push(myChart); + }; + // 当月游客趋势分析 + const initVisualizingContentRightBottom = () => { + const myChart = echarts.init(proxy.$refs.visualizingContentRightBottom); + const option = { + grid: { + top: 50, + right: 10, + bottom: 40, + left: 30, + }, + tooltip: { + trigger: 'axis', + }, + xAxis: { + data: ['1月', '2月', '3月', '4月', '5月', '6月'], + axisLine: { + lineStyle: { + color: 'rgba(22, 207, 208, 0.1)', + width: 1, + }, + }, + axisTick: { + show: false, + }, + axisLabel: { + color: '#16cfd0', + }, + }, + yAxis: [ + { + type: 'value', + name: '人数(万)', + axisLine: { + show: true, + lineStyle: { + color: 'rgba(22, 207, 208, 0.1)', + }, + }, + axisLabel: { + color: '#16cfd0', + }, + splitLine: { + show: true, + lineStyle: { + color: 'rgba(22, 207, 208, 0.3)', + }, + }, + splitArea: { + show: true, + areaStyle: { + color: 'rgba(22, 207, 208, 0.02)', + }, + }, + nameTextStyle: { + color: '#16cfd0', + }, + }, + ], + series: [ + { + name: '预购队列', + type: 'line', + data: [20, 15, 40, 55, 65, 85], + smooth: true, + itemStyle: { + color: '#EA7CCC', + }, + }, + { + name: '最新成交价', + type: 'line', + data: [30, 45, 65, 85, 60, 105], + smooth: true, + itemStyle: { + color: '#FAC958', + }, + }, + ], + }; + myChart.setOption(option); + state.myCharts.push(myChart); + }; + // 批量设置 echarts resize + const initEchartsResize = () => { + window.addEventListener('resize', () => { + for (let i = 0; i < state.myCharts.length; i++) { + state.myCharts[i].resize(); + } + }); + }; + // 页面加载时 + onMounted(async () => { + NextLoading.done(); + initTime(); + await initEchartsMap(); + await initVisualizingContentLeftTop(); + await initVisualizingContentLeftBottom(); + await initVisualizingContentCenterTop(); + await initVisualizingContentCenterBottom(); + await initVisualizingContentRightTop(); + await initVisualizingContentRightBottom(); + await initEchartsResize(); + }); + // 页面卸载时 + onUnmounted(() => { + window.clearInterval(state.time.fun); + }); + return { + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +// 左右两侧图表宽度 +$lrWidth: 288px; +// 中部图表高度 +$cheight: 240px; +// 标题宽度 +$titleWidth: 240px; +.visualizing-demo1 { + height: 100%; + width: 100%; + position: relative; + ::v-deep(.BMap_cpyCtrl) { + display: none; + } + ::v-deep(.anchorBL) { + display: none; + } + .visualizing-container { + .visualizing-container-head { + height: 60px; + width: 100%; + position: absolute; + top: 0; + left: 0; + display: flex; + align-items: center; + color: #ffffff; + background: linear-gradient(to bottom, rgba(0, 0, 0, 0.9), rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.02)); + z-index: 3; + .visualizing-container-head-left { + flex: 1; + position: relative; + height: 60px; + .visualizing-container-head-left-text { + position: relative; + z-index: 1; + font-size: 12px; + opacity: 0.6; + width: 93%; + padding-left: 15px; + top: 50%; + transform: translateY(-100%); + .visualizing-container-head-left-text-box { + width: 100%; + position: relative; + padding-left: 15px; + &::after { + content: ''; + height: 20px; + width: 100%; + position: absolute; + background: linear-gradient(to right, rgba(22, 207, 208, 0.1), rgba(22, 207, 208, 0.3)); + top: -1px; + left: 0; + transform: skew(30deg); + } + } + } + &::before, + &::after { + content: ''; + height: 3px; + background: linear-gradient(-90deg, #16cfd0, transparent); + position: absolute; + width: 100%; + } + &::before { + top: 1px; + right: 33px; + opacity: 0.8; + } + &::after { + top: 41px; + right: -2px; + } + } + .visualizing-container-head-center { + height: 60px; + font-size: 18px; + text-align: center; + display: flex; + flex-direction: column; + position: relative; + padding: 0 60px; + background: radial-gradient(rgba(0, 0, 0, 0.7) 5%, rgba(0, 0, 0, 0.5) 15%, rgba(0, 0, 0, 0.02) 70%); + .visualizing-container-head-center-box { + margin: auto; + position: relative; + z-index: 1; + .visualizing-container-head-center-maintitle { + position: relative; + &::before, + &::after { + content: ''; + position: absolute; + min-width: 21%; + height: 29px; + top: 2px; + opacity: 0.3; + border-top: 1px solid #16cfd0; + } + &::before { + left: -70px; + border-right: 2px solid #16cfd0; + transform: skew(50deg); + } + &::after { + right: -70px; + border-left: 2px solid #16cfd0; + transform: skew(-50deg); + } + } + .visualizing-container-head-center-subtitle { + font-size: 14px; + opacity: 0.8; + position: relative; + &::before, + &::after { + content: ''; + position: absolute; + min-width: 35%; + height: 23px; + bottom: 8px; + border-bottom: 2px solid #16cfd0; + } + &::before { + transform: skew(50deg); + left: -33px; + border-left: 3px solid #16cfd0; + border-image: linear-gradient(to right, #16cfd0, rgba(22, 207, 208, 0.02)) 1 10; + } + &::after { + transform: skew(-50deg); + right: -33px; + border-right: 3px solid #16cfd0; + border-image: linear-gradient(to left, rgba(22, 207, 208, 1), rgba(22, 207, 208, 0.02)) 1 10; + } + } + &::before, + &::after { + content: ''; + position: absolute; + width: 36px; + height: 17px; + top: -8px; + border-bottom: 2px solid rgba(22, 207, 208, 0.7); + } + &::before { + transform: skew(32deg); + left: -89px; + border-left: 3px solid rgba(22, 207, 208, 0.7); + } + &::after { + transform: skew(-32deg); + right: -89px; + border-right: 3px solid rgba(22, 207, 208, 0.7); + } + } + &::before, + &::after { + content: ''; + position: absolute; + min-width: 50%; + height: 15px; + bottom: 0px; + border-bottom: 4px solid #16cfd0; + } + &::before { + transform: skew(60deg); + left: 13px; + border-left: 5px solid #16cfd0; + } + &::after { + transform: skew(-60deg); + right: 13px; + border-right: 5px solid #16cfd0; + } + } + .visualizing-container-head-right { + flex: 1; + position: relative; + height: 60px; + .visualizing-container-head-right-text { + position: relative; + z-index: 1; + font-size: 12px; + opacity: 0.6; + width: 93%; + float: right; + text-align: right; + padding-right: 15px; + top: 50%; + transform: translateY(-100%); + .visualizing-container-head-right-text-box { + width: 100%; + position: relative; + padding-right: 15px; + &::after { + content: ''; + height: 20px; + width: 100%; + position: absolute; + background: linear-gradient(to left, rgba(22, 207, 208, 0.1), rgba(22, 207, 208, 0.3)); + top: -1px; + right: 0; + transform: skew(-30deg); + } + } + } + &::before, + &::after { + content: ''; + height: 3px; + background: linear-gradient(90deg, #16cfd0, transparent); + position: absolute; + width: 100%; + } + &::before { + top: 1px; + left: 33px; + opacity: 0.8; + } + &::after { + top: 41px; + left: -2px; + } + } + } + .visualizing-container-title { + max-width: $titleWidth; + font-size: 14px; + color: #ffffff; + opacity: 0.8; + padding: 0 5px; + border-bottom: 1px solid #ffffff; + border-image: linear-gradient(to right, #ffffff, rgba(22, 207, 208, 0.02)) 1 10; + position: relative; + i { + padding-right: 5px; + color: orange; + } + &::after { + content: ''; + position: absolute; + left: 0; + bottom: 0; + width: 1px; + height: 10px; + background: linear-gradient(to top, #ffffff, rgba(255, 255, 255, 0.5)); + } + } + .visualizing-container-title-colorful { + max-width: $titleWidth; + border: 0; + padding: 1px; + background: linear-gradient(135deg, red, orange, green, #16cfd0, purple); + --mask-image: repeating-linear-gradient(135deg, #000 0px, #000 1px, transparent 1px, transparent 4px); + -webkit-mask-image: var(--mask-image); + mask-image: var(--mask-image); + } + .visualizing-container-content-left { + width: $lrWidth; + height: 100%; + position: absolute; + top: 0; + left: 0; + background: linear-gradient(to right, rgba(0, 0, 0, 0.9), rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.01)); + padding-top: 60px; + z-index: 2; + .visualizing-container-content-left-flex { + height: 50%; + display: flex; + flex-direction: column; + padding-left: 15px; + } + } + .visualizing-container-content-center { + width: 100%; + height: $cheight; + position: absolute; + bottom: 0; + left: 0; + background: linear-gradient(to top, rgba(0, 0, 0, 0.9), rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.01)); + z-index: 1; + .visualizing-container-content-center-bottom { + width: calc(100% - #{$lrWidth * 2}); + height: $cheight; + left: $lrWidth; + bottom: 0; + position: absolute; + display: flex; + padding: 0 15px; + .visualizing-container-content-center-bottom-flex { + width: 50%; + padding: 0 15px; + } + } + } + .visualizing-container-content-right { + width: $lrWidth; + height: 100%; + position: absolute; + top: 0; + right: 0; + padding-top: 60px; + background: linear-gradient(to left, rgba(0, 0, 0, 0.9), rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.01)); + z-index: 2; + .visualizing-container-content-right-flex { + height: 50%; + display: flex; + flex-direction: column; + padding-right: 15px; + } + } + } +} +</style> diff --git a/src/views/visualizing/demo2.vue b/src/views/visualizing/demo2.vue new file mode 100644 index 0000000..2e973fc --- /dev/null +++ b/src/views/visualizing/demo2.vue @@ -0,0 +1,1344 @@ +<template> + <div class="visualizing-demo2"> + <!-- 顶部 --> + <div class="big-data-up"> + <div class="up-left"> + <SvgIcon name="ele-Timer" class="mr5" /> + <span>{{ time.txt }}</span> + </div> + <div class="up-center"> + <span>智慧农业系统平台</span> + </div> + <div class="up-right"> + <el-dropdown size="small"> + <span class="el-dropdown-link"> + {{ dropdownActive }} + <SvgIcon name="ele-ArrowDown" class="el-icon--right" /> + </span> + <template #dropdown> + <el-dropdown-menu> + <el-dropdown-item v-for="(v, k) in dropdownList" :key="k">{{ v.label }} </el-dropdown-item> + </el-dropdown-menu> + </template> + </el-dropdown> + <div class="ml15"> + <SvgIcon name="ele-Bell" class="mr5" /> + <span>消息</span> + </div> + <div class="ml15"> + <SvgIcon name="ele-User" class="mr5" /> + <span>个人</span> + </div> + <div class="ml15"> + <SvgIcon name="ele-SwitchButton" class="mr5" /> + <span>返回</span> + </div> + </div> + </div> + + <div class="big-data-down"> + <!-- 左边 --> + <div class="big-data-down-left"> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <div class="flex-title">天气预报</div> + <div class="flex-content flex-content-overflow"> + <div class="sky"> + <SvgIcon name="ele-Sunny" class="sky-left" /> + <div class="sky-center"> + <div class="mb2"> + <span class="font">多云转晴</span> + <span class="font">东南风</span> + <span>良</span> + </div> + <div class="sky-tip">温馨提示:多云转晴,南风转北风风力3级</div> + </div> + <div class="sky-right"> + <span>25</span> + <span class="font">°C</span> + </div> + </div> + <div class="sky-dd"> + <div class="sky-dl" v-for="(v, k) in skyList" :key="k" :class="{ 'sky-dl-first': k === 1 }"> + <div>{{ v.v1 }}</div> + <div v-if="v.type === 'title'">{{ v.v2 }}</div> + <div v-else> + <SvgIcon :name="v.v2" /> + </div> + <div>{{ v.v3 }}</div> + <div>{{ v.v4 }}</div> + <div class="tip">{{ v.v5 }}</div> + <div>{{ v.v6 }}</div> + <div>{{ v.v7 }}</div> + </div> + </div> + </div> + </div> + </div> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <div class="flex-title">当前设备状态</div> + <div class="flex-content flex-content-overflow"> + <div class="d-states"> + <div class="d-states-item"> + <SvgIcon name="ele-Odometer" class="i-bg1" /> + <div class="d-states-flex"> + <div class="d-states-item-label">园区设备数</div> + <div class="d-states-item-value">99</div> + </div> + </div> + <div class="d-states-item"> + <SvgIcon name="ele-FirstAidKit" class="i-bg2" /> + <div class="d-states-flex"> + <div class="d-states-item-label">预警设备数</div> + <div class="d-states-item-value">10</div> + </div> + </div> + <div class="d-states-item"> + <SvgIcon name="ele-VideoPlay" class="i-bg3" /> + <div class="d-states-flex"> + <div class="d-states-item-label">运行设备数</div> + <div class="d-states-item-value">20</div> + </div> + </div> + </div> + <div class="d-btn"> + <div class="d-btn-item" v-for="(v, k) in dBtnList" :key="k" :class="{ 'd-btn-active': dBtnActive === k }"> + <SvgIcon name="ele-Money" class="d-btn-item-left" /> + <div class="d-btn-item-center"> + <div>{{ v.v1 }}</div> + <div>{{ v.v2 }}|{{ v.v3 }}</div> + </div> + <div class="d-btn-item-eight">{{ v.v4 }}</div> + </div> + </div> + </div> + </div> + </div> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <div class="flex-title">近30天预警总数</div> + <div class="flex-content" ref="rightChartData1"></div> + </div> + </div> + </div> + + <!-- 中间 --> + <div class="big-data-down-center"> + <div class="big-data-down-center-one"> + <div class="big-data-down-center-one-content" ref="rightChartData5"> + <div ref="the3DEarth"></div> + <div :class="v.topLevelClass" v-for="(v, k) in earth3DBtnList" :key="k"> + <div class="circle" v-for="i in 4" :key="i"></div> + <div class="text-box"> + <SvgIcon :name="v.icon" /> + <div class="text">{{ v.label }}</div> + </div> + </div> + </div> + </div> + <div class="big-data-down-center-two"> + <div class="flex-warp-item-box"> + <div class="flex-title"> + <span>当前设备监测</span> + <span class="flex-title-small">单位:次</span> + </div> + <div class="flex-content"> + <div class="flex-content-left"> + <div class="monitor-item" v-for="(v, k) in chartData4List" :key="k"> + <div class="monitor-wave" :class="{ 'monitor-active': k === chartData4Index }"> + <div class="monitor-z-index"> + <div class="monitor-item-label">{{ v.label }}</div> + </div> + </div> + </div> + </div> + <div class="flex-content-right" ref="rightChartData4"></div> + </div> + </div> + </div> + </div> + + <!-- 右边 --> + <div class="big-data-down-right"> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <div class="flex-title"> + <span>近7天产品追溯扫码统计</span> + <span class="flex-title-small">单位:次</span> + </div> + <div class="flex-content" ref="rightChartData3"></div> + </div> + </div> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <div class="flex-title">当前任务统计</div> + <div class="flex-content"> + <div class="task"> + <div class="task-item task-first-item"> + <div class="task-item-value task-first">25</div> + <div class="task-item-label">待办任务</div> + </div> + <div class="task-item"> + <div class="task-item-box task1"> + <div class="task-item-value">12</div> + <div class="task-item-label">施肥</div> + </div> + </div> + <div class="task-item"> + <div class="task-item-box task2"> + <div class="task-item-value">3</div> + <div class="task-item-label">施药</div> + </div> + </div> + <div class="task-item"> + <div class="task-item-box task3"> + <div class="task-item-value">5</div> + <div class="task-item-label">农事</div> + </div> + </div> + <div class="task-item"> + <div class="task-item-box task4"> + <div class="task-item-value">3</div> + <div class="task-item-label">巡园</div> + </div> + </div> + <div class="task-item"> + <div class="task-item-box task5"> + <div class="task-item-value">2</div> + <div class="task-item-label">采集</div> + </div> + </div> + </div> + <div ref="rightChartData6" class="progress"></div> + </div> + </div> + </div> + <div class="flex-warp-item"> + <div class="flex-warp-item-box"> + <div class="flex-title"> + <span>近7天投入品记录</span> + <span class="flex-title-small">单位:件</span> + </div> + <div class="flex-content" ref="rightChartData2"></div> + </div> + </div> + </div> + </div> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, onMounted, onUnmounted, getCurrentInstance, defineComponent } from 'vue'; +import * as echarts from 'echarts'; +import 'echarts-gl'; +import { formatDate } from '/@/utils/formatTime'; +import { NextLoading } from '/@/utils/loading'; +import { dropdownList, skyList, dBtnList, earth3DBtnList, chartData4List } from './mock/demo2'; +import worldImg from './images/world.jpg'; +import bathymetryImg from './images/bathymetry.jpg'; + +export default defineComponent({ + name: 'visualizingLinkDemo2', + setup() { + const { proxy } = getCurrentInstance() as any; + const state = reactive({ + time: { + txt: '', + fun: 0, + }, + dropdownList, + dropdownActive: '请选择', + skyList, + dBtnList, + chartData4Index: 0, + dBtnActive: 0, + earth3DBtnList, + chartData4List, + myCharts: [], + the3DEarth: null as HTMLDivElement | null, + }); + // 初始化时间 + const initTime = () => { + state.time.txt = formatDate(new Date(), 'YYYY-mm-dd HH:MM:SS WWW QQQQ ZZZ'); + state.time.fun = window.setInterval(() => { + state.time.txt = formatDate(new Date(), 'YYYY-mm-dd HH:MM:SS WWW QQQQ ZZZ'); + }, 1000); + }; + // 近30天预警总数 + const initRightChartData1 = () => { + const myChart = echarts.init(proxy.$refs.rightChartData1); + const option = { + tooltip: { + trigger: 'item', + }, + series: [ + { + name: '面积模式', + type: 'pie', + radius: [10, 60], + center: ['50%', '50%'], + roseType: 'area', + itemStyle: { + borderRadius: 5, + }, + data: [ + { name: '天气预警', value: 100 }, + { name: '病虫害预警', value: 50 }, + { name: '任务预警', value: 130 }, + { name: '监测设备预警', value: 62 }, + ], + label: { + color: '#c0d1f2', + }, + }, + ], + }; + myChart.setOption(option); + state.myCharts.push(myChart); + }; + // 当前设备监测 + const initRightChartData4 = () => { + const myChart = echarts.init(proxy.$refs.rightChartData4); + const option = { + grid: { + top: 10, + right: 10, + bottom: 20, + left: 30, + }, + tooltip: { + trigger: 'axis', + }, + xAxis: { + type: 'category', + boundaryGap: false, + data: ['1月', '2月', '3月', '4月', '5月', '6月'], + axisLine: { + lineStyle: { + color: 'rgba(22, 207, 208, 0.1)', + width: 1, + }, + }, + axisTick: { + show: false, + }, + axisLabel: { + interval: 0, + color: '#c0d1f2', + textStyle: { + fontSize: 10, + }, + }, + }, + yAxis: [ + { + type: 'value', + axisLabel: { + color: '#c0d1f2', + }, + splitLine: { + show: true, + lineStyle: { + color: 'rgba(22, 207, 208, 0.3)', + }, + }, + splitArea: { + show: true, + areaStyle: { + color: 'rgba(22, 207, 208, 0.02)', + }, + }, + nameTextStyle: { + color: '#16cfd0', + }, + }, + ], + series: [ + { + name: '温度', + type: 'line', + smooth: true, + lineStyle: { + width: 0, + }, + areaStyle: { + opacity: 0.8, + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { + offset: 0, + color: 'rgba(128, 255, 165)', + }, + { + offset: 1, + color: 'rgba(1, 191, 236)', + }, + ]), + }, + emphasis: { + focus: 'series', + }, + data: [140, 232, 101, 264, 90, 70], + }, + ], + }; + myChart.setOption(option); + state.myCharts.push(myChart); + }; + // 近7天产品追溯扫码统计 + const initRightChartData3 = () => { + const myChart = echarts.init(proxy.$refs.rightChartData3); + const option = { + grid: { + top: 10, + right: 0, + bottom: 20, + left: 30, + }, + tooltip: { + trigger: 'axis', + }, + xAxis: { + data: ['1月', '2月', '3月', '4月', '5月', '6月'], + axisLine: { + lineStyle: { + color: 'rgba(22, 207, 208, 0.1)', + width: 1, + }, + }, + axisTick: { + show: false, + }, + axisLabel: { + color: '#c0d1f2', + }, + }, + yAxis: [ + { + type: 'value', + axisLine: { + show: true, + lineStyle: { + color: 'rgba(22, 207, 208, 0.1)', + }, + }, + axisLabel: { + color: '#c0d1f2', + }, + splitLine: { + show: true, + lineStyle: { + color: 'rgba(22, 207, 208, 0.3)', + }, + }, + splitArea: { + show: true, + areaStyle: { + color: 'rgba(22, 207, 208, 0.02)', + }, + }, + nameTextStyle: { + color: '#16cfd0', + }, + }, + ], + series: [ + { + name: '预购队列', + type: 'line', + data: [200, 85, 112, 275, 305, 415], + itemStyle: { + color: '#16cfd0', + }, + }, + { + name: '最新成交价', + type: 'line', + data: [50, 85, 22, 155, 170, 25], + itemStyle: { + color: '#febb50', + }, + }, + ], + }; + myChart.setOption(option); + state.myCharts.push(myChart); + }; + // 当前任务统计 + const initRightChartData6 = () => { + const myChart = echarts.init(proxy.$refs.rightChartData6); + const option = { + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'shadow', + }, + }, + grid: { + top: 20, + right: 50, + bottom: 0, + left: 80, + }, + xAxis: [ + { + splitLine: { + show: false, + }, + type: 'value', + show: false, + }, + ], + yAxis: [ + { + splitLine: { + show: false, + }, + axisLine: { + //y轴 + show: false, + }, + type: 'category', + axisTick: { + show: false, + }, + inverse: true, + data: ['施肥任务完成率', '施药任务完成率', '农事任务完成率'], + axisLabel: { + color: '#A7D6F4', + fontSize: 12, + }, + }, + ], + series: [ + { + name: '标准化', + type: 'bar', + barWidth: 10, // 柱子宽度 + label: { + show: true, + position: 'right', // 位置 + color: '#A7D6F4', + fontSize: 12, + distance: 15, // 距离 + formatter: '{c}%', // 这里是数据展示的时候显示的数据 + }, // 柱子上方的数值 + itemStyle: { + barBorderRadius: [0, 20, 20, 0], // 圆角(左上、右上、右下、左下) + + color: new echarts.graphic.LinearGradient( + 1, + 0, + 0, + 0, + [ + { + offset: 0, + color: '#51C5FD', + }, + { + offset: 1, + color: '#005BB1', + }, + ], + false + ), // 渐变 + }, + data: [75, 100, 60], + }, + ], + }; + myChart.setOption(option); + state.myCharts.push(myChart); + }; + // 近7天投入品记录 + const initRightChartData2 = () => { + const myChart = echarts.init(proxy.$refs.rightChartData2); + const option = { + grid: { + top: 10, + right: 0, + bottom: 20, + left: 30, + }, + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'shadow', + }, + }, + xAxis: { + data: ['1月', '2月', '3月', '4月', '5月', '6月'], + axisLine: { + lineStyle: { + color: 'rgba(22, 207, 208, 0.5)', + width: 1, + }, + }, + axisTick: { + show: false, + }, + axisLabel: { + color: '#c0d1f2', + }, + }, + yAxis: [ + { + type: 'value', + axisLine: { + show: true, + lineStyle: { + color: 'rgba(22, 207, 208, 0.1)', + }, + }, + axisLabel: { + color: '#c0d1f2', + }, + splitLine: { + show: true, + lineStyle: { + color: 'rgba(22, 207, 208, 0.3)', + }, + }, + splitArea: { + show: true, + areaStyle: { + color: 'rgba(22, 207, 208, 0.02)', + }, + }, + nameTextStyle: { + color: '#16cfd0', + }, + }, + { + type: 'value', + position: 'right', + axisLine: { + show: false, + }, + axisLabel: { + show: true, + formatter: '{value}%', + textStyle: { + color: '#16cfd0', + }, + }, + splitLine: { + show: false, + }, + axisTick: { + show: false, + }, + splitArea: { + show: true, + areaStyle: { + color: 'rgba(22, 207, 208, 0.02)', + }, + }, + nameTextStyle: { + color: '#16cfd0', + }, + }, + ], + series: [ + { + name: '销售水量', + type: 'line', + yAxisIndex: 1, + smooth: true, + showAllSymbol: true, + symbol: 'circle', + itemStyle: { + color: '#058cff', + }, + lineStyle: { + color: '#058cff', + }, + areaStyle: { + color: 'rgba(5,140,255, 0.2)', + }, + data: [4.2, 3.8, 4.8, 3.5, 2.9, 2.8], + }, + { + name: '主营业务', + type: 'bar', + barWidth: 15, + itemStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { + offset: 0, + color: '#00FFE3', + }, + { + offset: 1, + color: '#4693EC', + }, + ]), + }, + }, + data: [4.2, 3.8, 4.8, 3.5, 2.9, 2.8], + }, + ], + }; + myChart.setOption(option); + state.myCharts.push(myChart); + }; + // 3DEarth 地图 + const init3DEarth = (globeRadius) => { + let el = state.the3DEarth!; + el.style.height = `${proxy.$refs.rightChartData5.offsetHeight}px`; + const myChart = echarts.init(el); + const option = { + globe: { + baseTexture: worldImg, + heightTexture: bathymetryImg, + shading: 'realistic', + light: { + ambient: { + intensity: 0.4, + }, + main: { + intensity: 0.4, + }, + }, + viewControl: { + autoRotate: true, + }, + postEffect: { + enable: true, + bloom: { + enable: true, + }, + }, + globeRadius, + }, + series: { + type: 'lines3D', + coordinateSystem: 'globe', + blendMode: 'lighter', + lineStyle: { + width: 1, + color: 'rgb(50, 50, 150)', + opacity: 0.1, + }, + data: [], + }, + }; + // 随机模拟攻击线 + let rodamData = function () { + let longitude = 105.18; + let longitude2 = Math.random() * 360 - 180; + let latitude = 37.51; + let latitude2 = Math.random() * 180 - 90; + return { + coords: [ + [longitude2, latitude2], + [longitude, latitude], + ], + value: (Math.random() * 3000).toFixed(2), + }; + }; + for (let i = 0; i < 150; i++) { + option.series.data = option.series.data.concat(rodamData()); + } + myChart.setOption(option); + }; + // 监听地球大小变化 + const initAddEventListener3DEarth = () => { + let w = document.body.clientWidth; + let globeRadius = 0; + if (w >= 1920) globeRadius = 100; + else if (w > 1200 && w < 1920) globeRadius = 70; + else if (w > 992 && w < 1200) globeRadius = 60; + else if (w > 768 && w < 992) globeRadius = 40; + else if (w < 768) globeRadius = 20; + init3DEarth(globeRadius); + }; + // 批量设置 echarts resize + const initEchartsResize = () => { + initAddEventListener3DEarth(); + window.addEventListener('resize', () => { + for (let i = 0; i < state.myCharts.length; i++) { + state.myCharts[i].resize(); + } + initAddEventListener3DEarth(); + }); + }; + // 页面加载时 + onMounted(async () => { + NextLoading.done(); + initTime(); + await initRightChartData1(); + await initRightChartData4(); + await initRightChartData3(); + await initRightChartData2(); + await initRightChartData6(); + await initEchartsResize(); + }); + // 页面卸载时 + onUnmounted(() => { + window.clearInterval(state.time.fun); + }); + return { + ...toRefs(state), + }; + }, +}); +</script> + +<style scoped lang="scss"> +.visualizing-demo2 { + height: 100%; + width: 100%; + overflow: hidden; + background: url(https://img-blog.csdnimg.cn/6267533849444025811bf0840f9366e3.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbHl0LXRvcA==,size_20,color_FFFFFF,t_70,g_se,x_16); + background-size: 100% 100%; + display: flex; + flex-direction: column; + font-size: 13px; + .big-data-up { + height: 70px; + width: 100%; + display: flex; + align-items: center; + padding: 0 15px; + color: #43bdf0; + overflow: hidden; + .up-left { + width: 30%; + font-style: italic; + } + .up-center { + width: 40%; + display: flex; + justify-content: center; + font-size: 20px; + letter-spacing: 5px; + background-image: -webkit-linear-gradient(left, #43bdf0, #c0d1f2 25%, #43bdf0 50%, #c0d1f2 75%, #43bdf0); + -webkit-text-fill-color: transparent; + background-clip: text; + -webkit-background-clip: text; + background-size: 200% 100%; + animation: masked-animation 4s infinite linear; + -webkit-box-reflect: below -2px -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0)), to(rgba(255, 255, 255, 0.1))); + @keyframes masked-animation { + 0% { + background-position: 0 0; + } + 100% { + background-position: -100% 0; + } + } + position: relative; + &::after { + content: ''; + width: 50%; + position: absolute; + bottom: -15px; + left: 50%; + transform: translateX(-50%); + border: 1px transparent solid; + border-image: linear-gradient(to right, rgba(0, 0, 0, 0.1), #43bdf0) 1 10; + } + span { + cursor: pointer; + } + } + .up-right { + width: 30%; + justify-content: flex-end; + display: flex; + align-items: center; + .ml15:hover { + cursor: pointer; + } + ::v-deep(.el-dropdown) { + font-size: 13px !important; + color: #43bdf0; + cursor: pointer; + } + } + } + .big-data-down { + flex: 1; + overflow: hidden; + display: flex; + .big-data-down-left, + .big-data-down-right { + width: 30%; + display: flex; + flex-direction: column; + .flex-warp-item { + padding: 0 7.5px 15px 15px; + width: 100%; + height: 33.33%; + .flex-warp-item-box { + width: 100%; + height: 100%; + background: rgba(22, 34, 58, 0.4); + display: flex; + flex-direction: column; + padding: 15px; + .flex-title { + margin-bottom: 15px; + color: #c0d1f2; + display: flex; + justify-content: space-between; + .flex-title-small { + font-size: 12px; + } + } + .flex-content { + flex: 1; + font-size: 12px; + } + .flex-content-overflow { + overflow: hidden; + } + } + } + } + .big-data-down-left { + color: #c0d1f2; + .sky { + display: flex; + align-items: center; + .sky-left { + font-size: 30px; + } + .sky-center { + flex: 1; + overflow: hidden; + padding: 0 10px; + .font { + margin-right: 15px; + background: unset !important; + border-radius: unset !important; + padding: unset !important; + } + span { + background: #22bc76; + border-radius: 2px; + padding: 0 5px; + } + .sky-tip { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + } + .sky-right { + span { + font-size: 30px; + } + font { + font-size: 20px; + } + } + } + .sky-dd { + .sky-dl { + display: flex; + align-items: center; + height: 28px; + overflow: hidden; + div { + flex: 1; + overflow: hidden; + i { + font-size: 14px; + } + } + .tip { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + &:hover { + background: rgba(0, 0, 0, 0.05); + cursor: default; + border-radius: 4px; + } + &:first-child:hover { + background: unset; + } + } + .sky-dl-first { + color: #43bdf0; + } + } + .d-states { + display: flex; + .d-states-item { + flex: 1; + display: flex; + align-items: center; + overflow: hidden; + i { + font-size: 20px; + height: 33px; + width: 33px; + line-height: 33px; + text-align: center; + border-radius: 100%; + flex-shrink: 1; + display: flex; + align-items: center; + justify-content: center; + } + .i-bg1 { + background: #22bc76; + } + .i-bg2 { + background: #e2356d; + } + .i-bg3 { + background: #43bbef; + } + .d-states-flex { + overflow: hidden; + padding: 0 10px 0; + .d-states-item-label { + color: #43bdf0; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + .d-states-item-value { + font-size: 20px; + text-align: center; + } + } + } + } + .d-btn { + margin-top: 15px; + .d-btn-item { + border: 1px solid #c0d1f2; + display: flex; + width: 100%; + height: 35px; + border-radius: 35px; + align-items: center; + padding: 0 4px; + margin-top: 15px; + cursor: pointer; + transition: all ease 0.3s; + .d-btn-item-left { + font-size: 20px; + border: 1px solid #c0d1f2; + width: 25px; + height: 25px; + line-height: 25px; + border-radius: 100%; + text-align: center; + font-size: 14px; + } + .d-btn-item-center { + padding: 0 10px; + flex: 1; + } + .d-btn-item-eight { + text-align: right; + padding-right: 10px; + } + } + .d-btn-active { + transition: all ease 0.3s; + border: 1px solid #43bdf0; + color: #43bdf0; + .d-btn-item-left { + border: 1px solid #43bdf0; + } + } + } + } + .big-data-down-center { + width: 40%; + display: flex; + flex-direction: column; + .big-data-down-center-one { + height: 66.67%; + padding: 0 7.5px 15px; + .big-data-down-center-one-content { + height: 100%; + position: relative; + .fixed-top, + .fixed-right, + .fixed-bottom, + .fixed-left { + position: absolute; + width: 100px; + height: 100px; + display: flex; + cursor: pointer; + .circle { + position: absolute; + border-radius: 50%; + background: rgba(0, 0, 0, 0.01); + z-index: 10; + } + .text-box { + position: relative; + z-index: 11; + color: #c0d1f2; + margin: auto; + text-align: center; + font-size: 12px; + i { + font-size: 28px; + margin-bottom: 10px; + } + } + } + .fixed-top { + left: 20px; + top: 20px; + } + .fixed-right { + right: 20px; + top: 20px; + } + .fixed-bottom { + right: 20px; + bottom: 20px; + } + .fixed-left { + left: 20px; + bottom: 20px; + } + .circle:nth-of-type(1) { + width: 100px; + height: 95px; + animation: turnAround 6s infinite linear; + box-shadow: 0 0 1px 0 #869fe4, inset 0 0 10px 0 #869fe4; + } + .circle:nth-of-type(2) { + width: 95px; + height: 100px; + animation: turnAround 10s infinite linear; + box-shadow: 0 0 1px 0 #3397f2, inset 0 0 10px 0 #3397f2; + } + .circle:nth-of-type(3) { + width: 110px; + height: 100px; + animation: turnAround 5s infinite linear; + box-shadow: 0 0 1px 0 #3eaadc, inset 0 0 10px 0 #3eaadc; + } + .circle:nth-of-type(4) { + width: 100px; + height: 110px; + animation: turnAround 15s infinite linear; + box-shadow: 0 0 1px 0 #09f, inset 0 0 10px 0 #09f; + } + @keyframes turnAround { + 100% { + transform: rotate(360deg); + } + } + } + } + .big-data-down-center-two { + padding: 0 7.5px 15px; + height: 33.33%; + .flex-warp-item-box { + width: 100%; + height: 100%; + background: rgba(22, 34, 58, 0.4); + display: flex; + flex-direction: column; + padding: 15px; + .flex-title { + margin-bottom: 15px; + color: #c0d1f2; + display: flex; + justify-content: space-between; + .flex-title-small { + font-size: 12px; + } + } + .flex-content { + flex: 1; + font-size: 12px; + display: flex; + height: calc(100% - 30px); + .flex-content-left { + display: flex; + flex-wrap: wrap; + width: 120px; + height: 100%; + .monitor-item { + width: 50%; + display: flex; + align-items: center; + .monitor-wave { + cursor: pointer; + width: 40px; + height: 40px; + position: relative; + background-color: #43bdf0; + border-radius: 50%; + overflow: hidden; + text-align: center; + &::before, + &::after { + content: ''; + position: absolute; + left: 50%; + width: 40px; + height: 40px; + background: #f4f4f4; + animation: roateOne 10s linear infinite; + transform: translateX(-50%); + z-index: 1; + } + &::before { + bottom: 10px; + border-radius: 60%; + } + &::after { + bottom: 8px; + opacity: 0.7; + border-radius: 37%; + } + .monitor-z-index { + position: relative; + z-index: 2; + color: #4eb8ff; + display: flex; + align-items: center; + height: 100%; + justify-content: center; + font-weight: bold; + } + } + @keyframes roateOne { + 0% { + transform: translate(-50%, 0) rotateZ(0deg); + } + 50% { + transform: translate(-50%, -2%) rotateZ(180deg); + } + 100% { + transform: translate(-50%, 0%) rotateZ(360deg); + } + } + .monitor-active { + background-color: #22bc76; + .monitor-z-index { + color: #22bc76; + } + } + } + } + .flex-content-right { + flex: 1; + } + } + } + } + } + .big-data-down-right { + .flex-warp-item { + padding: 0 15px 15px 7.5px; + .flex-content { + display: flex; + flex-direction: column; + .task { + display: flex; + height: 45px; + .task-item { + flex: 1; + color: #c0d1f2; + display: flex; + justify-content: center; + .task-item-box { + position: relative; + width: 45px; + height: 45px; + overflow: hidden; + border-radius: 100%; + z-index: 0; + display: flex; + align-items: center; + flex-direction: column; + justify-content: center; + box-shadow: 0 10px 12px 0 rgba(0, 0, 0, 0.3); + &::before { + content: ''; + position: absolute; + z-index: -2; + left: -50%; + top: -50%; + width: 200%; + height: 200%; + background-repeat: no-repeat; + background-size: 50% 50%, 50% 50%; + background-position: 0 0, 100% 0, 100% 100%, 0 100%; + background-image: linear-gradient(#19d4ae, #19d4ae), linear-gradient(#5ab1ef, #5ab1ef), linear-gradient(#fa6e86, #fa6e86), + linear-gradient(#ffb980, #ffb980); + animation: rotate 2s linear infinite; + } + &::after { + content: ''; + position: absolute; + z-index: -1; + left: 1px; + top: 1px; + width: calc(100% - 2px); + height: calc(100% - 2px); + border-radius: 100%; + } + .task-item-value { + text-align: center; + font-size: 14px; + font-weight: bold; + } + .task-item-label { + text-align: center; + } + } + .task1 { + &::after { + background: #5492be; + } + } + .task2 { + &::after { + background: #43a177; + } + } + .task3 { + &::after { + background: #a76077; + } + } + .task4 { + &::after { + background: #b4825a; + } + } + .task5 { + &::after { + background: #74568f; + } + } + } + .task-first-item { + flex-direction: column; + text-align: center; + .task-first { + font-size: 20px; + } + } + } + } + } + .progress { + flex: 1; + } + } + } +} +</style> diff --git a/src/views/visualizing/images/bathymetry.jpg b/src/views/visualizing/images/bathymetry.jpg new file mode 100644 index 0000000..5f9eebe --- /dev/null +++ b/src/views/visualizing/images/bathymetry.jpg Binary files differ diff --git a/src/views/visualizing/images/world.jpg b/src/views/visualizing/images/world.jpg new file mode 100644 index 0000000..22c7566 --- /dev/null +++ b/src/views/visualizing/images/world.jpg Binary files differ diff --git a/src/views/visualizing/mock/demo1.ts b/src/views/visualizing/mock/demo1.ts new file mode 100644 index 0000000..60fd944 --- /dev/null +++ b/src/views/visualizing/mock/demo1.ts @@ -0,0 +1,51 @@ +// 地图模拟数据 +export const echartsMapList: Array<object> = [ + { name: '深圳市人民政府', value: '100' }, + { name: '莲花山公园', value: '100' }, + { name: '世界之窗', value: '100' }, + { name: '华侨城欢乐谷', value: '100' }, + { name: '宝安区西乡', value: '100' }, +]; + +// 地图经纬度数据 +export const echartsMapData: object = { + 深圳市人民政府: [114.064524, 22.549225], + 莲花山公园: [114.0658, 22.560072], + 世界之窗: [113.979419, 22.540579], + 华侨城欢乐谷: [113.986066, 22.548056], + 宝安区西乡: [113.869053, 22.581714], +}; + +// 地图图片显示 +export const echartsMapImgs: Array<object> = [ + { + url: 'https://img1.baidu.com/it/u=4244861097,3561366422&fm=11&fmt=auto&gp=0.jpg', + name: '深圳市人民政府', + add: '深圳市福田区福中三路市民中心C区', + dec: '深圳市人民政府是根据《中华人民共和国地方各级人民代表大会和地方各级人民政府组织法》设立的,是深圳市人民代表大会的执行机关,是深圳市的国家行政机关。', + }, + { + url: 'https://img1.baidu.com/it/u=3793608028,4006842751&fm=26&fmt=auto&gp=0.jpg', + name: '莲花山公园', + add: '广东省深圳市福田区莲花街道莲花北社区红荔路6030号', + dec: '莲花山公园筹建于1992年10月10日 ,1997年6月23日正式对外局部开放。', + }, + { + url: 'https://img0.baidu.com/it/u=1406340112,1927292660&fm=26&fmt=auto&gp=0.jpg', + name: '世界之窗', + add: '深圳市南山区深南大道9037号', + dec: '这里,世界首座实景拍摄悬空式球幕影院“飞跃美利坚””,为游客提供集休闲放松于一体的都市时尚生活空间。', + }, + { + url: 'https://img0.baidu.com/it/u=3042342330,902556630&fm=26&fmt=auto&gp=0.jpg', + name: '华侨城欢乐谷', + add: '广东省深圳市南山区沙河街道星河街社区侨城西街1号', + dec: '深圳欢乐谷注重满足人们参与、体验的新型诱游需求,营造出自然、清新、活泼、惊奇、热烈、刺激的休闲旅游氛围。', + }, + { + url: 'https://img2.baidu.com/it/u=1075072079,1229283519&fm=11&fmt=auto&gp=0.jpg', + name: '宝安区西乡', + add: '西乡街道下辖25个社区', + dec: '西乡街道,隶属于广东省深圳市宝安区,位于宝安区西南部,东接石岩街道,南接新安街道,西至珠江口岸边,北接航城街道。', + }, +]; diff --git a/src/views/visualizing/mock/demo2.ts b/src/views/visualizing/mock/demo2.ts new file mode 100644 index 0000000..6b302b4 --- /dev/null +++ b/src/views/visualizing/mock/demo2.ts @@ -0,0 +1,131 @@ +// 顶部下来菜单 +export const dropdownList: Array<object> = [ + { + label: '广东省农业农村厅', + }, + { + label: '广西省农业农村厅', + }, + { + label: '四川省农业农村厅', + }, + { + label: '湖北省农业农村厅', + }, + { + label: '福建省农业农村厅', + }, + { + label: '山东省农业农村厅', + }, + { + label: '江西省农业农村厅', + }, +]; + +// sky 天气 +export const skyList: Array<object> = [ + { + v1: '时间', + v2: '天气', + v3: '温度', + v4: '湿度', + v5: '降水概率', + v6: '风向', + v7: '风力', + type: 'title', + }, + { + v1: '今天', + v2: 'ele-Sunny', + v3: '20°/26°', + v4: '80%', + v5: '50%', + v6: '东南风', + v7: '13m/s', + }, + { + v1: '明天', + v2: 'ele-Lightning', + v3: '20°/26°', + v4: '80%', + v5: '50%', + v6: '东南风', + v7: '13m/s', + }, + { + v1: '后天', + v2: 'ele-Sunny', + v3: '20°/26°', + v4: '80%', + v5: '50%', + v6: '东南风', + v7: '13m/s', + }, +]; + +// 当前设置状态 +export const dBtnList: Array<object> = [ + { + v1: '地块A-灌溉', + v2: '阳光玫瑰种植', + v3: '126天', + v4: '设备在线', + }, + { + v1: '地块B-收割', + v2: '阳光玫瑰种植', + v3: '360天', + v4: '设备预警', + }, +]; + +// 当前设备监测 +export const chartData4List: Array<object> = [ + { + label: '温度', + }, + { + label: '光照', + }, + { + label: '湿度', + }, + { + label: '风力', + }, + { + label: '张力', + }, + { + label: '气压', + }, +]; + +// 3DEarth 地图周围按钮组 +export const earth3DBtnList: Array<object> = [ + { + topLevelClass: 'fixed-top', + icon: 'ele-MagicStick', + label: '环境监测', + type: 0, + }, + { + topLevelClass: 'fixed-right', + icon: 'ele-MoonNight', + label: '精准管理', + type: 1, + }, + { + topLevelClass: 'fixed-bottom', + icon: 'ele-TrendCharts', + label: '数据报表', + type: 2, + }, + { + topLevelClass: 'fixed-left', + icon: 'ele-Van', + label: '产品追溯', + type: 3, + }, +]; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..9d62054 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,72 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "esnext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, + "module": "esnext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, + "lib": ["esnext", "dom", "dom.iterable", "scripthost"] /* Specify library files to be included in the compilation. */, + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + "jsx": "preserve" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */, + // "declaration": true /* Generates corresponding '.d.ts' file. */, + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "./", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true /* Import emit helpers from 'tslib'. */, + // "downlevelIteration": true /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */, + // "isolatedModules": true /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */, + + /* Strict Type-Checking Options */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + + /* Module Resolution Options */ + "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, + "baseUrl": "." /* Base directory to resolve non-absolute module names. */, + "paths": { + "/@/*": ["src/*"] + } /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */, + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + "types": ["vite/client"] /* Type declaration files to be included in compilation. */, + "allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */, + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "skipLibCheck": true /* Skip type checking of declaration files. */, + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + } +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..cf7bc27 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,79 @@ +import vue from '@vitejs/plugin-vue'; +import { resolve } from 'path'; +import { defineConfig, loadEnv, ConfigEnv } from 'vite'; + +const pathResolve = (dir: string): any => { + return resolve(__dirname, '.', dir); +}; + +const alias: Record<string, string> = { + '/@': pathResolve('./src/'), + 'vue-i18n': 'vue-i18n/dist/vue-i18n.cjs.js', +}; + +const viteConfig = defineConfig((mode: ConfigEnv) => { + const env = loadEnv(mode.mode, process.cwd()); + return { + plugins: [vue()], + root: process.cwd(), + resolve: { alias }, + base: mode.command === 'serve' ? './' : env.VITE_PUBLIC_PATH, + hmr: true, + optimizeDeps: { + include: ['element-plus/lib/locale/lang/zh-cn', 'element-plus/lib/locale/lang/en', 'element-plus/lib/locale/lang/zh-tw'], + }, + server: { + host: '0.0.0.0', + port: env.VITE_PORT as unknown as number, + open: env.VITE_OPEN, + proxy: { + '/gitee': { + target: 'https://gitee.com', + ws: true, + changeOrigin: true, + rewrite: (path) => path.replace(/^\/gitee/, ''), + }, + }, + }, + build: { + outDir: 'dist', + sourcemap: false, + chunkSizeWarningLimit: 1500, + rollupOptions: { + output: { + entryFileNames: `assets/[name].${new Date().getTime()}.js`, + chunkFileNames: `assets/[name].${new Date().getTime()}.js`, + assetFileNames: `assets/[name].${new Date().getTime()}.[ext]`, + compact: true, + manualChunks: { + vue: ['vue', 'vue-router', 'pinia'], + echarts: ['echarts'], + }, + }, + }, + }, + css: { + postcss: { + plugins: [ + { + postcssPlugin: 'internal:charset-removal', + AtRule: { + charset: (atRule) => { + if (atRule.name === 'charset') { + atRule.remove(); + } + }, + }, + }, + ], + }, + }, + define: { + __VUE_I18N_LEGACY_API__: JSON.stringify(false), + __VUE_I18N_FULL_INSTALL__: JSON.stringify(false), + __INTLIFY_PROD_DEVTOOLS__: JSON.stringify(false), + }, + }; +}); + +export default viteConfig; diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..9c75e08 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,2236 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/parser@^7.16.4": + version "7.18.4" + resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.18.4.tgz#6774231779dd700e0af29f6ad8d479582d7ce5ef" + integrity sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow== + +"@babel/runtime@^7.12.0": + version "7.18.3" + resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.18.3.tgz#c7b654b57f6f63cf7f8b418ac9ca04408c4579f4" + integrity sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug== + dependencies: + regenerator-runtime "^0.13.4" + +"@ctrl/tinycolor@^3.4.1": + version "3.4.1" + resolved "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz#75b4c27948c81e88ccd3a8902047bcd797f38d32" + integrity sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw== + +"@element-plus/icons-vue@^2.0.3": + version "2.0.4" + resolved "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.0.4.tgz#98fb9680c814a2a4f231b8bdabc8cd59b1b79d86" + integrity sha512-UeBVBU3fuBsYa9mzM7DgkRztQ1Aftw3sMTI/1gZsqXq2NWiCOi16ZYXXGIc0jFDIu+k6SojzdlxOjv+rN/Y6FQ== + +"@element-plus/icons-vue@^2.0.5": + version "2.0.5" + resolved "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.0.5.tgz#8eb4143a7b5e4d8468d2e72af99eefee446f5ea0" + integrity sha512-jvNWyKcdvPvMDLTWjghrPY+bYHKqh7hbAFIPe+HWR073zilzt33csREzmKx3VwhdlJUW5u0nCqN+0rwI8jlH+w== + +"@eslint/eslintrc@^1.3.0": + version "1.3.0" + resolved "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" + integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.3.2" + globals "^13.15.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@floating-ui/core@^0.7.2": + version "0.7.2" + resolved "https://registry.npmmirror.com/@floating-ui/core/-/core-0.7.2.tgz#f7af9613d080dc29360e77c970965b79b524d45a" + integrity sha512-FRVAkSNU/vGXLIsgbggcs70GkXKEOXgBBbNpYPNHSaKsCAMMd00NrjbtKTesxkdv9xm9N3+XiDlcFGY6WnatBg== + +"@floating-ui/dom@^0.5.2": + version "0.5.2" + resolved "https://registry.npmmirror.com/@floating-ui/dom/-/dom-0.5.2.tgz#908f3febbfc0d6696d70921616ec194fe07af183" + integrity sha512-z1DnEa7F3d8Fm/eXSbii8UEGpcjZGkQaYYUI0WpEVgD3vBfebDW8j/3ysusxonuMexoigA+A3b/fYH7sEqiwyg== + dependencies: + "@floating-ui/core" "^0.7.2" + +"@humanwhocodes/config-array@^0.9.2": + version "0.9.5" + resolved "https://registry.npmmirror.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" + integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.npmmirror.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@interactjs/actions@1.10.13", "@interactjs/actions@^1.10.2": + version "1.10.13" + resolved "https://registry.npmmirror.com/@interactjs/actions/-/actions-1.10.13.tgz#278891ce7cfdc03124f1993cd45c434d43b71ef9" + integrity sha512-WRFfZKJ57Iwmn3w8nMvsOaryaRBBxYIWSX8iKTKsaqwHerQkd3el9yKp2miXsdsGkzabofqp5GDuB6Dwbq7Uew== + optionalDependencies: + "@interactjs/interact" "1.10.13" + +"@interactjs/auto-scroll@1.10.13": + version "1.10.13" + resolved "https://registry.npmmirror.com/@interactjs/auto-scroll/-/auto-scroll-1.10.13.tgz#f01599bc6b15b86027256c8dadf04349b28c4fb5" + integrity sha512-YfeMKjFtassTzFThDZPwZnzwGyHzELC+npzjjtb8AHcaMagYE89mZ+c61gSSDHJKpbp6YAEyU+F4uXuuhwwKsQ== + optionalDependencies: + "@interactjs/interact" "1.10.13" + +"@interactjs/auto-start@1.10.13", "@interactjs/auto-start@^1.10.2": + version "1.10.13" + resolved "https://registry.npmmirror.com/@interactjs/auto-start/-/auto-start-1.10.13.tgz#195a86f861820f3f6d3ff7d873e463fa164259ff" + integrity sha512-bZPL+aJd3YT9wlha7k7fcjjU8cXGUTAZN2G/eSds32pxhpjvlpKJMNvH0h2z7Mcnipyq9eRHVj0Q9oc1Zjy3qg== + optionalDependencies: + "@interactjs/interact" "1.10.13" + +"@interactjs/core@1.10.13": + version "1.10.13" + resolved "https://registry.npmmirror.com/@interactjs/core/-/core-1.10.13.tgz#62d7f9f98b047ab5046e8fe0fab58afd06f961cb" + integrity sha512-hHiY0yZ+vvmhGkJ4C3KhK3fFPh/ModRqdyqFMrlJ5djLCsilkA1SM+0WL6ckBwlIwKu2z+fHXLZuXt7v+7/Azw== + +"@interactjs/dev-tools@1.10.13", "@interactjs/dev-tools@^1.10.2": + version "1.10.13" + resolved "https://registry.npmmirror.com/@interactjs/dev-tools/-/dev-tools-1.10.13.tgz#6ac1ab3e369476321fc299b742b11ff1ccc3d4f1" + integrity sha512-niQ7k4xAr8vpgmYhv3aBjddNZjqvAvn57YWCR7YCrfnH+o72mDLnrYg5rcvXF88qr7Rv+xl22V1wBkTX6JOEzA== + optionalDependencies: + "@interactjs/interact" "1.10.13" + +"@interactjs/inertia@1.10.13": + version "1.10.13" + resolved "https://registry.npmmirror.com/@interactjs/inertia/-/inertia-1.10.13.tgz#57115d9b3d6f1d070b8a3013661f522926be50b4" + integrity sha512-9RRR92EsUjlMPQ5LH9SgP2Litcluk24VOqwm+LZP74w6+9SuApuVd0W+aZcXBGrOaUdm42KrywPU7801A0eomw== + dependencies: + "@interactjs/offset" "1.10.13" + optionalDependencies: + "@interactjs/interact" "1.10.13" + +"@interactjs/interact@1.10.13": + version "1.10.13" + resolved "https://registry.npmmirror.com/@interactjs/interact/-/interact-1.10.13.tgz#505724af99f46036bcfb2760de6788535a02d90b" + integrity sha512-ctz3CXpoxd4Z7FhayGERx6ufWNUjeP8Xim1KpdSrfpVv8SF0PDtgcYn3HHhL4ImeJtdn+yZFhdMc/x01MjvHHg== + dependencies: + "@interactjs/core" "1.10.13" + "@interactjs/types" "1.10.13" + "@interactjs/utils" "1.10.13" + +"@interactjs/interactjs@^1.10.2": + version "1.10.13" + resolved "https://registry.npmmirror.com/@interactjs/interactjs/-/interactjs-1.10.13.tgz#bd9d67755eadcd66459c12e96691e45982da00e3" + integrity sha512-RfSYrttHQkfj+hqkJb86upjcoUtmD0FVWr62xsAwJy0sCWKzk34n/ofXlBFPM1kl/d+LqpyINbZEKaaJDE6BOw== + dependencies: + "@interactjs/actions" "1.10.13" + "@interactjs/auto-scroll" "1.10.13" + "@interactjs/auto-start" "1.10.13" + "@interactjs/core" "1.10.13" + "@interactjs/dev-tools" "1.10.13" + "@interactjs/inertia" "1.10.13" + "@interactjs/interact" "1.10.13" + "@interactjs/modifiers" "1.10.13" + "@interactjs/offset" "1.10.13" + "@interactjs/pointer-events" "1.10.13" + "@interactjs/reflow" "1.10.13" + "@interactjs/utils" "1.10.13" + +"@interactjs/modifiers@1.10.13", "@interactjs/modifiers@^1.10.2": + version "1.10.13" + resolved "https://registry.npmmirror.com/@interactjs/modifiers/-/modifiers-1.10.13.tgz#09e0a8044909ef2c977873d7925ea165ba0370bd" + integrity sha512-WeIxPOtV/eZg23B95Z3dazy5Y6Kq5+1MQ2msnHJ22JBrJZ2nfNttXT6X9NNmXTPq1t5vqwoBsdlQ9YIwj78siQ== + dependencies: + "@interactjs/snappers" "1.10.13" + optionalDependencies: + "@interactjs/interact" "1.10.13" + +"@interactjs/offset@1.10.13": + version "1.10.13" + resolved "https://registry.npmmirror.com/@interactjs/offset/-/offset-1.10.13.tgz#8ca249ac6a0c6284765b3fd91ef657ea39adb5ed" + integrity sha512-fVZ5XAOHjafXzFTqt53bgwL5v4u6LgrYmx0/8ApMPLbrxX0W4IckETtAMx//3PUIOJ3Y6XhdKKKAOmPe8+LpiQ== + optionalDependencies: + "@interactjs/interact" "1.10.13" + +"@interactjs/pointer-events@1.10.13": + version "1.10.13" + resolved "https://registry.npmmirror.com/@interactjs/pointer-events/-/pointer-events-1.10.13.tgz#9b9032b3a07855f417473d85231cddcdf0c14c85" + integrity sha512-bIbajHzmQb6+ab53Apk9VzaSXXC03miuwuMXSn/jq9JvkVMgRaoCHjTXq8UI8eGyq5Pi4AT5kqnWhB3x9FqwEw== + optionalDependencies: + "@interactjs/interact" "1.10.13" + +"@interactjs/reflow@1.10.13": + version "1.10.13" + resolved "https://registry.npmmirror.com/@interactjs/reflow/-/reflow-1.10.13.tgz#ed2301d42873438c9f6d374b70331d20cc9edf8b" + integrity sha512-nTo0l6qEYlcWRmg3V+ko7HNDcsy/HljVc7F8LoJyRpgrE/ZXMKM8w7SPMdU3iGaQXGVNw6lPVXqJowPfS+LhIw== + optionalDependencies: + "@interactjs/interact" "1.10.13" + +"@interactjs/snappers@1.10.13": + version "1.10.13" + resolved "https://registry.npmmirror.com/@interactjs/snappers/-/snappers-1.10.13.tgz#bcc0985938145eb39020449daee6cd9050dea0e2" + integrity sha512-UT8IrFaZsLEMfiZn99o+X/7ixbhjo8+O/YqdlmHUJ3E/Ac+bVQmb1Qfz5VgiRNKgsjmTCi4uCj72Ikf7nf9kDg== + optionalDependencies: + "@interactjs/interact" "1.10.13" + +"@interactjs/types@1.10.13": + version "1.10.13" + resolved "https://registry.npmmirror.com/@interactjs/types/-/types-1.10.13.tgz#0ebcc9ab582cb27e84ccdd2a7a33c87076cd511e" + integrity sha512-VdsUBs2YSdrgB2ZuL2UL0WW3fH6XuINjdk7XE9K+r64X9k2IC3nQm7pIg7HjO3iiLtuBNUVEGy+eJwU1G8t/Lg== + +"@interactjs/utils@1.10.13": + version "1.10.13" + resolved "https://registry.npmmirror.com/@interactjs/utils/-/utils-1.10.13.tgz#dbdc8a15ed2470919b56f0e849d18da0c667ae95" + integrity sha512-WWgG2NmGIdPudytNaF5KhqnAZ/2JPpnUs9mX0AKwdbLSuG2n5kOYJv4t8IOHkXhPDuoY/PZ5r19ODHWUXkCVlQ== + +"@intlify/core-base@9.1.10": + version "9.1.10" + resolved "https://registry.npmmirror.com/@intlify/core-base/-/core-base-9.1.10.tgz#cbd3099f375c789a1b974f3ea79b6efb8bb148fa" + integrity sha512-So9CNUavB/IsZ+zBmk2Cv6McQp6vc2wbGi1S0XQmJ8Vz+UFcNn9MFXAe9gY67PreIHrbLsLxDD0cwo1qsxM1Nw== + dependencies: + "@intlify/devtools-if" "9.1.10" + "@intlify/message-compiler" "9.1.10" + "@intlify/message-resolver" "9.1.10" + "@intlify/runtime" "9.1.10" + "@intlify/shared" "9.1.10" + "@intlify/vue-devtools" "9.1.10" + +"@intlify/devtools-if@9.1.10": + version "9.1.10" + resolved "https://registry.npmmirror.com/@intlify/devtools-if/-/devtools-if-9.1.10.tgz#8704852a4fa547df43df71a16b1cc4b27e758aa3" + integrity sha512-SHaKoYu6sog3+Q8js1y3oXLywuogbH1sKuc7NSYkN3GElvXSBaMoCzW+we0ZSFqj/6c7vTNLg9nQ6rxhKqYwnQ== + dependencies: + "@intlify/shared" "9.1.10" + +"@intlify/message-compiler@9.1.10": + version "9.1.10" + resolved "https://registry.npmmirror.com/@intlify/message-compiler/-/message-compiler-9.1.10.tgz#271f5e1cb65f3cec4b1fb243e50615747613f4be" + integrity sha512-+JiJpXff/XTb0EadYwdxOyRTB0hXNd4n1HaJ/a4yuV960uRmPXaklJsedW0LNdcptd/hYUZtCkI7Lc9J5C1gxg== + dependencies: + "@intlify/message-resolver" "9.1.10" + "@intlify/shared" "9.1.10" + source-map "0.6.1" + +"@intlify/message-resolver@9.1.10": + version "9.1.10" + resolved "https://registry.npmmirror.com/@intlify/message-resolver/-/message-resolver-9.1.10.tgz#fb1dabdec2e29942df26f47e19444278a6e2f070" + integrity sha512-5YixMG/M05m0cn9+gOzd4EZQTFRUu8RGhzxJbR1DWN21x/Z3bJ8QpDYj6hC4FwBj5uKsRfKpJQ3Xqg98KWoA+w== + +"@intlify/runtime@9.1.10": + version "9.1.10" + resolved "https://registry.npmmirror.com/@intlify/runtime/-/runtime-9.1.10.tgz#70582a16810f68953d1cbf7183c8107a9137b580" + integrity sha512-7QsuByNzpe3Gfmhwq6hzgXcMPpxz8Zxb/XFI6s9lQdPLPe5Lgw4U1ovRPZTOs6Y2hwitR3j/HD8BJNGWpJnOFA== + dependencies: + "@intlify/message-compiler" "9.1.10" + "@intlify/message-resolver" "9.1.10" + "@intlify/shared" "9.1.10" + +"@intlify/shared@9.1.10": + version "9.1.10" + resolved "https://registry.npmmirror.com/@intlify/shared/-/shared-9.1.10.tgz#9e2527276b43ae3f354c4015eb04f855d9d7a707" + integrity sha512-Om54xJeo1Vw+K1+wHYyXngE8cAbrxZHpWjYzMR9wCkqbhGtRV5VLhVc214Ze2YatPrWlS2WSMOWXR8JktX/IgA== + +"@intlify/vue-devtools@9.1.10": + version "9.1.10" + resolved "https://registry.npmmirror.com/@intlify/vue-devtools/-/vue-devtools-9.1.10.tgz#c62535d86742bcd16593806a4fcae49f6fc8ae6d" + integrity sha512-5l3qYARVbkWAkagLu1XbDUWRJSL8br1Dj60wgMaKB0+HswVsrR6LloYZTg7ozyvM621V6+zsmwzbQxbVQyrytQ== + dependencies: + "@intlify/message-resolver" "9.1.10" + "@intlify/runtime" "9.1.10" + "@intlify/shared" "9.1.10" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@popperjs/core@npm:@sxzz/popperjs-es@^2.11.7": + version "2.11.7" + resolved "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz#a7f69e3665d3da9b115f9e71671dae1b97e13671" + integrity sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ== + +"@transloadit/prettier-bytes@0.0.7": + version "0.0.7" + resolved "https://registry.npmmirror.com/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz#cdb5399f445fdd606ed833872fa0cabdbc51686b" + integrity sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA== + +"@types/event-emitter@^0.3.3": + version "0.3.3" + resolved "https://registry.npmmirror.com/@types/event-emitter/-/event-emitter-0.3.3.tgz#727032a9fc67565f96bbd78b2e2809275c97d7e7" + integrity sha512-UfnOK1pIxO7P+EgPRZXD9jMpimd8QEFcEZ5R67R1UhGbv4zghU5+NE7U8M8G9H5Jc8FI51rqDWQs6FtUfq2e/Q== + +"@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + +"@types/lodash-es@^4.17.6": + version "4.17.6" + resolved "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.6.tgz#c2ed4c8320ffa6f11b43eb89e9eaeec65966a0a0" + integrity sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg== + dependencies: + "@types/lodash" "*" + +"@types/lodash@*", "@types/lodash@^4.14.182": + version "4.14.182" + resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.182.tgz#05301a4d5e62963227eaafe0ce04dd77c54ea5c2" + integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q== + +"@types/node@^17.0.39": + version "17.0.41" + resolved "https://registry.npmmirror.com/@types/node/-/node-17.0.41.tgz#1607b2fd3da014ae5d4d1b31bc792a39348dfb9b" + integrity sha512-xA6drNNeqb5YyV5fO3OAEsnXLfO7uF0whiOfPTz5AeDo8KeZFmODKnvwPymMNO8qE/an8pVY/O50tig2SQCrGw== + +"@types/nprogress@^0.2.0": + version "0.2.0" + resolved "https://registry.npmmirror.com/@types/nprogress/-/nprogress-0.2.0.tgz#86c593682d4199212a0509cc3c4d562bbbd6e45f" + integrity sha512-1cYJrqq9GezNFPsWTZpFut/d4CjpZqA0vhqDUPFWYKF1oIyBz5qnoYMzR+0C/T96t3ebLAC1SSnwrVOm5/j74A== + +"@types/sortablejs@^1.13.0": + version "1.13.0" + resolved "https://registry.npmmirror.com/@types/sortablejs/-/sortablejs-1.13.0.tgz#870223438f8f2cd81157b128a4c0261adbcaa946" + integrity sha512-C3064MH72iEfeGCYEGCt7FCxXoAXaMPG0QPnstcxvPmbl54erpISu06d++FY37Smja64iWy5L8wOyHHBghWbJQ== + +"@typescript-eslint/eslint-plugin@^5.27.0": + version "5.27.1" + resolved "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.27.1.tgz#fdf59c905354139046b41b3ed95d1609913d0758" + integrity sha512-6dM5NKT57ZduNnJfpY81Phe9nc9wolnMCnknb1im6brWi1RYv84nbMS3olJa27B6+irUVV1X/Wb+Am0FjJdGFw== + dependencies: + "@typescript-eslint/scope-manager" "5.27.1" + "@typescript-eslint/type-utils" "5.27.1" + "@typescript-eslint/utils" "5.27.1" + debug "^4.3.4" + functional-red-black-tree "^1.0.1" + ignore "^5.2.0" + regexpp "^3.2.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^5.27.0": + version "5.27.1" + resolved "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-5.27.1.tgz#3a4dcaa67e45e0427b6ca7bb7165122c8b569639" + integrity sha512-7Va2ZOkHi5NP+AZwb5ReLgNF6nWLGTeUJfxdkVUAPPSaAdbWNnFZzLZ4EGGmmiCTg+AwlbE1KyUYTBglosSLHQ== + dependencies: + "@typescript-eslint/scope-manager" "5.27.1" + "@typescript-eslint/types" "5.27.1" + "@typescript-eslint/typescript-estree" "5.27.1" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.27.1": + version "5.27.1" + resolved "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-5.27.1.tgz#4d1504392d01fe5f76f4a5825991ec78b7b7894d" + integrity sha512-fQEOSa/QroWE6fAEg+bJxtRZJTH8NTskggybogHt4H9Da8zd4cJji76gA5SBlR0MgtwF7rebxTbDKB49YUCpAg== + dependencies: + "@typescript-eslint/types" "5.27.1" + "@typescript-eslint/visitor-keys" "5.27.1" + +"@typescript-eslint/type-utils@5.27.1": + version "5.27.1" + resolved "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-5.27.1.tgz#369f695199f74c1876e395ebea202582eb1d4166" + integrity sha512-+UC1vVUWaDHRnC2cQrCJ4QtVjpjjCgjNFpg8b03nERmkHv9JV9X5M19D7UFMd+/G7T/sgFwX2pGmWK38rqyvXw== + dependencies: + "@typescript-eslint/utils" "5.27.1" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.27.1": + version "5.27.1" + resolved "https://registry.npmmirror.com/@typescript-eslint/types/-/types-5.27.1.tgz#34e3e629501349d38be6ae97841298c03a6ffbf1" + integrity sha512-LgogNVkBhCTZU/m8XgEYIWICD6m4dmEDbKXESCbqOXfKZxRKeqpiJXQIErv66sdopRKZPo5l32ymNqibYEH/xg== + +"@typescript-eslint/typescript-estree@5.27.1": + version "5.27.1" + resolved "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.27.1.tgz#7621ee78607331821c16fffc21fc7a452d7bc808" + integrity sha512-DnZvvq3TAJ5ke+hk0LklvxwYsnXpRdqUY5gaVS0D4raKtbznPz71UJGnPTHEFo0GDxqLOLdMkkmVZjSpET1hFw== + dependencies: + "@typescript-eslint/types" "5.27.1" + "@typescript-eslint/visitor-keys" "5.27.1" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.27.1": + version "5.27.1" + resolved "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-5.27.1.tgz#b4678b68a94bc3b85bf08f243812a6868ac5128f" + integrity sha512-mZ9WEn1ZLDaVrhRaYgzbkXBkTPghPFsup8zDbbsYTxC5OmqrFE7skkKS/sraVsLP3TcT3Ki5CSyEFBRkLH/H/w== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.27.1" + "@typescript-eslint/types" "5.27.1" + "@typescript-eslint/typescript-estree" "5.27.1" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/visitor-keys@5.27.1": + version "5.27.1" + resolved "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.27.1.tgz#05a62666f2a89769dac2e6baa48f74e8472983af" + integrity sha512-xYs6ffo01nhdJgPieyk7HAOpjhTsx7r/oB9LWEhwAXgwn33tkr+W8DI2ChboqhZlC4q3TC6geDYPoiX8ROqyOQ== + dependencies: + "@typescript-eslint/types" "5.27.1" + eslint-visitor-keys "^3.3.0" + +"@uppy/companion-client@^2.2.1": + version "2.2.1" + resolved "https://registry.npmmirror.com/@uppy/companion-client/-/companion-client-2.2.1.tgz#cef4b15185dd8ee6024386c8aae809e8e05dcd53" + integrity sha512-Y3E10NJLMfp/wjgthNhx3gJtT67fzFCPNPFwpNNRs5iJsW6PANhJ420eyMUFzfmEZ56ZzGYxr5pzJZx8YxHICQ== + dependencies: + "@uppy/utils" "^4.1.0" + namespace-emitter "^2.0.1" + +"@uppy/core@^2.1.1": + version "2.3.1" + resolved "https://registry.npmmirror.com/@uppy/core/-/core-2.3.1.tgz#1d7a40f0a0b96a2709115bf7d087b4e6ab1403f4" + integrity sha512-KV04X7ueYbYX1p37/i3QsoQSw8IDP8Yb+Bh9KNN0X2Vcun6K2VnNjhVtPmPXtyjDZooK7lVIqhRX8TZWcSfgSQ== + dependencies: + "@transloadit/prettier-bytes" "0.0.7" + "@uppy/store-default" "^2.1.0" + "@uppy/utils" "^4.1.0" + lodash.throttle "^4.1.1" + mime-match "^1.0.2" + namespace-emitter "^2.0.1" + nanoid "^3.1.25" + preact "^10.5.13" + +"@uppy/store-default@^2.1.0": + version "2.1.0" + resolved "https://registry.npmmirror.com/@uppy/store-default/-/store-default-2.1.0.tgz#3fbcac626dd515668b88762d812017bd4f9b75d4" + integrity sha512-BkcR1wGw6Kwbvr8m1tKF9EDDWSTJoTGnVseBF/iW4bzR22assbtxZIE1iroo68UMqYEG4rv63SX4BUEtNvVjdA== + +"@uppy/utils@^4.1.0": + version "4.1.0" + resolved "https://registry.npmmirror.com/@uppy/utils/-/utils-4.1.0.tgz#19f3f08cd21b383cdcdf95adbec76d9c1a694b68" + integrity sha512-C47DUl4uLzmQZdW+VmetIgGRurXuPsvb+/pyYqh9DJn0Phep8u7AOj/tlJA5CHv4pefNHsFjXpaWfSUG3HtW3A== + dependencies: + lodash.throttle "^4.1.1" + +"@uppy/xhr-upload@^2.0.3": + version "2.1.2" + resolved "https://registry.npmmirror.com/@uppy/xhr-upload/-/xhr-upload-2.1.2.tgz#0f644e3371b611b10cd5ddbd7d799ab9f88a3786" + integrity sha512-VCsb7J5yHsof49nnUa+Y1n27UMtqHPttQmmoCa5hmjqa9R7ZISpBkXKOQmZo526eopKNuAKSAdkHWfCm8efJTA== + dependencies: + "@uppy/companion-client" "^2.2.1" + "@uppy/utils" "^4.1.0" + nanoid "^3.1.25" + +"@vitejs/plugin-vue@^2.3.3": + version "2.3.3" + resolved "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-2.3.3.tgz#fbf80cc039b82ac21a1acb0f0478de8f61fbf600" + integrity sha512-SmQLDyhz+6lGJhPELsBdzXGc+AcaT8stgkbiTFGpXPe8Tl1tJaBw1A6pxDqDuRsVkD8uscrkx3hA7QDOoKYtyw== + +"@vue/compiler-core@3.2.37": + version "3.2.37" + resolved "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.2.37.tgz#b3c42e04c0e0f2c496ff1784e543fbefe91e215a" + integrity sha512-81KhEjo7YAOh0vQJoSmAD68wLfYqJvoiD4ulyedzF+OEk/bk6/hx3fTNVfuzugIIaTrOx4PGx6pAiBRe5e9Zmg== + dependencies: + "@babel/parser" "^7.16.4" + "@vue/shared" "3.2.37" + estree-walker "^2.0.2" + source-map "^0.6.1" + +"@vue/compiler-dom@3.2.37": + version "3.2.37" + resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.2.37.tgz#10d2427a789e7c707c872da9d678c82a0c6582b5" + integrity sha512-yxJLH167fucHKxaqXpYk7x8z7mMEnXOw3G2q62FTkmsvNxu4FQSu5+3UMb+L7fjKa26DEzhrmCxAgFLLIzVfqQ== + dependencies: + "@vue/compiler-core" "3.2.37" + "@vue/shared" "3.2.37" + +"@vue/compiler-sfc@3.2.37", "@vue/compiler-sfc@^3.2.36": + version "3.2.37" + resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.2.37.tgz#3103af3da2f40286edcd85ea495dcb35bc7f5ff4" + integrity sha512-+7i/2+9LYlpqDv+KTtWhOZH+pa8/HnX/905MdVmAcI/mPQOBwkHHIzrsEsucyOIZQYMkXUiTkmZq5am/NyXKkg== + dependencies: + "@babel/parser" "^7.16.4" + "@vue/compiler-core" "3.2.37" + "@vue/compiler-dom" "3.2.37" + "@vue/compiler-ssr" "3.2.37" + "@vue/reactivity-transform" "3.2.37" + "@vue/shared" "3.2.37" + estree-walker "^2.0.2" + magic-string "^0.25.7" + postcss "^8.1.10" + source-map "^0.6.1" + +"@vue/compiler-ssr@3.2.37": + version "3.2.37" + resolved "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.2.37.tgz#4899d19f3a5fafd61524a9d1aee8eb0505313cff" + integrity sha512-7mQJD7HdXxQjktmsWp/J67lThEIcxLemz1Vb5I6rYJHR5vI+lON3nPGOH3ubmbvYGt8xEUaAr1j7/tIFWiEOqw== + dependencies: + "@vue/compiler-dom" "3.2.37" + "@vue/shared" "3.2.37" + +"@vue/devtools-api@^6.0.0", "@vue/devtools-api@^6.0.0-beta.7", "@vue/devtools-api@^6.1.4": + version "6.1.4" + resolved "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.1.4.tgz#b4aec2f4b4599e11ba774a50c67fa378c9824e53" + integrity sha512-IiA0SvDrJEgXvVxjNkHPFfDx6SXw0b/TUkqMcDZWNg9fnCAHbTpoo59YfJ9QLFkwa3raau5vSlRVzMSLDnfdtQ== + +"@vue/reactivity-transform@3.2.37": + version "3.2.37" + resolved "https://registry.npmmirror.com/@vue/reactivity-transform/-/reactivity-transform-3.2.37.tgz#0caa47c4344df4ae59f5a05dde2a8758829f8eca" + integrity sha512-IWopkKEb+8qpu/1eMKVeXrK0NLw9HicGviJzhJDEyfxTR9e1WtpnnbYkJWurX6WwoFP0sz10xQg8yL8lgskAZg== + dependencies: + "@babel/parser" "^7.16.4" + "@vue/compiler-core" "3.2.37" + "@vue/shared" "3.2.37" + estree-walker "^2.0.2" + magic-string "^0.25.7" + +"@vue/reactivity@3.2.37": + version "3.2.37" + resolved "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.2.37.tgz#5bc3847ac58828e2b78526e08219e0a1089f8848" + integrity sha512-/7WRafBOshOc6m3F7plwzPeCu/RCVv9uMpOwa/5PiY1Zz+WLVRWiy0MYKwmg19KBdGtFWsmZ4cD+LOdVPcs52A== + dependencies: + "@vue/shared" "3.2.37" + +"@vue/runtime-core@3.2.37": + version "3.2.37" + resolved "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.2.37.tgz#7ba7c54bb56e5d70edfc2f05766e1ca8519966e3" + integrity sha512-JPcd9kFyEdXLl/i0ClS7lwgcs0QpUAWj+SKX2ZC3ANKi1U4DOtiEr6cRqFXsPwY5u1L9fAjkinIdB8Rz3FoYNQ== + dependencies: + "@vue/reactivity" "3.2.37" + "@vue/shared" "3.2.37" + +"@vue/runtime-dom@3.2.37": + version "3.2.37" + resolved "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.2.37.tgz#002bdc8228fa63949317756fb1e92cdd3f9f4bbd" + integrity sha512-HimKdh9BepShW6YozwRKAYjYQWg9mQn63RGEiSswMbW+ssIht1MILYlVGkAGGQbkhSh31PCdoUcfiu4apXJoPw== + dependencies: + "@vue/runtime-core" "3.2.37" + "@vue/shared" "3.2.37" + csstype "^2.6.8" + +"@vue/server-renderer@3.2.37": + version "3.2.37" + resolved "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.2.37.tgz#840a29c8dcc29bddd9b5f5ffa22b95c0e72afdfc" + integrity sha512-kLITEJvaYgZQ2h47hIzPh2K3jG8c1zCVbp/o/bzQOyvzaKiCquKS7AaioPI28GNxIsE/zSx+EwWYsNxDCX95MA== + dependencies: + "@vue/compiler-ssr" "3.2.37" + "@vue/shared" "3.2.37" + +"@vue/shared@3.2.37": + version "3.2.37" + resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.2.37.tgz#8e6adc3f2759af52f0e85863dfb0b711ecc5c702" + integrity sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw== + +"@vueuse/core@^8.6.0": + version "8.6.0" + resolved "https://registry.npmmirror.com/@vueuse/core/-/core-8.6.0.tgz#a8f80363cc63d17382423f16beae57696f376e67" + integrity sha512-VirzExCm/N+QdrEWT7J4uSrvJ5hquKIAU9alQ37kUvIJk9XxCLxmfRnmekYc1kz2+6BnoyuKYXVmrMV351CB4w== + dependencies: + "@vueuse/metadata" "8.6.0" + "@vueuse/shared" "8.6.0" + vue-demi "*" + +"@vueuse/metadata@8.6.0": + version "8.6.0" + resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-8.6.0.tgz#34771443a72ee891ae001a70aa05dd9a1d799372" + integrity sha512-F+CKPvaExsm7QgRr8y+ZNJFwXasn89rs5wth/HeX9lJ1q8XEt+HJ16Q5Sxh4rfG5YSKXrStveVge8TKvPjMjFA== + +"@vueuse/shared@8.6.0": + version "8.6.0" + resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-8.6.0.tgz#63dad9fc4b73a7fccbe5d6b97adeacf73d4fec41" + integrity sha512-Y/IVywZo7IfEoSSEtCYpkVEmPV7pU35mEIxV7PbD/D3ly18B3mEsBaPbtDkNM/QP3zAZ5mn4nEkOfddX4uwuIA== + dependencies: + vue-demi "*" + +"@wangeditor/basic-modules@^1.1.1": + version "1.1.1" + resolved "https://registry.npmmirror.com/@wangeditor/basic-modules/-/basic-modules-1.1.1.tgz#1ae0b11202b2ac319b4883e46f4d069ffce2f78d" + integrity sha512-tQl2Pw8M2g3CM+ESx2phzr9zSKeuFCM1AMBoPdnlbatU7Dnae0CsEB/b3C+gI0dIQzM2jh34yTmqgbbhrwuRLg== + dependencies: + is-url "^1.2.4" + +"@wangeditor/code-highlight@^1.0.2": + version "1.0.2" + resolved "https://registry.npmmirror.com/@wangeditor/code-highlight/-/code-highlight-1.0.2.tgz#df6bf7ac8d232c6afb0cb8189baa9f8d52feeded" + integrity sha512-SCtOcUxjKqIso/LSxGSOaYr3G6MC2En0gNTyHIMCG928T0fo0ufaqp/vIXKQzVL2Y+X/CSAOB2EbrFlgGvr0AQ== + dependencies: + prismjs "^1.23.0" + +"@wangeditor/core@^1.1.1": + version "1.1.1" + resolved "https://registry.npmmirror.com/@wangeditor/core/-/core-1.1.1.tgz#f749a7d65ad95dbffccdf4d6f11272be8134eb88" + integrity sha512-SrbvOGlONMNMOeFIJI7fC9x0/6T6LvQHTITPCqjgbCm2QF+POcrHzRKGQOqKCsyKi9UJz9hLsjsvJnvP10rxjQ== + dependencies: + "@types/event-emitter" "^0.3.3" + event-emitter "^0.3.5" + html-void-elements "^2.0.0" + i18next "^20.4.0" + scroll-into-view-if-needed "^2.2.28" + slate-history "^0.66.0" + +"@wangeditor/editor@^5.1.1": + version "5.1.1" + resolved "https://registry.npmmirror.com/@wangeditor/editor/-/editor-5.1.1.tgz#009b11277de86a4052087d0428934e7d2dd30147" + integrity sha512-BtccuHFm0QvYunIhIu7tllQWkwppkmEkD3OJ5Mn+F0REPQ/Z3HiEXbtlss2t9c/kHO4CtiFwv2XD/k/VEg7taA== + dependencies: + "@uppy/core" "^2.1.1" + "@uppy/xhr-upload" "^2.0.3" + "@wangeditor/basic-modules" "^1.1.1" + "@wangeditor/code-highlight" "^1.0.2" + "@wangeditor/core" "^1.1.1" + "@wangeditor/list-module" "^1.0.2" + "@wangeditor/table-module" "^1.1.0" + "@wangeditor/upload-image-module" "^1.0.1" + "@wangeditor/video-module" "^1.1.0" + dom7 "^3.0.0" + is-hotkey "^0.2.0" + lodash.camelcase "^4.3.0" + lodash.clonedeep "^4.5.0" + lodash.debounce "^4.0.8" + lodash.foreach "^4.5.0" + lodash.isequal "^4.5.0" + lodash.throttle "^4.1.1" + lodash.toarray "^4.4.0" + nanoid "^3.2.0" + slate "^0.72.0" + snabbdom "^3.1.0" + +"@wangeditor/list-module@^1.0.2": + version "1.0.2" + resolved "https://registry.npmmirror.com/@wangeditor/list-module/-/list-module-1.0.2.tgz#c9e57c4c34bbcc32df3a9030df2fda0bb4f77a39" + integrity sha512-VfENZEFvsLTiLxN/cj8cibFGy9NVV+/cfATTiLiH9ef+8lgKv8apttXYVlqIAfnlJLLuCk0cIm8c/zH+hbtrZg== + +"@wangeditor/table-module@^1.1.0": + version "1.1.0" + resolved "https://registry.npmmirror.com/@wangeditor/table-module/-/table-module-1.1.0.tgz#5cd4ebdd0500915c51793efd6227c43b5e185d77" + integrity sha512-QpjCXSzsXcsR0pEI5Pu28e8aYh9+lHcVV4TTmGV6lRGE/etQF3PHUZNGUlfhkCgmGPq+E7n/Whb4RpAM3PJVhw== + +"@wangeditor/upload-image-module@^1.0.1": + version "1.0.1" + resolved "https://registry.npmmirror.com/@wangeditor/upload-image-module/-/upload-image-module-1.0.1.tgz#a074518d73ce9c5cfd3e8ee56d1adf831996f142" + integrity sha512-vgUV4ENttTITblqtVuzleIq732OmzmzzgrIvX6b3GRGPSw5u8glJ/87tOEhvHjHECc4oFo18B7xzJ1GpBj79/w== + +"@wangeditor/video-module@^1.1.0": + version "1.1.0" + resolved "https://registry.npmmirror.com/@wangeditor/video-module/-/video-module-1.1.0.tgz#664405b1eeef1e9ab09f84a50270a4394f885355" + integrity sha512-VR6x7Vk9ebvXtxCPwobiNiTGZGgqEzCVc6ViWlNH3v4jlDIeo/s7N7OCgpvELR7X/X7GHecBu7wySDkHIskB5w== + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.7.1: + version "8.7.1" + resolved "https://registry.npmmirror.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" + integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== + +ajv@^6.10.0, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +async-validator@^4.1.1: + version "4.1.1" + resolved "https://registry.npmmirror.com/async-validator/-/async-validator-4.1.1.tgz#3cd1437faa2de64743f7d56649dd904c946a18fe" + integrity sha512-p4DO/JXwjs8klJyJL8Q2oM4ks5fUTze/h5k10oPPKMiLe1fj3G1QMzPHNmN1Py4ycOk7WlO2DcGXv1qiESJCZA== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +axios@^0.27.2: + version "0.27.2" + resolved "https://registry.npmmirror.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" + integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== + dependencies: + follow-redirects "^1.14.9" + form-data "^4.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +batch-processor@1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/batch-processor/-/batch-processor-1.0.0.tgz#75c95c32b748e0850d10c2b168f6bdbe9891ace8" + integrity sha512-xoLQD8gmmR32MeuBHgH0Tzd5PuSZx71ZsbhVxOCRbgktZEPe4SQy7s9Z50uPp0F/f7iw2XmkHN2xkgbMfckMDA== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +boolbase@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +"chokidar@>=3.0.0 <4.0.0": + version "3.5.3" + resolved "https://registry.npmmirror.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +claygl@^1.2.1: + version "1.3.0" + resolved "https://registry.npmmirror.com/claygl/-/claygl-1.3.0.tgz#7a6e2903210519ac358848f5d78070ed211685f3" + integrity sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ== + +clipboard@^2.0.6: + version "2.0.11" + resolved "https://registry.npmmirror.com/clipboard/-/clipboard-2.0.11.tgz#62180360b97dd668b6b3a84ec226975762a70be5" + integrity sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw== + dependencies: + good-listener "^1.2.2" + select "^1.1.2" + tiny-emitter "^2.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +compute-scroll-into-view@^1.0.17: + version "1.0.17" + resolved "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz#6a88f18acd9d42e9cf4baa6bec7e0522607ab7ab" + integrity sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +countup.js@^2.2.0: + version "2.2.0" + resolved "https://registry.npmmirror.com/countup.js/-/countup.js-2.2.0.tgz#e20e247abf801190056c5eeed51ceb13cef6ea0c" + integrity sha512-m0TvFNXm9/eFqJm+QiKVI8e0wRUHzlQSewz9dqVjlhl2DFoZtceLbomwzxHz0hJ1+r4zBC7wSpR/TpthG49h6g== + +cropperjs@^1.5.12: + version "1.5.12" + resolved "https://registry.npmmirror.com/cropperjs/-/cropperjs-1.5.12.tgz#d9c0db2bfb8c0d769d51739e8f916bbc44e10f50" + integrity sha512-re7UdjE5UnwdrovyhNzZ6gathI4Rs3KGCBSc8HCIjUo5hO42CtzyblmWLj6QWVw7huHyDMfpKxhiO2II77nhDw== + +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +csstype@^2.6.8: + version "2.6.20" + resolved "https://registry.npmmirror.com/csstype/-/csstype-2.6.20.tgz#9229c65ea0b260cf4d3d997cb06288e36a8d6dda" + integrity sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA== + +d@1, d@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + +dayjs@^1.11.3: + version "1.11.3" + resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.3.tgz#4754eb694a624057b9ad2224b67b15d552589258" + integrity sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A== + +debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +delegate@^3.1.2: + version "3.2.0" + resolved "https://registry.npmmirror.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166" + integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dom7@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/dom7/-/dom7-3.0.0.tgz#b861ce5d67a6becd7aaa3ad02942ff14b1240331" + integrity sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g== + dependencies: + ssr-window "^3.0.0-alpha.1" + +dotenv@^16.0.1: + version "16.0.1" + resolved "https://registry.npmmirror.com/dotenv/-/dotenv-16.0.1.tgz#8f8f9d94876c35dac989876a5d3a82a267fdce1d" + integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ== + +echarts-gl@^2.0.9: + version "2.0.9" + resolved "https://registry.npmmirror.com/echarts-gl/-/echarts-gl-2.0.9.tgz#ee228a6c7520a6fb7bbb71ea94394f3637ade033" + integrity sha512-oKeMdkkkpJGWOzjgZUsF41DOh6cMsyrGGXimbjK2l6Xeq/dBQu4ShG2w2Dzrs/1bD27b2pLTGSaUzouY191gzA== + dependencies: + claygl "^1.2.1" + zrender "^5.1.1" + +echarts-wordcloud@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/echarts-wordcloud/-/echarts-wordcloud-2.0.0.tgz#52ef817895801ffe9e99dd1bacab7686b2dec04a" + integrity sha512-K7l6pTklqdW7ZWzT/1CS0KhBSINr/cd7c5N1fVMzZMwLQHEwT7x+nivK7g5hkVh7WNcAv4Dn6/ZS5zMKRozC1g== + +echarts@^5.3.2: + version "5.3.2" + resolved "https://registry.npmmirror.com/echarts/-/echarts-5.3.2.tgz#0a7b3be8c48a48b2e7cb1b82121df0c208d42d2c" + integrity sha512-LWCt7ohOKdJqyiBJ0OGBmE9szLdfA9sGcsMEi+GGoc6+Xo75C+BkcT/6NNGRHAWtnQl2fNow05AQjznpap28TQ== + dependencies: + tslib "2.3.0" + zrender "5.3.1" + +element-plus@^2.2.2: + version "2.2.5" + resolved "https://registry.npmmirror.com/element-plus/-/element-plus-2.2.5.tgz#2bb889660c9bcb9bb71e18619915b35e0f48d569" + integrity sha512-Kl0yn/PQca5YQo3M3NPBP4Xl71NQuMtDx5zNXZGVyl5FjdMujXiFB9SXKYGDUCgFU3d/Rl14vB4Fpmcl2Iz+Hw== + dependencies: + "@ctrl/tinycolor" "^3.4.1" + "@element-plus/icons-vue" "^2.0.5" + "@floating-ui/dom" "^0.5.2" + "@popperjs/core" "npm:@sxzz/popperjs-es@^2.11.7" + "@types/lodash" "^4.14.182" + "@types/lodash-es" "^4.17.6" + "@vueuse/core" "^8.6.0" + async-validator "^4.1.1" + dayjs "^1.11.3" + escape-html "^1.0.3" + lodash "^4.17.21" + lodash-es "^4.17.21" + lodash-unified "^1.0.2" + memoize-one "^6.0.0" + normalize-wheel-es "^1.1.2" + +element-resize-detector@^1.2.1: + version "1.2.4" + resolved "https://registry.npmmirror.com/element-resize-detector/-/element-resize-detector-1.2.4.tgz#3e6c5982dd77508b5fa7e6d5c02170e26325c9b1" + integrity sha512-Fl5Ftk6WwXE0wqCgNoseKWndjzZlDCwuPTcoVZfCP9R3EHQF8qUtr3YUPNETegRBOKqQKPW3n4kiIWngGi8tKg== + dependencies: + batch-processor "1.0.0" + +es5-ext@^0.10.35, es5-ext@^0.10.50, es5-ext@~0.10.14: + version "0.10.61" + resolved "https://registry.npmmirror.com/es5-ext/-/es5-ext-0.10.61.tgz#311de37949ef86b6b0dcea894d1ffedb909d3269" + integrity sha512-yFhIqQAzu2Ca2I4SE2Au3rxVfmohU9Y7wqGR+s7+H7krk26NXhIRAZDgqd6xqjCEFUomDEA3/Bo/7fKmIkW1kA== + dependencies: + es6-iterator "^2.0.3" + es6-symbol "^3.1.3" + next-tick "^1.1.0" + +es6-iterator@^2.0.3: + version "2.0.3" + resolved "https://registry.npmmirror.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-symbol@^3.1.1, es6-symbol@^3.1.3: + version "3.1.3" + resolved "https://registry.npmmirror.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== + dependencies: + d "^1.0.1" + ext "^1.1.2" + +esbuild-android-64@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-android-64/-/esbuild-android-64-0.14.43.tgz#59bf3edad6863c27aa92bbb5c1d83a9a5c981495" + integrity sha512-kqFXAS72K6cNrB6RiM7YJ5lNvmWRDSlpi7ZuRZ1hu1S3w0zlwcoCxWAyM23LQUyZSs1PbjHgdbbfYAN8IGh6xg== + +esbuild-android-arm64@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.43.tgz#0258704edf92ce2463af6d2900b844b5423bed63" + integrity sha512-bKS2BBFh+7XZY9rpjiHGRNA7LvWYbZWP87pLehggTG7tTaCDvj8qQGOU/OZSjCSKDYbgY7Q+oDw8RlYQ2Jt2BA== + +esbuild-darwin-64@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.43.tgz#72a47295678d4aa0656979baa8cf6d5c8c92656f" + integrity sha512-/3PSilx011ttoieRGkSZ0XV8zjBf2C9enV4ScMMbCT4dpx0mFhMOpFnCHkOK0pWGB8LklykFyHrWk2z6DENVUg== + +esbuild-darwin-arm64@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.43.tgz#5f5823170b8d85b888957f0794e186caac447aca" + integrity sha512-1HyFUKs8DMCBOvw1Qxpr5Vv/ThNcVIFb5xgXWK3pyT40WPvgYIiRTwJCvNs4l8i5qWF8/CK5bQxJVDjQvtv0Yw== + +esbuild-freebsd-64@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.43.tgz#e4a48b08181053837e6cd9bda19ae0af94d493b0" + integrity sha512-FNWc05TPHYgaXjbPZO5/rJKSBslfG6BeMSs8GhwnqAKP56eEhvmzwnIz1QcC9cRVyO+IKqWNfmHFkCa1WJTULA== + +esbuild-freebsd-arm64@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.43.tgz#386e780d36c1dedf3a1cdab79e0bbacd873274e6" + integrity sha512-amrYopclz3VohqisOPR6hA3GOWA3LZC1WDLnp21RhNmoERmJ/vLnOpnrG2P/Zao+/erKTCUqmrCIPVtj58DRoA== + +esbuild-linux-32@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-linux-32/-/esbuild-linux-32-0.14.43.tgz#040ed6b9ebf06d73acdf2acce7f1cd0c12fbc6a5" + integrity sha512-KoxoEra+9O3AKVvgDFvDkiuddCds6q71owSQEYwjtqRV7RwbPzKxJa6+uyzUulHcyGVq0g15K0oKG5CFBcvYDw== + +esbuild-linux-64@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-linux-64/-/esbuild-linux-64-0.14.43.tgz#8abbb7594ab6a008f2aae72d95d8a4fdc59d9000" + integrity sha512-EwINwGMyiJMgBby5/SbMqKcUhS5AYAZ2CpEBzSowsJPNBJEdhkCTtEjk757TN/wxgbu3QklqDM6KghY660QCUw== + +esbuild-linux-arm64@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.43.tgz#4e8e9ce77cbf7efec65e79e512b3d2fbd2da398f" + integrity sha512-UlSpjMWllAc70zYbHxWuDS3FJytyuR/gHJYBr8BICcTNb/TSOYVBg6U7b3jZ3mILTrgzwJUHwhEwK18FZDouUQ== + +esbuild-linux-arm@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.43.tgz#9e41ee5e099c0ffdfd150da154330c2c0226cc96" + integrity sha512-e6YzQUoDxxtyamuF12eVzzRC7bbEFSZohJ6igQB9tBqnNmIQY3fI6Cns3z2wxtbZ3f2o6idkD2fQnlvs2902Dg== + +esbuild-linux-mips64le@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.43.tgz#4b41f465a787f91cc4fe7dffa0dcabf655935a1a" + integrity sha512-f+v8cInPEL1/SDP//CfSYzcDNgE4CY3xgDV81DWm3KAPWzhvxARrKxB1Pstf5mB56yAslJDxu7ryBUPX207EZA== + +esbuild-linux-ppc64le@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.43.tgz#ca15934f5b46728dd9ac05270e783e7feaca9eaf" + integrity sha512-5wZYMDGAL/K2pqkdIsW+I4IR41kyfHr/QshJcNpUfK3RjB3VQcPWOaZmc+74rm4ZjVirYrtz+jWw0SgxtxRanA== + +esbuild-linux-riscv64@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.43.tgz#70fce2b5a0605a67e58b5a357b0e00be1029836d" + integrity sha512-lYcAOUxp85hC7lSjycJUVSmj4/9oEfSyXjb/ua9bNl8afonaduuqtw7hvKMoKuYnVwOCDw4RSfKpcnIRDWq+Bw== + +esbuild-linux-s390x@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.43.tgz#318d03b4f4ccc7fa44ac7562121cf4a4529e477a" + integrity sha512-27e43ZhHvhFE4nM7HqtUbMRu37I/4eNSUbb8FGZWszV+uLzMIsHDwLoBiJmw7G9N+hrehNPeQ4F5Ujad0DrUKQ== + +esbuild-netbsd-64@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.43.tgz#86130ce204ef0162a96e863b55851efecc92f423" + integrity sha512-2mH4QF6hHBn5zzAfxEI/2eBC0mspVsZ6UVo821LpAJKMvLJPBk3XJO5xwg7paDqSqpl7p6IRrAenW999AEfJhQ== + +esbuild-openbsd-64@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.43.tgz#0229dc2db2ded97b03bb93bba7646b30ffdf5d0d" + integrity sha512-ZhQpiZjvqCqO8jKdGp9+8k9E/EHSA+zIWOg+grwZasI9RoblqJ1QiZqqi7jfd6ZrrG1UFBNGe4m0NFxCFbMVbg== + +esbuild-sunos-64@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.43.tgz#17e316216eb9f1de25d52a9000356ae5b869e736" + integrity sha512-DgxSi9DaHReL9gYuul2rrQCAapgnCJkh3LSHPKsY26zytYppG0HgkgVF80zjIlvEsUbGBP/GHQzBtrezj/Zq1Q== + +esbuild-windows-32@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-windows-32/-/esbuild-windows-32-0.14.43.tgz#a173757bc6dfd0f2656ff40b64f7f9290745778e" + integrity sha512-Ih3+2O5oExiqm0mY6YYE5dR0o8+AspccQ3vIAtRodwFvhuyGLjb0Hbmzun/F3Lw19nuhPMu3sW2fqIJ5xBxByw== + +esbuild-windows-64@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-windows-64/-/esbuild-windows-64-0.14.43.tgz#c447b23126aad158c4fe6a394342cafd97926ed1" + integrity sha512-8NsuNfI8xwFuJbrCuI+aBqNTYkrWErejFO5aYM+yHqyHuL8mmepLS9EPzAzk8rvfaJrhN0+RvKWAcymViHOKEw== + +esbuild-windows-arm64@0.14.43: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.43.tgz#3caed1b430d394d7a7836407b9d36c4750246e76" + integrity sha512-7ZlD7bo++kVRblJEoG+cepljkfP8bfuTPz5fIXzptwnPaFwGS6ahvfoYzY7WCf5v/1nX2X02HDraVItTgbHnKw== + +esbuild@^0.14.27: + version "0.14.43" + resolved "https://registry.npmmirror.com/esbuild/-/esbuild-0.14.43.tgz#c227d585c512d3e0f23b88f50b8e16501147f647" + integrity sha512-Uf94+kQmy/5jsFwKWiQB4hfo/RkM9Dh7b79p8yqd1tshULdr25G2szLz631NoH3s2ujnKEKVD16RmOxvCNKRFA== + optionalDependencies: + esbuild-android-64 "0.14.43" + esbuild-android-arm64 "0.14.43" + esbuild-darwin-64 "0.14.43" + esbuild-darwin-arm64 "0.14.43" + esbuild-freebsd-64 "0.14.43" + esbuild-freebsd-arm64 "0.14.43" + esbuild-linux-32 "0.14.43" + esbuild-linux-64 "0.14.43" + esbuild-linux-arm "0.14.43" + esbuild-linux-arm64 "0.14.43" + esbuild-linux-mips64le "0.14.43" + esbuild-linux-ppc64le "0.14.43" + esbuild-linux-riscv64 "0.14.43" + esbuild-linux-s390x "0.14.43" + esbuild-netbsd-64 "0.14.43" + esbuild-openbsd-64 "0.14.43" + esbuild-sunos-64 "0.14.43" + esbuild-windows-32 "0.14.43" + esbuild-windows-64 "0.14.43" + esbuild-windows-arm64 "0.14.43" + +escape-html@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-plugin-vue@^9.1.0: + version "9.1.0" + resolved "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-9.1.0.tgz#b528941325e26a24bc5d5c5030c0a8996c36659c" + integrity sha512-EPCeInPicQ/YyfOWJDr1yfEeSNoFCMzUus107lZyYi37xejdOolNzS5MXGXp8+9bkoKZMdv/1AcZzQebME6r+g== + dependencies: + eslint-utils "^3.0.0" + natural-compare "^1.4.0" + nth-check "^2.0.1" + postcss-selector-parser "^6.0.9" + semver "^7.3.5" + vue-eslint-parser "^9.0.1" + xml-name-validator "^4.0.0" + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint@^8.17.0: + version "8.17.0" + resolved "https://registry.npmmirror.com/eslint/-/eslint-8.17.0.tgz#1cfc4b6b6912f77d24b874ca1506b0fe09328c21" + integrity sha512-gq0m0BTJfci60Fz4nczYxNAlED+sMcihltndR8t9t1evnU/azx53x3t2UHXC/uRjcbvRw/XctpaNygSTcQD+Iw== + dependencies: + "@eslint/eslintrc" "^1.3.0" + "@humanwhocodes/config-array" "^0.9.2" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.2" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^6.0.1" + globals "^13.15.0" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.1" + regexpp "^3.2.0" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^9.3.1, espree@^9.3.2: + version "9.3.2" + resolved "https://registry.npmmirror.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596" + integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA== + dependencies: + acorn "^8.7.1" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.3.0" + +esquery@^1.4.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.npmmirror.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.npmmirror.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +event-emitter@^0.3.5: + version "0.3.5" + resolved "https://registry.npmmirror.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA== + dependencies: + d "1" + es5-ext "~0.10.14" + +ext@^1.1.2: + version "1.6.0" + resolved "https://registry.npmmirror.com/ext/-/ext-1.6.0.tgz#3871d50641e874cc172e2b53f919842d19db4c52" + integrity sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg== + dependencies: + type "^2.5.0" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.9: + version "3.2.11" + resolved "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.npmmirror.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.npmmirror.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.npmmirror.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.5" + resolved "https://registry.npmmirror.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" + integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== + +follow-redirects@^1.14.9: + version "1.15.1" + resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5" + integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^13.15.0: + version "13.15.0" + resolved "https://registry.npmmirror.com/globals/-/globals-13.15.0.tgz#38113218c907d2f7e98658af246cef8b77e90bac" + integrity sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog== + dependencies: + type-fest "^0.20.2" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.npmmirror.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +good-listener@^1.2.2: + version "1.2.2" + resolved "https://registry.npmmirror.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50" + integrity sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw== + dependencies: + delegate "^3.1.2" + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +html-void-elements@^2.0.0: + version "2.0.1" + resolved "https://registry.npmmirror.com/html-void-elements/-/html-void-elements-2.0.1.tgz#29459b8b05c200b6c5ee98743c41b979d577549f" + integrity sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A== + +i18next@^20.4.0: + version "20.6.1" + resolved "https://registry.npmmirror.com/i18next/-/i18next-20.6.1.tgz#535e5f6e5baeb685c7d25df70db63bf3cc0aa345" + integrity sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A== + dependencies: + "@babel/runtime" "^7.12.0" + +ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.npmmirror.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + +immer@^9.0.6: + version "9.0.14" + resolved "https://registry.npmmirror.com/immer/-/immer-9.0.14.tgz#e05b83b63999d26382bb71676c9d827831248a48" + integrity sha512-ubBeqQutOSLIFCUBN03jGeOS6a3DoYlSYwYJTa+gSKEZKU5redJIqkIdZ3JVv/4RZpfcXdAWH5zCNLWPRv2WDw== + +immutable@^4.0.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/immutable/-/immutable-4.1.0.tgz#f795787f0db780183307b9eb2091fcac1f6fafef" + integrity sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.8.1: + version "2.9.0" + resolved "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" + integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== + dependencies: + has "^1.0.3" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-hotkey@^0.2.0: + version "0.2.0" + resolved "https://registry.npmmirror.com/is-hotkey/-/is-hotkey-0.2.0.tgz#1835a68171a91e5c9460869d96336947c8340cef" + integrity sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== + +is-url@^1.2.4: + version "1.2.4" + resolved "https://registry.npmmirror.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" + integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +js-cookie@^3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/js-cookie/-/js-cookie-3.0.1.tgz#9e39b4c6c2f56563708d7d31f6f5f21873a92414" + integrity sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +jsplumb@^2.15.6: + version "2.15.6" + resolved "https://registry.npmmirror.com/jsplumb/-/jsplumb-2.15.6.tgz#16d97a195a52cc8e4227d9e29971ff82b83e8faf" + integrity sha512-sIpbpz5eMVM+vV+MQzFCidlaa1RsknrQs6LOTKYDjYUDdTAi2AN2bFi94TxB33TifcIsRNV1jebcaxg0tCoPzg== + +klona@^2.0.4: + version "2.0.5" + resolved "https://registry.npmmirror.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" + integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lodash-es@^4.17.21: + version "4.17.21" + resolved "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + +lodash-unified@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.2.tgz#bb2694db3533781e5cce984af60cfaea318b83c1" + integrity sha512-OGbEy+1P+UT26CYi4opY4gebD8cWRDxAT6MAObIVQMiqYdxZr1g3QHWCToVsm31x2NkLS4K3+MC2qInaRMa39g== + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.npmmirror.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + +lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.npmmirror.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + +lodash.foreach@^4.5.0: + version "4.5.0" + resolved "https://registry.npmmirror.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" + integrity sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ== + +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.npmmirror.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.throttle@^4.1.1: + version "4.1.1" + resolved "https://registry.npmmirror.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" + integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ== + +lodash.toarray@^4.4.0: + version "4.4.0" + resolved "https://registry.npmmirror.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561" + integrity sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +magic-string@^0.25.7: + version "0.25.9" + resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" + integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== + dependencies: + sourcemap-codec "^1.4.8" + +memoize-one@^6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" + integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-match@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/mime-match/-/mime-match-1.0.2.tgz#3f87c31e9af1a5fd485fb9db134428b23bbb7ba8" + integrity sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg== + dependencies: + wildcard "^1.1.0" + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +mitt@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/mitt/-/mitt-2.1.0.tgz#f740577c23176c6205b121b2973514eade1b2230" + integrity sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg== + +mitt@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/mitt/-/mitt-3.0.0.tgz#69ef9bd5c80ff6f57473e8d89326d01c414be0bd" + integrity sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +namespace-emitter@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/namespace-emitter/-/namespace-emitter-2.0.1.tgz#978d51361c61313b4e6b8cf6f3853d08dfa2b17c" + integrity sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g== + +nanoid@^3.1.25, nanoid@^3.2.0, nanoid@^3.3.4: + version "3.3.4" + resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" + integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.npmmirror.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +next-tick@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-wheel-es@^1.1.2: + version "1.1.2" + resolved "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.1.2.tgz#285e43676a62d687bf145e33452ea6be435162d0" + integrity sha512-scX83plWJXYH1J4+BhAuIHadROzxX0UBF3+HuZNY2Ks8BciE7tSTQ+5JhTsvzjaO0/EJdm4JBGrfObKxFf3Png== + +nprogress@^0.2.0: + version "0.2.0" + resolved "https://registry.npmmirror.com/nprogress/-/nprogress-0.2.0.tgz#cb8f34c53213d895723fcbab907e9422adbcafb1" + integrity sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA== + +nth-check@^2.0.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" + integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== + dependencies: + boolbase "^1.0.0" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.npmmirror.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pinia@^2.0.14: + version "2.0.14" + resolved "https://registry.npmmirror.com/pinia/-/pinia-2.0.14.tgz#0837898c20291ebac982bbfca95c8d3c6099925f" + integrity sha512-0nPuZR4TetT/WcLN+feMSjWJku3SQU7dBbXC6uw+R6FLQJCsg+/0pzXyD82T1FmAYe0lsx+jnEDQ1BLgkRKlxA== + dependencies: + "@vue/devtools-api" "^6.1.4" + vue-demi "*" + +postcss-selector-parser@^6.0.9: + version "6.0.10" + resolved "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d" + integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss@^8.1.10, postcss@^8.4.13: + version "8.4.14" + resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf" + integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig== + dependencies: + nanoid "^3.3.4" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +preact@^10.5.13: + version "10.7.3" + resolved "https://registry.npmmirror.com/preact/-/preact-10.7.3.tgz#f98c09a29cb8dbb22e5fc824a1edcc377fc42b5a" + integrity sha512-giqJXP8VbtA1tyGa3f1n9wiN7PrHtONrDyE3T+ifjr/tTkg+2N4d/6sjC9WyJKv8wM7rOYDveqy5ZoFmYlwo4w== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier@^2.6.2: + version "2.6.2" + resolved "https://registry.npmmirror.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032" + integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew== + +print-js@^1.6.0: + version "1.6.0" + resolved "https://registry.npmmirror.com/print-js/-/print-js-1.6.0.tgz#692b046cf31992b46afa6c6d8a9db1c69d431d1f" + integrity sha512-BfnOIzSKbqGRtO4o0rnj/K3681BSd2QUrsIZy/+WdCIugjIswjmx3lDEZpXB2ruGf9d4b3YNINri81+J0FsBWg== + +prismjs@^1.23.0: + version "1.28.0" + resolved "https://registry.npmmirror.com/prismjs/-/prismjs-1.28.0.tgz#0d8f561fa0f7cf6ebca901747828b149147044b6" + integrity sha512-8aaXdYvl1F7iC7Xm1spqSaY/OJBpYW3v+KJ+F17iYxvdc8sfjW194COK5wVhMZX45tGteiBQgdvD/nhxcRwylw== + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.npmmirror.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qrcodejs2-fixes@^0.0.2: + version "0.0.2" + resolved "https://registry.npmmirror.com/qrcodejs2-fixes/-/qrcodejs2-fixes-0.0.2.tgz#a2f5d7816100073d1c09088ac75a34404d025b30" + integrity sha512-wMUXYMOixAEJlLnjk5MbLiFaz0gQObWYm/TIFWB5+j7sTY5gPyr09Cx1EpcLYbsgfFdN3wHjrKAhZofTuCBGhg== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.npmmirror.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve@^1.22.0: + version "1.22.0" + resolved "https://registry.npmmirror.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" + integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== + dependencies: + is-core-module "^2.8.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rollup@^2.59.0: + version "2.75.6" + resolved "https://registry.npmmirror.com/rollup/-/rollup-2.75.6.tgz#ac4dc8600f95942a0180f61c7c9d6200e374b439" + integrity sha512-OEf0TgpC9vU6WGROJIk1JA3LR5vk/yvqlzxqdrE2CzzXnqKXNzbAwlWUXis8RS3ZPe7LAq+YUxsRa0l3r27MLA== + optionalDependencies: + fsevents "~2.3.2" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +sass-loader@^13.0.0: + version "13.0.0" + resolved "https://registry.npmmirror.com/sass-loader/-/sass-loader-13.0.0.tgz#0b4bff0289951ed21240bca54453eca3dbda1713" + integrity sha512-IHCFecI+rbPvXE2zO/mqdVFe8MU7ElGrwga9hh2H65Ru4iaBJAMRteum1c4Gsxi9Cq1FOtTEDd6+/AEYuQDM4Q== + dependencies: + klona "^2.0.4" + neo-async "^2.6.2" + +sass@^1.52.2: + version "1.52.3" + resolved "https://registry.npmmirror.com/sass/-/sass-1.52.3.tgz#b7cc7ffea2341ccc9a0c4fd372bf1b3f9be1b6cb" + integrity sha512-LNNPJ9lafx+j1ArtA7GyEJm9eawXN8KlA1+5dF6IZyoONg1Tyo/g+muOsENWJH/2Q1FHbbV4UwliU0cXMa/VIA== + dependencies: + chokidar ">=3.0.0 <4.0.0" + immutable "^4.0.0" + source-map-js ">=0.6.2 <2.0.0" + +screenfull@^6.0.1: + version "6.0.1" + resolved "https://registry.npmmirror.com/screenfull/-/screenfull-6.0.1.tgz#3b71e6f06b72d817a8d3be73c45ebe71fa8da1ce" + integrity sha512-yzQW+j4zMUBQC51xxWaoDYjxOtl8Kn+xvue3p6v/fv2pIi1jH4AldgVLU8TBfFVgH2x3VXlf3+YiA/AYIPlaew== + +scroll-into-view-if-needed@^2.2.28: + version "2.2.29" + resolved "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.29.tgz#551791a84b7e2287706511f8c68161e4990ab885" + integrity sha512-hxpAR6AN+Gh53AdAimHM6C8oTN1ppwVZITihix+WqalywBeFcQ6LdQP5ABNl26nX8GTEL7VT+b8lKpdqq65wXg== + dependencies: + compute-scroll-into-view "^1.0.17" + +select@^1.1.2: + version "1.1.2" + resolved "https://registry.npmmirror.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" + integrity sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA== + +semver@^7.3.5, semver@^7.3.6, semver@^7.3.7: + version "7.3.7" + resolved "https://registry.npmmirror.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slate-history@^0.66.0: + version "0.66.0" + resolved "https://registry.npmmirror.com/slate-history/-/slate-history-0.66.0.tgz#ac63fddb903098ceb4c944433e3f75fe63acf940" + integrity sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng== + dependencies: + is-plain-object "^5.0.0" + +slate@^0.72.0: + version "0.72.8" + resolved "https://registry.npmmirror.com/slate/-/slate-0.72.8.tgz#5a018edf24e45448655293a68bfbcf563aa5ba81" + integrity sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw== + dependencies: + immer "^9.0.6" + is-plain-object "^5.0.0" + tiny-warning "^1.0.3" + +snabbdom@^3.1.0: + version "3.5.0" + resolved "https://registry.npmmirror.com/snabbdom/-/snabbdom-3.5.0.tgz#e75acbdedb26ea327c75028a433ba064db0ccf6e" + integrity sha512-Ff5BKG18KrrPuskHJlA9aujPHqEabItaDl96l7ZZndF4zt5AYSczz7ZjjgQAX5IBd5cd25lw9NfgX21yVUJ+9g== + +sortablejs@^1.15.0: + version "1.15.0" + resolved "https://registry.npmmirror.com/sortablejs/-/sortablejs-1.15.0.tgz#53230b8aa3502bb77a29e2005808ffdb4a5f7e2a" + integrity sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w== + +"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map@0.6.1, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sourcemap-codec@^1.4.8: + version "1.4.8" + resolved "https://registry.npmmirror.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + +splitpanes@^3.1.1: + version "3.1.1" + resolved "https://registry.npmmirror.com/splitpanes/-/splitpanes-3.1.1.tgz#be806205681a87c34075f1a06192df684e370e32" + integrity sha512-VUkxDJfIGSvTM/fm/+OSrx8ha9URwE/9B8FPvfzoBuAxVELIHBWpsfnJXIXv77zVwuex//QQL4kTU9SDBPeHjA== + +ssr-window@^3.0.0-alpha.1: + version "3.0.0" + resolved "https://registry.npmmirror.com/ssr-window/-/ssr-window-3.0.0.tgz#fd5b82801638943e0cc704c4691801435af7ac37" + integrity sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA== + +strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +tiny-emitter@^2.0.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" + integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== + +tiny-warning@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" + integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tslib@2.3.0: + version "2.3.0" + resolved "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" + integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.npmmirror.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.npmmirror.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.npmmirror.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type@^1.0.1: + version "1.2.0" + resolved "https://registry.npmmirror.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== + +type@^2.5.0: + version "2.6.0" + resolved "https://registry.npmmirror.com/type/-/type-2.6.0.tgz#3ca6099af5981d36ca86b78442973694278a219f" + integrity sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ== + +typescript@^4.7.3: + version "4.7.3" + resolved "https://registry.npmmirror.com/typescript/-/typescript-4.7.3.tgz#8364b502d5257b540f9de4c40be84c98e23a129d" + integrity sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.npmmirror.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +vite@^2.9.9: + version "2.9.10" + resolved "https://registry.npmmirror.com/vite/-/vite-2.9.10.tgz#f574d96655622c2e0fbc662edd0ed199c60fe91a" + integrity sha512-TwZRuSMYjpTurLqXspct+HZE7ONiW9d+wSWgvADGxhDPPyoIcNywY+RX4ng+QpK30DCa1l/oZgi2PLZDibhzbQ== + dependencies: + esbuild "^0.14.27" + postcss "^8.4.13" + resolve "^1.22.0" + rollup "^2.59.0" + optionalDependencies: + fsevents "~2.3.2" + +vue-clipboard3@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/vue-clipboard3/-/vue-clipboard3-2.0.0.tgz#79b026c765c0f6a5cde18a477c2dbfc7d3b9f178" + integrity sha512-Q9S7dzWGax7LN5iiSPcu/K1GGm2gcBBlYwmMsUc5/16N6w90cbKow3FnPmPs95sungns4yvd9/+JhbAznECS2A== + dependencies: + clipboard "^2.0.6" + +vue-demi@*: + version "0.13.1" + resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.1.tgz#7604904c88be338418a10abbc94d5b8caa14cb8c" + integrity sha512-xmkJ56koG3ptpLnpgmIzk9/4nFf4CqduSJbUM0OdPoU87NwRuZ6x49OLhjSa/fC15fV+5CbEnrxU4oyE022svg== + +vue-eslint-parser@^9.0.1, vue-eslint-parser@^9.0.2: + version "9.0.2" + resolved "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-9.0.2.tgz#d2535516f3f55adb387939427fe741065eb7948a" + integrity sha512-uCPQwTGjOtAYrwnU+76pYxalhjsh7iFBsHwBqDHiOPTxtICDaraO4Szw54WFTNZTAEsgHHzqFOu1mmnBOBRzDA== + dependencies: + debug "^4.3.4" + eslint-scope "^7.1.1" + eslint-visitor-keys "^3.3.0" + espree "^9.3.1" + esquery "^1.4.0" + lodash "^4.17.21" + semver "^7.3.6" + +vue-grid-layout@^3.0.0-beta1: + version "3.0.0-beta1" + resolved "https://registry.npmmirror.com/vue-grid-layout/-/vue-grid-layout-3.0.0-beta1.tgz#f8ce8eb7dbb1ff58f64820332afcc12c8cf873aa" + integrity sha512-MsW0yfYNtnAO/uDhfZvkP6effxSJxvhAFbIL37x6Rn3vW9xf0WHVefKaSbQMLpSq3mXnR6ut0pg2Cd5lqIIZzg== + dependencies: + "@interactjs/actions" "^1.10.2" + "@interactjs/auto-start" "^1.10.2" + "@interactjs/dev-tools" "^1.10.2" + "@interactjs/interactjs" "^1.10.2" + "@interactjs/modifiers" "^1.10.2" + element-resize-detector "^1.2.1" + mitt "^2.1.0" + +vue-i18n@^9.1.10: + version "9.1.10" + resolved "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-9.1.10.tgz#7ad516b89ba28debb90fc4181c9a2faec9ad97f9" + integrity sha512-jpr7gV5KPk4n+sSPdpZT8Qx3XzTcNDWffRlHV/cT2NUyEf+sEgTTmLvnBAibjOFJ0zsUyZlVTAWH5DDnYep+1g== + dependencies: + "@intlify/core-base" "9.1.10" + "@intlify/shared" "9.1.10" + "@intlify/vue-devtools" "9.1.10" + "@vue/devtools-api" "^6.0.0-beta.7" + +vue-router@^4.0.15: + version "4.0.15" + resolved "https://registry.npmmirror.com/vue-router/-/vue-router-4.0.15.tgz#b4a0661efe197f8c724e0f233308f8776e2c3667" + integrity sha512-xa+pIN9ZqORdIW1MkN2+d9Ui2pCM1b/UMgwYUCZOiFYHAvz/slKKBDha8DLrh5aCG/RibtrpyhKjKOZ85tYyWg== + dependencies: + "@vue/devtools-api" "^6.0.0" + +vue@^3.2.36: + version "3.2.37" + resolved "https://registry.npmmirror.com/vue/-/vue-3.2.37.tgz#da220ccb618d78579d25b06c7c21498ca4e5452e" + integrity sha512-bOKEZxrm8Eh+fveCqS1/NkG/n6aMidsI6hahas7pa0w/l7jkbssJVsRhVDs07IdDq7h9KHswZOgItnwJAgtVtQ== + dependencies: + "@vue/compiler-dom" "3.2.37" + "@vue/compiler-sfc" "3.2.37" + "@vue/runtime-dom" "3.2.37" + "@vue/server-renderer" "3.2.37" + "@vue/shared" "3.2.37" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.npmmirror.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wildcard@^1.1.0: + version "1.1.2" + resolved "https://registry.npmmirror.com/wildcard/-/wildcard-1.1.2.tgz#a7020453084d8cd2efe70ba9d3696263de1710a5" + integrity sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng== + +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +xml-name-validator@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" + integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +zrender@5.3.1, zrender@^5.1.1: + version "5.3.1" + resolved "https://registry.npmmirror.com/zrender/-/zrender-5.3.1.tgz#fa8e63ac7e719cfd563831fe8c42a9756c5af384" + integrity sha512-7olqIjy0gWfznKr6vgfnGBk7y4UtdMvdwFmK92vVQsQeDPyzkHW1OlrLEKg6GHz1W5ePf0FeN1q2vkl/HFqhXw== + dependencies: + tslib "2.3.0" -- Gitblit v1.9.2