完成项目搭建,完成page、form等公用组件基础功能,初步实现快速开发zk authored at 2023-04-11 16:26:22
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..f36b7f1
--- /dev/null
+++ b/.env.development
@@ -0,0 +1,5 @@
+# 本地环境
+ENV = development
+
+# 本地环境接口地址
+VITE_API_URL = https://cube3.newlifex.com
\ No newline at end of file
diff --git a/.env.production b/.env.production
new file mode 100644
index 0000000..478a841
--- /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..0a42a49
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,77 @@
+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'],
+ overrides: [
+ {
+ files: ['*.ts', '*.tsx', '*.vue'],
+ rules: {
+ 'no-undef': 'off',
+ },
+ },
+ ],
+ rules: {
+ // http://eslint.cn/docs/rules/
+ // https://eslint.vuejs.org/rules/
+ // https://typescript-eslint.io/rules/no-unused-vars/
+ '@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',
+ '@typescript-eslint/no-redeclare': 'error',
+ '@typescript-eslint/no-non-null-asserted-optional-chain': 'off',
+ '@typescript-eslint/no-unused-vars': [2],
+ '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',
+ 'vue/no-v-for-template-key': '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',
+ 'no-redeclare': 'off',
+ },
+};
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..c7e3969
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,451 @@
+# <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.4.3
+
+`2023.02.22`
+
+🚩🚩🚩 感谢 [驰骋工作流引擎-表单引擎-低代码开发平台](http://www.ccflow.org/) 赞助商的赞助。驰骋公司为社会提供流程引擎+表单引擎+低代码开发平台一体的开源软件解决方案,欢迎广大开发者前去体验!
+
+- 🌟 更新 依赖更新最新版本
+- 🎉 新增 赞助商组件(`/src/layout/sponsors`),[项目目录结构查看](https://lyt-top.gitee.io/vue-next-admin-doc-preview/config/)
+- 🐞 修复 [过滤筛选组件展开点击不了](https://gitee.com/lyt-top/vue-next-admin/issues/I688WG)
+- 🐞 修复 [设置锁屏时间时直接白屏了不能恢复,除非删除主题配置才会重新加载](https://gitee.com/lyt-top/vue-next-admin/issues/I6AF8P),感谢[@baizunxian](https://gitee.com/xb_xiaobai)
+- 🐞 修复 `分栏布局` 地址栏输入不存在的路由报错问题
+- 🎨 合并 [!44 tagsViewName 正则匹配错误,匹配到含 en 单词](https://gitee.com/lyt-top/vue-next-admin/pulls/44/files),感谢[@tony 星](https://gitee.com/tony_tong_xin)
+- 🎨 合并 [!45 fix 地址栏出现 false 问题](https://gitee.com/lyt-top/vue-next-admin/pulls/45),感谢[@随心](https://gitee.com/jiangqiang1996)
+- 🎯 优化 `/src/utils/storage` 下 `key` 编写成 `${__NEXT_NAME__}:${key}`,防止部署多套系统到同一域名不同目录时,变量共用的问题(`__NEXT_NAME__`为 `package.json` 中的 `name`)
+- 🎯 优化 watermark 单词拼写错误
+
+## 2.4.21
+
+`2022.12.12`
+
+- 🌟 更新 依赖更新最新版本
+- 🎉 新增 菜单背景高亮颜色可自定义,通过 `布局配置 -> 菜单设置 -> 菜单高亮背景色` 进行设置
+- 🐞 修复 `分栏布局` 二级导航菜单内容多时,无法滚动问题,感谢群友@静雨轩主人
+- 🐞 修复 [!42 修复 工作流无法添加新节点问题](https://gitee.com/lyt-top/vue-next-admin/pulls/42),感谢[@beta](https://gitee.com/beta_dz)
+- 🎯 优化 `/make/tableDemo` 表头很多时,无法滚动问题,感谢群友@糊涂涂涂
+
+## 2.4.2
+
+`2022.12.09`
+
+- 🌟 更新 依赖更新最新版本
+- 🎉 新增 国际化自动导入文件功能,只需在 `/src/i18n/pages` 下新建文件夹定义即可
+- 🎉 新增 `/make/tableDemo` 中 [搜索框展开,收缩功能,高级筛选组件 有计划做吗](https://gitee.com/lyt-top/vue-next-admin/issues/I6511L)
+- 🐞 修复 [!40 开启 TagsView 缓存后,刷新后所有的路由都变成组件缓存了](https://gitee.com/lyt-top/vue-next-admin/pulls/40),感谢[@mrjimin](https://gitee.com/mrjimin)
+- 🐞 修复 [!41 修复 get 请求传递嵌套对象或数组时无法正常编码问题](https://gitee.com/lyt-top/vue-next-admin/pulls/41),感谢[@随心](https://gitee.com/jiangqiang1996)
+- 🐞 修复 组件 wangEditor 回显值的问题
+- 🐞 修复 `/fun/echartsMap`(地理坐标/地图)、`visualizingDemo2`(数据可视化演示 2) 演示报错问题
+- 🎯 优化 版本升级提示
+- 🎯 优化 无权限登录时增加提示信息,[BUG:因前端加载路由(initFrontEndControlRoutes)中当前用户角色为一个陌生角色, 导致 router.beforeEach 会死循环 浏览器崩溃](https://gitee.com/lyt-top/vue-next-admin/issues/I64HVO),感谢[@canroc](https://gitee.com/canroc)、[@随心](https://gitee.com/jiangqiang1996)
+- 🌈 重构 `/views/system` 新增修改组件合并。[可以把新增修改组件合并成一个吧](https://gitee.com/lyt-top/vue-next-admin/issues/I64WES)
+- 🌈 重构 图标选择器,[图标选择器没办法筛选,只能筛选 ali 的](https://gitee.com/lyt-top/vue-next-admin/issues/I64HZD),感谢[@随心](https://gitee.com/jiangqiang1996)
+
+## 2.4.1
+
+`2022.11.30`
+
+- 🎉 新增 版本升级提示
+- 🐞 修复 [先打开 F12 再登录进去,然后改变浏览器大小 js 报错](https://gitee.com/lyt-top/vue-next-admin/issues/I63ZZT),感谢[@Quber](https://gitee.com/quber)
+
+## 2.4.0
+
+`2022.11.29`
+
+⚡⚡⚡ 此版为破坏性更新,应群友建议 `script lang="ts"` 改 `script lang="ts" setup 语法糖`。
+
+- 🌟 更新 依赖更新最新版本
+- 🎉 新增 表格封装演示,路径:`组件封装 -> 表格封装演示`
+- 🎉 新增 master 分支 script lang="ts" 改成 script lang="ts" setup 语法糖,将同步基础分支
+- 🐞 修复 [v2.3.0 版本报错问题处理](https://gitee.com/lyt-top/vue-next-admin/issues/I623RP)
+- 🐞 修复 [el-backtop 滚动高度不触发(固定了 header)](https://gitee.com/lyt-top/vue-next-admin/issues/I63N0D),感谢[@dejavuuuuu](https://gitee.com/zc19951010)
+- 🎯 优化 完善 ts 类型,删除根目录 `plugins.d.ts、shim.d.ts、source.d.ts`,移入到 `/src/types/global.d.ts`
+- 🎯 优化 代码 `watch` 移动到 `生命周期钩子` 最后,文字注释等
+
+## 2.3.0
+
+`2022.11.16`
+
+- 🌟 更新 依赖更新最新版本
+- 🎉 新增 新版登录页
+- 🎉 新增 tagsview 鼠标中键 `关闭当前 tagsview`
+- 🎉 新增 `分栏菜单鼠标悬停预加载`。[分栏模式如何去掉鼠标悬浮父级菜单,分栏菜单自动加载的功能啊](https://gitee.com/lyt-top/vue-next-admin/issues/I5RUY7)。操作路径:`布局配置 -> 分栏设置`
+- 🐞 修复 [vue-i18n](https://vue-i18n.intlify.dev/api/general.html#createi18n) 报错,[!39 修复 i18n 兼容性问题](https://toscode.gitee.com/lyt-top/vue-next-admin/pulls/39/files),感谢[@随心](https://toscode.gitee.com/jiangqiang1996)
+- 🐞 修复 顶栏搜索功能点击蒙蔽弹窗不关闭
+- 🐞 修复 [!38 fix: bug refreshRouterViewKey 值为 null 导致路由缓存第一次无效](https://toscode.gitee.com/lyt-top/vue-next-admin/pulls/38/files),感谢[@P)](https://toscode.gitee.com/foxp8y)
+- 🐞 修复 `路由参数 -> 普通路由/动态路由` 国际化演示时,`tagsView` 和 `浏览器标题` 显示异常。[演示中:路由参数界面 -> 动态路由,国际化显示时面包屑、浏览器标题有 bug](https://gitee.com/lyt-top/vue-next-admin/issues/I5JRJG)
+- 🐞 修复 `路由参数 -> 普通路由/动态路由` 动态设置 `tagsViewName` 时,`tagsView 右键菜单刷新` 功能失效(也就是路由后面有参数时,query、params)。[普通或动态路由新建页面后点击 tagview 刷新无效](https://gitee.com/lyt-top/vue-next-admin/issues/I5K3YO),感谢[@dejavuuuuu](https://gitee.com/zc19951010)
+- 🐞 修复 [表单(el-form)中,字体图标偏移问题](https://gitee.com/lyt-top/vue-next-admin/issues/I5K1PM)
+- 🐞 修复 路由 `router.addRoute` 时,一直提示 `No match found for location with path 'xxx'`
+- 🎯 优化 全局 `getCurrentInstance` 替换成 [`provide/inject`](https://cn.vuejs.org/api/application.html#app-provide) 或通过 `ref` 处理
+- 🎯 优化 引入组件方式 `(import xxx from xxx)` 改成 `defineAsyncComponent(() => import(xxx))`
+- 🎯 优化 页面高度 100% 问题,重写布局配置 `界面设置 -> 固定 Header` 多余的 `el-scrollbar` 逻辑、重写各界面需 `计算属性 computed` 设置动态高度问题(改为 css `flex` 设置自适应高度,具体查看文档:[设置可视区高度 100%](https://lyt-top.gitee.io/vue-next-admin-doc-preview/config/otherIssues/#%E8%AE%BE%E7%BD%AE%E5%8F%AF%E8%A7%86%E5%8C%BA%E9%AB%98%E5%BA%A6-100)。[!31 修复页面样式无法通过百分比设置的问题](https://toscode.gitee.com/lyt-top/vue-next-admin/pulls/31),感谢[@LostDeer](https://toscode.gitee.com/lyt-top/vue-next-admin/pulls/31/files)。`(改动较大,删除多余代码)`
+- 🎯 优化 [wangeditor](https://www.wangeditor.com/) 组件,`@wangeditor/editor-for-vue`。可自行修改,组件位置:`/src/components/editor`。相关 Issues:[wangeditor 编辑器多个菜单不能回弹](https://gitee.com/lyt-top/vue-next-admin/issues/I5M5H7)
+- 🌈 重构 外链、内嵌 iframe 逻辑 + 美化,iframe 支持缓存
+
+## 2.2.0
+
+`2022.07.10`
+
+⚡⚡⚡ [/sec/stores/userInfo.ts](https://gitee.com/lyt-top/vue-next-admin/blob/master/src/stores/userInfo.ts) 下添加了 `getApiUserInfo` 接口模拟数据 `setTimeout` 为 3 秒
+
+- 🌟 更新 依赖更新最新版本
+- 🐞 修复 [主界面重新授权按钮点击卡死不跳转登录界面#I5C3JS](https://gitee.com/lyt-top/vue-next-admin/issues/I5C3JS),感谢[@Hero-Typ](https://gitee.com/tian_yu_peng)
+- 🐞 修复 编译警告[#I5CVSB](https://gitee.com/lyt-top/vue-next-admin/issues/I5CVSB),全局替换成 `:deep(attr)`,感谢[@Linvas](https://gitee.com/linvas)。参考文档:[vue3 sfc-style](https://v3.cn.vuejs.org/api/sfc-style.html#style-scoped)。`node_modules\print-js\dist\print.js` 需 `print-js` 作者适配或去除 `package.json` 中的 `"print-js": "^1.6.0"`
+- 🐞 修复 [vue-next-admin-template-js 版本前端控制路由:userInfo.js 请求用户信息接口报错,加载不到路由 可以写个定时器模拟一下接口 一样的报错#I5F1HP](https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP),感谢[@白开水](https://gitee.com/libin951223)
+
+## 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/index.html b/index.html
new file mode 100644
index 0000000..dc8466c
--- /dev/null
+++ b/index.html
@@ -0,0 +1,32 @@
+<!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 的后台开源免费管理系统模板!"
+ />
+ <link rel="icon" href="/favicon.ico" />
+ <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/LICENSE b/LICENSE
index 4e647d5..6f6a7ea 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2023 方泽坤
+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
@@ -18,4 +18,4 @@ 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.
+SOFTWARE.
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..aafc793
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,7716 @@
+{
+ "name": "vue-next-admin",
+ "version": "2.4.3",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "vue-next-admin",
+ "version": "2.4.3",
+ "license": "MIT",
+ "dependencies": {
+ "@element-plus/icons-vue": "^2.0.10",
+ "@form-create/element-ui": "^3.1.18",
+ "@wangeditor/editor": "^5.1.23",
+ "@wangeditor/editor-for-vue": "^5.1.12",
+ "axios": "^1.3.3",
+ "countup.js": "^2.4.2",
+ "cropperjs": "^1.5.13",
+ "echarts": "^5.4.1",
+ "echarts-gl": "^2.0.9",
+ "echarts-wordcloud": "^2.1.0",
+ "element-plus": "^2.2.32",
+ "js-cookie": "^3.0.1",
+ "js-table2excel": "^1.0.3",
+ "jsplumb": "^2.15.6",
+ "mitt": "^3.0.0",
+ "nprogress": "^0.2.0",
+ "pinia": "^2.0.32",
+ "print-js": "^1.6.0",
+ "qrcodejs2-fixes": "^0.0.2",
+ "qs": "^6.11.0",
+ "screenfull": "^6.0.2",
+ "sortablejs": "^1.15.0",
+ "splitpanes": "^3.1.5",
+ "ts-enum-util": "^4.0.2",
+ "vue": "^3.2.47",
+ "vue-clipboard3": "^2.0.0",
+ "vue-grid-layout": "^3.0.0-beta1",
+ "vue-i18n": "^9.2.2",
+ "vue-router": "^4.1.6",
+ "vuedraggable": "^4.1.0"
+ },
+ "devDependencies": {
+ "@iconify/vue": "^4.1.0",
+ "@types/node": "^18.14.0",
+ "@types/nprogress": "^0.2.0",
+ "@types/sortablejs": "^1.15.0",
+ "@typescript-eslint/eslint-plugin": "^5.53.0",
+ "@typescript-eslint/parser": "^5.53.0",
+ "@vitejs/plugin-vue": "^4.0.0",
+ "@vue/compiler-sfc": "^3.2.47",
+ "autoprefixer": "^10.4.13",
+ "eslint": "^8.34.0",
+ "eslint-plugin-vue": "^9.9.0",
+ "postcss": "^8.4.21",
+ "prettier": "^2.8.4",
+ "sass": "^1.58.3",
+ "tailwindcss": "^3.2.7",
+ "typescript": "^4.9.5",
+ "vite": "^4.1.4",
+ "vite-plugin-vue-setup-extend": "^0.4.0",
+ "vue-eslint-parser": "^9.1.0"
+ },
+ "engines": {
+ "node": ">=16.0.0",
+ "npm": ">= 7.0.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.21.1",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.1.tgz",
+ "integrity": "sha512-JzhBFpkuhBNYUY7qs+wTzNmyCWUHEaAFpQQD2YfU1rPL38/L43Wvid0fFkiOCnHvsGncRZgEPyGnltABLcVDTg==",
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz",
+ "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==",
+ "dependencies": {
+ "regenerator-runtime": "^0.13.11"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@ctrl/tinycolor": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.0.tgz",
+ "integrity": "sha512-/Z3l6pXthq0JvMYdUFyX9j0MaCltlIn6mfh9jLyQwg5aPKxkyNa0PTHtU1AlFXLNk55ZuAeJRcpvq+tmLfKmaQ==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@element-plus/icons-vue": {
+ "version": "2.0.10",
+ "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.0.10.tgz",
+ "integrity": "sha512-ygEZ1mwPjcPo/OulhzLE7mtDrQBWI8vZzEWSNB2W/RNCRjoQGwbaK4N8lV4rid7Ts4qvySU3njMN7YCiSlSaTQ==",
+ "peerDependencies": {
+ "vue": "^3.2.0"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz",
+ "integrity": "sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz",
+ "integrity": "sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz",
+ "integrity": "sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz",
+ "integrity": "sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz",
+ "integrity": "sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz",
+ "integrity": "sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz",
+ "integrity": "sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz",
+ "integrity": "sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz",
+ "integrity": "sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz",
+ "integrity": "sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz",
+ "integrity": "sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz",
+ "integrity": "sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz",
+ "integrity": "sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz",
+ "integrity": "sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz",
+ "integrity": "sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz",
+ "integrity": "sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz",
+ "integrity": "sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz",
+ "integrity": "sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz",
+ "integrity": "sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz",
+ "integrity": "sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz",
+ "integrity": "sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz",
+ "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
+ "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.4.0",
+ "globals": "^13.19.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"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@floating-ui/core": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.2.1.tgz",
+ "integrity": "sha512-LSqwPZkK3rYfD7GKoIeExXOyYx6Q1O4iqZWwIehDNuv3Dv425FIAE8PRwtAx1imEolFTHgBEcoFHm9MDnYgPCg=="
+ },
+ "node_modules/@floating-ui/dom": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.2.1.tgz",
+ "integrity": "sha512-Rt45SmRiV8eU+xXSB9t0uMYiQ/ZWGE/jumse2o3i5RGlyvcbqOF4q+1qBnzLE2kZ5JGhq0iMkcGXUKbFe7MpTA==",
+ "dependencies": {
+ "@floating-ui/core": "^1.2.1"
+ }
+ },
+ "node_modules/@form-create/component-elm-checkbox": {
+ "version": "3.1.15",
+ "resolved": "https://registry.npmmirror.com/@form-create/component-elm-checkbox/-/component-elm-checkbox-3.1.15.tgz",
+ "integrity": "sha512-bAl3k0p76wwMX0OxeR8KAEiUl2RP1Jl1kAqbjD762EcSXGgaXgP94v9ag1JhUoiwZkSKWl6IF+e/utjEonRSFw==",
+ "dependencies": {
+ "@form-create/utils": "^3.1.15"
+ }
+ },
+ "node_modules/@form-create/component-elm-frame": {
+ "version": "3.1.15",
+ "resolved": "https://registry.npmmirror.com/@form-create/component-elm-frame/-/component-elm-frame-3.1.15.tgz",
+ "integrity": "sha512-78WbMpMLTYwTo3QP7Fa+N2VF/u1vmRuwDmiobtBtVg9EE7m6//bQV96ibnLNXX27MD41gIg+o1GUJtx/qxZ8Ew==",
+ "dependencies": {
+ "@form-create/utils": "^3.1.15"
+ }
+ },
+ "node_modules/@form-create/component-elm-group": {
+ "version": "3.1.15",
+ "resolved": "https://registry.npmmirror.com/@form-create/component-elm-group/-/component-elm-group-3.1.15.tgz",
+ "integrity": "sha512-V/oVxHf9rHqqMHRV0XRVED9EYFCVZ8Tv/EbbIN/4rORruHtzdQOH8I0QHQ9T4vZO9Q4eblApzcJb8Y7bbHX23Q==",
+ "dependencies": {
+ "@form-create/utils": "^3.1.15"
+ }
+ },
+ "node_modules/@form-create/component-elm-radio": {
+ "version": "3.1.15",
+ "resolved": "https://registry.npmmirror.com/@form-create/component-elm-radio/-/component-elm-radio-3.1.15.tgz",
+ "integrity": "sha512-qAf1VlhrUvMlgzkz6BYLRn0UOLahkTI/cbzt8nkp5PL1oGoSXp5xqIOtHMjbnGEkEXW57kjRKI5Q7UjzIhYmvQ==",
+ "dependencies": {
+ "@form-create/utils": "^3.1.15"
+ }
+ },
+ "node_modules/@form-create/component-elm-select": {
+ "version": "3.1.15",
+ "resolved": "https://registry.npmmirror.com/@form-create/component-elm-select/-/component-elm-select-3.1.15.tgz",
+ "integrity": "sha512-ZnvPn/TGqgFDed7bKabjRvlwlQ8RYq5WCG9Iy63d2igC8577tv5QTI2rNvfGfxxH/254MPwgNlA94JukxzEOTw==",
+ "dependencies": {
+ "@form-create/utils": "^3.1.15"
+ }
+ },
+ "node_modules/@form-create/component-elm-tree": {
+ "version": "3.1.15",
+ "resolved": "https://registry.npmmirror.com/@form-create/component-elm-tree/-/component-elm-tree-3.1.15.tgz",
+ "integrity": "sha512-4VPN406A8Mvannn8P/2DvStqDYFfDHZ+ILG/0JndOyfe+GdYdSA5SwD3LfC4zD6AhpGrkOJXbd4YYXlBUtzt8g==",
+ "dependencies": {
+ "@form-create/utils": "^3.1.15"
+ }
+ },
+ "node_modules/@form-create/component-elm-upload": {
+ "version": "3.1.18",
+ "resolved": "https://registry.npmmirror.com/@form-create/component-elm-upload/-/component-elm-upload-3.1.18.tgz",
+ "integrity": "sha512-+jHZ1vfNusEqKSvpLpFcKbF0lE7S+YuWtAturzW2O5K+qYDw6SmGyB3/XeYqVXN9rfne0rqMbyYw6CGglVe7nw==",
+ "dependencies": {
+ "@form-create/utils": "^3.1.15"
+ }
+ },
+ "node_modules/@form-create/component-subform": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmmirror.com/@form-create/component-subform/-/component-subform-3.1.5.tgz",
+ "integrity": "sha512-JHNEFGuwpnjGvCJ0I0GCqPL5al0qXoN4ymnRBpm+oL+6MMo5bz1kUyoqMX1MutuC96gHTqpeqc67hssi8g2mIw=="
+ },
+ "node_modules/@form-create/core": {
+ "version": "3.1.18",
+ "resolved": "https://registry.npmmirror.com/@form-create/core/-/core-3.1.18.tgz",
+ "integrity": "sha512-kFu+fH88KvdkJoMPuLaBOG/4jNv+YPJbJHzvF4HZLn9XEtJgO9flef5WcvMyz12moI6uNGJ4Hs8+sdkXBJtkMw==",
+ "dependencies": {
+ "@form-create/utils": "^3.1.15"
+ },
+ "peerDependencies": {
+ "vue": "^3.1.0"
+ }
+ },
+ "node_modules/@form-create/element-ui": {
+ "version": "3.1.18",
+ "resolved": "https://registry.npmmirror.com/@form-create/element-ui/-/element-ui-3.1.18.tgz",
+ "integrity": "sha512-FstZrrfUBm9cRipqi6BW3cTPShQsgDWaHXYA5Uj/3fQ5y5EuoSRkNnlgqEoAjwUsQznL4tMC4BzqxoAHsP9zlg==",
+ "dependencies": {
+ "@form-create/component-elm-checkbox": "^3.1.15",
+ "@form-create/component-elm-frame": "^3.1.15",
+ "@form-create/component-elm-group": "^3.1.15",
+ "@form-create/component-elm-radio": "^3.1.15",
+ "@form-create/component-elm-select": "^3.1.15",
+ "@form-create/component-elm-tree": "^3.1.15",
+ "@form-create/component-elm-upload": "^3.1.18",
+ "@form-create/component-subform": "^3.1.5",
+ "@form-create/core": "^3.1.18",
+ "@form-create/utils": "^3.1.15"
+ },
+ "peerDependencies": {
+ "vue": "^3.1.0"
+ }
+ },
+ "node_modules/@form-create/utils": {
+ "version": "3.1.15",
+ "resolved": "https://registry.npmmirror.com/@form-create/utils/-/utils-3.1.15.tgz",
+ "integrity": "sha512-tP6Z/c2XC6OYrI8D9/XWvJc2h6apsyMFTy051sY+tCcxppqyR7dBEEXmgfWOrAr980N7k10g27kwJ9TdVn+bfw=="
+ },
+ "node_modules/@humanwhocodes/config-array": {
+ "version": "0.11.8",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
+ "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
+ "dev": true,
+ "dependencies": {
+ "@humanwhocodes/object-schema": "^1.2.1",
+ "debug": "^4.1.1",
+ "minimatch": "^3.0.5"
+ },
+ "engines": {
+ "node": ">=10.10.0"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "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/@iconify/types": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmmirror.com/@iconify/types/-/types-2.0.0.tgz",
+ "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==",
+ "dev": true
+ },
+ "node_modules/@iconify/vue": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmmirror.com/@iconify/vue/-/vue-4.1.0.tgz",
+ "integrity": "sha512-rBQVxNoSDooqgWkQg2MqkIHkH/huNuvXGqui5wijc1zLnU7TKzbBHW9VGmbnV4asNTmIHmqV4Nvt0M2rZ/9nHA==",
+ "dev": true,
+ "dependencies": {
+ "@iconify/types": "^2.0.0"
+ },
+ "peerDependencies": {
+ "vue": ">=3"
+ }
+ },
+ "node_modules/@interactjs/actions": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/actions/-/actions-1.10.17.tgz",
+ "integrity": "sha512-wyB1ZqpaZy5gmz6VDqK9KWh98xKnFgL7VyLvxHODFi9V0IYX4HJAAOBlhtfze0D1R1f1cY+gqPDK+dLaHMlE+w==",
+ "optionalDependencies": {
+ "@interactjs/interact": "1.10.17"
+ },
+ "peerDependencies": {
+ "@interactjs/core": "1.10.17",
+ "@interactjs/utils": "1.10.17"
+ }
+ },
+ "node_modules/@interactjs/auto-scroll": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/auto-scroll/-/auto-scroll-1.10.17.tgz",
+ "integrity": "sha512-IQcW7N3xOaoL8RnAGOGMk0Y2gue7L4S3BT6Id4VBBu8so163DtLiZVW6jXu9rKVntzbluaAeqNZlfAVyu3kIWg==",
+ "optionalDependencies": {
+ "@interactjs/interact": "1.10.17"
+ },
+ "peerDependencies": {
+ "@interactjs/utils": "1.10.17"
+ }
+ },
+ "node_modules/@interactjs/auto-start": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/auto-start/-/auto-start-1.10.17.tgz",
+ "integrity": "sha512-qYVxhAbYnwxjD/NLEegUoAST7WASJ4VmWNjsyWRx/js5Op+I4E2zteARIeZGgrutcGIXMCcQzhCMgE3PjOpbpw==",
+ "optionalDependencies": {
+ "@interactjs/interact": "1.10.17"
+ },
+ "peerDependencies": {
+ "@interactjs/core": "1.10.17",
+ "@interactjs/utils": "1.10.17"
+ }
+ },
+ "node_modules/@interactjs/core": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/core/-/core-1.10.17.tgz",
+ "integrity": "sha512-rL9w+83HDRuXub8Ezqs+97CYLl/ne7bLT/sAeduUWaxYhsW9iOqBoob9JnkkCZOaOsYizWI1EWy0+fNc5ibtLQ==",
+ "peerDependencies": {
+ "@interactjs/utils": "1.10.17"
+ }
+ },
+ "node_modules/@interactjs/dev-tools": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/dev-tools/-/dev-tools-1.10.17.tgz",
+ "integrity": "sha512-Oi9nEw3FfSwkNmW+V0WwdHqvzEkVHc24mH1v5EjRn60sqgrGLK9nTQ+NSuqcnUY8GxC3TkyuxnsOodxiadIRmA==",
+ "optionalDependencies": {
+ "@interactjs/interact": "1.10.17"
+ },
+ "peerDependencies": {
+ "@interactjs/modifiers": "1.10.17",
+ "@interactjs/utils": "1.10.17"
+ }
+ },
+ "node_modules/@interactjs/inertia": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/inertia/-/inertia-1.10.17.tgz",
+ "integrity": "sha512-41vbYUjZIDCKt2/yhmjPrEW5+0uoL/hldFsll9pkvnLhmm12Xk0VXOlmR2zXKAmsTK3fJlKMyBYUX92qHLkyVQ==",
+ "dependencies": {
+ "@interactjs/offset": "1.10.17"
+ },
+ "optionalDependencies": {
+ "@interactjs/interact": "1.10.17"
+ },
+ "peerDependencies": {
+ "@interactjs/core": "1.10.17",
+ "@interactjs/modifiers": "1.10.17",
+ "@interactjs/utils": "1.10.17"
+ }
+ },
+ "node_modules/@interactjs/interact": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/interact/-/interact-1.10.17.tgz",
+ "integrity": "sha512-NyKsf8EFudvdahBjPz1Gt5QnynVwa/2LUfBc2/w8QOnOBiyzUm0HLloJSaB8a50QbQkSWN243/Lgpd8GTMQvuQ==",
+ "dependencies": {
+ "@interactjs/core": "1.10.17",
+ "@interactjs/types": "1.10.17",
+ "@interactjs/utils": "1.10.17"
+ }
+ },
+ "node_modules/@interactjs/interactjs": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/interactjs/-/interactjs-1.10.17.tgz",
+ "integrity": "sha512-hHmiukARbZhiM12zNKx0yQlFVl4C+NMeYNAYh6Mf9U3ZziQ47C+JEW8Gr7Zr/MxfNZyPu5nLKCpVQjh/JvBO9g==",
+ "dependencies": {
+ "@interactjs/actions": "1.10.17",
+ "@interactjs/auto-scroll": "1.10.17",
+ "@interactjs/auto-start": "1.10.17",
+ "@interactjs/core": "1.10.17",
+ "@interactjs/dev-tools": "1.10.17",
+ "@interactjs/inertia": "1.10.17",
+ "@interactjs/interact": "1.10.17",
+ "@interactjs/modifiers": "1.10.17",
+ "@interactjs/offset": "1.10.17",
+ "@interactjs/pointer-events": "1.10.17",
+ "@interactjs/reflow": "1.10.17",
+ "@interactjs/utils": "1.10.17"
+ }
+ },
+ "node_modules/@interactjs/modifiers": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/modifiers/-/modifiers-1.10.17.tgz",
+ "integrity": "sha512-Dxw8kv9VBIxnhNvQncR6CKAGMzKXczLvuAUIdSPFYtyerX/XiDulJUqhR+jVKNp/WjF1DvdBxWo0kGGLbM84LQ==",
+ "dependencies": {
+ "@interactjs/snappers": "1.10.17"
+ },
+ "optionalDependencies": {
+ "@interactjs/interact": "1.10.17"
+ },
+ "peerDependencies": {
+ "@interactjs/core": "1.10.17",
+ "@interactjs/utils": "1.10.17"
+ }
+ },
+ "node_modules/@interactjs/offset": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/offset/-/offset-1.10.17.tgz",
+ "integrity": "sha512-wWBnIQWgLrmJNTBbd/FdxHxAJjiXl/5ND8Jbw2DuP9gIGDxhFSdEt62Fgqimn9ICb8v8ycvSLObEmcvJF/8hQQ==",
+ "optionalDependencies": {
+ "@interactjs/interact": "1.10.17"
+ },
+ "peerDependencies": {
+ "@interactjs/core": "1.10.17",
+ "@interactjs/utils": "1.10.17"
+ }
+ },
+ "node_modules/@interactjs/pointer-events": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/pointer-events/-/pointer-events-1.10.17.tgz",
+ "integrity": "sha512-VsfluouEKb8QRGyH6jQATCW+QdAd/3dkENS7rj2m+EcVUhz2Ob5mpMRopjALi4pwltMowqTfuJ4LtwMSX2G29A==",
+ "optionalDependencies": {
+ "@interactjs/interact": "1.10.17"
+ },
+ "peerDependencies": {
+ "@interactjs/core": "1.10.17",
+ "@interactjs/utils": "1.10.17"
+ }
+ },
+ "node_modules/@interactjs/reflow": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/reflow/-/reflow-1.10.17.tgz",
+ "integrity": "sha512-ncpWP5k93FRQptEhjzPZsbuRRajd4rkW17lDavCrEjrDi/LHnYekWGqZTaFzfJ80n1x8xUm9ujDjxCTylNqEIA==",
+ "optionalDependencies": {
+ "@interactjs/interact": "1.10.17"
+ },
+ "peerDependencies": {
+ "@interactjs/core": "1.10.17",
+ "@interactjs/utils": "1.10.17"
+ }
+ },
+ "node_modules/@interactjs/snappers": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/snappers/-/snappers-1.10.17.tgz",
+ "integrity": "sha512-m753DGsNOts797e3zDT6wqELoc+BlpIC1w+TyMyISRxU6n1RlS8Q6LHBGgwAgV79LHLaahv/a5haFF9H1VG0FQ==",
+ "optionalDependencies": {
+ "@interactjs/interact": "1.10.17"
+ },
+ "peerDependencies": {
+ "@interactjs/utils": "1.10.17"
+ }
+ },
+ "node_modules/@interactjs/types": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/types/-/types-1.10.17.tgz",
+ "integrity": "sha512-X2JpoM7xUw0p9Me0tMaI0HNfcF/Hd07ZZlzpnpEMpGerUZOLoyeThrV9P+CrBHxZrluWJrigJbcdqXliFd0YMA=="
+ },
+ "node_modules/@interactjs/utils": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/utils/-/utils-1.10.17.tgz",
+ "integrity": "sha512-sZAW08CkqgvqRjUIaLRjScjObcCzN9D75yekLA21EClYAZIhi4A+GEt2z/WqOCOksTaEPLYmQyhkpXcboc0LhQ=="
+ },
+ "node_modules/@intlify/core-base": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.2.2.tgz",
+ "integrity": "sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==",
+ "dependencies": {
+ "@intlify/devtools-if": "9.2.2",
+ "@intlify/message-compiler": "9.2.2",
+ "@intlify/shared": "9.2.2",
+ "@intlify/vue-devtools": "9.2.2"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/@intlify/devtools-if": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.2.2.tgz",
+ "integrity": "sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==",
+ "dependencies": {
+ "@intlify/shared": "9.2.2"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/@intlify/message-compiler": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.2.2.tgz",
+ "integrity": "sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==",
+ "dependencies": {
+ "@intlify/shared": "9.2.2",
+ "source-map": "0.6.1"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/@intlify/shared": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.2.2.tgz",
+ "integrity": "sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/@intlify/vue-devtools": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.2.2.tgz",
+ "integrity": "sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==",
+ "dependencies": {
+ "@intlify/core-base": "9.2.2",
+ "@intlify/shared": "9.2.2"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "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/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.191",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
+ "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ=="
+ },
+ "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": "18.14.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.0.tgz",
+ "integrity": "sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A==",
+ "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/semver": {
+ "version": "7.3.13",
+ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
+ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
+ "dev": true
+ },
+ "node_modules/@types/sortablejs": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/@types/sortablejs/-/sortablejs-1.15.0.tgz",
+ "integrity": "sha512-qrhtM7M41EhH4tZQTNw2/RJkxllBx3reiJpTbgWCM2Dx0U1sZ6LwKp9lfNln9uqE26ZMKUaPEYaD4rzvOWYtZw==",
+ "dev": true
+ },
+ "node_modules/@types/web-bluetooth": {
+ "version": "0.0.16",
+ "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
+ "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ=="
+ },
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "5.53.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.53.0.tgz",
+ "integrity": "sha512-alFpFWNucPLdUOySmXCJpzr6HKC3bu7XooShWM+3w/EL6J2HIoB2PFxpLnq4JauWVk6DiVeNKzQlFEaE+X9sGw==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "5.53.0",
+ "@typescript-eslint/type-utils": "5.53.0",
+ "@typescript-eslint/utils": "5.53.0",
+ "debug": "^4.3.4",
+ "grapheme-splitter": "^1.0.4",
+ "ignore": "^5.2.0",
+ "natural-compare-lite": "^1.4.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.53.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.53.0.tgz",
+ "integrity": "sha512-MKBw9i0DLYlmdOb3Oq/526+al20AJZpANdT6Ct9ffxcV8nKCHz63t/S0IhlTFNsBIHJv+GY5SFJ0XfqVeydQrQ==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "5.53.0",
+ "@typescript-eslint/types": "5.53.0",
+ "@typescript-eslint/typescript-estree": "5.53.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.53.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.53.0.tgz",
+ "integrity": "sha512-Opy3dqNsp/9kBBeCPhkCNR7fmdSQqA+47r21hr9a14Bx0xnkElEQmhoHga+VoaoQ6uDHjDKmQPIYcUcKJifS7w==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "5.53.0",
+ "@typescript-eslint/visitor-keys": "5.53.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.53.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.53.0.tgz",
+ "integrity": "sha512-HO2hh0fmtqNLzTAme/KnND5uFNwbsdYhCZghK2SoxGp3Ifn2emv+hi0PBUjzzSh0dstUIFqOj3bp0AwQlK4OWw==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/typescript-estree": "5.53.0",
+ "@typescript-eslint/utils": "5.53.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.53.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.53.0.tgz",
+ "integrity": "sha512-5kcDL9ZUIP756K6+QOAfPkigJmCPHcLN7Zjdz76lQWWDdzfOhZDTj1irs6gPBKiXx5/6O3L0+AvupAut3z7D2A==",
+ "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.53.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.53.0.tgz",
+ "integrity": "sha512-eKmipH7QyScpHSkhbptBBYh9v8FxtngLquq292YTEQ1pxVs39yFBlLC1xeIZcPPz1RWGqb7YgERJRGkjw8ZV7w==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "5.53.0",
+ "@typescript-eslint/visitor-keys": "5.53.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.53.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.53.0.tgz",
+ "integrity": "sha512-VUOOtPv27UNWLxFwQK/8+7kvxVC+hPHNsJjzlJyotlaHjLSIgOCKj9I0DBUjwOOA64qjBwx5afAPjksqOxMO0g==",
+ "dev": true,
+ "dependencies": {
+ "@types/json-schema": "^7.0.9",
+ "@types/semver": "^7.3.12",
+ "@typescript-eslint/scope-manager": "5.53.0",
+ "@typescript-eslint/types": "5.53.0",
+ "@typescript-eslint/typescript-estree": "5.53.0",
+ "eslint-scope": "^5.1.1",
+ "eslint-utils": "^3.0.0",
+ "semver": "^7.3.7"
+ },
+ "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.53.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.53.0.tgz",
+ "integrity": "sha512-JqNLnX3leaHFZEN0gCh81sIvgrp/2GOACZNgO4+Tkf64u51kTpAyWFOY8XHx8XuXr3N2C9zgPPHtcpMg6z1g0w==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "5.53.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.2.2",
+ "resolved": "https://registry.npmjs.org/@uppy/companion-client/-/companion-client-2.2.2.tgz",
+ "integrity": "sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==",
+ "dependencies": {
+ "@uppy/utils": "^4.1.2",
+ "namespace-emitter": "^2.0.1"
+ }
+ },
+ "node_modules/@uppy/core": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/@uppy/core/-/core-2.3.4.tgz",
+ "integrity": "sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==",
+ "dependencies": {
+ "@transloadit/prettier-bytes": "0.0.7",
+ "@uppy/store-default": "^2.1.1",
+ "@uppy/utils": "^4.1.3",
+ "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.1.1",
+ "resolved": "https://registry.npmjs.org/@uppy/store-default/-/store-default-2.1.1.tgz",
+ "integrity": "sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ=="
+ },
+ "node_modules/@uppy/utils": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/@uppy/utils/-/utils-4.1.3.tgz",
+ "integrity": "sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==",
+ "dependencies": {
+ "lodash.throttle": "^4.1.1"
+ }
+ },
+ "node_modules/@uppy/xhr-upload": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@uppy/xhr-upload/-/xhr-upload-2.1.3.tgz",
+ "integrity": "sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==",
+ "dependencies": {
+ "@uppy/companion-client": "^2.2.2",
+ "@uppy/utils": "^4.1.2",
+ "nanoid": "^3.1.25"
+ },
+ "peerDependencies": {
+ "@uppy/core": "^2.3.3"
+ }
+ },
+ "node_modules/@vitejs/plugin-vue": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.0.0.tgz",
+ "integrity": "sha512-e0X4jErIxAB5oLtDqbHvHpJe/uWNkdpYV83AOG2xo2tEVSzCzewgJMtREZM30wXnM5ls90hxiOtAuVU6H5JgbA==",
+ "dev": true,
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^4.0.0",
+ "vue": "^3.2.25"
+ }
+ },
+ "node_modules/@vue/compiler-core": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.47.tgz",
+ "integrity": "sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==",
+ "dependencies": {
+ "@babel/parser": "^7.16.4",
+ "@vue/shared": "3.2.47",
+ "estree-walker": "^2.0.2",
+ "source-map": "^0.6.1"
+ }
+ },
+ "node_modules/@vue/compiler-dom": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz",
+ "integrity": "sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==",
+ "dependencies": {
+ "@vue/compiler-core": "3.2.47",
+ "@vue/shared": "3.2.47"
+ }
+ },
+ "node_modules/@vue/compiler-sfc": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz",
+ "integrity": "sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==",
+ "dependencies": {
+ "@babel/parser": "^7.16.4",
+ "@vue/compiler-core": "3.2.47",
+ "@vue/compiler-dom": "3.2.47",
+ "@vue/compiler-ssr": "3.2.47",
+ "@vue/reactivity-transform": "3.2.47",
+ "@vue/shared": "3.2.47",
+ "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.47",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.47.tgz",
+ "integrity": "sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==",
+ "dependencies": {
+ "@vue/compiler-dom": "3.2.47",
+ "@vue/shared": "3.2.47"
+ }
+ },
+ "node_modules/@vue/devtools-api": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz",
+ "integrity": "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q=="
+ },
+ "node_modules/@vue/reactivity": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.47.tgz",
+ "integrity": "sha512-7khqQ/75oyyg+N/e+iwV6lpy1f5wq759NdlS1fpAhFXa8VeAIKGgk2E/C4VF59lx5b+Ezs5fpp/5WsRYXQiKxQ==",
+ "dependencies": {
+ "@vue/shared": "3.2.47"
+ }
+ },
+ "node_modules/@vue/reactivity-transform": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz",
+ "integrity": "sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==",
+ "dependencies": {
+ "@babel/parser": "^7.16.4",
+ "@vue/compiler-core": "3.2.47",
+ "@vue/shared": "3.2.47",
+ "estree-walker": "^2.0.2",
+ "magic-string": "^0.25.7"
+ }
+ },
+ "node_modules/@vue/runtime-core": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.47.tgz",
+ "integrity": "sha512-RZxbLQIRB/K0ev0K9FXhNbBzT32H9iRtYbaXb0ZIz2usLms/D55dJR2t6cIEUn6vyhS3ALNvNthI+Q95C+NOpA==",
+ "dependencies": {
+ "@vue/reactivity": "3.2.47",
+ "@vue/shared": "3.2.47"
+ }
+ },
+ "node_modules/@vue/runtime-dom": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.47.tgz",
+ "integrity": "sha512-ArXrFTjS6TsDei4qwNvgrdmHtD930KgSKGhS5M+j8QxXrDJYLqYw4RRcDy1bz1m1wMmb6j+zGLifdVHtkXA7gA==",
+ "dependencies": {
+ "@vue/runtime-core": "3.2.47",
+ "@vue/shared": "3.2.47",
+ "csstype": "^2.6.8"
+ }
+ },
+ "node_modules/@vue/server-renderer": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.47.tgz",
+ "integrity": "sha512-dN9gc1i8EvmP9RCzvneONXsKfBRgqFeFZLurmHOveL7oH6HiFXJw5OGu294n1nHc/HMgTy6LulU/tv5/A7f/LA==",
+ "dependencies": {
+ "@vue/compiler-ssr": "3.2.47",
+ "@vue/shared": "3.2.47"
+ },
+ "peerDependencies": {
+ "vue": "3.2.47"
+ }
+ },
+ "node_modules/@vue/shared": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.47.tgz",
+ "integrity": "sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ=="
+ },
+ "node_modules/@vueuse/core": {
+ "version": "9.13.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.13.0.tgz",
+ "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==",
+ "dependencies": {
+ "@types/web-bluetooth": "^0.0.16",
+ "@vueuse/metadata": "9.13.0",
+ "@vueuse/shared": "9.13.0",
+ "vue-demi": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/@vueuse/core/node_modules/vue-demi": {
+ "version": "0.13.11",
+ "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
+ "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
+ "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": "9.13.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.13.0.tgz",
+ "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/@vueuse/shared": {
+ "version": "9.13.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.13.0.tgz",
+ "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==",
+ "dependencies": {
+ "vue-demi": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/@vueuse/shared/node_modules/vue-demi": {
+ "version": "0.13.11",
+ "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
+ "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
+ "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/@wangeditor/basic-modules": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@wangeditor/basic-modules/-/basic-modules-1.1.7.tgz",
+ "integrity": "sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==",
+ "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.3",
+ "resolved": "https://registry.npmjs.org/@wangeditor/code-highlight/-/code-highlight-1.0.3.tgz",
+ "integrity": "sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==",
+ "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.19",
+ "resolved": "https://registry.npmjs.org/@wangeditor/core/-/core-1.1.19.tgz",
+ "integrity": "sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==",
+ "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.23",
+ "resolved": "https://registry.npmjs.org/@wangeditor/editor/-/editor-5.1.23.tgz",
+ "integrity": "sha512-0RxfeVTuK1tktUaPROnCoFfaHVJpRAIE2zdS0mpP+vq1axVQpLjM8+fCvKzqYIkH0Pg+C+44hJpe3VVroSkEuQ==",
+ "dependencies": {
+ "@uppy/core": "^2.1.1",
+ "@uppy/xhr-upload": "^2.0.3",
+ "@wangeditor/basic-modules": "^1.1.7",
+ "@wangeditor/code-highlight": "^1.0.3",
+ "@wangeditor/core": "^1.1.19",
+ "@wangeditor/list-module": "^1.0.5",
+ "@wangeditor/table-module": "^1.1.4",
+ "@wangeditor/upload-image-module": "^1.0.2",
+ "@wangeditor/video-module": "^1.1.4",
+ "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-for-vue": {
+ "version": "5.1.12",
+ "resolved": "https://registry.npmjs.org/@wangeditor/editor-for-vue/-/editor-for-vue-5.1.12.tgz",
+ "integrity": "sha512-0Ds3D8I+xnpNWezAeO7HmPRgTfUxHLMd9JKcIw+QzvSmhC5xUHbpCcLU+KLmeBKTR/zffnS5GQo6qi3GhTMJWQ==",
+ "peerDependencies": {
+ "@wangeditor/editor": ">=5.1.0",
+ "vue": "^3.0.5"
+ }
+ },
+ "node_modules/@wangeditor/list-module": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@wangeditor/list-module/-/list-module-1.0.5.tgz",
+ "integrity": "sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ==",
+ "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.4",
+ "resolved": "https://registry.npmjs.org/@wangeditor/table-module/-/table-module-1.1.4.tgz",
+ "integrity": "sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w==",
+ "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.2",
+ "resolved": "https://registry.npmjs.org/@wangeditor/upload-image-module/-/upload-image-module-1.0.2.tgz",
+ "integrity": "sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA==",
+ "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.4",
+ "resolved": "https://registry.npmjs.org/@wangeditor/video-module/-/video-module-1.1.4.tgz",
+ "integrity": "sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==",
+ "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/acorn": {
+ "version": "8.8.2",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
+ "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "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/acorn-node": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmmirror.com/acorn-node/-/acorn-node-1.8.2.tgz",
+ "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^7.0.0",
+ "acorn-walk": "^7.0.0",
+ "xtend": "^4.0.2"
+ }
+ },
+ "node_modules/acorn-node/node_modules/acorn": {
+ "version": "7.4.1",
+ "resolved": "https://registry.npmmirror.com/acorn/-/acorn-7.4.1.tgz",
+ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-walk": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-7.2.0.tgz",
+ "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.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/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.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/arg": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmmirror.com/arg/-/arg-5.0.2.tgz",
+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
+ "dev": true
+ },
+ "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.2.5",
+ "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
+ "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
+ },
+ "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/autoprefixer": {
+ "version": "10.4.13",
+ "resolved": "https://registry.npmmirror.com/autoprefixer/-/autoprefixer-10.4.13.tgz",
+ "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==",
+ "dev": true,
+ "dependencies": {
+ "browserslist": "^4.21.4",
+ "caniuse-lite": "^1.0.30001426",
+ "fraction.js": "^4.2.0",
+ "normalize-range": "^0.1.2",
+ "picocolors": "^1.0.0",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "bin": {
+ "autoprefixer": "bin/autoprefixer"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ },
+ "peerDependencies": {
+ "postcss": "^8.1.0"
+ }
+ },
+ "node_modules/axios": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.3.tgz",
+ "integrity": "sha512-eYq77dYIFS77AQlhzEL937yUBSepBfPIe8FcgEDN35vMNZKMrs81pgnyrQpwfy4NF4b4XWX1Zgx7yX+25w8QJA==",
+ "dependencies": {
+ "follow-redirects": "^1.15.0",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.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.21.5",
+ "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.21.5.tgz",
+ "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==",
+ "dev": true,
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001449",
+ "electron-to-chromium": "^1.4.284",
+ "node-releases": "^2.0.8",
+ "update-browserslist-db": "^1.0.10"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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/camelcase-css": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmmirror.com/camelcase-css/-/camelcase-css-2.0.1.tgz",
+ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001458",
+ "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001458.tgz",
+ "integrity": "sha512-lQ1VlUUq5q9ro9X+5gOEyH7i3vm+AYVT1WDCVB69XOZ17KZRhnZ9J0Sqz7wTHQaLBJccNCHq8/Ww5LlOIZbB0w==",
+ "dev": 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/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/compute-scroll-into-view": {
+ "version": "1.0.20",
+ "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz",
+ "integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg=="
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "node_modules/countup.js": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/countup.js/-/countup.js-2.4.2.tgz",
+ "integrity": "sha512-EExCcu5rd7ffBj65B3CVNuS1HddN1Y4WuTfJEuocJXwZlNnlXZQ4sD9M/Cq32ZS0zR38F9vGMCw/iFcVImrNbw=="
+ },
+ "node_modules/cropperjs": {
+ "version": "1.5.13",
+ "resolved": "https://registry.npmjs.org/cropperjs/-/cropperjs-1.5.13.tgz",
+ "integrity": "sha512-by7jKAo73y5/Do0K6sxdTKHgndY0NMjG2bEdgeJxycbcmHuCiMXqw8sxy5C5Y5WTOTcDGmbT7Sr5CgKOXR06OA=="
+ },
+ "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.21",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz",
+ "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w=="
+ },
+ "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.7",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz",
+ "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ=="
+ },
+ "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/defined": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmmirror.com/defined/-/defined-1.0.1.tgz",
+ "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==",
+ "dev": true
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "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/detective": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmmirror.com/detective/-/detective-5.2.1.tgz",
+ "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==",
+ "dev": true,
+ "dependencies": {
+ "acorn-node": "^1.8.2",
+ "defined": "^1.0.0",
+ "minimist": "^1.2.6"
+ },
+ "bin": {
+ "detective": "bin/detective.js"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/didyoumean": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmmirror.com/didyoumean/-/didyoumean-1.2.2.tgz",
+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
+ "dev": true
+ },
+ "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/dlv": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmmirror.com/dlv/-/dlv-1.1.3.tgz",
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
+ "dev": true
+ },
+ "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/echarts": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.4.1.tgz",
+ "integrity": "sha512-9ltS3M2JB0w2EhcYjCdmtrJ+6haZcW6acBolMGIuf01Hql1yrIV01L1aRj7jsaaIULJslEP9Z3vKlEmnJaWJVQ==",
+ "dependencies": {
+ "tslib": "2.3.0",
+ "zrender": "5.4.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.1.0",
+ "resolved": "https://registry.npmjs.org/echarts-wordcloud/-/echarts-wordcloud-2.1.0.tgz",
+ "integrity": "sha512-Kt1JmbcROgb+3IMI48KZECK2AP5lG6bSsOEs+AsuwaWJxQom31RTNd6NFYI01E/YaI1PFZeueaupjlmzSQasjQ==",
+ "peerDependencies": {
+ "echarts": "^5.0.1"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.4.313",
+ "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.313.tgz",
+ "integrity": "sha512-QckB9OVqr2oybjIrbMI99uF+b9+iTja5weFe0ePbqLb5BHqXOJUO1SG6kDj/1WtWPRIBr51N153AEq8m7HuIaA==",
+ "dev": true
+ },
+ "node_modules/element-plus": {
+ "version": "2.2.32",
+ "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.2.32.tgz",
+ "integrity": "sha512-DTJMhYOy6MApbmh6z/95hPTK5WrBiNHGzV4IN+uEkup1WoimQ+Qyt8RxKdTe/X1LWEJ8YgWv/Cl8P4ocrt5z5g==",
+ "dependencies": {
+ "@ctrl/tinycolor": "^3.4.1",
+ "@element-plus/icons-vue": "^2.0.6",
+ "@floating-ui/dom": "^1.0.1",
+ "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
+ "@types/lodash": "^4.14.182",
+ "@types/lodash-es": "^4.17.6",
+ "@vueuse/core": "^9.1.0",
+ "async-validator": "^4.2.5",
+ "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.2.0"
+ },
+ "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/es5-ext": {
+ "version": "0.10.62",
+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
+ "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
+ "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": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+ "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.16.17",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz",
+ "integrity": "sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/android-arm": "0.16.17",
+ "@esbuild/android-arm64": "0.16.17",
+ "@esbuild/android-x64": "0.16.17",
+ "@esbuild/darwin-arm64": "0.16.17",
+ "@esbuild/darwin-x64": "0.16.17",
+ "@esbuild/freebsd-arm64": "0.16.17",
+ "@esbuild/freebsd-x64": "0.16.17",
+ "@esbuild/linux-arm": "0.16.17",
+ "@esbuild/linux-arm64": "0.16.17",
+ "@esbuild/linux-ia32": "0.16.17",
+ "@esbuild/linux-loong64": "0.16.17",
+ "@esbuild/linux-mips64el": "0.16.17",
+ "@esbuild/linux-ppc64": "0.16.17",
+ "@esbuild/linux-riscv64": "0.16.17",
+ "@esbuild/linux-s390x": "0.16.17",
+ "@esbuild/linux-x64": "0.16.17",
+ "@esbuild/netbsd-x64": "0.16.17",
+ "@esbuild/openbsd-x64": "0.16.17",
+ "@esbuild/sunos-x64": "0.16.17",
+ "@esbuild/win32-arm64": "0.16.17",
+ "@esbuild/win32-ia32": "0.16.17",
+ "@esbuild/win32-x64": "0.16.17"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": 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": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+ },
+ "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.34.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz",
+ "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==",
+ "dev": true,
+ "dependencies": {
+ "@eslint/eslintrc": "^1.4.1",
+ "@humanwhocodes/config-array": "^0.11.8",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "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.4.0",
+ "esquery": "^1.4.0",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "grapheme-splitter": "^1.0.4",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-sdsl": "^4.1.4",
+ "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"
+ },
+ "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.9.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.9.0.tgz",
+ "integrity": "sha512-YbubS7eK0J7DCf0U2LxvVP7LMfs6rC6UltihIgval3azO3gyDwEGVgsCMe1TmDiEkl6GdMKfRpaME6QxIYtzDQ==",
+ "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.4.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz",
+ "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^8.8.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.2.tgz",
+ "integrity": "sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==",
+ "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": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
+ "dependencies": {
+ "d": "1",
+ "es5-ext": "~0.10.14"
+ }
+ },
+ "node_modules/ext": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
+ "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
+ "dependencies": {
+ "type": "^2.7.2"
+ }
+ },
+ "node_modules/ext/node_modules/type": {
+ "version": "2.7.2",
+ "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
+ "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw=="
+ },
+ "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.12",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
+ "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+ "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": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true
+ },
+ "node_modules/fastq": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+ "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+ "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/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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.7",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
+ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
+ "dev": true
+ },
+ "node_modules/follow-redirects": {
+ "version": "1.15.2",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
+ "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
+ "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/fraction.js": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmmirror.com/fraction.js/-/fraction.js-4.2.0.tgz",
+ "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "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=="
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
+ "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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/globals": {
+ "version": "13.20.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
+ "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+ "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": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==",
+ "dependencies": {
+ "delegate": "^3.1.2"
+ }
+ },
+ "node_modules/grapheme-splitter": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+ "dev": 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==",
+ "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/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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.4",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+ "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/immer": {
+ "version": "9.0.19",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.19.tgz",
+ "integrity": "sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/immer"
+ }
+ },
+ "node_modules/immutable": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.4.tgz",
+ "integrity": "sha512-WDxL3Hheb1JkRN3sQkyujNlL/xRjAo3rJtaU5xeufUauG66JdMr32bLj4gF+vWl84DIA3Zxw7tiAjneYzRRw+w==",
+ "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": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "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": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "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.11.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
+ "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
+ "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": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "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-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "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": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true
+ },
+ "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-sdsl": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
+ "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
+ "dev": true,
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/js-sdsl"
+ }
+ },
+ "node_modules/js-table2excel": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/js-table2excel/-/js-table2excel-1.0.3.tgz",
+ "integrity": "sha512-ivzOdgYqOD3zqzJZfW0Nm35P9BWffxD0Unwr+2QBeEawV7hhRY9RHBVNcvO6A9PhGkMyqPVL/u4/NeufaTTTXw=="
+ },
+ "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-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": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "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/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/lilconfig": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmmirror.com/lilconfig/-/lilconfig-2.0.6.tgz",
+ "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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.3",
+ "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.3.tgz",
+ "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==",
+ "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": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
+ },
+ "node_modules/lodash.clonedeep": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+ "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ=="
+ },
+ "node_modules/lodash.debounce": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
+ },
+ "node_modules/lodash.foreach": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
+ "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ=="
+ },
+ "node_modules/lodash.isequal": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+ "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
+ },
+ "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.throttle": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
+ "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="
+ },
+ "node_modules/lodash.toarray": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
+ "integrity": "sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw=="
+ },
+ "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/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": "sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==",
+ "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/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "dev": true
+ },
+ "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": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true
+ },
+ "node_modules/natural-compare-lite": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
+ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
+ "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.10",
+ "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.10.tgz",
+ "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==",
+ "dev": 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-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmmirror.com/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/normalize-wheel-es": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz",
+ "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw=="
+ },
+ "node_modules/nprogress": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz",
+ "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA=="
+ },
+ "node_modules/nth-check": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+ "dev": true,
+ "dependencies": {
+ "boolbase": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/nth-check?sponsor=1"
+ }
+ },
+ "node_modules/object-hash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmmirror.com/object-hash/-/object-hash-3.0.0.tgz",
+ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.12.3",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
+ "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "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/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "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": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "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/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmmirror.com/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pinia": {
+ "version": "2.0.32",
+ "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.0.32.tgz",
+ "integrity": "sha512-8Tw4OrpCSJ028UUyp0gYPP/wyjigLoEceuO/x1G+FlHVf73337e5vLm4uDmrRIoBG1hvaed/eSHnrCFjOc4nkA==",
+ "dependencies": {
+ "@vue/devtools-api": "^6.5.0",
+ "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.13.11",
+ "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
+ "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
+ "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.21",
+ "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.21.tgz",
+ "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
+ "dependencies": {
+ "nanoid": "^3.3.4",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.0.2"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/postcss-import": {
+ "version": "14.1.0",
+ "resolved": "https://registry.npmmirror.com/postcss-import/-/postcss-import-14.1.0.tgz",
+ "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==",
+ "dev": true,
+ "dependencies": {
+ "postcss-value-parser": "^4.0.0",
+ "read-cache": "^1.0.0",
+ "resolve": "^1.1.7"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.0.0"
+ }
+ },
+ "node_modules/postcss-js": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmmirror.com/postcss-js/-/postcss-js-4.0.1.tgz",
+ "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
+ "dev": true,
+ "dependencies": {
+ "camelcase-css": "^2.0.1"
+ },
+ "engines": {
+ "node": "^12 || ^14 || >= 16"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.21"
+ }
+ },
+ "node_modules/postcss-load-config": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmmirror.com/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
+ "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
+ "dev": true,
+ "dependencies": {
+ "lilconfig": "^2.0.5",
+ "yaml": "^1.10.2"
+ },
+ "engines": {
+ "node": ">= 10"
+ },
+ "peerDependencies": {
+ "postcss": ">=8.0.9",
+ "ts-node": ">=9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "postcss": {
+ "optional": true
+ },
+ "ts-node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/postcss-nested": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmmirror.com/postcss-nested/-/postcss-nested-6.0.0.tgz",
+ "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==",
+ "dev": true,
+ "dependencies": {
+ "postcss-selector-parser": "^6.0.10"
+ },
+ "engines": {
+ "node": ">=12.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.2.14"
+ }
+ },
+ "node_modules/postcss-selector-parser": {
+ "version": "6.0.11",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz",
+ "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==",
+ "dev": true,
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "dev": true
+ },
+ "node_modules/preact": {
+ "version": "10.12.1",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.12.1.tgz",
+ "integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==",
+ "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.8.4",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz",
+ "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==",
+ "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.29.0",
+ "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz",
+ "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+ },
+ "node_modules/punycode": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
+ "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
+ "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/qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "dependencies": {
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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/quick-lru": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmmirror.com/quick-lru/-/quick-lru-5.1.1.tgz",
+ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/read-cache": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz",
+ "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+ "dev": true,
+ "dependencies": {
+ "pify": "^2.3.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.11",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
+ },
+ "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.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+ "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+ "dev": true,
+ "dependencies": {
+ "is-core-module": "^2.9.0",
+ "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": "3.17.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.17.2.tgz",
+ "integrity": "sha512-qMNZdlQPCkWodrAZ3qnJtvCAl4vpQ8q77uEujVCCbC/6CLB7Lcmvjq7HyiOSnf4fxTT9XgsE36oLHJBH49xjqA==",
+ "dev": true,
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=14.18.0",
+ "npm": ">=8.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/sass": {
+ "version": "1.58.3",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.58.3.tgz",
+ "integrity": "sha512-Q7RaEtYf6BflYrQ+buPudKR26/lH+10EmO9bBqbmPh/KeLqv8bjpTNqxe71ocONqXq+jYiCbpPUmQMS+JJPk4A==",
+ "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/screenfull": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/screenfull/-/screenfull-6.0.2.tgz",
+ "integrity": "sha512-AQdy8s4WhNvUZ6P8F6PB21tSPIYKniic+Ogx0AacBMjKP1GUHN2E9URxQHtCusiwxudnCKkdy4GrHXPPJSkCCw==",
+ "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.31",
+ "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz",
+ "integrity": "sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==",
+ "dependencies": {
+ "compute-scroll-into-view": "^1.0.20"
+ }
+ },
+ "node_modules/select": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
+ "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA=="
+ },
+ "node_modules/semver": {
+ "version": "7.3.8",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+ "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "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/side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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.1",
+ "resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.5.1.tgz",
+ "integrity": "sha512-wHMNIOjkm/YNE5EM3RCbr/+DVgPg6AqQAX1eOxO46zYNvCXjKP5Y865tqQj3EXnaMBjkxmQA5jFuDpDK/dbfiA==",
+ "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/sourcemap-codec": {
+ "version": "1.4.8",
+ "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
+ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
+ "deprecated": "Please use @jridgewell/sourcemap-codec instead"
+ },
+ "node_modules/splitpanes": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/splitpanes/-/splitpanes-3.1.5.tgz",
+ "integrity": "sha512-r3Mq2ITFQ5a2VXLOy4/Sb2Ptp7OfEO8YIbhVJqJXoFc9hc5nTXXkCvtVDjIGbvC0vdE7tse+xTM9BMjsszP6bw==",
+ "funding": {
+ "url": "https://github.com/sponsors/antoniandre"
+ }
+ },
+ "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/tailwindcss": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.2.7.tgz",
+ "integrity": "sha512-B6DLqJzc21x7wntlH/GsZwEXTBttVSl1FtCzC8WP4oBc/NKef7kaax5jeihkkCEWc831/5NDJ9gRNDK6NEioQQ==",
+ "dev": true,
+ "dependencies": {
+ "arg": "^5.0.2",
+ "chokidar": "^3.5.3",
+ "color-name": "^1.1.4",
+ "detective": "^5.2.1",
+ "didyoumean": "^1.2.2",
+ "dlv": "^1.1.3",
+ "fast-glob": "^3.2.12",
+ "glob-parent": "^6.0.2",
+ "is-glob": "^4.0.3",
+ "lilconfig": "^2.0.6",
+ "micromatch": "^4.0.5",
+ "normalize-path": "^3.0.0",
+ "object-hash": "^3.0.0",
+ "picocolors": "^1.0.0",
+ "postcss": "^8.0.9",
+ "postcss-import": "^14.1.0",
+ "postcss-js": "^4.0.0",
+ "postcss-load-config": "^3.1.4",
+ "postcss-nested": "6.0.0",
+ "postcss-selector-parser": "^6.0.11",
+ "postcss-value-parser": "^4.2.0",
+ "quick-lru": "^5.1.1",
+ "resolve": "^1.22.1"
+ },
+ "bin": {
+ "tailwind": "lib/cli.js",
+ "tailwindcss": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=12.13.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.0.9"
+ }
+ },
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "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/ts-enum-util": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmmirror.com/ts-enum-util/-/ts-enum-util-4.0.2.tgz",
+ "integrity": "sha512-BB5qjvHYgYgOB/CaoA1Cy/B2QNnZ+nVBrJ15VV/AXGWx+AO83k5wgeLOJvkSLoKKavvH/M8Wj4ZbgROjsuYwzw=="
+ },
+ "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.9.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
+ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
+ "devOptional": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
+ "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
+ "dev": true,
+ "dependencies": {
+ "escalade": "^3.1.1",
+ "picocolors": "^1.0.0"
+ },
+ "bin": {
+ "browserslist-lint": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.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": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true
+ },
+ "node_modules/vite": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-4.1.4.tgz",
+ "integrity": "sha512-3knk/HsbSTKEin43zHu7jTwYWv81f8kgAL99G5NWBcA1LKvtvcVAC4JjBH1arBunO9kQka+1oGbrMKOjk4ZrBg==",
+ "dev": true,
+ "dependencies": {
+ "esbuild": "^0.16.14",
+ "postcss": "^8.4.21",
+ "resolve": "^1.22.1",
+ "rollup": "^3.10.0"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ },
+ "peerDependencies": {
+ "@types/node": ">= 14",
+ "less": "*",
+ "sass": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite-plugin-vue-setup-extend": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/vite-plugin-vue-setup-extend/-/vite-plugin-vue-setup-extend-0.4.0.tgz",
+ "integrity": "sha512-WMbjPCui75fboFoUTHhdbXzu4Y/bJMv5N9QT9a7do3wNMNHHqrk+Tn2jrSJU0LS5fGl/EG+FEDBYVUeWIkDqXQ==",
+ "dev": true,
+ "dependencies": {
+ "@vue/compiler-sfc": "^3.2.29",
+ "magic-string": "^0.25.7"
+ },
+ "peerDependencies": {
+ "vite": ">=2.0.0"
+ }
+ },
+ "node_modules/vue": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.47.tgz",
+ "integrity": "sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ==",
+ "dependencies": {
+ "@vue/compiler-dom": "3.2.47",
+ "@vue/compiler-sfc": "3.2.47",
+ "@vue/runtime-dom": "3.2.47",
+ "@vue/server-renderer": "3.2.47",
+ "@vue/shared": "3.2.47"
+ }
+ },
+ "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.1.0",
+ "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.1.0.tgz",
+ "integrity": "sha512-NGn/iQy8/Wb7RrRa4aRkokyCZfOUWk19OP5HP6JEozQFX5AoS/t+Z0ZN7FY4LlmWc4FNI922V7cvX28zctN8dQ==",
+ "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.2.2",
+ "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.2.2.tgz",
+ "integrity": "sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==",
+ "dependencies": {
+ "@intlify/core-base": "9.2.2",
+ "@intlify/shared": "9.2.2",
+ "@intlify/vue-devtools": "9.2.2",
+ "@vue/devtools-api": "^6.2.1"
+ },
+ "engines": {
+ "node": ">= 14"
+ },
+ "peerDependencies": {
+ "vue": "^3.0.0"
+ }
+ },
+ "node_modules/vue-router": {
+ "version": "4.1.6",
+ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.1.6.tgz",
+ "integrity": "sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==",
+ "dependencies": {
+ "@vue/devtools-api": "^6.4.5"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/posva"
+ },
+ "peerDependencies": {
+ "vue": "^3.2.0"
+ }
+ },
+ "node_modules/vuedraggable": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmmirror.com/vuedraggable/-/vuedraggable-4.1.0.tgz",
+ "integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==",
+ "dependencies": {
+ "sortablejs": "1.14.0"
+ },
+ "peerDependencies": {
+ "vue": "^3.0.1"
+ }
+ },
+ "node_modules/vuedraggable/node_modules/sortablejs": {
+ "version": "1.14.0",
+ "resolved": "https://registry.npmmirror.com/sortablejs/-/sortablejs-1.14.0.tgz",
+ "integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="
+ },
+ "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": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng=="
+ },
+ "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": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "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/xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4"
+ }
+ },
+ "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/yaml": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmmirror.com/yaml/-/yaml-1.10.2.tgz",
+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/zrender": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.4.1.tgz",
+ "integrity": "sha512-M4Z05BHWtajY2241EmMPHglDQAJ1UyHQcYsxDNzD9XLSkPDqMq4bB28v9Pb4mvHnVQ0GxyTklZ/69xCFP6RXBA==",
+ "dependencies": {
+ "tslib": "2.3.0"
+ }
+ }
+ },
+ "dependencies": {
+ "@babel/parser": {
+ "version": "7.21.1",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.1.tgz",
+ "integrity": "sha512-JzhBFpkuhBNYUY7qs+wTzNmyCWUHEaAFpQQD2YfU1rPL38/L43Wvid0fFkiOCnHvsGncRZgEPyGnltABLcVDTg=="
+ },
+ "@babel/runtime": {
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz",
+ "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==",
+ "requires": {
+ "regenerator-runtime": "^0.13.11"
+ }
+ },
+ "@ctrl/tinycolor": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.0.tgz",
+ "integrity": "sha512-/Z3l6pXthq0JvMYdUFyX9j0MaCltlIn6mfh9jLyQwg5aPKxkyNa0PTHtU1AlFXLNk55ZuAeJRcpvq+tmLfKmaQ=="
+ },
+ "@element-plus/icons-vue": {
+ "version": "2.0.10",
+ "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.0.10.tgz",
+ "integrity": "sha512-ygEZ1mwPjcPo/OulhzLE7mtDrQBWI8vZzEWSNB2W/RNCRjoQGwbaK4N8lV4rid7Ts4qvySU3njMN7YCiSlSaTQ==",
+ "requires": {}
+ },
+ "@esbuild/android-arm": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz",
+ "integrity": "sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/android-arm64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz",
+ "integrity": "sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/android-x64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz",
+ "integrity": "sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/darwin-arm64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz",
+ "integrity": "sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/darwin-x64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz",
+ "integrity": "sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/freebsd-arm64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz",
+ "integrity": "sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/freebsd-x64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz",
+ "integrity": "sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-arm": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz",
+ "integrity": "sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-arm64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz",
+ "integrity": "sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-ia32": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz",
+ "integrity": "sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-loong64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz",
+ "integrity": "sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-mips64el": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz",
+ "integrity": "sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-ppc64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz",
+ "integrity": "sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-riscv64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz",
+ "integrity": "sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-s390x": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz",
+ "integrity": "sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-x64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz",
+ "integrity": "sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/netbsd-x64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz",
+ "integrity": "sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/openbsd-x64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz",
+ "integrity": "sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/sunos-x64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz",
+ "integrity": "sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/win32-arm64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz",
+ "integrity": "sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/win32-ia32": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz",
+ "integrity": "sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/win32-x64": {
+ "version": "0.16.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz",
+ "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==",
+ "dev": true,
+ "optional": true
+ },
+ "@eslint/eslintrc": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
+ "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.4.0",
+ "globals": "^13.19.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": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.2.1.tgz",
+ "integrity": "sha512-LSqwPZkK3rYfD7GKoIeExXOyYx6Q1O4iqZWwIehDNuv3Dv425FIAE8PRwtAx1imEolFTHgBEcoFHm9MDnYgPCg=="
+ },
+ "@floating-ui/dom": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.2.1.tgz",
+ "integrity": "sha512-Rt45SmRiV8eU+xXSB9t0uMYiQ/ZWGE/jumse2o3i5RGlyvcbqOF4q+1qBnzLE2kZ5JGhq0iMkcGXUKbFe7MpTA==",
+ "requires": {
+ "@floating-ui/core": "^1.2.1"
+ }
+ },
+ "@form-create/component-elm-checkbox": {
+ "version": "3.1.15",
+ "resolved": "https://registry.npmmirror.com/@form-create/component-elm-checkbox/-/component-elm-checkbox-3.1.15.tgz",
+ "integrity": "sha512-bAl3k0p76wwMX0OxeR8KAEiUl2RP1Jl1kAqbjD762EcSXGgaXgP94v9ag1JhUoiwZkSKWl6IF+e/utjEonRSFw==",
+ "requires": {
+ "@form-create/utils": "^3.1.15"
+ }
+ },
+ "@form-create/component-elm-frame": {
+ "version": "3.1.15",
+ "resolved": "https://registry.npmmirror.com/@form-create/component-elm-frame/-/component-elm-frame-3.1.15.tgz",
+ "integrity": "sha512-78WbMpMLTYwTo3QP7Fa+N2VF/u1vmRuwDmiobtBtVg9EE7m6//bQV96ibnLNXX27MD41gIg+o1GUJtx/qxZ8Ew==",
+ "requires": {
+ "@form-create/utils": "^3.1.15"
+ }
+ },
+ "@form-create/component-elm-group": {
+ "version": "3.1.15",
+ "resolved": "https://registry.npmmirror.com/@form-create/component-elm-group/-/component-elm-group-3.1.15.tgz",
+ "integrity": "sha512-V/oVxHf9rHqqMHRV0XRVED9EYFCVZ8Tv/EbbIN/4rORruHtzdQOH8I0QHQ9T4vZO9Q4eblApzcJb8Y7bbHX23Q==",
+ "requires": {
+ "@form-create/utils": "^3.1.15"
+ }
+ },
+ "@form-create/component-elm-radio": {
+ "version": "3.1.15",
+ "resolved": "https://registry.npmmirror.com/@form-create/component-elm-radio/-/component-elm-radio-3.1.15.tgz",
+ "integrity": "sha512-qAf1VlhrUvMlgzkz6BYLRn0UOLahkTI/cbzt8nkp5PL1oGoSXp5xqIOtHMjbnGEkEXW57kjRKI5Q7UjzIhYmvQ==",
+ "requires": {
+ "@form-create/utils": "^3.1.15"
+ }
+ },
+ "@form-create/component-elm-select": {
+ "version": "3.1.15",
+ "resolved": "https://registry.npmmirror.com/@form-create/component-elm-select/-/component-elm-select-3.1.15.tgz",
+ "integrity": "sha512-ZnvPn/TGqgFDed7bKabjRvlwlQ8RYq5WCG9Iy63d2igC8577tv5QTI2rNvfGfxxH/254MPwgNlA94JukxzEOTw==",
+ "requires": {
+ "@form-create/utils": "^3.1.15"
+ }
+ },
+ "@form-create/component-elm-tree": {
+ "version": "3.1.15",
+ "resolved": "https://registry.npmmirror.com/@form-create/component-elm-tree/-/component-elm-tree-3.1.15.tgz",
+ "integrity": "sha512-4VPN406A8Mvannn8P/2DvStqDYFfDHZ+ILG/0JndOyfe+GdYdSA5SwD3LfC4zD6AhpGrkOJXbd4YYXlBUtzt8g==",
+ "requires": {
+ "@form-create/utils": "^3.1.15"
+ }
+ },
+ "@form-create/component-elm-upload": {
+ "version": "3.1.18",
+ "resolved": "https://registry.npmmirror.com/@form-create/component-elm-upload/-/component-elm-upload-3.1.18.tgz",
+ "integrity": "sha512-+jHZ1vfNusEqKSvpLpFcKbF0lE7S+YuWtAturzW2O5K+qYDw6SmGyB3/XeYqVXN9rfne0rqMbyYw6CGglVe7nw==",
+ "requires": {
+ "@form-create/utils": "^3.1.15"
+ }
+ },
+ "@form-create/component-subform": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmmirror.com/@form-create/component-subform/-/component-subform-3.1.5.tgz",
+ "integrity": "sha512-JHNEFGuwpnjGvCJ0I0GCqPL5al0qXoN4ymnRBpm+oL+6MMo5bz1kUyoqMX1MutuC96gHTqpeqc67hssi8g2mIw=="
+ },
+ "@form-create/core": {
+ "version": "3.1.18",
+ "resolved": "https://registry.npmmirror.com/@form-create/core/-/core-3.1.18.tgz",
+ "integrity": "sha512-kFu+fH88KvdkJoMPuLaBOG/4jNv+YPJbJHzvF4HZLn9XEtJgO9flef5WcvMyz12moI6uNGJ4Hs8+sdkXBJtkMw==",
+ "requires": {
+ "@form-create/utils": "^3.1.15"
+ }
+ },
+ "@form-create/element-ui": {
+ "version": "3.1.18",
+ "resolved": "https://registry.npmmirror.com/@form-create/element-ui/-/element-ui-3.1.18.tgz",
+ "integrity": "sha512-FstZrrfUBm9cRipqi6BW3cTPShQsgDWaHXYA5Uj/3fQ5y5EuoSRkNnlgqEoAjwUsQznL4tMC4BzqxoAHsP9zlg==",
+ "requires": {
+ "@form-create/component-elm-checkbox": "^3.1.15",
+ "@form-create/component-elm-frame": "^3.1.15",
+ "@form-create/component-elm-group": "^3.1.15",
+ "@form-create/component-elm-radio": "^3.1.15",
+ "@form-create/component-elm-select": "^3.1.15",
+ "@form-create/component-elm-tree": "^3.1.15",
+ "@form-create/component-elm-upload": "^3.1.18",
+ "@form-create/component-subform": "^3.1.5",
+ "@form-create/core": "^3.1.18",
+ "@form-create/utils": "^3.1.15"
+ }
+ },
+ "@form-create/utils": {
+ "version": "3.1.15",
+ "resolved": "https://registry.npmmirror.com/@form-create/utils/-/utils-3.1.15.tgz",
+ "integrity": "sha512-tP6Z/c2XC6OYrI8D9/XWvJc2h6apsyMFTy051sY+tCcxppqyR7dBEEXmgfWOrAr980N7k10g27kwJ9TdVn+bfw=="
+ },
+ "@humanwhocodes/config-array": {
+ "version": "0.11.8",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
+ "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
+ "dev": true,
+ "requires": {
+ "@humanwhocodes/object-schema": "^1.2.1",
+ "debug": "^4.1.1",
+ "minimatch": "^3.0.5"
+ }
+ },
+ "@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true
+ },
+ "@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
+ },
+ "@iconify/types": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmmirror.com/@iconify/types/-/types-2.0.0.tgz",
+ "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==",
+ "dev": true
+ },
+ "@iconify/vue": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmmirror.com/@iconify/vue/-/vue-4.1.0.tgz",
+ "integrity": "sha512-rBQVxNoSDooqgWkQg2MqkIHkH/huNuvXGqui5wijc1zLnU7TKzbBHW9VGmbnV4asNTmIHmqV4Nvt0M2rZ/9nHA==",
+ "dev": true,
+ "requires": {
+ "@iconify/types": "^2.0.0"
+ }
+ },
+ "@interactjs/actions": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/actions/-/actions-1.10.17.tgz",
+ "integrity": "sha512-wyB1ZqpaZy5gmz6VDqK9KWh98xKnFgL7VyLvxHODFi9V0IYX4HJAAOBlhtfze0D1R1f1cY+gqPDK+dLaHMlE+w==",
+ "requires": {
+ "@interactjs/interact": "1.10.17"
+ }
+ },
+ "@interactjs/auto-scroll": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/auto-scroll/-/auto-scroll-1.10.17.tgz",
+ "integrity": "sha512-IQcW7N3xOaoL8RnAGOGMk0Y2gue7L4S3BT6Id4VBBu8so163DtLiZVW6jXu9rKVntzbluaAeqNZlfAVyu3kIWg==",
+ "requires": {
+ "@interactjs/interact": "1.10.17"
+ }
+ },
+ "@interactjs/auto-start": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/auto-start/-/auto-start-1.10.17.tgz",
+ "integrity": "sha512-qYVxhAbYnwxjD/NLEegUoAST7WASJ4VmWNjsyWRx/js5Op+I4E2zteARIeZGgrutcGIXMCcQzhCMgE3PjOpbpw==",
+ "requires": {
+ "@interactjs/interact": "1.10.17"
+ }
+ },
+ "@interactjs/core": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/core/-/core-1.10.17.tgz",
+ "integrity": "sha512-rL9w+83HDRuXub8Ezqs+97CYLl/ne7bLT/sAeduUWaxYhsW9iOqBoob9JnkkCZOaOsYizWI1EWy0+fNc5ibtLQ==",
+ "requires": {}
+ },
+ "@interactjs/dev-tools": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/dev-tools/-/dev-tools-1.10.17.tgz",
+ "integrity": "sha512-Oi9nEw3FfSwkNmW+V0WwdHqvzEkVHc24mH1v5EjRn60sqgrGLK9nTQ+NSuqcnUY8GxC3TkyuxnsOodxiadIRmA==",
+ "requires": {
+ "@interactjs/interact": "1.10.17"
+ }
+ },
+ "@interactjs/inertia": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/inertia/-/inertia-1.10.17.tgz",
+ "integrity": "sha512-41vbYUjZIDCKt2/yhmjPrEW5+0uoL/hldFsll9pkvnLhmm12Xk0VXOlmR2zXKAmsTK3fJlKMyBYUX92qHLkyVQ==",
+ "requires": {
+ "@interactjs/interact": "1.10.17",
+ "@interactjs/offset": "1.10.17"
+ }
+ },
+ "@interactjs/interact": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/interact/-/interact-1.10.17.tgz",
+ "integrity": "sha512-NyKsf8EFudvdahBjPz1Gt5QnynVwa/2LUfBc2/w8QOnOBiyzUm0HLloJSaB8a50QbQkSWN243/Lgpd8GTMQvuQ==",
+ "requires": {
+ "@interactjs/core": "1.10.17",
+ "@interactjs/types": "1.10.17",
+ "@interactjs/utils": "1.10.17"
+ }
+ },
+ "@interactjs/interactjs": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/interactjs/-/interactjs-1.10.17.tgz",
+ "integrity": "sha512-hHmiukARbZhiM12zNKx0yQlFVl4C+NMeYNAYh6Mf9U3ZziQ47C+JEW8Gr7Zr/MxfNZyPu5nLKCpVQjh/JvBO9g==",
+ "requires": {
+ "@interactjs/actions": "1.10.17",
+ "@interactjs/auto-scroll": "1.10.17",
+ "@interactjs/auto-start": "1.10.17",
+ "@interactjs/core": "1.10.17",
+ "@interactjs/dev-tools": "1.10.17",
+ "@interactjs/inertia": "1.10.17",
+ "@interactjs/interact": "1.10.17",
+ "@interactjs/modifiers": "1.10.17",
+ "@interactjs/offset": "1.10.17",
+ "@interactjs/pointer-events": "1.10.17",
+ "@interactjs/reflow": "1.10.17",
+ "@interactjs/utils": "1.10.17"
+ }
+ },
+ "@interactjs/modifiers": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/modifiers/-/modifiers-1.10.17.tgz",
+ "integrity": "sha512-Dxw8kv9VBIxnhNvQncR6CKAGMzKXczLvuAUIdSPFYtyerX/XiDulJUqhR+jVKNp/WjF1DvdBxWo0kGGLbM84LQ==",
+ "requires": {
+ "@interactjs/interact": "1.10.17",
+ "@interactjs/snappers": "1.10.17"
+ }
+ },
+ "@interactjs/offset": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/offset/-/offset-1.10.17.tgz",
+ "integrity": "sha512-wWBnIQWgLrmJNTBbd/FdxHxAJjiXl/5ND8Jbw2DuP9gIGDxhFSdEt62Fgqimn9ICb8v8ycvSLObEmcvJF/8hQQ==",
+ "requires": {
+ "@interactjs/interact": "1.10.17"
+ }
+ },
+ "@interactjs/pointer-events": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/pointer-events/-/pointer-events-1.10.17.tgz",
+ "integrity": "sha512-VsfluouEKb8QRGyH6jQATCW+QdAd/3dkENS7rj2m+EcVUhz2Ob5mpMRopjALi4pwltMowqTfuJ4LtwMSX2G29A==",
+ "requires": {
+ "@interactjs/interact": "1.10.17"
+ }
+ },
+ "@interactjs/reflow": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/reflow/-/reflow-1.10.17.tgz",
+ "integrity": "sha512-ncpWP5k93FRQptEhjzPZsbuRRajd4rkW17lDavCrEjrDi/LHnYekWGqZTaFzfJ80n1x8xUm9ujDjxCTylNqEIA==",
+ "requires": {
+ "@interactjs/interact": "1.10.17"
+ }
+ },
+ "@interactjs/snappers": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/snappers/-/snappers-1.10.17.tgz",
+ "integrity": "sha512-m753DGsNOts797e3zDT6wqELoc+BlpIC1w+TyMyISRxU6n1RlS8Q6LHBGgwAgV79LHLaahv/a5haFF9H1VG0FQ==",
+ "requires": {
+ "@interactjs/interact": "1.10.17"
+ }
+ },
+ "@interactjs/types": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/types/-/types-1.10.17.tgz",
+ "integrity": "sha512-X2JpoM7xUw0p9Me0tMaI0HNfcF/Hd07ZZlzpnpEMpGerUZOLoyeThrV9P+CrBHxZrluWJrigJbcdqXliFd0YMA=="
+ },
+ "@interactjs/utils": {
+ "version": "1.10.17",
+ "resolved": "https://registry.npmjs.org/@interactjs/utils/-/utils-1.10.17.tgz",
+ "integrity": "sha512-sZAW08CkqgvqRjUIaLRjScjObcCzN9D75yekLA21EClYAZIhi4A+GEt2z/WqOCOksTaEPLYmQyhkpXcboc0LhQ=="
+ },
+ "@intlify/core-base": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.2.2.tgz",
+ "integrity": "sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==",
+ "requires": {
+ "@intlify/devtools-if": "9.2.2",
+ "@intlify/message-compiler": "9.2.2",
+ "@intlify/shared": "9.2.2",
+ "@intlify/vue-devtools": "9.2.2"
+ }
+ },
+ "@intlify/devtools-if": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.2.2.tgz",
+ "integrity": "sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==",
+ "requires": {
+ "@intlify/shared": "9.2.2"
+ }
+ },
+ "@intlify/message-compiler": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.2.2.tgz",
+ "integrity": "sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==",
+ "requires": {
+ "@intlify/shared": "9.2.2",
+ "source-map": "0.6.1"
+ }
+ },
+ "@intlify/shared": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.2.2.tgz",
+ "integrity": "sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q=="
+ },
+ "@intlify/vue-devtools": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.2.2.tgz",
+ "integrity": "sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==",
+ "requires": {
+ "@intlify/core-base": "9.2.2",
+ "@intlify/shared": "9.2.2"
+ }
+ },
+ "@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/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.191",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
+ "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ=="
+ },
+ "@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": "18.14.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.0.tgz",
+ "integrity": "sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A==",
+ "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/semver": {
+ "version": "7.3.13",
+ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
+ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
+ "dev": true
+ },
+ "@types/sortablejs": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/@types/sortablejs/-/sortablejs-1.15.0.tgz",
+ "integrity": "sha512-qrhtM7M41EhH4tZQTNw2/RJkxllBx3reiJpTbgWCM2Dx0U1sZ6LwKp9lfNln9uqE26ZMKUaPEYaD4rzvOWYtZw==",
+ "dev": true
+ },
+ "@types/web-bluetooth": {
+ "version": "0.0.16",
+ "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
+ "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ=="
+ },
+ "@typescript-eslint/eslint-plugin": {
+ "version": "5.53.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.53.0.tgz",
+ "integrity": "sha512-alFpFWNucPLdUOySmXCJpzr6HKC3bu7XooShWM+3w/EL6J2HIoB2PFxpLnq4JauWVk6DiVeNKzQlFEaE+X9sGw==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/scope-manager": "5.53.0",
+ "@typescript-eslint/type-utils": "5.53.0",
+ "@typescript-eslint/utils": "5.53.0",
+ "debug": "^4.3.4",
+ "grapheme-splitter": "^1.0.4",
+ "ignore": "^5.2.0",
+ "natural-compare-lite": "^1.4.0",
+ "regexpp": "^3.2.0",
+ "semver": "^7.3.7",
+ "tsutils": "^3.21.0"
+ }
+ },
+ "@typescript-eslint/parser": {
+ "version": "5.53.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.53.0.tgz",
+ "integrity": "sha512-MKBw9i0DLYlmdOb3Oq/526+al20AJZpANdT6Ct9ffxcV8nKCHz63t/S0IhlTFNsBIHJv+GY5SFJ0XfqVeydQrQ==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/scope-manager": "5.53.0",
+ "@typescript-eslint/types": "5.53.0",
+ "@typescript-eslint/typescript-estree": "5.53.0",
+ "debug": "^4.3.4"
+ }
+ },
+ "@typescript-eslint/scope-manager": {
+ "version": "5.53.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.53.0.tgz",
+ "integrity": "sha512-Opy3dqNsp/9kBBeCPhkCNR7fmdSQqA+47r21hr9a14Bx0xnkElEQmhoHga+VoaoQ6uDHjDKmQPIYcUcKJifS7w==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "5.53.0",
+ "@typescript-eslint/visitor-keys": "5.53.0"
+ }
+ },
+ "@typescript-eslint/type-utils": {
+ "version": "5.53.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.53.0.tgz",
+ "integrity": "sha512-HO2hh0fmtqNLzTAme/KnND5uFNwbsdYhCZghK2SoxGp3Ifn2emv+hi0PBUjzzSh0dstUIFqOj3bp0AwQlK4OWw==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/typescript-estree": "5.53.0",
+ "@typescript-eslint/utils": "5.53.0",
+ "debug": "^4.3.4",
+ "tsutils": "^3.21.0"
+ }
+ },
+ "@typescript-eslint/types": {
+ "version": "5.53.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.53.0.tgz",
+ "integrity": "sha512-5kcDL9ZUIP756K6+QOAfPkigJmCPHcLN7Zjdz76lQWWDdzfOhZDTj1irs6gPBKiXx5/6O3L0+AvupAut3z7D2A==",
+ "dev": true
+ },
+ "@typescript-eslint/typescript-estree": {
+ "version": "5.53.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.53.0.tgz",
+ "integrity": "sha512-eKmipH7QyScpHSkhbptBBYh9v8FxtngLquq292YTEQ1pxVs39yFBlLC1xeIZcPPz1RWGqb7YgERJRGkjw8ZV7w==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "5.53.0",
+ "@typescript-eslint/visitor-keys": "5.53.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.53.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.53.0.tgz",
+ "integrity": "sha512-VUOOtPv27UNWLxFwQK/8+7kvxVC+hPHNsJjzlJyotlaHjLSIgOCKj9I0DBUjwOOA64qjBwx5afAPjksqOxMO0g==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.9",
+ "@types/semver": "^7.3.12",
+ "@typescript-eslint/scope-manager": "5.53.0",
+ "@typescript-eslint/types": "5.53.0",
+ "@typescript-eslint/typescript-estree": "5.53.0",
+ "eslint-scope": "^5.1.1",
+ "eslint-utils": "^3.0.0",
+ "semver": "^7.3.7"
+ }
+ },
+ "@typescript-eslint/visitor-keys": {
+ "version": "5.53.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.53.0.tgz",
+ "integrity": "sha512-JqNLnX3leaHFZEN0gCh81sIvgrp/2GOACZNgO4+Tkf64u51kTpAyWFOY8XHx8XuXr3N2C9zgPPHtcpMg6z1g0w==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "5.53.0",
+ "eslint-visitor-keys": "^3.3.0"
+ }
+ },
+ "@uppy/companion-client": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/@uppy/companion-client/-/companion-client-2.2.2.tgz",
+ "integrity": "sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==",
+ "requires": {
+ "@uppy/utils": "^4.1.2",
+ "namespace-emitter": "^2.0.1"
+ }
+ },
+ "@uppy/core": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/@uppy/core/-/core-2.3.4.tgz",
+ "integrity": "sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==",
+ "requires": {
+ "@transloadit/prettier-bytes": "0.0.7",
+ "@uppy/store-default": "^2.1.1",
+ "@uppy/utils": "^4.1.3",
+ "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.1.1",
+ "resolved": "https://registry.npmjs.org/@uppy/store-default/-/store-default-2.1.1.tgz",
+ "integrity": "sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ=="
+ },
+ "@uppy/utils": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/@uppy/utils/-/utils-4.1.3.tgz",
+ "integrity": "sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==",
+ "requires": {
+ "lodash.throttle": "^4.1.1"
+ }
+ },
+ "@uppy/xhr-upload": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@uppy/xhr-upload/-/xhr-upload-2.1.3.tgz",
+ "integrity": "sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==",
+ "requires": {
+ "@uppy/companion-client": "^2.2.2",
+ "@uppy/utils": "^4.1.2",
+ "nanoid": "^3.1.25"
+ }
+ },
+ "@vitejs/plugin-vue": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.0.0.tgz",
+ "integrity": "sha512-e0X4jErIxAB5oLtDqbHvHpJe/uWNkdpYV83AOG2xo2tEVSzCzewgJMtREZM30wXnM5ls90hxiOtAuVU6H5JgbA==",
+ "dev": true,
+ "requires": {}
+ },
+ "@vue/compiler-core": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.47.tgz",
+ "integrity": "sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==",
+ "requires": {
+ "@babel/parser": "^7.16.4",
+ "@vue/shared": "3.2.47",
+ "estree-walker": "^2.0.2",
+ "source-map": "^0.6.1"
+ }
+ },
+ "@vue/compiler-dom": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz",
+ "integrity": "sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==",
+ "requires": {
+ "@vue/compiler-core": "3.2.47",
+ "@vue/shared": "3.2.47"
+ }
+ },
+ "@vue/compiler-sfc": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz",
+ "integrity": "sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==",
+ "requires": {
+ "@babel/parser": "^7.16.4",
+ "@vue/compiler-core": "3.2.47",
+ "@vue/compiler-dom": "3.2.47",
+ "@vue/compiler-ssr": "3.2.47",
+ "@vue/reactivity-transform": "3.2.47",
+ "@vue/shared": "3.2.47",
+ "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.47",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.47.tgz",
+ "integrity": "sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==",
+ "requires": {
+ "@vue/compiler-dom": "3.2.47",
+ "@vue/shared": "3.2.47"
+ }
+ },
+ "@vue/devtools-api": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz",
+ "integrity": "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q=="
+ },
+ "@vue/reactivity": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.47.tgz",
+ "integrity": "sha512-7khqQ/75oyyg+N/e+iwV6lpy1f5wq759NdlS1fpAhFXa8VeAIKGgk2E/C4VF59lx5b+Ezs5fpp/5WsRYXQiKxQ==",
+ "requires": {
+ "@vue/shared": "3.2.47"
+ }
+ },
+ "@vue/reactivity-transform": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz",
+ "integrity": "sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==",
+ "requires": {
+ "@babel/parser": "^7.16.4",
+ "@vue/compiler-core": "3.2.47",
+ "@vue/shared": "3.2.47",
+ "estree-walker": "^2.0.2",
+ "magic-string": "^0.25.7"
+ }
+ },
+ "@vue/runtime-core": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.47.tgz",
+ "integrity": "sha512-RZxbLQIRB/K0ev0K9FXhNbBzT32H9iRtYbaXb0ZIz2usLms/D55dJR2t6cIEUn6vyhS3ALNvNthI+Q95C+NOpA==",
+ "requires": {
+ "@vue/reactivity": "3.2.47",
+ "@vue/shared": "3.2.47"
+ }
+ },
+ "@vue/runtime-dom": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.47.tgz",
+ "integrity": "sha512-ArXrFTjS6TsDei4qwNvgrdmHtD930KgSKGhS5M+j8QxXrDJYLqYw4RRcDy1bz1m1wMmb6j+zGLifdVHtkXA7gA==",
+ "requires": {
+ "@vue/runtime-core": "3.2.47",
+ "@vue/shared": "3.2.47",
+ "csstype": "^2.6.8"
+ }
+ },
+ "@vue/server-renderer": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.47.tgz",
+ "integrity": "sha512-dN9gc1i8EvmP9RCzvneONXsKfBRgqFeFZLurmHOveL7oH6HiFXJw5OGu294n1nHc/HMgTy6LulU/tv5/A7f/LA==",
+ "requires": {
+ "@vue/compiler-ssr": "3.2.47",
+ "@vue/shared": "3.2.47"
+ }
+ },
+ "@vue/shared": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.47.tgz",
+ "integrity": "sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ=="
+ },
+ "@vueuse/core": {
+ "version": "9.13.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.13.0.tgz",
+ "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==",
+ "requires": {
+ "@types/web-bluetooth": "^0.0.16",
+ "@vueuse/metadata": "9.13.0",
+ "@vueuse/shared": "9.13.0",
+ "vue-demi": "*"
+ },
+ "dependencies": {
+ "vue-demi": {
+ "version": "0.13.11",
+ "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
+ "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
+ "requires": {}
+ }
+ }
+ },
+ "@vueuse/metadata": {
+ "version": "9.13.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.13.0.tgz",
+ "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ=="
+ },
+ "@vueuse/shared": {
+ "version": "9.13.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.13.0.tgz",
+ "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==",
+ "requires": {
+ "vue-demi": "*"
+ },
+ "dependencies": {
+ "vue-demi": {
+ "version": "0.13.11",
+ "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
+ "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
+ "requires": {}
+ }
+ }
+ },
+ "@wangeditor/basic-modules": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@wangeditor/basic-modules/-/basic-modules-1.1.7.tgz",
+ "integrity": "sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==",
+ "requires": {
+ "is-url": "^1.2.4"
+ }
+ },
+ "@wangeditor/code-highlight": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@wangeditor/code-highlight/-/code-highlight-1.0.3.tgz",
+ "integrity": "sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==",
+ "requires": {
+ "prismjs": "^1.23.0"
+ }
+ },
+ "@wangeditor/core": {
+ "version": "1.1.19",
+ "resolved": "https://registry.npmjs.org/@wangeditor/core/-/core-1.1.19.tgz",
+ "integrity": "sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==",
+ "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.23",
+ "resolved": "https://registry.npmjs.org/@wangeditor/editor/-/editor-5.1.23.tgz",
+ "integrity": "sha512-0RxfeVTuK1tktUaPROnCoFfaHVJpRAIE2zdS0mpP+vq1axVQpLjM8+fCvKzqYIkH0Pg+C+44hJpe3VVroSkEuQ==",
+ "requires": {
+ "@uppy/core": "^2.1.1",
+ "@uppy/xhr-upload": "^2.0.3",
+ "@wangeditor/basic-modules": "^1.1.7",
+ "@wangeditor/code-highlight": "^1.0.3",
+ "@wangeditor/core": "^1.1.19",
+ "@wangeditor/list-module": "^1.0.5",
+ "@wangeditor/table-module": "^1.1.4",
+ "@wangeditor/upload-image-module": "^1.0.2",
+ "@wangeditor/video-module": "^1.1.4",
+ "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/editor-for-vue": {
+ "version": "5.1.12",
+ "resolved": "https://registry.npmjs.org/@wangeditor/editor-for-vue/-/editor-for-vue-5.1.12.tgz",
+ "integrity": "sha512-0Ds3D8I+xnpNWezAeO7HmPRgTfUxHLMd9JKcIw+QzvSmhC5xUHbpCcLU+KLmeBKTR/zffnS5GQo6qi3GhTMJWQ==",
+ "requires": {}
+ },
+ "@wangeditor/list-module": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@wangeditor/list-module/-/list-module-1.0.5.tgz",
+ "integrity": "sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ==",
+ "requires": {}
+ },
+ "@wangeditor/table-module": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@wangeditor/table-module/-/table-module-1.1.4.tgz",
+ "integrity": "sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w==",
+ "requires": {}
+ },
+ "@wangeditor/upload-image-module": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@wangeditor/upload-image-module/-/upload-image-module-1.0.2.tgz",
+ "integrity": "sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA==",
+ "requires": {}
+ },
+ "@wangeditor/video-module": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@wangeditor/video-module/-/video-module-1.1.4.tgz",
+ "integrity": "sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==",
+ "requires": {}
+ },
+ "acorn": {
+ "version": "8.8.2",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
+ "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
+ "dev": true
+ },
+ "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": {}
+ },
+ "acorn-node": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmmirror.com/acorn-node/-/acorn-node-1.8.2.tgz",
+ "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==",
+ "dev": true,
+ "requires": {
+ "acorn": "^7.0.0",
+ "acorn-walk": "^7.0.0",
+ "xtend": "^4.0.2"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "7.4.1",
+ "resolved": "https://registry.npmmirror.com/acorn/-/acorn-7.4.1.tgz",
+ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+ "dev": true
+ }
+ }
+ },
+ "acorn-walk": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-7.2.0.tgz",
+ "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "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.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "requires": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ }
+ },
+ "arg": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmmirror.com/arg/-/arg-5.0.2.tgz",
+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
+ "dev": true
+ },
+ "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.2.5",
+ "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
+ "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+ },
+ "autoprefixer": {
+ "version": "10.4.13",
+ "resolved": "https://registry.npmmirror.com/autoprefixer/-/autoprefixer-10.4.13.tgz",
+ "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==",
+ "dev": true,
+ "requires": {
+ "browserslist": "^4.21.4",
+ "caniuse-lite": "^1.0.30001426",
+ "fraction.js": "^4.2.0",
+ "normalize-range": "^0.1.2",
+ "picocolors": "^1.0.0",
+ "postcss-value-parser": "^4.2.0"
+ }
+ },
+ "axios": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.3.tgz",
+ "integrity": "sha512-eYq77dYIFS77AQlhzEL937yUBSepBfPIe8FcgEDN35vMNZKMrs81pgnyrQpwfy4NF4b4XWX1Zgx7yX+25w8QJA==",
+ "requires": {
+ "follow-redirects": "^1.15.0",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.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.21.5",
+ "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.21.5.tgz",
+ "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==",
+ "dev": true,
+ "requires": {
+ "caniuse-lite": "^1.0.30001449",
+ "electron-to-chromium": "^1.4.284",
+ "node-releases": "^2.0.8",
+ "update-browserslist-db": "^1.0.10"
+ }
+ },
+ "call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "requires": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ }
+ },
+ "callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true
+ },
+ "camelcase-css": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmmirror.com/camelcase-css/-/camelcase-css-2.0.1.tgz",
+ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+ "dev": true
+ },
+ "caniuse-lite": {
+ "version": "1.0.30001458",
+ "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001458.tgz",
+ "integrity": "sha512-lQ1VlUUq5q9ro9X+5gOEyH7i3vm+AYVT1WDCVB69XOZ17KZRhnZ9J0Sqz7wTHQaLBJccNCHq8/Ww5LlOIZbB0w==",
+ "dev": 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"
+ }
+ }
+ }
+ },
+ "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"
+ }
+ },
+ "compute-scroll-into-view": {
+ "version": "1.0.20",
+ "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz",
+ "integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg=="
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "countup.js": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/countup.js/-/countup.js-2.4.2.tgz",
+ "integrity": "sha512-EExCcu5rd7ffBj65B3CVNuS1HddN1Y4WuTfJEuocJXwZlNnlXZQ4sD9M/Cq32ZS0zR38F9vGMCw/iFcVImrNbw=="
+ },
+ "cropperjs": {
+ "version": "1.5.13",
+ "resolved": "https://registry.npmjs.org/cropperjs/-/cropperjs-1.5.13.tgz",
+ "integrity": "sha512-by7jKAo73y5/Do0K6sxdTKHgndY0NMjG2bEdgeJxycbcmHuCiMXqw8sxy5C5Y5WTOTcDGmbT7Sr5CgKOXR06OA=="
+ },
+ "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.21",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz",
+ "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w=="
+ },
+ "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.7",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz",
+ "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ=="
+ },
+ "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
+ },
+ "defined": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmmirror.com/defined/-/defined-1.0.1.tgz",
+ "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==",
+ "dev": true
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
+ },
+ "delegate": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
+ "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw=="
+ },
+ "detective": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmmirror.com/detective/-/detective-5.2.1.tgz",
+ "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==",
+ "dev": true,
+ "requires": {
+ "acorn-node": "^1.8.2",
+ "defined": "^1.0.0",
+ "minimist": "^1.2.6"
+ }
+ },
+ "didyoumean": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmmirror.com/didyoumean/-/didyoumean-1.2.2.tgz",
+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "dlv": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmmirror.com/dlv/-/dlv-1.1.3.tgz",
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "echarts": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.4.1.tgz",
+ "integrity": "sha512-9ltS3M2JB0w2EhcYjCdmtrJ+6haZcW6acBolMGIuf01Hql1yrIV01L1aRj7jsaaIULJslEP9Z3vKlEmnJaWJVQ==",
+ "requires": {
+ "tslib": "2.3.0",
+ "zrender": "5.4.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.1.0",
+ "resolved": "https://registry.npmjs.org/echarts-wordcloud/-/echarts-wordcloud-2.1.0.tgz",
+ "integrity": "sha512-Kt1JmbcROgb+3IMI48KZECK2AP5lG6bSsOEs+AsuwaWJxQom31RTNd6NFYI01E/YaI1PFZeueaupjlmzSQasjQ==",
+ "requires": {}
+ },
+ "electron-to-chromium": {
+ "version": "1.4.313",
+ "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.313.tgz",
+ "integrity": "sha512-QckB9OVqr2oybjIrbMI99uF+b9+iTja5weFe0ePbqLb5BHqXOJUO1SG6kDj/1WtWPRIBr51N153AEq8m7HuIaA==",
+ "dev": true
+ },
+ "element-plus": {
+ "version": "2.2.32",
+ "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.2.32.tgz",
+ "integrity": "sha512-DTJMhYOy6MApbmh6z/95hPTK5WrBiNHGzV4IN+uEkup1WoimQ+Qyt8RxKdTe/X1LWEJ8YgWv/Cl8P4ocrt5z5g==",
+ "requires": {
+ "@ctrl/tinycolor": "^3.4.1",
+ "@element-plus/icons-vue": "^2.0.6",
+ "@floating-ui/dom": "^1.0.1",
+ "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
+ "@types/lodash": "^4.14.182",
+ "@types/lodash-es": "^4.17.6",
+ "@vueuse/core": "^9.1.0",
+ "async-validator": "^4.2.5",
+ "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.2.0"
+ }
+ },
+ "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"
+ }
+ },
+ "es5-ext": {
+ "version": "0.10.62",
+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
+ "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
+ "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": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+ "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.16.17",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz",
+ "integrity": "sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==",
+ "dev": true,
+ "requires": {
+ "@esbuild/android-arm": "0.16.17",
+ "@esbuild/android-arm64": "0.16.17",
+ "@esbuild/android-x64": "0.16.17",
+ "@esbuild/darwin-arm64": "0.16.17",
+ "@esbuild/darwin-x64": "0.16.17",
+ "@esbuild/freebsd-arm64": "0.16.17",
+ "@esbuild/freebsd-x64": "0.16.17",
+ "@esbuild/linux-arm": "0.16.17",
+ "@esbuild/linux-arm64": "0.16.17",
+ "@esbuild/linux-ia32": "0.16.17",
+ "@esbuild/linux-loong64": "0.16.17",
+ "@esbuild/linux-mips64el": "0.16.17",
+ "@esbuild/linux-ppc64": "0.16.17",
+ "@esbuild/linux-riscv64": "0.16.17",
+ "@esbuild/linux-s390x": "0.16.17",
+ "@esbuild/linux-x64": "0.16.17",
+ "@esbuild/netbsd-x64": "0.16.17",
+ "@esbuild/openbsd-x64": "0.16.17",
+ "@esbuild/sunos-x64": "0.16.17",
+ "@esbuild/win32-arm64": "0.16.17",
+ "@esbuild/win32-ia32": "0.16.17",
+ "@esbuild/win32-x64": "0.16.17"
+ }
+ },
+ "escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": true
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+ },
+ "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.34.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz",
+ "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==",
+ "dev": true,
+ "requires": {
+ "@eslint/eslintrc": "^1.4.1",
+ "@humanwhocodes/config-array": "^0.11.8",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "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.4.0",
+ "esquery": "^1.4.0",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "grapheme-splitter": "^1.0.4",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-sdsl": "^4.1.4",
+ "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"
+ },
+ "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.9.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.9.0.tgz",
+ "integrity": "sha512-YbubS7eK0J7DCf0U2LxvVP7LMfs6rC6UltihIgval3azO3gyDwEGVgsCMe1TmDiEkl6GdMKfRpaME6QxIYtzDQ==",
+ "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.4.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz",
+ "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==",
+ "dev": true,
+ "requires": {
+ "acorn": "^8.8.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.3.0"
+ }
+ },
+ "esquery": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.2.tgz",
+ "integrity": "sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==",
+ "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": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
+ "requires": {
+ "d": "1",
+ "es5-ext": "~0.10.14"
+ }
+ },
+ "ext": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
+ "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
+ "requires": {
+ "type": "^2.7.2"
+ },
+ "dependencies": {
+ "type": {
+ "version": "2.7.2",
+ "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
+ "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw=="
+ }
+ }
+ },
+ "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.12",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
+ "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+ "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": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true
+ },
+ "fastq": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+ "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+ "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"
+ }
+ },
+ "find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "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.7",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
+ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
+ "dev": true
+ },
+ "follow-redirects": {
+ "version": "1.15.2",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
+ "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
+ },
+ "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"
+ }
+ },
+ "fraction.js": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmmirror.com/fraction.js/-/fraction.js-4.2.0.tgz",
+ "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==",
+ "dev": true
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "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=="
+ },
+ "get-intrinsic": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
+ "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
+ "requires": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.3"
+ }
+ },
+ "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"
+ }
+ },
+ "globals": {
+ "version": "13.20.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
+ "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+ "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": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==",
+ "requires": {
+ "delegate": "^3.1.2"
+ }
+ },
+ "grapheme-splitter": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+ "dev": true
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "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
+ },
+ "has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
+ },
+ "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.4",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+ "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+ "dev": true
+ },
+ "immer": {
+ "version": "9.0.19",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.19.tgz",
+ "integrity": "sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ=="
+ },
+ "immutable": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.4.tgz",
+ "integrity": "sha512-WDxL3Hheb1JkRN3sQkyujNlL/xRjAo3rJtaU5xeufUauG66JdMr32bLj4gF+vWl84DIA3Zxw7tiAjneYzRRw+w==",
+ "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": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "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.11.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
+ "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
+ "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": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "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-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "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": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true
+ },
+ "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-sdsl": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
+ "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
+ "dev": true
+ },
+ "js-table2excel": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/js-table2excel/-/js-table2excel-1.0.3.tgz",
+ "integrity": "sha512-ivzOdgYqOD3zqzJZfW0Nm35P9BWffxD0Unwr+2QBeEawV7hhRY9RHBVNcvO6A9PhGkMyqPVL/u4/NeufaTTTXw=="
+ },
+ "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-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": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true
+ },
+ "jsplumb": {
+ "version": "2.15.6",
+ "resolved": "https://registry.npmjs.org/jsplumb/-/jsplumb-2.15.6.tgz",
+ "integrity": "sha512-sIpbpz5eMVM+vV+MQzFCidlaa1RsknrQs6LOTKYDjYUDdTAi2AN2bFi94TxB33TifcIsRNV1jebcaxg0tCoPzg=="
+ },
+ "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"
+ }
+ },
+ "lilconfig": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmmirror.com/lilconfig/-/lilconfig-2.0.6.tgz",
+ "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==",
+ "dev": true
+ },
+ "locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^5.0.0"
+ }
+ },
+ "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.3",
+ "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.3.tgz",
+ "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==",
+ "requires": {}
+ },
+ "lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
+ },
+ "lodash.clonedeep": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+ "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ=="
+ },
+ "lodash.debounce": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
+ },
+ "lodash.foreach": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
+ "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ=="
+ },
+ "lodash.isequal": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+ "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
+ },
+ "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.throttle": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
+ "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="
+ },
+ "lodash.toarray": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
+ "integrity": "sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw=="
+ },
+ "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=="
+ },
+ "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": "sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==",
+ "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"
+ }
+ },
+ "minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "dev": true
+ },
+ "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": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true
+ },
+ "natural-compare-lite": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
+ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
+ "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.10",
+ "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.10.tgz",
+ "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==",
+ "dev": 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-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmmirror.com/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+ "dev": true
+ },
+ "normalize-wheel-es": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz",
+ "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw=="
+ },
+ "nprogress": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz",
+ "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA=="
+ },
+ "nth-check": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+ "dev": true,
+ "requires": {
+ "boolbase": "^1.0.0"
+ }
+ },
+ "object-hash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmmirror.com/object-hash/-/object-hash-3.0.0.tgz",
+ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
+ "dev": true
+ },
+ "object-inspect": {
+ "version": "1.12.3",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
+ "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g=="
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "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"
+ }
+ },
+ "p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "requires": {
+ "yocto-queue": "^0.1.0"
+ }
+ },
+ "p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^3.0.2"
+ }
+ },
+ "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-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "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
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmmirror.com/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "dev": true
+ },
+ "pinia": {
+ "version": "2.0.32",
+ "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.0.32.tgz",
+ "integrity": "sha512-8Tw4OrpCSJ028UUyp0gYPP/wyjigLoEceuO/x1G+FlHVf73337e5vLm4uDmrRIoBG1hvaed/eSHnrCFjOc4nkA==",
+ "requires": {
+ "@vue/devtools-api": "^6.5.0",
+ "vue-demi": "*"
+ },
+ "dependencies": {
+ "vue-demi": {
+ "version": "0.13.11",
+ "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
+ "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
+ "requires": {}
+ }
+ }
+ },
+ "postcss": {
+ "version": "8.4.21",
+ "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.21.tgz",
+ "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
+ "requires": {
+ "nanoid": "^3.3.4",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.0.2"
+ }
+ },
+ "postcss-import": {
+ "version": "14.1.0",
+ "resolved": "https://registry.npmmirror.com/postcss-import/-/postcss-import-14.1.0.tgz",
+ "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==",
+ "dev": true,
+ "requires": {
+ "postcss-value-parser": "^4.0.0",
+ "read-cache": "^1.0.0",
+ "resolve": "^1.1.7"
+ }
+ },
+ "postcss-js": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmmirror.com/postcss-js/-/postcss-js-4.0.1.tgz",
+ "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
+ "dev": true,
+ "requires": {
+ "camelcase-css": "^2.0.1"
+ }
+ },
+ "postcss-load-config": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmmirror.com/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
+ "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
+ "dev": true,
+ "requires": {
+ "lilconfig": "^2.0.5",
+ "yaml": "^1.10.2"
+ }
+ },
+ "postcss-nested": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmmirror.com/postcss-nested/-/postcss-nested-6.0.0.tgz",
+ "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==",
+ "dev": true,
+ "requires": {
+ "postcss-selector-parser": "^6.0.10"
+ }
+ },
+ "postcss-selector-parser": {
+ "version": "6.0.11",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz",
+ "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==",
+ "dev": true,
+ "requires": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ }
+ },
+ "postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "dev": true
+ },
+ "preact": {
+ "version": "10.12.1",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.12.1.tgz",
+ "integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg=="
+ },
+ "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.8.4",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz",
+ "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==",
+ "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.29.0",
+ "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz",
+ "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q=="
+ },
+ "proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+ },
+ "punycode": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
+ "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
+ "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=="
+ },
+ "qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "requires": {
+ "side-channel": "^1.0.4"
+ }
+ },
+ "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
+ },
+ "quick-lru": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmmirror.com/quick-lru/-/quick-lru-5.1.1.tgz",
+ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+ "dev": true
+ },
+ "read-cache": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz",
+ "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+ "dev": true,
+ "requires": {
+ "pify": "^2.3.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.11",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
+ },
+ "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.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+ "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+ "dev": true,
+ "requires": {
+ "is-core-module": "^2.9.0",
+ "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": "3.17.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.17.2.tgz",
+ "integrity": "sha512-qMNZdlQPCkWodrAZ3qnJtvCAl4vpQ8q77uEujVCCbC/6CLB7Lcmvjq7HyiOSnf4fxTT9XgsE36oLHJBH49xjqA==",
+ "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"
+ }
+ },
+ "sass": {
+ "version": "1.58.3",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.58.3.tgz",
+ "integrity": "sha512-Q7RaEtYf6BflYrQ+buPudKR26/lH+10EmO9bBqbmPh/KeLqv8bjpTNqxe71ocONqXq+jYiCbpPUmQMS+JJPk4A==",
+ "dev": true,
+ "requires": {
+ "chokidar": ">=3.0.0 <4.0.0",
+ "immutable": "^4.0.0",
+ "source-map-js": ">=0.6.2 <2.0.0"
+ }
+ },
+ "screenfull": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/screenfull/-/screenfull-6.0.2.tgz",
+ "integrity": "sha512-AQdy8s4WhNvUZ6P8F6PB21tSPIYKniic+Ogx0AacBMjKP1GUHN2E9URxQHtCusiwxudnCKkdy4GrHXPPJSkCCw=="
+ },
+ "scroll-into-view-if-needed": {
+ "version": "2.2.31",
+ "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz",
+ "integrity": "sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==",
+ "requires": {
+ "compute-scroll-into-view": "^1.0.20"
+ }
+ },
+ "select": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
+ "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA=="
+ },
+ "semver": {
+ "version": "7.3.8",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+ "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.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
+ },
+ "side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "requires": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ }
+ },
+ "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.1",
+ "resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.5.1.tgz",
+ "integrity": "sha512-wHMNIOjkm/YNE5EM3RCbr/+DVgPg6AqQAX1eOxO46zYNvCXjKP5Y865tqQj3EXnaMBjkxmQA5jFuDpDK/dbfiA=="
+ },
+ "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=="
+ },
+ "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.5",
+ "resolved": "https://registry.npmjs.org/splitpanes/-/splitpanes-3.1.5.tgz",
+ "integrity": "sha512-r3Mq2ITFQ5a2VXLOy4/Sb2Ptp7OfEO8YIbhVJqJXoFc9hc5nTXXkCvtVDjIGbvC0vdE7tse+xTM9BMjsszP6bw=="
+ },
+ "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
+ },
+ "tailwindcss": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.2.7.tgz",
+ "integrity": "sha512-B6DLqJzc21x7wntlH/GsZwEXTBttVSl1FtCzC8WP4oBc/NKef7kaax5jeihkkCEWc831/5NDJ9gRNDK6NEioQQ==",
+ "dev": true,
+ "requires": {
+ "arg": "^5.0.2",
+ "chokidar": "^3.5.3",
+ "color-name": "^1.1.4",
+ "detective": "^5.2.1",
+ "didyoumean": "^1.2.2",
+ "dlv": "^1.1.3",
+ "fast-glob": "^3.2.12",
+ "glob-parent": "^6.0.2",
+ "is-glob": "^4.0.3",
+ "lilconfig": "^2.0.6",
+ "micromatch": "^4.0.5",
+ "normalize-path": "^3.0.0",
+ "object-hash": "^3.0.0",
+ "picocolors": "^1.0.0",
+ "postcss": "^8.0.9",
+ "postcss-import": "^14.1.0",
+ "postcss-js": "^4.0.0",
+ "postcss-load-config": "^3.1.4",
+ "postcss-nested": "6.0.0",
+ "postcss-selector-parser": "^6.0.11",
+ "postcss-value-parser": "^4.2.0",
+ "quick-lru": "^5.1.1",
+ "resolve": "^1.22.1"
+ }
+ },
+ "text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "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"
+ }
+ },
+ "ts-enum-util": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmmirror.com/ts-enum-util/-/ts-enum-util-4.0.2.tgz",
+ "integrity": "sha512-BB5qjvHYgYgOB/CaoA1Cy/B2QNnZ+nVBrJ15VV/AXGWx+AO83k5wgeLOJvkSLoKKavvH/M8Wj4ZbgROjsuYwzw=="
+ },
+ "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.9.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
+ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
+ "devOptional": true
+ },
+ "update-browserslist-db": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
+ "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
+ "dev": true,
+ "requires": {
+ "escalade": "^3.1.1",
+ "picocolors": "^1.0.0"
+ }
+ },
+ "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": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true
+ },
+ "vite": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-4.1.4.tgz",
+ "integrity": "sha512-3knk/HsbSTKEin43zHu7jTwYWv81f8kgAL99G5NWBcA1LKvtvcVAC4JjBH1arBunO9kQka+1oGbrMKOjk4ZrBg==",
+ "dev": true,
+ "requires": {
+ "esbuild": "^0.16.14",
+ "fsevents": "~2.3.2",
+ "postcss": "^8.4.21",
+ "resolve": "^1.22.1",
+ "rollup": "^3.10.0"
+ }
+ },
+ "vite-plugin-vue-setup-extend": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/vite-plugin-vue-setup-extend/-/vite-plugin-vue-setup-extend-0.4.0.tgz",
+ "integrity": "sha512-WMbjPCui75fboFoUTHhdbXzu4Y/bJMv5N9QT9a7do3wNMNHHqrk+Tn2jrSJU0LS5fGl/EG+FEDBYVUeWIkDqXQ==",
+ "dev": true,
+ "requires": {
+ "@vue/compiler-sfc": "^3.2.29",
+ "magic-string": "^0.25.7"
+ }
+ },
+ "vue": {
+ "version": "3.2.47",
+ "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.47.tgz",
+ "integrity": "sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ==",
+ "requires": {
+ "@vue/compiler-dom": "3.2.47",
+ "@vue/compiler-sfc": "3.2.47",
+ "@vue/runtime-dom": "3.2.47",
+ "@vue/server-renderer": "3.2.47",
+ "@vue/shared": "3.2.47"
+ }
+ },
+ "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.1.0",
+ "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.1.0.tgz",
+ "integrity": "sha512-NGn/iQy8/Wb7RrRa4aRkokyCZfOUWk19OP5HP6JEozQFX5AoS/t+Z0ZN7FY4LlmWc4FNI922V7cvX28zctN8dQ==",
+ "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.2.2",
+ "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.2.2.tgz",
+ "integrity": "sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==",
+ "requires": {
+ "@intlify/core-base": "9.2.2",
+ "@intlify/shared": "9.2.2",
+ "@intlify/vue-devtools": "9.2.2",
+ "@vue/devtools-api": "^6.2.1"
+ }
+ },
+ "vue-router": {
+ "version": "4.1.6",
+ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.1.6.tgz",
+ "integrity": "sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==",
+ "requires": {
+ "@vue/devtools-api": "^6.4.5"
+ }
+ },
+ "vuedraggable": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmmirror.com/vuedraggable/-/vuedraggable-4.1.0.tgz",
+ "integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==",
+ "requires": {
+ "sortablejs": "1.14.0"
+ },
+ "dependencies": {
+ "sortablejs": {
+ "version": "1.14.0",
+ "resolved": "https://registry.npmmirror.com/sortablejs/-/sortablejs-1.14.0.tgz",
+ "integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="
+ }
+ }
+ },
+ "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": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng=="
+ },
+ "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": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "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
+ },
+ "xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "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
+ },
+ "yaml": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmmirror.com/yaml/-/yaml-1.10.2.tgz",
+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+ "dev": true
+ },
+ "yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true
+ },
+ "zrender": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.4.1.tgz",
+ "integrity": "sha512-M4Z05BHWtajY2241EmMPHglDQAJ1UyHQcYsxDNzD9XLSkPDqMq4bB28v9Pb4mvHnVQ0GxyTklZ/69xCFP6RXBA==",
+ "requires": {
+ "tslib": "2.3.0"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..32be4ba
--- /dev/null
+++ b/package.json
@@ -0,0 +1,90 @@
+{
+ "name": "vue-next-admin",
+ "version": "2.4.3",
+ "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.10",
+ "@form-create/element-ui": "^3.1.18",
+ "@wangeditor/editor": "^5.1.23",
+ "@wangeditor/editor-for-vue": "^5.1.12",
+ "axios": "^1.3.3",
+ "countup.js": "^2.4.2",
+ "cropperjs": "^1.5.13",
+ "echarts": "^5.4.1",
+ "echarts-gl": "^2.0.9",
+ "echarts-wordcloud": "^2.1.0",
+ "element-plus": "^2.2.32",
+ "js-cookie": "^3.0.1",
+ "js-table2excel": "^1.0.3",
+ "jsplumb": "^2.15.6",
+ "mitt": "^3.0.0",
+ "nprogress": "^0.2.0",
+ "pinia": "^2.0.32",
+ "print-js": "^1.6.0",
+ "qrcodejs2-fixes": "^0.0.2",
+ "qs": "^6.11.0",
+ "screenfull": "^6.0.2",
+ "sortablejs": "^1.15.0",
+ "splitpanes": "^3.1.5",
+ "ts-enum-util": "^4.0.2",
+ "vue": "^3.2.47",
+ "vue-clipboard3": "^2.0.0",
+ "vue-grid-layout": "^3.0.0-beta1",
+ "vue-i18n": "^9.2.2",
+ "vue-router": "^4.1.6",
+ "vuedraggable": "^4.1.0"
+ },
+ "devDependencies": {
+ "@iconify/vue": "^4.1.0",
+ "@types/node": "^18.14.0",
+ "@types/nprogress": "^0.2.0",
+ "@types/sortablejs": "^1.15.0",
+ "@typescript-eslint/eslint-plugin": "^5.53.0",
+ "@typescript-eslint/parser": "^5.53.0",
+ "@vitejs/plugin-vue": "^4.0.0",
+ "@vue/compiler-sfc": "^3.2.47",
+ "autoprefixer": "^10.4.13",
+ "eslint": "^8.34.0",
+ "eslint-plugin-vue": "^9.9.0",
+ "postcss": "^8.4.21",
+ "prettier": "^2.8.4",
+ "sass": "^1.58.3",
+ "tailwindcss": "^3.2.7",
+ "typescript": "^4.9.5",
+ "vite": "^4.1.4",
+ "vite-plugin-vue-setup-extend": "^0.4.0",
+ "vue-eslint-parser": "^9.1.0"
+ },
+ "browserslist": [
+ "> 1%",
+ "last 2 versions",
+ "not dead"
+ ],
+ "bugs": {
+ "url": "https://gitee.com/lyt-top/vue-next-admin/issues"
+ },
+ "engines": {
+ "node": ">=16.0.0",
+ "npm": ">= 7.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/postcss.config.js b/postcss.config.js
new file mode 100644
index 0000000..33ad091
--- /dev/null
+++ b/postcss.config.js
@@ -0,0 +1,6 @@
+module.exports = {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+}
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000..542c1bc
Binary files /dev/null and b/public/favicon.ico differ
diff --git a/README.md b/README.md
index 53cafa0..d7c1f35 100644
--- a/README.md
+++ b/README.md
@@ -1,23 +1,26 @@
# NewLife.QuickVue
#### 介绍
+
前端页面快速开发
#### 软件架构
-软件架构说明
+软件架构说明
#### 安装教程
-1. xxxx
-2. xxxx
-3. xxxx
+1. 克隆项目到本地
+2. npm i
+3. npm run dev
#### 使用说明
-1. xxxx
-2. xxxx
-3. xxxx
+1. 从接口读取到的路由默认使用 views/modules/index.vue 文件
+2. 在 views/modules 下面按照路由规则新建文件会自动引用
+3. 可参考 views/modules/admin/user/index 进行页面编写
+4. page 组件可通过 usePageSetting 函数按照一定的规则进行页面配置
+ 若组件不够可以增加组件,对于复杂组件支持使用自定义插槽渲染(通过配置项 slot)
#### 参与贡献
@@ -25,13 +28,3 @@
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
-
-
-#### 特技
-
-1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
-2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
-3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
-4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
-5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
-6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
diff --git a/src/api/menu.ts b/src/api/menu.ts
new file mode 100644
index 0000000..116b65b
--- /dev/null
+++ b/src/api/menu.ts
@@ -0,0 +1,40 @@
+import { Menu } from '../model/api/menu';
+import { ApiResult } from '/@/model/api/common';
+import { GetMenuTree } from '/@/model/api/login';
+import request from '/@/utils/request';
+
+/**
+ * 以下为模拟接口地址,gitee 的不通,就换自己的真实接口地址
+ *
+ * (不建议写成 request.post(xxx),因为这样 post 时,无法 params 与 data 同时传参)
+ *
+ * 后端控制菜单模拟json,路径在 https://gitee.com/lyt-top/vue-next-admin-images/tree/master/menu
+ * 后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
+ * @method getAdminMenu 获取后端动态路由菜单(admin)
+ * @method getTestMenu 获取后端动态路由菜单(test)
+ */
+export function useMenuApi() {
+ return {
+ getAdminMenu: (params?: object) => {
+ return request<GetMenuTree>({
+ url: '/admin/index/GetMenuTree',
+ method: 'get',
+ params,
+ });
+ },
+ getTestMenu: (params?: object) => {
+ return request<GetMenuTree>({
+ url: '/admin/index/GetMenuTree',
+ method: 'get',
+ params,
+ });
+ },
+ getMenu: (params?: object) => {
+ return request<Menu[]>({
+ url: '/Admin/Index/GetMenuTree',
+ method: 'get',
+ params,
+ });
+ },
+ };
+}
diff --git a/src/api/page.ts b/src/api/page.ts
new file mode 100644
index 0000000..8ceeaf2
--- /dev/null
+++ b/src/api/page.ts
@@ -0,0 +1,70 @@
+import { PageProps } from '../model/api/common';
+import { Column } from '../model/api/page';
+import request from '/@/utils/request';
+
+export enum ColumnKind {
+ LIST = 1,
+ DETAIL,
+ ADD,
+ EDIT,
+ SEARCH
+}
+/**
+ * (不建议写成 request.post(xxx),因为这样 post 时,无法 params 与 data 同时传参)
+ *
+ * 登录api接口集合
+ * @method signIn 用户登录
+ * @method signOut 用户退出登录
+ */
+export function usePageApi() {
+ return {
+ getColumns: (type: string, kind: ColumnKind) => {
+ return request<Column[]>({
+ url: `${type}/GetFields`,
+ method: 'get',
+ params: {
+ kind
+ }
+ });
+ },
+ getTableData: <T extends {}>(type: string, params: EmptyObjectType & PageProps) => {
+ return request<T[]>({
+ url: type,
+ method: 'get',
+ params
+ });
+ },
+ getTableDetail: <T extends {}>(type: string, id: number) => {
+ return request<T>({
+ url: type + '/Detail',
+ method: 'get',
+ params: {
+ id
+ }
+ });
+ },
+ setTableItem: (type: string, data: EmptyObjectType) => {
+ return request({
+ url: type,
+ method: 'put',
+ data
+ });
+ },
+ addTableItem: (type: string, data: EmptyObjectType) => {
+ return request({
+ url: type,
+ method: 'post',
+ data
+ });
+ },
+ delTableItem: (type: string, id: number) => {
+ return request({
+ url: type,
+ method: 'delete',
+ params: {
+ id
+ }
+ });
+ },
+ };
+}
\ No newline at end of file
diff --git a/src/api/user.ts b/src/api/user.ts
new file mode 100644
index 0000000..6771e22
--- /dev/null
+++ b/src/api/user.ts
@@ -0,0 +1,34 @@
+import { Login, UserInfo } from '../model/api/user';
+import request from '/@/utils/request';
+
+/**
+ * (不建议写成 request.post(xxx),因为这样 post 时,无法 params 与 data 同时传参)
+ *
+ * 登录api接口集合
+ * @method signIn 用户登录
+ * @method signOut 用户退出登录
+ */
+export function useUserApi() {
+ return {
+ signIn: (data: object) => {
+ return request<Login>({
+ url: '/admin/user/login',
+ method: 'post',
+ data,
+ });
+ },
+ signOut: (data: object) => {
+ return request({
+ url: '/user/signOut',
+ method: 'post',
+ data,
+ });
+ },
+ info: () => {
+ return request<UserInfo>({
+ url: '/Admin/User/Info/',
+ method: 'get'
+ });
+ },
+ };
+}
\ No newline at end of file
diff --git a/src/App.vue b/src/App.vue
new file mode 100644
index 0000000..ba1ca55
--- /dev/null
+++ b/src/App.vue
@@ -0,0 +1,101 @@
+<template>
+ <el-config-provider :size="getGlobalComponentSize" :locale="getGlobalI18n">
+ <router-view v-show="setLockScreen" />
+ <LockScreen v-if="themeConfig.isLockScreen" />
+ <Setings ref="setingsRef" v-show="setLockScreen" />
+ <CloseFull v-if="!themeConfig.isLockScreen" />
+ <!-- <Upgrade v-if="getVersion" /> -->
+ <!-- <Sponsors /> -->
+ </el-config-provider>
+</template>
+
+<script setup lang="ts" name="app">
+import { defineAsyncComponent, computed, ref, onBeforeMount, onMounted, onUnmounted, nextTick, watch } from 'vue';
+import { useRoute } from 'vue-router';
+import { useI18n } from 'vue-i18n';
+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 mittBus from '/@/utils/mitt';
+import setIntroduction from '/@/utils/setIconfont';
+
+// 引入组件
+const LockScreen = defineAsyncComponent(() => import('/@/layout/lockScreen/index.vue'));
+const Setings = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/setings.vue'));
+const CloseFull = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/closeFull.vue'));
+const Upgrade = defineAsyncComponent(() => import('/@/layout/upgrade/index.vue'));
+const Sponsors = defineAsyncComponent(() => import('/@/layout/sponsors/index.vue'));
+
+// 定义变量内容
+const { messages, locale } = useI18n();
+const setingsRef = ref();
+const route = useRoute();
+const stores = useTagsViewRoutes();
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+
+// 设置锁屏时组件显示隐藏
+const setLockScreen = computed(() => {
+ // 防止锁屏后,刷新出现不相关界面
+ // https://gitee.com/lyt-top/vue-next-admin/issues/I6AF8P
+ return themeConfig.value.isLockScreen ? themeConfig.value.lockScreenTime > 1 : themeConfig.value.lockScreenTime >= 0;
+});
+// 获取版本号
+const getVersion = computed(() => {
+ let isVersion = false;
+ if (route.path !== '/login') {
+ // @ts-ignore
+ if ((Local.get('version') && Local.get('version') !== __NEXT_VERSION__) || !Local.get('version')) isVersion = true;
+ }
+ return isVersion;
+});
+// 获取全局组件大小
+const getGlobalComponentSize = computed(() => {
+ return other.globalComponentSize();
+});
+// 获取全局 i18n
+const getGlobalI18n = computed(() => {
+ return messages.value[locale.value];
+});
+// 设置初始化,防止刷新时恢复默认
+onBeforeMount(() => {
+ // 设置批量第三方 icon 图标
+ setIntroduction.cssCdn();
+ // 设置批量第三方 js
+ setIntroduction.jsCdn();
+});
+// 页面加载时
+onMounted(() => {
+ nextTick(() => {
+ // 监听布局配'置弹窗点击打开
+ mittBus.on('openSetingsDrawer', () => {
+ setingsRef.value.openDrawer();
+ });
+ // 获取缓存中的布局配置
+ if (Local.get('themeConfig')) {
+ storesThemeConfig.setThemeConfig({ themeConfig: Local.get('themeConfig') });
+ document.documentElement.style.cssText = Local.get('themeConfigStyle');
+ }
+ // 获取缓存中的全屏配置
+ if (Session.get('isTagsViewCurrenFull')) {
+ stores.setCurrenFullscreen(Session.get('isTagsViewCurrenFull'));
+ }
+ });
+});
+// 页面销毁时,关闭监听布局配置/i18n监听
+onUnmounted(() => {
+ mittBus.off('openSetingsDrawer', () => {});
+});
+// 监听路由的变化,设置网站标题
+watch(
+ () => route.path,
+ () => {
+ other.useTitle();
+ },
+ {
+ deep: true,
+ }
+);
+</script>
diff --git a/src/assets/ccflowRightNextAdmin.png b/src/assets/ccflowRightNextAdmin.png
new file mode 100644
index 0000000..9b44a6e
Binary files /dev/null and b/src/assets/ccflowRightNextAdmin.png differ
diff --git a/src/assets/login-bg.svg b/src/assets/login-bg.svg
new file mode 100644
index 0000000..a345a54
--- /dev/null
+++ b/src/assets/login-bg.svg
@@ -0,0 +1,19 @@
+<svg width="100" height="969"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" shape-rendering="auto" preserveAspectRatio="none" class="layout-footer-waves">
+ <g id="Layer_1">
+ <title>Layer 1</title>
+ <g transform="rotate(2.18686 -4.09974 506.2)" stroke="null" id="svg_5">
+ <defs stroke="null" transform="translate(0.00121616 0.0635973) translate(-0.844727 0.185777) translate(-4.69751 0.0674522) translate(4.80739 0.470252) translate(4.47211 0.0666505) translate(-47.1425 4.28569) translate(7.74305 4.90188) translate(-28.5712 -22.857) translate(-0.219291 4.06319) translate(-1.32311 -4.516) translate(22.5706 18.2109) translate(-49.4342 -5.96675) translate(-0.909089 0) translate(0.909089 0) translate(-0.909089 0) translate(-0.909089 0) translate(-0.909089 0) translate(-3.33335 0) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(-7.34665 -0.396492) translate(-1.66666 0) translate(-1.66666 0) translate(-0.12551 2.32567) translate(-0.707827 0.218105) translate(-1.66666 0) translate(1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-2.15731 0.0264734) translate(1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(0 -1.66666) translate(0 -1.66666) translate(1.66666 0) translate(0 -1.66666) translate(1.66666 0) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(0 -1.66666) translate(0 -1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(-1.66666 0) translate(0 1.66666) translate(-1.66666 0) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(0 -1.66666) translate(0 -1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.56355 1.02885) translate(-7.50004 -25.0001) translate(-3.19245 0.846904) translate(5.00003 -97.5005) translate(-9.62431 -0.829817) translate(27.5002 -220.001) translate(-6.96615 1.62281) translate(1.10472 -2.23004) translate(-9.63847 0.899196) translate(7.04019 0.0560654) translate(-11.25 -16.25) translate(2.11523 2.02597) translate(-27.1193 -20.3394) translate(-10.8798 -0.397069) translate(-44.0688 -110.172) translate(-1.69495 5.08486) translate(-8.57191 2.416) translate(-67.7982 -69.4931) translate(-0.127168 3.4846) translate(-16.9495 -283.057) translate(-4.64027 -0.169348) translate(1 0) translate(71.5022 0) translate(0 127.337) translate(-78.8263 -168.947) scale(0.564803 0.937256) translate(78.8263 168.947) translate(-139.564 1126.64) scale(1 0.752632) translate(139.564 -1126.64) translate(-139.564 190.036) scale(1 0.902375) translate(139.564 -190.036) translate(-139.564 210.595) scale(1.30003 1) translate(139.564 -210.595) translate(-107.355 1517.49) scale(1 1.16096) translate(107.355 -1517.49) translate(-107.355 0.205247) scale(1 1.13183) translate(107.355 -0.205247) translate(-136.758 -338.436) scale(1.50148 1) translate(136.758 338.436) translate(-152.694 -417.354) scale(1.2612 1.21266) translate(152.694 417.354) translate(-160.148 -445.389) scale(1 1.22519) translate(160.148 445.389) translate(-187.477 -380.211) scale(1.1479 0.963065) translate(187.477 380.211) translate(-169.043 -406.673) scale(0.986706 0.876627) translate(169.043 406.673) translate(-166.85 -463.854) scale(1.08382 1.19196) translate(166.85 463.854) translate(-159.592 918.456) scale(0.859634 1.01716) translate(159.592 -918.456) translate(-184.899 -405.678) scale(1.135 1.11385) translate(184.899 405.678) translate(-150.577 -518.346) scale(0.986699 1.09676) translate(150.577 518.346) translate(-155.421 -535.896) scale(1.04426 1.02871) translate(155.421 535.896) translate(-155.064 -536.049) scale(1.0463 1.01338) translate(155.064 536.049) translate(-165.783 -521.136) scale(1.00568 1.01887) translate(165.783 521.136) translate(-170.657 -511.469) scale(1.01013 1.00598) translate(170.657 511.469) translate(-169.334 -508.298) scale(1.09126 1) translate(169.334 508.298) translate(-156.911 -506.897) scale(1 1.06292) translate(156.911 506.897) translate(-163.644 765.54) scale(0.881707 0.600266) translate(163.644 -765.54) translate(45.8836 -37.1657) scale(0.309 0.684766) translate(-45.8836 37.1657) translate(-69.5385 1277.7) scale(0.415094 0.969376) translate(69.5385 -1277.7) translate(-173.403 4.77105) scale(2.29193 1) translate(173.403 -4.77105) translate(-131.465 -21.955) scale(1.62026 0.838547) translate(131.465 21.955) translate(-128.274 -10.6013) scale(0.965372 1.26492) translate(128.274 10.6013) translate(-127.333 -8.29175) scale(0.874565 1.22473) translate(127.333 8.29175) translate(-138.784 -6.2554) scale(1.00883 0.82026) translate(138.784 6.2554) translate(-144.168 -7.53605) scale(1.05722 1.04501) translate(144.168 7.53605) translate(-137.487 -6.97423) scale(1.01704 0.999876) translate(137.487 6.97423)">
+ <path stroke="null" id="svg_3" d="m-160,44c30,0 58,-18 88,-18s58,18 88,18s58,-18 88,-18s58,18 88,18l0,44l-352,0l0,-44z"/>
+ </defs>
+ <g stroke="null" id="svg_6">
+ <title stroke="null">Layer 1</title>
+ <g stroke="null" transform="matrix(-0.0217456 0.782606 -0.765199 -0.0222404 584.591 1129.22)" class="layout-footer-waves-g" id="svg_1">
+ <use stroke="null" href="#svg_3" x="-328.61098" y="405.36815" fill="rgba(211, 239, 255, 1)" id="svg_4" transform="matrix(3.69628 0 0 3.42743 381.903 -787.25)"/>
+ <use stroke="null" href="#svg_3" x="-333.61098" y="401.76815" fill="rgba(211, 239, 255, 0.5)" id="svg_2" transform="matrix(3.69628 0 0 3.42743 381.903 -787.25)"/>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
\ No newline at end of file
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/login-main.svg b/src/assets/login-main.svg
new file mode 100644
index 0000000..60dbe7c
--- /dev/null
+++ b/src/assets/login-main.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" data-name="Layer 1" width="1030.01" height="729.86" viewBox="0 0 1030.01 729.86"><defs><linearGradient id="a5312bde-8c7e-4767-9e17-08a43f21bf92-27" x1="889.13" y1="701.85" x2="889.13" y2="363.3" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="gray" stop-opacity="0.25"/><stop offset="0.54" stop-color="gray" stop-opacity="0.12"/><stop offset="1" stop-color="gray" stop-opacity="0.1"/></linearGradient><linearGradient id="016d359d-0d48-4404-968f-1612e9b5c7a7-28" x1="376.53" y1="777.06" x2="376.53" y2="381.85" xlink:href="#a5312bde-8c7e-4767-9e17-08a43f21bf92-27"/></defs><title>static_assets</title><ellipse cx="814.66" cy="585.22" rx="211.36" ry="41.08" fill="#f9a826" opacity="0.1"/><g opacity="0.5"><path d="M718.61,188.63c-2.85.81-6.34,2.92-8.06,8.69-3.37,11.31,4.46,19,1.88,30.79a23,23,0,0,1-4,8.64c-3.15,4.27-6.57,6.29-9.89,9.28a29.5,29.5,0,0,0-8.69,14.27,39.5,39.5,0,0,0-.39,18.55c1.18,5.12,3.19,8.85,4.95,13a96,96,0,0,1,5.11,16.37,39.87,39.87,0,0,1,1.12,8.32,73.21,73.21,0,0,1-1,11.12l-4.79,33.42a100.43,100.43,0,0,0-1.31,13.21,65.61,65.61,0,0,0,1.53,13.19c1.68,8.84,3.49,18,7.34,22.68s10.41,3,14.44-6.47c3.83-9.06,3.92-21.15,7.3-30.83,5.33-15.25,15.92-17.3,21.8-31.85,5.64-14,3.91-31.08,6.77-47,2-11.41,6.41-21.81,9-33.08,3.72-16.23,3.35-33.08.38-45.56a60.55,60.55,0,0,0-14.18-27.54c-2.49-2.75-5.16-5.2-8.29-5.45-3.33-.26-6.24,3.93-9.53,5.19C726.3,189.06,722.48,187.53,718.61,188.63Z" transform="translate(-84.99 -85.07)" fill="#f9a826"/><path d="M736.64,183.23S731,327.57,707.28,412.68" transform="translate(-84.99 -85.07)" fill="none" stroke="#535461" stroke-miterlimit="10" stroke-width="2"/><path d="M710.41,198s25.35,23.08,20.54,67" transform="translate(-84.99 -85.07)" fill="none" stroke="#535461" stroke-miterlimit="10" stroke-width="2"/><path d="M689.14,263.68s41.61,8.37,38.52,33.26" transform="translate(-84.99 -85.07)" fill="none" stroke="#535461" stroke-miterlimit="10" stroke-width="2"/><path d="M762.17,215.07s-16.84,14.74-31.84,56.49" transform="translate(-84.99 -85.07)" fill="none" stroke="#535461" stroke-miterlimit="10" stroke-width="2"/><path d="M745.72,341.25s-11.49,9-20.71-22.51" transform="translate(-84.99 -85.07)" fill="none" stroke="#535461" stroke-miterlimit="10" stroke-width="2"/><path d="M696.14,359.66s23.43-3.06,25.59-17.73" transform="translate(-84.99 -85.07)" fill="none" stroke="#535461" stroke-miterlimit="10" stroke-width="2"/></g><path d="M775.25,91.82c-5.8.86-12.78,3.55-15.65,11.84-5.63,16.26,11.48,28.57,7.54,45.56A25.53,25.53,0,0,1,760,161.47c-6,5.91-12.86,8.49-19.36,12.5s-13.25,10.32-16.3,20c-2.93,9.31-1.66,19.59,1.39,27.27s7.66,13.41,11.78,19.73A133.69,133.69,0,0,1,750,265.67,46.94,46.94,0,0,1,753.32,278c.53,5.2-.14,10.79-.81,16.26L746.56,343c-.79,6.48-1.59,13.06-1.14,19.3.51,7.19,2.64,13.47,4.74,19.6,4.52,13.22,9.36,27,17.89,34.28s21.91,5.72,29.12-7.82c6.86-12.89,5.6-30.68,11.45-44.53,9.22-21.83,30.9-23.6,41.33-44.32,10-19.88,4.41-45.31,8.43-68.41,2.88-16.55,10.68-31.35,14.68-47.64,5.77-23.47,3-48.32-4.62-67s-19.67-32-32.6-42.23c-5.48-4.35-11.29-8.28-17.8-9-6.92-.77-12.45,5.05-19.1,6.52C791.2,93.36,783.12,90.65,775.25,91.82Z" transform="translate(-84.99 -85.07)" fill="#f9a826"/><path d="M811.93,86s5.46,211.89-33.56,334.42" transform="translate(-84.99 -85.07)" fill="none" stroke="#535461" stroke-miterlimit="10" stroke-width="2"/><path d="M759.38,104.68s55.2,37,50.47,101.16" transform="translate(-84.99 -85.07)" fill="none" stroke="#535461" stroke-miterlimit="10" stroke-width="2"/><path d="M723.15,198.85s87.12,17.26,83.68,53.54" transform="translate(-84.99 -85.07)" fill="none" stroke="#535461" stroke-miterlimit="10" stroke-width="2"/><path d="M868.54,135.92s-33.11,19.71-59.19,79.41" transform="translate(-84.99 -85.07)" fill="none" stroke="#535461" stroke-miterlimit="10" stroke-width="2"/><path d="M849.43,319.79s-22.7,12-45.53-35.61" transform="translate(-84.99 -85.07)" fill="none" stroke="#535461" stroke-miterlimit="10" stroke-width="2"/><path d="M749,341s48.13-1.73,50.87-23.08" transform="translate(-84.99 -85.07)" fill="none" stroke="#535461" stroke-miterlimit="10" stroke-width="2"/><path d="M152.24,663.66s8.38,11-3.87,27.5S126,721.68,130.11,732c0,0,18.48-30.73,33.52-31.16S168.79,682.14,152.24,663.66Z" transform="translate(-84.99 -85.07)" fill="#f9a826"/><path d="M152.24,663.66A13.57,13.57,0,0,1,154,667.1c14.68,17.24,22.49,33.33,8.39,33.74-13.14.38-28.9,23.87-32.68,29.81a12.74,12.74,0,0,0,.45,1.35s18.48-30.73,33.52-31.16S168.79,682.14,152.24,663.66Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M167.82,677.63c0,3.86-.43,7-1,7s-1-3.13-1-7,.54-2,1.07-2S167.82,673.77,167.82,677.63Z" transform="translate(-84.99 -85.07)" fill="#ffd037"/><path d="M173.17,682.23c-3.39,1.85-6.34,3-6.59,2.49s2.28-2.35,5.67-4.19,2.05-.5,2.31,0S176.55,680.38,173.17,682.23Z" transform="translate(-84.99 -85.07)" fill="#ffd037"/><path d="M108,663.66s-8.38,11,3.87,27.5,22.35,30.51,18.26,40.83c0,0-18.48-30.73-33.52-31.16S91.43,682.14,108,663.66Z" transform="translate(-84.99 -85.07)" fill="#f9a826"/><path d="M108,663.66a13.57,13.57,0,0,0-1.71,3.44c-14.68,17.24-22.49,33.33-8.39,33.74,13.14.38,28.9,23.87,32.68,29.81a12.74,12.74,0,0,1-.45,1.35s-18.48-30.73-33.52-31.16S91.43,682.14,108,663.66Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M92.4,677.63c0,3.86.43,7,1,7s1-3.13,1-7-.54-2-1.07-2S92.4,673.77,92.4,677.63Z" transform="translate(-84.99 -85.07)" fill="#ffd037"/><path d="M87.05,682.23c3.39,1.85,6.34,3,6.59,2.49s-2.28-2.35-5.67-4.19-2.05-.5-2.31,0S83.67,680.38,87.05,682.23Z" transform="translate(-84.99 -85.07)" fill="#ffd037"/><path d="M95.07,730.56s23.43-.72,30.49-5.75,36-11,37.79-3,35.21,40.11,8.76,40.32-61.46-4.12-68.51-8.41S95.07,730.56,95.07,730.56Z" transform="translate(-84.99 -85.07)" fill="#a8a8a8"/><path d="M172.58,759.35c-26.45.21-61.46-4.12-68.51-8.41-5.37-3.27-7.51-15-8.22-20.41l-.78,0s1.48,18.9,8.53,23.19,42.06,8.63,68.51,8.41c7.64-.06,10.27-2.78,10.13-6.8C181.18,757.79,178.27,759.31,172.58,759.35Z" transform="translate(-84.99 -85.07)" opacity="0.2"/><path d="M1067.35,659.11a11.67,11.67,0,0,0,3.83-5.78c.5-2.3-.48-5.05-2.68-5.89-2.46-.94-5.09.76-7.08,2.49s-4.28,3.69-6.89,3.32a10.48,10.48,0,0,0,3.24-9.81,4.1,4.1,0,0,0-.9-2c-1.37-1.46-3.84-.83-5.48.32-5.2,3.66-6.65,10.72-6.68,17.08-.52-2.29-.08-4.68-.1-7s-.66-5-2.64-6.22a8,8,0,0,0-4-.95c-2.34-.09-4.94.15-6.54,1.86-2,2.12-1.47,5.69.26,8s4.35,3.8,6.77,5.42a15,15,0,0,1,4.84,4.61,4.57,4.57,0,0,1,.36.82h14.65A40.83,40.83,0,0,0,1067.35,659.11Z" transform="translate(-84.99 -85.07)" fill="#f9a826"/><path d="M231.72,565.39c31.82,40.46,19.46,99.57-.76,146.9-6.77,15.85-14.43,32.62-11.57,49.61,3.49,20.78,22,36,41.52,44,35.5,14.68,78,11.18,110.61-9.11,28.19-17.54,48.38-46.06,77.05-62.8,48-28,109.06-17.43,161.16,1.86,36.86,13.65,77.16,31.41,113.79,17.14,25.77-10,43.59-34.47,53.3-60.37,4.69-12.51,8.09-26,17-36,5.32-5.89,12.26-10.08,19.38-13.6,65-32.21,147-15,210.08-50.68,42.61-24.12,69.89-69.63,82-117.08s10.67-97.21,7.6-146.07c-2.18-34.73-6.09-71.8-28.28-98.61-23.47-28.35-63.76-38.9-100.17-33.51S915,221.76,886,244.38c-36.29,28.27-69.94,63.48-114.5,74.94-30.34,7.8-62.26,3.53-93.56,2.06-52.32-2.47-104.65,3-156.68,9-49.81,5.76-100,12.1-147.43,28.3-33.58,11.47-60.5,32.28-92.21,46.82-20.67,9.48-43.21,12.1-62.77,24.17-24.11,14.87-46.2,40.74-40,71C184.67,529.48,214.82,543.92,231.72,565.39Z" transform="translate(-84.99 -85.07)" fill="#f9a826" opacity="0.1"/><ellipse cx="552.35" cy="439.22" rx="427.67" ry="41.08" fill="#f9a826" opacity="0.1"/><ellipse cx="223.66" cy="676.22" rx="211.36" ry="41.08" fill="#f9a826" opacity="0.1"/><path d="M524.71,511.48l-3.35,4.87s3.65,4.87,4,5.48,10.65-.3,10.65-.3l.91-3.65-1.52-4.26Z" transform="translate(-84.99 -85.07)" fill="#e6e6f0"/><polygon points="327.09 423.67 320.39 424.88 324.65 433.11 329.22 435.54 333.48 438.58 334.7 435.24 331.65 428.84 327.09 423.67" fill="#fdc2cc"/><path d="M521.67,429.59s35.62,8.52,42.31,18c0,0,6.09,5.18,0,14.61s-14.61,30.75-14.61,30.75-6.09,20.7-8.52,22.22-16.44,2.74-17.66-3c0,0,7.91-12.48,7.91-18.27s13.09-33.18,13.09-33.18-29.83-3.35-39.27-1.22S509.19,426.24,521.67,429.59Z" transform="translate(-84.99 -85.07)" fill="#565171"/><path d="M521.67,429.59s35.62,8.52,42.31,18c0,0,6.09,5.18,0,14.61s-14.61,30.75-14.61,30.75-6.09,20.7-8.52,22.22-16.44,2.74-17.66-3c0,0,7.91-12.48,7.91-18.27s13.09-33.18,13.09-33.18-29.83-3.35-39.27-1.22S509.19,426.24,521.67,429.59Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M514.36,437.81c-.07,1.77-.26,3.76-.53,5.9-1.95,15.5-8.3,38.55-8.3,38.55s-6.39,13.7-8.22,22.53-14.31,11-14.31,11-34.1,4-41.1,2.44-18,4.57-23.44,3.65-8.83-13.7-8.83-13.7a66,66,0,0,0,27.4-5.78c14-6.39,34.1-3.35,34.1-3.35a11.45,11.45,0,0,0,7-5.78c2.13-4.57,2.13-32.27,1.52-34.1-4-12-3.67-19.7-2.52-24.19a12.07,12.07,0,0,1,2.52-5.34Z" transform="translate(-84.99 -85.07)" fill="#565171"/><path d="M514.36,437.81c-.07,1.77-.26,3.76-.53,5.9-3.06.24-11.64.47-18-3.46-6-3.68-14.73-4.93-18.66-5.32a12.07,12.07,0,0,1,2.52-5.34Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M518.57,434c-1.42,4-3.6,8.69-3.6,8.69s-11.26,1.52-19.18-3.35-20.7-5.48-20.7-5.48c2.07-1.27,3.47-5.13,4.34-8.51a53.93,53.93,0,0,0,1.14-5.8s37.44,7.61,39,8.83C520.15,428.86,519.53,431.28,518.57,434Z" transform="translate(-84.99 -85.07)" fill="#e6e6f0"/><path d="M585.29,305.69,539.88,333.1l-4.51,2.72V322.43l3.13-1.5,38.27-18.29s1.83-33.18,6.7-28S585.29,305.69,585.29,305.69Z" transform="translate(-84.99 -85.07)" fill="#fdc2cc"/><path d="M539.88,333.1l-4.51,2.72V322.43l3.13-1.5A98.54,98.54,0,0,0,539.88,333.1Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M504.93,338l32.57-18.87s.61,18.27,4.26,21c0,0-13.39,4-18.57,12.48Z" transform="translate(-84.99 -85.07)" fill="#b45181"/><path d="M504.93,338l32.57-18.87s.61,18.27,4.26,21c0,0-13.39,4-18.57,12.48Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M585,354.09s-15.49,6.75-25.75,9.23a20.22,20.22,0,0,1-7.13.82c-7-1.22,1.83-10,1.83-10l3.68-.57,19.76-3.08s2.13-30.44,5.78-28S585,354.09,585,354.09Z" transform="translate(-84.99 -85.07)" fill="#fdc2cc"/><path d="M519.54,326.69s-13.09,9.74-8.22,21.92-25.27-7.31-25.27-7.31,9.74-14.61,11.87-25.57S519.54,326.69,519.54,326.69Z" transform="translate(-84.99 -85.07)" fill="#fdc2cc"/><path d="M518.57,434a69,69,0,0,0-17.6-4.1c-8.8-1-16.86-2.69-21.53-4.55a53.93,53.93,0,0,0,1.14-5.8s37.44,7.61,39,8.83C520.15,428.86,519.53,431.28,518.57,434Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M559.24,363.32a20.22,20.22,0,0,1-7.13.82c-7-1.22,1.83-10,1.83-10l3.68-.57C559.16,355.94,560.73,359.64,559.24,363.32Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M498.23,332.17s-11.87-.3-16.13,4.57-3.35,18-3.35,18-.89,26.29,5.78,41a2,2,0,0,1,.07,1.51c-.07.18-.07.07-.07.07s-4.26,19.18-8.52,22.53,9.13,7.31,25,9.13,22.22,6.39,22.22,6.39,2.74-3,3-9.74S522,369.92,522,369.92s16.74,4.26,26.79-.91c0,0,4.57,2.44,8.83-4.26s-3-14-3-14-6.7,6.7-25.27-2.13S504,331.87,498.23,332.17Z" transform="translate(-84.99 -85.07)" fill="#b45181"/><path d="M407.21,509.35h-3.65v5.18l3.65,8.22s4.87.91,5.18.91,4.26-.91,4.26-.91l1.22-2.13S404.47,515.43,407.21,509.35Z" transform="translate(-84.99 -85.07)" fill="#e6e6f0"/><path d="M521.67,514.22l-5.48,12.18,23.14,11,18.27.61s1.52-4.26-4.57-6.39l-4.87-.91s-6.39-11.57-7-17c0,0-6.09,1.22-7,5.78C534.15,519.39,525.63,523.65,521.67,514.22Z" transform="translate(-84.99 -85.07)" fill="#b45181"/><path d="M404.47,508.13l-1.86,1.52-8.18,6.7,18.87,25s10.65,4.57,15.53,0c0,0,3-3-3.65-5.48,0,0-5.18.91-5.18-4.26s1.22-10.65,3-11.87c0,0-4.57-1.52-5.78-.3a19.32,19.32,0,0,0-2.44,3.35S403.86,518.48,404.47,508.13Z" transform="translate(-84.99 -85.07)" fill="#b45181"/><path d="M497.32,316.34a37,37,0,0,1-1.22,4.56,15.83,15.83,0,0,0,20.27,8.71,25.18,25.18,0,0,1,2.57-2.31S499.45,305.38,497.32,316.34Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M495.64,357s9.44,12.48,23.14,12.79" transform="translate(-84.99 -85.07)" opacity="0.1"/><g opacity="0.1"><path d="M552.06,369.22a3.44,3.44,0,0,1-.56-.21q-.44.23-.9.43A5.69,5.69,0,0,0,552.06,369.22Z" transform="translate(-84.99 -85.07)"/><path d="M555.3,352a15.06,15.06,0,0,0-1.06-1.22s-2,2-6.94,2.38A16.8,16.8,0,0,0,555.3,352Z" transform="translate(-84.99 -85.07)"/><path d="M524.71,369.92l.06.65a60.46,60.46,0,0,0,12.18,1A63.38,63.38,0,0,1,524.71,369.92Z" transform="translate(-84.99 -85.07)"/><path d="M503.71,429c-15.83-1.83-29.22-5.78-25-9.13s8.52-22.53,8.52-22.53,0,.11.07-.07a2,2,0,0,0-.07-1.51c-6.67-14.75-5.78-41-5.78-41s-.91-13.09,3.35-18c3.17-3.63,10.56-4.38,14.13-4.53a6.47,6.47,0,0,0-1,0s-11.87-.3-16.13,4.57-3.35,18-3.35,18-.89,26.29,5.78,41a2,2,0,0,1,.07,1.51c-.07.18-.07.07-.07.07S480,416.5,475.7,419.85s9.13,7.31,25,9.13,22.22,6.39,22.22,6.39a7.8,7.8,0,0,0,.84-1.23C520.67,432.65,514.31,430.2,503.71,429Z" transform="translate(-84.99 -85.07)"/></g><circle cx="426.33" cy="229.14" r="15.83" fill="#fdc2cc"/><path d="M533.85,307.13c-1.31,3.28-5.22,4.52-8.65,5.37-4.9,1.2-10.18,2.38-14.87.52a3.25,3.25,0,0,0-2-.39,2.66,2.66,0,0,0-1.32,1.15c-5.17,7.36-4.33,17.17-5.67,26.07-.42,2.77-1.13,5.63-3,7.7-3.64,4-10.51,3.85-13.86,8.1-2.21,2.8-2.23,6.69-2.21,10.26q0,5.71-.1,11.43c-.06,2.5-.18,5.09-1.31,7.31-1.92,3.76-6.2,5.55-10.15,7-2.46.92-5,1.85-7.64,1.6s-5.28-2-5.62-4.64c-.47-3.58,3.22-6.08,5.76-8.66,4.06-4.11,5.73-10.09,5.88-15.87a17,17,0,0,0-1-6.87c-.93-2.27-2.59-4.18-3.59-6.42-3.08-6.9.72-14.88,5.27-20.92s10.14-11.93,11.11-19.42a26.93,26.93,0,0,1,.69-4.81c.7-2.18,2.36-8.2,4.19-9.58a21.77,21.77,0,0,1,10-4.16c2.81-.41,5.68-.26,8.47-.8,3.26-.63,6.29-2.18,9.55-2.76,7.05-1.25,14.7,6.94,17.79,13.4C532.42,303.72,534.65,305.12,533.85,307.13Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M533.85,306.52c-1.31,3.28-5.22,4.52-8.65,5.37-4.9,1.2-10.18,2.38-14.87.52a3.25,3.25,0,0,0-2-.39,2.66,2.66,0,0,0-1.32,1.15c-5.17,7.36-4.33,17.17-5.67,26.07-.42,2.77-1.13,5.63-3,7.7-3.64,4-10.51,3.85-13.86,8.1-2.21,2.8-2.23,6.69-2.21,10.26q0,5.71-.1,11.43c-.06,2.5-.18,5.09-1.31,7.31-1.92,3.76-6.2,5.55-10.15,7-2.46.92-5,1.85-7.64,1.6s-5.28-2-5.62-4.64c-.47-3.58,3.22-6.08,5.76-8.66,4.06-4.11,5.73-10.09,5.88-15.87a17,17,0,0,0-1-6.87c-.93-2.27-2.59-4.18-3.59-6.42-3.08-6.9.72-14.88,5.27-20.92s10.14-11.93,11.11-19.42a26.93,26.93,0,0,1,.69-4.81c.7-2.18,2.36-8.2,4.19-9.58a21.77,21.77,0,0,1,10-4.16c2.81-.41,5.68-.26,8.47-.8,3.26-.63,6.29-2.18,9.55-2.76,7.05-1.25,14.7,6.94,17.79,13.4C532.42,303.11,534.65,304.51,533.85,306.52Z" transform="translate(-84.99 -85.07)" fill="#f569bc"/><path d="M585,276.09H848.17V539.24H585Z" transform="translate(-84.99 -85.07)" fill="#f7df1e"/><path d="M654.21,496l20.14-12.19c3.89,6.89,7.42,12.72,15.9,12.72,8.13,0,13.25-3.18,13.25-15.54V396.9h24.73v84.43c0,25.61-15,37.27-36.92,37.27-19.78,0-31.26-10.25-37.09-22.61m87.44-2.65,20.13-11.66c5.3,8.66,12.19,15,24.38,15,10.25,0,16.78-5.12,16.78-12.19,0-8.48-6.71-11.48-18-16.43l-6.18-2.65c-17.84-7.59-29.68-17.13-29.68-37.27,0-18.55,14.13-32.68,36.21-32.68,15.72,0,27,5.48,35.15,19.78l-19.25,12.37c-4.24-7.6-8.83-10.6-15.9-10.6-7.24,0-11.84,4.59-11.84,10.6,0,7.42,4.59,10.42,15.19,15l6.18,2.65c21,9,32.86,18.19,32.86,38.86,0,22.26-17.49,34.45-41,34.45-23,0-37.8-11-45-25.26" transform="translate(-84.99 -85.07)"/><path d="M963.61,685.28S953.34,686,947,675a36.88,36.88,0,0,0-4.37-6.21,21,21,0,0,1-3.07-11.15c.35-8.15-8.15-52.79-8.15-52.79s1.06-17-7.44-27.63c-5.6-7-13.65-27-18.5-39.92a2.67,2.67,0,0,0,1.14.6l-.2-1.11.2,0L904.1,523a62.88,62.88,0,0,1-9.16-13.88l.57-.12,7.52-1.58s12.22-17.37,13-25.91l1,0h1.41a294,294,0,0,1,33.86,1.77h0c0-.05-.08-.27-.18-.62h0a42.5,42.5,0,0,1-1.1-5.23l.7,0,7-.46s24.09-26.92,15.23-31.88-18.07,22.32-18.07,22.32l-3,.54-.81.15c.08-.12.16-.23.25-.34S913,466,906.93,456.42c0,0-17.36-13.82-18.07-23a10.39,10.39,0,0,0-6.24-8.84,13.62,13.62,0,0,0-6.89-1.29l-8.13.56.57,1-.23,0a27.35,27.35,0,0,1-1.28-3.6l.17,0c-.06-.25-.11-.5-.16-.75a19.13,19.13,0,0,0,14.09-23.56,7.65,7.65,0,0,0,2.39-.07c3-.61,5.11-3.65,5.19-6.69,0-.2,0-.4,0-.59,0,0,0-.08,0-.12a10.28,10.28,0,0,0-3.95-7.9c-1.62-1.35-3.56-2.31-5-3.81-1.75-1.79-2.71-4.19-4.07-6.3a18.7,18.7,0,0,0-9.6-7.47c-2.93-1-6.53-1.1-8.78,1-1.16,1.09-1.83,2.67-3.13,3.59-1.87,1.34-4.41.94-6.7,1.21a12.78,12.78,0,0,0-9.63,7.21,16.61,16.61,0,0,0-1.58,7.62,20.35,20.35,0,0,0,.64,5.35c.44,1.74,1.09,3.42,1.57,5.16,1,3.6,1.23,7.39,2.38,10.94a13.77,13.77,0,0,0,4.43,6.73l-.34,1.46c-.22,0-5.74,1.23-9.55,9.56-3,6.57-13.21,13.35-17.7,16.09a7.38,7.38,0,0,0-3.34,4.64,24.1,24.1,0,0,0-.57,5.89c-.08,4.27.81,10.18,4.24,17.67,7.79,17,13.46,24.44,13.46,24.44s.43,5.21.46,10.7c0,4.09-.3,8.16-1.17,10.2-.74,1.72-1,6.11-.94,11.13,0,9.62.94,22.17.94,22.17s2.71.52,6.9,1.13l2.61,45.92a22.08,22.08,0,0,1-5,15.34,33.94,33.94,0,0,1-6.29,6c-7.44,5.31-23.38,61.29-23.38,61.29s.78,0,2.06.15l-4.9,13.67s19.58,15,31.49,10.9a11.54,11.54,0,0,1,4-.56c2.35,0,7.38-1.86,4.58-4.31a181.52,181.52,0,0,1-15.27-15.88,8.12,8.12,0,0,1,1.1.65v-.11l.17.11s0-.55.13-1.45l-.17-.06c.36-3.68,1.5-13,3.76-14.08,2.83-1.42,23.74-42.87,23.74-42.87l20.9-53.85s16.65,28.7,30.82,33.65v12s7.79,35.43,10.63,39.32,0,19.48,0,19.48a9.71,9.71,0,0,0,1.91,1.68l-2.27,12.84s16.3-.71,43.93,7.79C961.84,695.55,972.47,690.95,963.61,685.28ZM898.43,500l-3.45.86-.68.17c-.07-.43-.12-.68-.12-.68a7,7,0,0,1-2.51.61,46.15,46.15,0,0,1-2.1-11.95,80.52,80.52,0,0,1-2.11-14.8c0-2.58.43-4.83,1.4-6.1l1.15.09.8.76.06.05.41.37h0l.43.38.07.06.46.41.08.07.47.4,0,0,.53.44.12.1.56.45,0,0,.55.44.13.1.61.46.13.09.58.43.1.07.66.47.16.11.7.48.06,0,.68.45.16.11.73.47.16.1.68.42.13.08.78.46.19.11.81.45.06,0,.79.42.19.1.84.42.17.08.78.36.15.07.88.38.21.09.91.37h0C901.33,485.5,898.43,500,898.43,500Z" transform="translate(-84.99 -85.07)" fill="url(#a5312bde-8c7e-4767-9e17-08a43f21bf92-27)"/><path d="M811.05,668.16l-6.57,18.33s18,13.8,29.7,10.94a32.69,32.69,0,0,1,5.37-.87c2.42-.18,6.59-1.95,4-4.19-8.3-7.26-19.37-20.75-19.37-20.75Z" transform="translate(-84.99 -85.07)" fill="#4f4d59"/><path d="M920.34,666.43l-3.11,17.64s15.91-.69,42.89,7.61c0,0,10.38-4.5,1.73-10,0,0-10,.69-16.25-10s-10-9.34-10-9.34Z" transform="translate(-84.99 -85.07)" fill="#4f4d59"/><path d="M838,538.47l3,53.68a22.2,22.2,0,0,1-5.29,15.7,32.54,32.54,0,0,1-5.71,5.33c-7.26,5.19-22.83,59.83-22.83,59.83s17.64,1,22.48,4.5c0,0,1-13.83,3.8-15.22s23.17-41.85,23.17-41.85l20.41-52.57s16.25,28,30.09,32.86v11.76s7.61,34.59,10.38,38.39,0,19,0,19,8,10,26.28-.69c0,0-5.88-6.57-5.53-14.53s-8-51.53-8-51.53,1-16.6-7.26-27S901,526,901,526l-9.52-20.48Z" transform="translate(-84.99 -85.07)" fill="#c48c96"/><g opacity="0.1"><path d="M810.53,673s15.56-54.64,22.83-59.83a33,33,0,0,0,6-5.68,22,22,0,0,0,5-15.34l-3.05-53.69,51-31.44-.69-1.49L838.2,538.47l3.05,53.69a22,22,0,0,1-5,15.34,33,33,0,0,1-6,5.68C823,618.36,807.42,673,807.42,673s17.64,1,22.48,4.5c0,0,0-.54.13-1.41C823.22,673.75,810.53,673,810.53,673Z" transform="translate(-84.99 -85.07)"/><path d="M920.86,669.89s2.77-15.22,0-19-10.38-38.39-10.38-38.39V600.72c-13.83-4.84-30.09-32.86-30.09-32.86L879.19,571c4.69,7.44,17.2,25.9,28.19,29.74v11.76s7.61,34.59,10.38,38.39,0,19,0,19,3.86,4.86,12.38,4.2C923.77,673.56,920.86,669.89,920.86,669.89Z" transform="translate(-84.99 -85.07)"/></g><path d="M957,478.29l-6.79.45-3.58.24v-8.65l4.7-.85,2.91-.53s9-26.63,17.64-21.79S957,478.29,957,478.29Z" transform="translate(-84.99 -85.07)" fill="#714b4f"/><path d="M848.06,407s-4.5,17.29-5.88,28,32.16,2.08,32.16,2.08-12.8-15.56-5.53-23.86Z" transform="translate(-84.99 -85.07)" fill="#714b4f"/><path d="M884.37,479l.69,6.57-10.72-.69-10.72-9.34L852.9,445.44,846,434.71l-5.19-6.57,2.08-8s.95.83,2.55,2.05c5.27,4,17.62,12.41,26.65,10.09a10.76,10.76,0,0,0,1.23-.39l13.49,23.17Z" transform="translate(-84.99 -85.07)" fill="#e6e6f0"/><path d="M845.64,418.11s-5.53,1-9.34,9.34c-2.92,6.38-12.8,13-17.21,15.67a7.38,7.38,0,0,0-3.35,4.66c-.89,3.94-1.23,11.29,3.61,21.86,7.61,16.6,13.14,23.86,13.14,23.86s1.38,16.6-.69,21.44,0,31.47,0,31.47,36.31,6.92,48.42,0,10.38-33.55,10.38-33.55,11.41,24.21,15.56,24.9l-2.42-13.49s-13.49-14.53-14.18-33.2c0,0-4.15-16.95-.69-21.44,0,0,58.45,4.84,61.91.69,0,0-38.39-1.73-44.27-11.07,0,0-16.95-13.49-17.64-22.48a9.94,9.94,0,0,0-5.19-8.15,13.54,13.54,0,0,0-7.75-1.73l-7.81.54s13.49,23.86,12.8,27,.69,28.36.69,28.36S866,449.24,859.13,445.44,844.25,426,844.25,426l1.38-7.9" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M884.37,479l.69,6.57-10.72-.69-10.72-9.34L852.9,445.44,846,434.71l-5.19-6.57,2.08-8s.95.83,2.55,2.05l-.48,2.73s8,15.62,14.87,19.43,22.48,37.35,22.48,37.35-1.38-25.25-.69-28.36c.47-2.11-5.59-13.77-9.53-21.06a10.76,10.76,0,0,0,1.23-.39l13.49,23.17Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M950.21,478.74l-3.58.24v-8.65l4.7-.85C949.69,471.65,949.75,475.49,950.21,478.74Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M845.64,417.08s-5.53,1-9.34,9.34c-2.92,6.38-12.8,13-17.21,15.67a7.38,7.38,0,0,0-3.35,4.66c-.89,3.94-1.23,11.29,3.61,21.86,7.61,16.6,13.14,23.86,13.14,23.86s1.38,16.6-.69,21.44,0,31.47,0,31.47,36.31,6.92,48.42,0,10.38-33.55,10.38-33.55S902,536,906.16,536.74l-2.42-13.49s-13.49-14.53-14.18-33.2c0,0-4.15-16.95-.69-21.44,0,0,13.49,14.53,28.71,14.18a286.36,286.36,0,0,1,33.2,1.73s-3.46-11.07,0-15.22c0,0-38.39-1.73-44.27-11.07,0,0-16.95-13.49-17.64-22.48a9.94,9.94,0,0,0-5.19-8.15,13.54,13.54,0,0,0-7.75-1.73l-7.81.54s13.49,23.86,12.8,27,.69,28.36.69,28.36S866,448.2,859.13,444.4,844.25,425,844.25,425l1.38-7.9" transform="translate(-84.99 -85.07)" fill="#c48c96"/><path d="M838,453.39s8.3,28,13.14,31.47,34.24,21.1,42.89,16.95c0,0,2.08,10.38-1,12.8,0,0-32.25-1.26-32.51-1.38,0,0-21.1-2.77-24.56-13.14s-7.61-28-7.61-28Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><ellipse cx="797.31" cy="398.24" rx="1.21" ry="1.73" fill="#ba7855"/><ellipse cx="800.76" cy="410.34" rx="1.21" ry="1.73" fill="#ba7855"/><g opacity="0.1"><path d="M834.23,545s-2.08-26.63,0-31.47.69-21.44.69-21.44-5.53-7.26-13.14-23.86c-4.85-10.57-4.5-17.92-3.61-21.86a7.38,7.38,0,0,1,3.35-4.66c4.41-2.7,14.28-9.29,17.21-15.67,2.15-4.68,4.84-7.05,6.78-8.23l.13-.76s-5.53,1-9.34,9.34c-2.92,6.38-12.8,13-17.21,15.67a7.38,7.38,0,0,0-3.35,4.66c-.89,3.94-1.23,11.29,3.61,21.86,7.61,16.6,13.14,23.86,13.14,23.86s1.38,16.6-.69,21.44,0,31.47,0,31.47,25.94,4.94,41.28,2.29C857.59,549.49,834.23,545,834.23,545Z" transform="translate(-84.99 -85.07)"/><path d="M880.91,453.39c-.47,2.13,0,14.66.39,22.34,1.67,3.41,2.72,5.68,2.72,5.68s-1.38-25.25-.69-28.36c.66-3-11.49-24.66-12.7-26.8l-2.52.17S881.61,450.28,880.91,453.39Z" transform="translate(-84.99 -85.07)"/><path d="M920,482.44c-15.22.35-28.71-14.18-28.71-14.18a5.54,5.54,0,0,0-.87,1.87c4,3.72,15,12.93,27.16,12.65a286.36,286.36,0,0,1,33.2,1.73s-.07-.23-.18-.62A275.32,275.32,0,0,0,920,482.44Z" transform="translate(-84.99 -85.07)"/><path d="M893,511.49s.14,2.16.06,5.4c3.6,7.14,10.15,19.35,13.08,19.84l-.51-2.84C900.6,527.57,893,511.49,893,511.49Z" transform="translate(-84.99 -85.07)"/></g><path d="M902.7,508l-7.35,1.55-5.8,1.22,3.11-8.65,2.17-.54,3.37-.84s4.84-24.21,14.53-22.48S902.7,508,902.7,508Z" transform="translate(-84.99 -85.07)" fill="#714b4f"/><path d="M895.36,509.58l-5.8,1.22,3.11-8.65,2.17-.54A34.54,34.54,0,0,1,895.36,509.58Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M838,452.7s8.3,28,13.14,31.47,34.24,21.1,42.89,16.95c0,0,2.08,10.38-1,12.8,0,0-32.25-1.26-32.51-1.38,0,0-21.1-2.77-24.56-13.14s-7.61-28-7.61-28Z" transform="translate(-84.99 -85.07)" fill="#c48c96"/><path d="M848.4,407.74s-.7,2.71-1.64,6.65a18.67,18.67,0,0,0,20.61,9.5c-.83-3.55-.65-7.14,1.78-9.92Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><circle cx="777.94" cy="319.9" r="18.68" fill="#714b4f"/><path d="M879.15,399.83a10,10,0,0,0,4.16.26,6.85,6.85,0,0,0,5.06-6.53,10,10,0,0,0-3.85-7.71c-1.58-1.32-3.47-2.25-4.92-3.72-1.71-1.75-2.65-4.09-4-6.15a18.25,18.25,0,0,0-9.37-7.29c-2.86-1-6.37-1.08-8.57,1-1.13,1.07-1.79,2.6-3.05,3.51-1.83,1.3-4.31.92-6.54,1.18a12.47,12.47,0,0,0-9.4,7,17.61,17.61,0,0,0-.92,12c.43,1.7,1.07,3.34,1.53,5,1,3.52,1.2,7.21,2.32,10.68s3.43,6.87,6.93,7.91a21.91,21.91,0,0,1,2.23-11.29,3.24,3.24,0,0,1,1.58-1.76,3.82,3.82,0,0,1,1.9,0,19,19,0,0,0,12.65-2.56c1.33-.8,3.4-3.56,4.81-3.83C873.52,397.22,877.25,399.41,879.15,399.83Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M879.15,399.14a10,10,0,0,0,4.16.26,6.85,6.85,0,0,0,5.06-6.53,10,10,0,0,0-3.85-7.71c-1.58-1.32-3.47-2.25-4.92-3.72-1.71-1.75-2.65-4.09-4-6.15a18.25,18.25,0,0,0-9.37-7.29c-2.86-1-6.37-1.08-8.57,1-1.13,1.07-1.79,2.6-3.05,3.51-1.83,1.3-4.31.92-6.54,1.18a12.47,12.47,0,0,0-9.4,7,17.61,17.61,0,0,0-.92,12c.43,1.7,1.07,3.34,1.53,5,1,3.52,1.2,7.21,2.32,10.68s3.43,6.87,6.93,7.91A21.91,21.91,0,0,1,850.78,405a3.24,3.24,0,0,1,1.58-1.76,3.82,3.82,0,0,1,1.9,0,19,19,0,0,0,12.65-2.56c1.33-.8,3.4-3.56,4.81-3.83C873.52,396.53,877.25,398.72,879.15,399.14Z" transform="translate(-84.99 -85.07)" fill="#503f43"/><path d="M1065.5,337.49l-15.24,170.7-68.5,19-68.31-19L898.23,337.49H1065.5Z" transform="translate(-84.99 -85.07)" fill="#e44d26"/><path d="M981.86,512.67l55.35-15.34,13-145.88H981.86Z" transform="translate(-84.99 -85.07)" fill="#f16529"/><path d="M952.24,393.33h29.62V372.39H929.36l.5,5.62,5.15,57.7h46.86V414.77H954.16ZM957,446.18h-21l2.93,32.88L981.77,491l.1,0V469.15l-.09,0-23.32-6.3L957,446.18Z" transform="translate(-84.99 -85.07)" fill="#ebebeb"/><path d="M913.8,291.09h10.64V301.6h9.73V291.09h10.64v31.84H934.17V312.27h-9.73v10.66H913.8V291.09Zm45,10.56h-9.37V291.09h29.38v10.56h-9.37v21.28H958.81V301.65h0Zm24.68-10.56h11.1l6.83,11.19,6.82-11.19h11.1v31.84h-10.6V307.15l-7.32,11.32h-.18l-7.33-11.32v15.78H983.48Zm41.14,0h10.64V312.4h15v10.52h-25.61V291.09Z" transform="translate(-84.99 -85.07)"/><path d="M981.79,435.71h25.78l-2.43,27.16-23.35,6.3V491l42.93-11.9.31-3.54,4.92-55.13.51-5.62H981.79v20.94Zm0-42.43v.05h50.58l.42-4.71,1-10.62.5-5.62H981.79v20.89Z" transform="translate(-84.99 -85.07)" fill="#fff"/><path d="M451.72,463.51c-1.95-5.71-4.76-13-7-14.66a2.09,2.09,0,0,0-.44-.27H444v-7.05l-5.26.84a50.27,50.27,0,0,1-1.91-7.81,3.63,3.63,0,0,0,3.95.79c-.09-.14-.16-.29-.24-.44l.24-.1a9.77,9.77,0,0,1-1.27-4.79,17.44,17.44,0,0,1,.73-4.52c.94-3.25,2.53-6.29,3.42-9.55a23.22,23.22,0,0,0,.8-6.46A23.54,23.54,0,0,0,442,398.84a6.22,6.22,0,0,0-1.86-2.43,24,24,0,0,0-2.28-1.11,12.31,12.31,0,0,1-3.31-3.3,29.74,29.74,0,0,0-14.37-9.59,8.41,8.41,0,0,0-4.59-.36c-3.53,1-4.82,5.33-7.68,7.62-2.53,2-6,2.23-9.16,2.91a15.58,15.58,0,0,0-8.53,4.47,9.26,9.26,0,0,0-2.29,6.18,6.21,6.21,0,0,0,2.53,5.52,7.93,7.93,0,0,0,6.7.95,22.79,22.79,0,0,0,17.25,28.65l.62,1.1h0a47.19,47.19,0,0,1,4.27,11.17c-4.84,2.75-10.13,5.32-13.32,5.56a22.45,22.45,0,0,1-.69,3.69,20.37,20.37,0,0,1-4.19,8.25c-4.34,4.88-23.87,41.78-23.87,41.78s-.62,1.47-1.62,4c-12.13,1.49-31.92,3.64-37.45,2.53l-21.7-20.62s-7,5.35-6.4,11.85l-3.91-3.72s-20.62,15.73,11.94,26l49.54,5.75c-4.72,14.24-9.12,30.81-7.76,39.83h.41a18.73,18.73,0,0,0,2.83-.22l-.09,1.6-4.77,85.43s-1.09,15.73,13.56,22.79c0,0,17.91,52.63,10.85,58.6,0,0,.84.44,2.25,1.06l-14.73,13s-10.85,2.71-16.82,2.17a4.31,4.31,0,0,0-4.76,3.21c0,.11,0,.22-.06.34l0,.14c0,.11,0,.23,0,.35s0,.09,0,.13,0,.2,0,.3l0,.13c0,.12,0,.23.07.35l0,.13q.05.19.12.37l0,.12c.05.12.11.24.17.36l0,.08c.07.12.14.24.22.36l.07.1q.13.19.29.38l.08.1c.11.13.23.25.36.38l.06,0,.4.34.09.07.49.35.12.08.57.33.09,0,.61.3.09,0,.71.29.15.06.79.26.13,0,.85.22.07,0,1,.19.19,0,1,.15.19,0,1.15.11c2.23.17,5.24.23,8.72.22h0s0,.09,0,.13,0,.2,0,.3l0,.13c0,.12,0,.23.07.35l0,.13q.05.19.12.37l0,.12c.05.12.11.24.17.36l0,.08c.07.12.14.24.22.36l.07.1q.13.19.29.38l.08.1c.11.13.23.25.36.38l.05,0,.4.34.09.07.49.35.12.08.56.33.09,0,.61.3.09,0,.71.29.15.06.79.26.13,0,.85.22.07,0,1,.19.19,0,1,.15.19,0,1.15.11c14.11,1.09,59.14-2.17,59.14-2.17l0-.13v0l0-.16v0c.45-2.1,2.61-14.31-5.07-23.34.23-.24.45-.49.66-.75,0,0-6-10.31-2.71-13.56S413.63,677,413.63,677s-10.31-16.28-4.34-34.73-.54-38.52-.54-38.52S423,599.53,423.26,582c0-.53,0-1.08,0-1.63a5.76,5.76,0,0,0,.9.06,4.21,4.21,0,0,0,.6,0s-2.71-9.77.54-16.82,10.31-.54,16.82-29.3c4.71-20.81,8.85-44.74,10.79-56.39A29.69,29.69,0,0,0,451.72,463.51Zm-123.82,61-4.95-4.7c1.64.68,3.46,1.34,5.49,2L347.09,524C338.77,524.75,331,525.17,327.9,524.54Z" transform="translate(-84.99 -85.07)" fill="url(#016d359d-0d48-4404-968f-1612e9b5c7a7-28)"/><path d="M375.13,521.77s-38.38,5.33-46.38,3.73l-21.32-20.26s-20.26,15.46,11.73,25.59l59.7,6.93Z" transform="translate(-84.99 -85.07)" fill="#fdc2cc"/><path d="M375.13,521.77s-38.38,5.33-46.38,3.73l-21.32-20.26s-20.26,15.46,11.73,25.59l59.7,6.93Z" transform="translate(-84.99 -85.07)" opacity="0.05"/><path d="M300,535.22l-82.94-23-18.48-207.3H401.67l-18.5,207.27L300,535.22Z" transform="translate(-84.99 -85.07)" fill="#264de4"/><path d="M367.33,499l15.81-177.12h-83V517.59L367.33,499Z" transform="translate(-84.99 -85.07)" fill="#2965f1"/><path d="M241,398.73l2.28,25.42h56.9V398.73Zm-4.58-51.46,2.31,25.42h61.44V347.27H236.37Zm63.75,117.49-.11,0-28.32-7.65-1.81-20.28H244.36l3.56,39.92L300,491.24l.12,0Z" transform="translate(-84.99 -85.07)" fill="#ebebeb"/><path d="M246.38,248.56h30.79v12.88H259.25v12.88h17.92v12.88H246.38Zm37,0h30.79v11.2H296.21V262h17.92v25.76H283.33V276h17.92v-2.24H283.33V248.56Zm37,0h30.79v11.2H333.16V262h17.92v25.76H320.28V276H338.2v-2.24H320.28V248.56Z" transform="translate(-84.99 -85.07)"/><path d="M359.14,398.73l4.59-51.46H300v25.42h35.83l-2.31,26H300v25.42h31.31l-3,33L300,464.78v26.45l52.12-14.45.38-4.3,6-66.94.62-6.83Z" transform="translate(-84.99 -85.07)" fill="#fff"/><path d="M389,738.19l-18.66,16.52s-10.66,2.67-16.52,2.13-8.53,9.06,5.33,10.13,58.1-2.13,58.1-2.13,4.26-17.06-8.53-26.65Z" transform="translate(-84.99 -85.07)" fill="#47465a"/><path d="M389,738.19l-18.66,16.52s-10.66,2.67-16.52,2.13-8.53,9.06,5.33,10.13,58.1-2.13,58.1-2.13,4.26-17.06-8.53-26.65Z" transform="translate(-84.99 -85.07)" opacity="0.05"/><path d="M417.91,757.47a29.4,29.4,0,0,1-.67,5.78s-44.24,3.2-58.1,2.13c-6.67-.51-9.5-3-10-5.38-.61,2.74,1.81,6.35,10,7,13.86,1.07,58.1-2.13,58.1-2.13A30.8,30.8,0,0,0,417.91,757.47Z" transform="translate(-84.99 -85.07)" fill="#fff" opacity="0.3"/><path d="M410.84,436s11.73,16.52,7.46,27.72,22.39-11.73,22.39-11.73S432.16,437,436.43,421Z" transform="translate(-84.99 -85.07)" fill="#fdc2cc"/><path d="M407.64,744.59,389,761.11s-10.66,2.67-16.52,2.13-8.53,9.06,5.33,10.13,58.1-2.13,58.1-2.13,4.26-17.06-8.53-26.65Z" transform="translate(-84.99 -85.07)" fill="#47465a"/><path d="M413,740.86c-2.78,3.43-6.7,4.75-10.8,4.95-9.32.44-19.58-4.95-19.58-4.95,6.93-5.86-10.66-57.57-10.66-57.57-14.39-6.93-13.33-22.39-13.33-22.39L363.29,577l1.18-21.08,14.93-9.06,11.76,9,11.16,8.56a44.86,44.86,0,0,1,1.4,8.32c1.3,19.59-14.19,24.2-14.19,24.2s6.4,19.72.53,37.85,4.26,34.12,4.26,34.12,19.19,55.44,16,58.64S413,740.86,413,740.86Z" transform="translate(-84.99 -85.07)" fill="#565171"/><path d="M413,740.86c-2.78,3.43-6.7,4.75-10.8,4.95-9.32.44-19.58-4.95-19.58-4.95,6.93-5.86-10.66-57.57-10.66-57.57-14.39-6.93-13.33-22.39-13.33-22.39L363.29,577l1.18-21.08,14.93-9.06,11.76,9,11.16,8.56a44.86,44.86,0,0,1,1.4,8.32c1.3,19.59-14.19,24.2-14.19,24.2s6.4,19.72.53,37.85,4.26,34.12,4.26,34.12,19.19,55.44,16,58.64S413,740.86,413,740.86Z" transform="translate(-84.99 -85.07)" opacity="0.05"/><path d="M431.63,747.25c-9.06,11.19-30.38,0-30.38,0a3.4,3.4,0,0,0,.93-1.45c3.91-10.63-13.19-61.45-13.19-61.45-14.39-6.93-16-23.45-16-23.45l-3.77-85.42-.49-11.06,22.43-8.56,6.89-2.63L421,570.82A41.57,41.57,0,0,1,422.44,582c-.29,17.21-14.26,21.37-14.26,21.37s6.4,19.72.53,37.85S413,675.29,413,675.29s19.19,55.44,16,58.64S431.63,747.25,431.63,747.25Z" transform="translate(-84.99 -85.07)" fill="#565171"/><path d="M422.44,582c-4.61-.66-13.94-6.21-18.73-9.22-1.83-1.15-3-1.92-3-1.92s-4.8-13.33-17.59-3.2a47.89,47.89,0,0,1-13.9,7.86,32.52,32.52,0,0,1-5.93,1.49l1.18-21.08,14.93-9.06,11.76,9,6.89-2.63L421,570.82A41.57,41.57,0,0,1,422.44,582Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M451.29,479.71c-1.9,11.44-6,35-10.6,55.39-6.4,28.25-13.33,21.85-16.52,28.78s-.53,16.52-.53,16.52c-5.33.53-22.92-11.19-22.92-11.19s-4.8-13.33-17.59-3.2-22.92,9.59-22.92,9.59c-2.67-17.59,17.06-64.5,17.06-64.5s19.19-36.25,23.45-41a20,20,0,0,0,4.12-8.1,22.05,22.05,0,0,0,.68-3.62c6.93-.53,24-12.26,24-12.26l13.33-2.13v6.93a2,2,0,0,1,.44.27c2.19,1.67,5,8.79,6.87,14.4A29.17,29.17,0,0,1,451.29,479.71Z" transform="translate(-84.99 -85.07)" fill="#e1a0a7"/><path d="M389,529.77l-6.89-.8-52.81-6.13c-32-10.13-11.73-25.59-11.73-25.59l21.32,20.26c6.15,1.23,30.28-1.64,41.09-3,3.24-.42,5.29-.7,5.29-.7Z" transform="translate(-84.99 -85.07)" fill="#fdc2cc"/><path d="M440.69,457.81S426.83,446.62,406,482.86s-25.59,30.38-25.59,30.38,4.26,16,2.13,19.19c0,0,14.39-1.07,19.72,0s38.38-40.51,38.38-40.51S457.75,468.47,440.69,457.81Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M440.16,455.68s-13.86-11.19-34.65,25.05-25.59,30.38-25.59,30.38,16.52,18.12,21.85,19.19,38.38-40.51,38.38-40.51S457.22,466.34,440.16,455.68Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M382.1,529c.22-3.95-1.27-10.89-2.13-14.49,3.24-.42,5.29-.7,5.29-.7l3.73,16Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M440.69,456.74S426.83,445.55,406,481.8s-25.59,30.38-25.59,30.38,4.26,16,2.13,19.19c0,0,14.39-1.07,19.72,0s38.38-40.51,38.38-40.51S457.75,467.4,440.69,456.74Z" transform="translate(-84.99 -85.07)" fill="#e1a0a7"/><path d="M437,422.09,411.37,437a54.69,54.69,0,0,1,3,4.88,22.49,22.49,0,0,0,4.48.45c6.83,0,10-7.17,14.13-12C432.68,426.49,435.82,426.39,437,422.09Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><circle cx="333.31" cy="333.83" r="22.39" fill="#fdc2cc"/><path d="M390,400.79a15.3,15.3,0,0,1,8.38-4.4c3.11-.67,6.52-.87,9-2.86,2.81-2.25,4.07-6.53,7.54-7.49a8.27,8.27,0,0,1,4.51.36,29.21,29.21,0,0,1,14.12,9.42,12.09,12.09,0,0,0,3.26,3.25,23.6,23.6,0,0,1,2.24,1.09,6.11,6.11,0,0,1,1.82,2.39,23.18,23.18,0,0,1,1.62,16.27c-.87,3.21-2.43,6.19-3.36,9.39s-1.16,6.82.53,9.68c-1.64.84-3.71-.22-4.74-1.75s-1.34-3.41-1.88-5.18a19.75,19.75,0,0,0-5.78-9c-1.68-1.48-4.68-2.48-5.85-.57-.45.74-.42,1.69-.81,2.46-.76,1.51-3,1.81-4.43,1a6.79,6.79,0,0,1-2.77-4.11c-2.19-7.43-5.94-12.1-13.88-8.93-3,1.18-6.45,2-9.3,0C386.57,409.13,387.3,403.82,390,400.79Z" transform="translate(-84.99 -85.07)" opacity="0.1"/><path d="M390,400.25a15.3,15.3,0,0,1,8.38-4.4c3.11-.67,6.52-.87,9-2.86,2.81-2.25,4.07-6.53,7.54-7.49a8.27,8.27,0,0,1,4.51.36,29.21,29.21,0,0,1,14.12,9.42,12.09,12.09,0,0,0,3.26,3.25,23.6,23.6,0,0,1,2.24,1.09,6.11,6.11,0,0,1,1.82,2.39,23.18,23.18,0,0,1,1.62,16.27c-.87,3.21-2.43,6.19-3.36,9.39s-1.16,6.82.53,9.68c-1.64.84-3.71-.22-4.74-1.75s-1.34-3.41-1.88-5.18a19.75,19.75,0,0,0-5.78-9c-1.68-1.48-4.68-2.48-5.85-.57-.45.74-.42,1.69-.81,2.46-.76,1.51-3,1.81-4.43,1a6.79,6.79,0,0,1-2.77-4.11c-2.19-7.43-5.94-12.1-13.88-8.93-3,1.18-6.45,2-9.3,0C386.57,408.6,387.3,403.29,390,400.25Z" transform="translate(-84.99 -85.07)" fill="#8f5a6a"/><path d="M443.26,451.15H432.43s-21.32,10.66-21.85,10.13c-.36-.36-3.66.26-5.75.69a22.05,22.05,0,0,0,.68-3.62c6.93-.53,24-12.26,24-12.26l13.33-2.13v6.93A2,2,0,0,1,443.26,451.15Z" transform="translate(-84.99 -85.07)" opacity="0.05"/><path d="M436.56,763.86a29.4,29.4,0,0,1-.67,5.78s-44.24,3.2-58.1,2.13c-6.67-.51-9.5-3-10-5.38-.61,2.74,1.81,6.35,10,7,13.86,1.07,58.1-2.13,58.1-2.13A30.8,30.8,0,0,0,436.56,763.86Z" transform="translate(-84.99 -85.07)" fill="#fff" opacity="0.3"/><g opacity="0.05"><path d="M378.06,565.48c-7.19,5.7-13.55,8-17.73,9,0,.4.08.79.14,1.17,0,0,10.13.53,22.92-9.59a17.18,17.18,0,0,1,6.85-3.58C387.45,561.11,383.47,561.2,378.06,565.48Z" transform="translate(-84.99 -85.07)"/><path d="M450.4,465.54c-1.91-5.61-4.68-12.72-6.87-14.4a2,2,0,0,0-.44-.27s-4.41.15-4.26.27c2.19,1.67,4.33,8.26,6.24,13.86a29.17,29.17,0,0,1,1.16,14.16c-1.9,11.44-6,35-10.6,55.39-6.4,28.25-13.33,21.85-16.52,28.78-2.62,5.68-1.31,13.14-.74,15.65a13.41,13.41,0,0,0,5.54,1.41s-2.67-9.59.53-16.52,10.13-.53,16.52-28.78c4.63-20.44,8.7-44,10.6-55.39A29.17,29.17,0,0,0,450.4,465.54Z" transform="translate(-84.99 -85.07)"/></g><path d="M512.35,565.11a11.67,11.67,0,0,0,3.83-5.78c.5-2.3-.48-5.05-2.68-5.89-2.46-.94-5.09.76-7.08,2.49s-4.28,3.69-6.89,3.32a10.48,10.48,0,0,0,3.24-9.81,4.1,4.1,0,0,0-.9-2c-1.37-1.46-3.84-.83-5.48.32-5.2,3.66-6.65,10.72-6.68,17.08-.52-2.29-.08-4.68-.1-7s-.66-5-2.64-6.22a8,8,0,0,0-4-.95c-2.34-.09-4.94.15-6.54,1.86-2,2.12-1.47,5.69.26,8s4.35,3.8,6.77,5.42a15,15,0,0,1,4.84,4.61,4.57,4.57,0,0,1,.36.82h14.65A40.83,40.83,0,0,0,512.35,565.11Z" transform="translate(-84.99 -85.07)" fill="#f9a826"/><path d="M539.26,752.88c2.33-2.17,4.52-4.73,5.2-7.84s-.65-6.85-3.63-8c-3.33-1.28-6.9,1-9.6,3.37s-5.8,5-9.33,4.5a14.21,14.21,0,0,0,4.39-13.3,5.56,5.56,0,0,0-1.22-2.7c-1.85-2-5.21-1.13-7.42.43-7,5-9,14.53-9.05,23.15-.71-3.11-.11-6.35-.13-9.54s-.89-6.72-3.58-8.44a10.79,10.79,0,0,0-5.46-1.28c-3.17-.12-6.7.2-8.86,2.52-2.69,2.88-2,7.71.35,10.88s5.9,5.16,9.17,7.35a20.34,20.34,0,0,1,6.55,6.25,6.19,6.19,0,0,1,.49,1.12H527A55.36,55.36,0,0,0,539.26,752.88Z" transform="translate(-84.99 -85.07)" fill="#f9a826"/></svg>
\ No newline at end of file
diff --git a/src/assets/logo-mini.png b/src/assets/logo-mini.png
new file mode 100644
index 0000000..542c1bc
Binary files /dev/null and b/src/assets/logo-mini.png differ
diff --git a/src/assets/logo-mini1.svg b/src/assets/logo-mini1.svg
new file mode 100644
index 0000000..53df94c
--- /dev/null
+++ b/src/assets/logo-mini1.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..0585888
--- /dev/null
+++ b/src/components/auth/auth.vue
@@ -0,0 +1,26 @@
+<template>
+ <slot v-if="getUserAuthBtnList" />
+</template>
+
+<script setup lang="ts" name="auth">
+import { computed } from 'vue';
+import { storeToRefs } from 'pinia';
+import { useUserInfo } from '/@/stores/userInfo';
+
+// 定义父组件传过来的值
+const props = defineProps({
+ value: {
+ type: String,
+ default: () => '',
+ },
+});
+
+// 定义变量内容
+const stores = useUserInfo();
+const { userInfos } = storeToRefs(stores);
+
+// 获取 pinia 中的用户权限
+const getUserAuthBtnList = computed(() => {
+ return userInfos.value.authBtnList.some((v: string) => v === props.value);
+});
+</script>
diff --git a/src/components/auth/authAll.vue b/src/components/auth/authAll.vue
new file mode 100644
index 0000000..54c8d58
--- /dev/null
+++ b/src/components/auth/authAll.vue
@@ -0,0 +1,27 @@
+<template>
+ <slot v-if="getUserAuthBtnList" />
+</template>
+
+<script setup lang="ts" name="authAll">
+import { computed } from 'vue';
+import { storeToRefs } from 'pinia';
+import { useUserInfo } from '/@/stores/userInfo';
+import { judementSameArr } from '/@/utils/arrayOperation';
+
+// 定义父组件传过来的值
+const props = defineProps({
+ value: {
+ type: Array,
+ default: () => [],
+ },
+});
+
+// 定义变量内容
+const stores = useUserInfo();
+const { userInfos } = storeToRefs(stores);
+
+// 获取 pinia 中的用户权限
+const getUserAuthBtnList = computed(() => {
+ return judementSameArr(props.value, userInfos.value.authBtnList);
+});
+</script>
diff --git a/src/components/auth/auths.vue b/src/components/auth/auths.vue
new file mode 100644
index 0000000..41b8b27
--- /dev/null
+++ b/src/components/auth/auths.vue
@@ -0,0 +1,32 @@
+<template>
+ <slot v-if="getUserAuthBtnList" />
+</template>
+
+<script setup lang="ts" name="auths">
+import { computed } from 'vue';
+import { storeToRefs } from 'pinia';
+import { useUserInfo } from '/@/stores/userInfo';
+
+// 定义父组件传过来的值
+const props = defineProps({
+ value: {
+ type: Array,
+ default: () => [],
+ },
+});
+
+// 定义变量内容
+const stores = useUserInfo();
+const { userInfos } = storeToRefs(stores);
+
+// 获取 pinia 中的用户权限
+const getUserAuthBtnList = computed(() => {
+ let flag = false;
+ userInfos.value.authBtnList.map((val: string) => {
+ props.value.map((v) => {
+ if (val === v) flag = true;
+ });
+ });
+ return flag;
+});
+</script>
diff --git a/src/components/checkboxGroup/index.vue b/src/components/checkboxGroup/index.vue
new file mode 100644
index 0000000..3a60e47
--- /dev/null
+++ b/src/components/checkboxGroup/index.vue
@@ -0,0 +1,26 @@
+<template>
+ <el-checkbox-group>
+ <el-checkbox v-for="item in myOptions" :key="item[props.valueKey]" v-bind="item" :label="item[props.valueKey]">
+ {{item[props.labelKey]}}
+ </el-checkbox>
+ </el-checkbox-group>
+
+</template>
+
+<script setup lang="ts">
+import useOptions from '/@/hook/useOptions';
+interface Props {
+ options?: Array<EmptyObjectType>;
+ valueKey?: string;
+ labelKey?: string;
+ resultKey?: string;
+ api?: () => Promise<EmptyObjectType | Array<EmptyObjectType>>;
+ url?: string;
+}
+const props = withDefaults(defineProps<Props>(), {
+ valueKey: 'id',
+ labelKey: 'name',
+ resultKey: 'data',
+});
+const { myOptions } = useOptions(props)
+</script>
diff --git a/src/components/cropper/index.vue b/src/components/cropper/index.vue
new file mode 100644
index 0000000..d7448d9
--- /dev/null
+++ b/src/components/cropper/index.vue
@@ -0,0 +1,143 @@
+<template>
+ <div>
+ <el-dialog title="更换头像" v-model="state.isShowDialog" width="769px">
+ <div class="cropper-warp">
+ <div class="cropper-warp-left">
+ <img :src="state.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="state.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="state.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 setup lang="ts" name="cropper">
+import { reactive, nextTick } from 'vue';
+import Cropper from 'cropperjs';
+import 'cropperjs/dist/cropper.css';
+
+// 定义变量内容
+const state = reactive({
+ isShowDialog: false,
+ cropperImg: '',
+ cropperImgBase64: '',
+ cropper: '' as RefType,
+});
+
+// 打开弹窗
+const openDialog = (imgs: string) => {
+ 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 = <HTMLImageElement>document.querySelector('.cropper-warp-left-img');
+ 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 = state.cropper.getCroppedCanvas().toDataURL('image/jpeg');
+ },
+ });
+};
+
+// 暴露变量
+defineExpose({
+ openDialog,
+});
+</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..c5fed8a
--- /dev/null
+++ b/src/components/editor/index.vue
@@ -0,0 +1,101 @@
+<template>
+ <div class="editor-container">
+ <Toolbar :editor="editorRef" :mode="mode" />
+ <Editor
+ :mode="mode"
+ :defaultConfig="state.editorConfig"
+ :style="{ height }"
+ v-model="state.editorVal"
+ @onCreated="handleCreated"
+ @onChange="handleChange"
+ />
+ </div>
+</template>
+
+<script setup lang="ts" name="wngEditor">
+// https://www.wangeditor.com/v5/for-frame.html#vue3
+import '@wangeditor/editor/dist/css/style.css';
+import { reactive, shallowRef, watch, onBeforeUnmount } from 'vue';
+import { IDomEditor } from '@wangeditor/editor';
+import { Toolbar, Editor } from '@wangeditor/editor-for-vue';
+
+// 定义父组件传过来的值
+const props = defineProps({
+ // 是否禁用
+ disable: {
+ type: Boolean,
+ default: () => false,
+ },
+ // 内容框默认 placeholder
+ placeholder: {
+ type: String,
+ default: () => '请输入内容...',
+ },
+ // 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',
+ },
+ // 双向绑定,用于获取 editor.getHtml()
+ getHtml: String,
+ // 双向绑定,用于获取 editor.getText()
+ getText: String,
+});
+
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['update:getHtml', 'update:getText']);
+
+// 定义变量内容
+const editorRef = shallowRef();
+const state = reactive({
+ editorConfig: {
+ placeholder: props.placeholder,
+ },
+ editorVal: props.getHtml,
+});
+
+// 编辑器回调函数
+const handleCreated = (editor: IDomEditor) => {
+ editorRef.value = editor;
+};
+// 编辑器内容改变时
+const handleChange = (editor: IDomEditor) => {
+ emit('update:getHtml', editor.getHtml());
+ emit('update:getText', editor.getText());
+};
+// 页面销毁时
+onBeforeUnmount(() => {
+ const editor = editorRef.value;
+ if (editor == null) return;
+ editor.destroy();
+});
+// 监听是否禁用改变
+// https://gitee.com/lyt-top/vue-next-admin/issues/I4LM7I
+watch(
+ () => props.disable,
+ (bool) => {
+ const editor = editorRef.value;
+ if (editor == null) return;
+ bool ? editor.disable() : editor.enable();
+ },
+ {
+ deep: true,
+ }
+);
+// 监听双向绑定值改变,用于回显
+watch(
+ () => props.getHtml,
+ (val) => {
+ state.editorVal = val;
+ },
+ {
+ deep: true,
+ }
+);
+</script>
diff --git a/src/components/form/component.ts b/src/components/form/component.ts
new file mode 100644
index 0000000..91ac505
--- /dev/null
+++ b/src/components/form/component.ts
@@ -0,0 +1,23 @@
+import { ElAutocomplete, ElCascader, ElCheckbox, ElColorPicker, ElDatePicker, ElInput, ElInputNumber, ElRadio, ElRate, ElSlider, ElSwitch, ElTimePicker, ElTimeSelect, ElUpload } from "element-plus";
+import Select from '../select/index.vue'
+import CheckboxGroup from '../checkboxGroup/index.vue'
+import RadioGroup from '../radioGroup/index.vue'
+export const forms = {
+ autocomplete: ElAutocomplete,
+ cascader: ElCascader,
+ checkbox: ElCheckbox,
+ checkboxGroup: CheckboxGroup,
+ colorPicker: ElColorPicker,
+ datePicker: ElDatePicker,
+ input: ElInput,
+ inputNumber: ElInputNumber,
+ radioGroup: RadioGroup,
+ radio: ElRadio,
+ rate: ElRate,
+ select: Select,
+ slider: ElSlider,
+ switch: ElSwitch,
+ timePicker: ElTimePicker,
+ timeSelect: ElTimeSelect,
+ upload: ElUpload
+}
diff --git a/src/components/form/hooks/useForm.ts b/src/components/form/hooks/useForm.ts
new file mode 100644
index 0000000..f4a2889
--- /dev/null
+++ b/src/components/form/hooks/useForm.ts
@@ -0,0 +1,32 @@
+import { FormInstance } from "element-plus";
+import { computed, ref } from "vue";
+import { FormEmits, FormProps } from "../model/form";
+
+export default function useForm (props: FormProps, emits: FormEmits) {
+ const formEl = ref<FormInstance>();
+ const formValue = computed({
+ get () {
+ return props.modelValue;
+ },
+ set (val) {
+ emits('update:modelValue', val);
+ }
+ });
+ const onChange = (...props: any[]) => {
+ emits('change', ...props);
+ }
+ const getColBind = (col?: number | Col) => {
+ if (typeof col === 'number') {
+ return {
+ span: col
+ }
+ }
+ return col
+ }
+ return {
+ formEl,
+ formValue,
+ onChange,
+ getColBind
+ }
+}
\ No newline at end of file
diff --git a/src/components/form/hooks/useFormWrapper.ts b/src/components/form/hooks/useFormWrapper.ts
new file mode 100644
index 0000000..ccc40e4
--- /dev/null
+++ b/src/components/form/hooks/useFormWrapper.ts
@@ -0,0 +1,34 @@
+import { ElDialog, ElDrawer } from "element-plus";
+import { computed } from "vue";
+import { WrapperEmits, WrapperProps } from "../model/wrapper";
+
+
+export default function useFormWrapper (props: WrapperProps, emits: WrapperEmits) {
+ const layoutComponent = computed(() => {
+ const is = {
+ div: 'div',
+ dialog: ElDialog,
+ drawer: ElDrawer,
+ }
+ return is[props.wrapper]
+ })
+ const layoutBind = computed(() => {
+ return props.wrapper === 'div' ? {} : {
+ title: props.title,
+ [props.wrapper === 'dialog' ? 'width' : 'size']: '50%',
+ }
+ });
+ const layoutVisible = computed({
+ get () {
+ return props.visible
+ },
+ set (val) {
+ emits('update:visible', val)
+ }
+ })
+ return {
+ layoutComponent,
+ layoutBind,
+ layoutVisible
+ }
+}
diff --git a/src/components/form/index.vue b/src/components/form/index.vue
new file mode 100644
index 0000000..4f5729a
--- /dev/null
+++ b/src/components/form/index.vue
@@ -0,0 +1,107 @@
+<template>
+ <component :is="layoutComponent" v-bind="layoutBind" v-model="layoutVisible" class="form-wrapper">
+ <div class="h-full flex flex-col overflow-auto form-body">
+ <div class="flex-1 overflow-auto p-4">
+ <el-form ref="formEl" :model="formValue" size="default" label-width="100px" class="table-form">
+ <el-row>
+ <template v-for="(item, key) in config" :key="key">
+ <el-col v-bind="getColBind(item.col)" v-if="item.if === undefined ? true : item.if" v-show="item.show === undefined ? true : item.show">
+ <el-form-item
+ class="form-item"
+ :label="item.label"
+ :prop="item.prop"
+ :rules="[{ required: item.required, message: `${item.label}不能为空`, trigger: item.component === 'input' || item.component === 'inputNumber' ? 'blur' : 'change' }]"
+ >
+ <slot v-if="item.slot" :name="item.slot" :model="formValue" :prop="item.prop"></slot>
+ <component v-else v-bind="item.props" v-model="formValue[item.prop]" :is="forms[item.component || 'input']" @change="onChange"></component>
+ </el-form-item>
+ </el-col>
+ </template>
+ <slot name="form-after"></slot>
+ </el-row>
+ </el-form>
+ </div>
+ <div class="p-4 flex justify-end border-t" v-if="handleVisible">
+ <el-button type="primary" @click="submit">
+ 保存
+ </el-button>
+ <el-button @click="cancel">取消</el-button>
+ </div>
+ </div>
+ </component>
+</template>
+
+<script setup lang="ts">
+import { ElMessage } from 'element-plus';
+import { forms } from './component';
+import { ColumnConfig } from './model/form';
+import useFormWrapper from './hooks/useFormWrapper';
+// import { WrapperEmits, WrapperProps } from './model/wrapper';
+import useForm from './hooks/useForm';
+
+interface Props {
+ wrapper?: 'div' | 'dialog' | 'drawer';
+ title?: string;
+ visible?: boolean;
+ config: ColumnConfig[];
+ modelValue: EmptyObjectType;
+ handleVisible?: boolean;
+}
+interface Emits {
+ (e: 'update:visible', val: boolean): void;
+ (e: 'update:modelValue', val: EmptyObjectType): void;
+ (e: 'change', ...val: any[] ): void;
+ (e: 'submit', val: EmptyObjectType): void;
+ (e: 'cancel'): void;
+}
+const props = withDefaults(defineProps<Props>(), {
+ wrapper: 'div',
+ config: () => [],
+ modelValue: () => ({}),
+ handleVisible: true,
+});
+const emits = defineEmits<Emits>();
+
+const { layoutComponent, layoutBind, layoutVisible } = useFormWrapper(props, emits);
+const { formEl, formValue, onChange, getColBind } = useForm(props, emits)
+
+const submit = async () => {
+ if (!formEl.value) return
+ await formEl.value.validate((valid, fields) => {
+ if (valid) {
+ emits('submit', formValue.value)
+ layoutVisible.value = false;
+ } else {
+ // console.log('error submit!', fields)
+ ElMessage.error(fields)
+ }
+ })
+}
+const cancel = () => {
+ layoutVisible.value = false;
+ emits('cancel')
+}
+defineExpose({
+ formEl
+})
+</script>
+
+<style lang="scss" scoped>
+.form-item {
+ :deep(.el-date-editor),
+ :deep(.el-date-editor) .el-input__wrapper,
+ :deep(.el-select) {
+ width: 100%;
+ }
+}
+</style>
+<style lang="scss">
+.form-wrapper {
+ .el-dialog__body {
+ padding: 0 !important;
+ .form-body {
+ max-height: calc(90vh - 111px) !important;
+ }
+ }
+}
+</style>
\ No newline at end of file
diff --git a/src/components/form/model/form.ts b/src/components/form/model/form.ts
new file mode 100644
index 0000000..09db69b
--- /dev/null
+++ b/src/components/form/model/form.ts
@@ -0,0 +1,50 @@
+import { FormRule } from "@form-create/element-ui";
+import { DefineComponent } from "vue";
+import { forms } from '../component';
+
+export type FormType = typeof forms;
+export type InstanceProps<T extends DefineComponent> = InstanceType<T>['$props'];
+export type ColumnProp<T> = T extends keyof FormType ? InstanceType<FormType[T]>['$props'] : undefined;
+
+export interface ColumnConfig {
+ // 字段名
+ prop: string;
+ // 字段中文名称
+ label?: string;
+ // 组件
+ component?: keyof FormType;
+ // 是否渲染
+ if?: boolean;
+ // 是否显示
+ show?: boolean;
+ // 自定义组件插槽
+ slot?: string;
+ // 必填
+ required?: boolean;
+ // 组件参数
+ props?: ColumnProp<ColumnConfig['component']>;
+ // 校验规则
+ rules?: FormRule[];
+ // 排序下标
+ index?: number;
+ // 所占列数
+ col?: number | Col;
+ // isCheck?: boolean;
+}
+
+export interface Col {
+ xs: number;
+ sm: number;
+ md: number;
+ lg: number;
+ xl: number;
+}
+
+export interface FormProps {
+ config: ColumnConfig[];
+ modelValue: EmptyObjectType;
+}
+export interface FormEmits {
+ (e: 'update:modelValue', val: EmptyObjectType): void;
+ (e: 'change', ...val: any[] ): void;
+}
\ No newline at end of file
diff --git a/src/components/form/model/wrapper.ts b/src/components/form/model/wrapper.ts
new file mode 100644
index 0000000..4118a97
--- /dev/null
+++ b/src/components/form/model/wrapper.ts
@@ -0,0 +1,9 @@
+export interface WrapperProps {
+ wrapper: 'div' | 'dialog' | 'drawer';
+ title?: string;
+ visible: boolean
+}
+
+export interface WrapperEmits {
+ (e: 'update:visible', val: boolean): void;
+}
\ No newline at end of file
diff --git a/src/components/iconSelector/index.vue b/src/components/iconSelector/index.vue
new file mode 100644
index 0000000..0c44d11
--- /dev/null
+++ b/src/components/iconSelector/index.vue
@@ -0,0 +1,241 @@
+<template>
+ <div class="icon-selector w100 h100">
+ <el-input
+ v-model="state.fontIconSearch"
+ :placeholder="state.fontIconPlaceholder"
+ :clearable="clearable"
+ :disabled="disabled"
+ :size="size"
+ ref="inputWidthRef"
+ @clear="onClearFontIcon"
+ @focus="onIconFocus"
+ @blur="onIconBlur"
+ >
+ <template #prepend>
+ <SvgIcon
+ :name="state.fontIconPrefix === '' ? prepend : state.fontIconPrefix"
+ class="font14"
+ v-if="state.fontIconPrefix === '' ? prepend?.indexOf('ele-') > -1 : state.fontIconPrefix?.indexOf('ele-') > -1"
+ />
+ <i v-else :class="state.fontIconPrefix === '' ? prepend : state.fontIconPrefix" class="font14"></i>
+ </template>
+ </el-input>
+ <el-popover
+ placement="bottom"
+ :width="state.fontIconWidth"
+ transition="el-zoom-in-top"
+ popper-class="icon-selector-popper"
+ trigger="click"
+ :virtual-ref="inputWidthRef"
+ virtual-triggering
+ >
+ <template #default>
+ <div class="icon-selector-warp">
+ <div class="icon-selector-warp-title">{{ title }}</div>
+ <el-tabs v-model="state.fontIconTabActive" @tab-click="onIconClick">
+ <el-tab-pane lazy label="ali" name="ali">
+ <IconList :list="fontIconSheetsFilterList" :empty="emptyDescription" :prefix="state.fontIconPrefix" @get-icon="onColClick" />
+ </el-tab-pane>
+ <el-tab-pane lazy label="ele" name="ele">
+ <IconList :list="fontIconSheetsFilterList" :empty="emptyDescription" :prefix="state.fontIconPrefix" @get-icon="onColClick" />
+ </el-tab-pane>
+ <el-tab-pane lazy label="awe" name="awe">
+ <IconList :list="fontIconSheetsFilterList" :empty="emptyDescription" :prefix="state.fontIconPrefix" @get-icon="onColClick" />
+ </el-tab-pane>
+ </el-tabs>
+ </div>
+ </template>
+ </el-popover>
+ </div>
+</template>
+
+<script setup lang="ts" name="iconSelector">
+import { defineAsyncComponent, ref, reactive, onMounted, nextTick, computed, watch } from 'vue';
+import type { TabsPaneContext } from 'element-plus';
+import initIconfont from '/@/utils/getStyleSheets';
+import '/@/theme/iconSelector.scss';
+
+// 定义父组件传过来的值
+const props = defineProps({
+ // 输入框前置内容
+ prepend: {
+ type: String,
+ default: () => 'ele-Pointer',
+ },
+ // 输入框占位文本
+ placeholder: {
+ type: String,
+ default: () => '请输入内容搜索图标或者选择图标',
+ },
+ // 输入框占位文本
+ size: {
+ type: String,
+ default: () => 'default',
+ },
+ // 弹窗标题
+ title: {
+ type: String,
+ default: () => '请选择图标',
+ },
+ // 禁用
+ 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,
+});
+
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['update:modelValue', 'get', 'clear']);
+
+// 引入组件
+const IconList = defineAsyncComponent(() => import('/@/components/iconSelector/list.vue'));
+
+// 定义变量内容
+const inputWidthRef = ref();
+const state = reactive({
+ fontIconPrefix: '',
+ fontIconWidth: 0,
+ fontIconSearch: '',
+ fontIconPlaceholder: '',
+ fontIconTabActive: 'ali',
+ fontIconList: {
+ ali: [],
+ ele: [],
+ awe: [],
+ },
+});
+
+// 处理 input 获取焦点时,modelValue 有值时,改变 input 的 placeholder 值
+const onIconFocus = () => {
+ if (!props.modelValue) return false;
+ state.fontIconSearch = '';
+ state.fontIconPlaceholder = props.modelValue;
+};
+// 处理 input 失去焦点时,为空将清空 input 值,为点击选中图标时,将取原先值
+const onIconBlur = () => {
+ const list = fontIconTabNameList();
+ setTimeout(() => {
+ const icon = list.filter((icon: string) => icon === state.fontIconSearch);
+ if (icon.length <= 0) state.fontIconSearch = '';
+ }, 300);
+};
+// 图标搜索及图标数据显示
+const fontIconSheetsFilterList = computed(() => {
+ const list = fontIconTabNameList();
+ if (!state.fontIconSearch) return list;
+ let search = state.fontIconSearch.trim().toLowerCase();
+ return list.filter((item: string) => {
+ if (item.toLowerCase().indexOf(search) !== -1) return item;
+ });
+});
+// 根据 tab name 类型设置图标
+const fontIconTabNameList = () => {
+ let iconList: any = [];
+ if (state.fontIconTabActive === 'ali') iconList = state.fontIconList.ali;
+ else if (state.fontIconTabActive === 'ele') iconList = state.fontIconList.ele;
+ else if (state.fontIconTabActive === 'awe') iconList = state.fontIconList.awe;
+ return iconList;
+};
+// 处理 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 类型,用于回显时,tab 高亮与初始化数据
+const initFontIconName = () => {
+ let name = 'ali';
+ if (props.modelValue!.indexOf('iconfont') > -1) name = 'ali';
+ else if (props.modelValue!.indexOf('ele-') > -1) name = 'ele';
+ else if (props.modelValue!.indexOf('fa') > -1) name = 'awe';
+ // 初始化 tab 高亮回显
+ state.fontIconTabActive = name;
+ return name;
+};
+// 初始化数据
+const initFontIconData = async (name: string) => {
+ if (name === 'ali') {
+ // 阿里字体图标使用 `iconfont xxx`
+ if (state.fontIconList.ali.length > 0) return;
+ await initIconfont.ali().then((res: any) => {
+ state.fontIconList.ali = res.map((i: string) => `iconfont ${i}`);
+ });
+ } else if (name === 'ele') {
+ // element plus 图标
+ if (state.fontIconList.ele.length > 0) return;
+ await initIconfont.ele().then((res: any) => {
+ state.fontIconList.ele = res;
+ });
+ } else if (name === 'awe') {
+ // fontawesome字体图标使用 `fa xxx`
+ if (state.fontIconList.awe.length > 0) return;
+ await initIconfont.awe().then((res: any) => {
+ state.fontIconList.awe = 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 onIconClick = (pane: TabsPaneContext) => {
+ initFontIconData(pane.paneName as string);
+ inputWidthRef.value.focus();
+};
+// 获取当前点击的 icon 图标
+const onColClick = (v: string) => {
+ state.fontIconPlaceholder = v;
+ state.fontIconPrefix = v;
+ emit('get', state.fontIconPrefix);
+ emit('update:modelValue', state.fontIconPrefix);
+ inputWidthRef.value.focus();
+};
+// 清空当前点击的 icon 图标
+const onClearFontIcon = () => {
+ state.fontIconPrefix = '';
+ emit('clear', state.fontIconPrefix);
+ emit('update:modelValue', state.fontIconPrefix);
+};
+// 获取 input 的宽度
+const getInputWidth = () => {
+ nextTick(() => {
+ state.fontIconWidth = inputWidthRef.value.$el.offsetWidth;
+ });
+};
+// 监听页面宽度改变
+const initResize = () => {
+ window.addEventListener('resize', () => {
+ getInputWidth();
+ });
+};
+// 页面加载时
+onMounted(() => {
+ initFontIconData(initFontIconName());
+ initResize();
+ getInputWidth();
+});
+// 监听双向绑定 modelValue 的变化
+watch(
+ () => props.modelValue,
+ () => {
+ initModeValueEcho();
+ initFontIconName();
+ }
+);
+</script>
diff --git a/src/components/iconSelector/list.vue b/src/components/iconSelector/list.vue
new file mode 100644
index 0000000..8bf837b
--- /dev/null
+++ b/src/components/iconSelector/list.vue
@@ -0,0 +1,84 @@
+<template>
+ <div class="icon-selector-warp-row">
+ <el-scrollbar ref="selectorScrollbarRef">
+ <el-row :gutter="10" v-if="props.list.length > 0">
+ <el-col :xs="6" :sm="4" :md="4" :lg="4" :xl="4" v-for="(v, k) in list" :key="k" @click="onColClick(v)">
+ <div class="icon-selector-warp-item" :class="{ 'icon-selector-active': prefix === v }">
+ <SvgIcon :name="v" />
+ </div>
+ </el-col>
+ </el-row>
+ <el-empty :image-size="100" v-if="list.length <= 0" :description="empty"></el-empty>
+ </el-scrollbar>
+ </div>
+</template>
+
+<script setup lang="ts" name="iconSelectorList">
+// 定义父组件传过来的值
+const props = defineProps({
+ // 图标列表数据
+ list: {
+ type: Array,
+ default: () => [],
+ },
+ // 自定义空状态描述文字
+ empty: {
+ type: String,
+ default: () => '无相关图标',
+ },
+ // 高亮当前选中图标
+ prefix: {
+ type: String,
+ default: () => '',
+ },
+});
+
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['get-icon']);
+
+// 当前 icon 图标点击时
+const onColClick = (v: unknown | string) => {
+ emit('get-icon', v);
+};
+</script>
+
+<style scoped lang="scss">
+.icon-selector-warp-row {
+ height: 230px;
+ overflow: hidden;
+ .el-row {
+ padding: 15px;
+ }
+ .el-scrollbar__bar.is-horizontal {
+ display: none;
+ }
+ .icon-selector-warp-item {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border: 1px solid var(--el-border-color);
+ border-radius: 5px;
+ margin-bottom: 10px;
+ height: 30px;
+ 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);
+ 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);
+ i {
+ color: var(--el-color-primary);
+ }
+ }
+}
+</style>
diff --git a/src/components/noticeBar/index.vue b/src/components/noticeBar/index.vue
new file mode 100644
index 0000000..8198bce
--- /dev/null
+++ b/src/components/noticeBar/index.vue
@@ -0,0 +1,191 @@
+<template>
+ <div class="notice-bar" :style="{ background, height: `${height}px` }" v-show="!state.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 setup lang="ts" name="noticeBar">
+import { reactive, ref, onMounted, nextTick } from 'vue';
+
+// 定义父组件传过来的值
+const props = defineProps({
+ // 通知栏模式,可选值为 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: () => '',
+ },
+});
+
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['close', 'link']);
+
+// 定义变量内容
+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();
+});
+</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;
+ :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/page/edit.vue b/src/components/page/edit.vue
new file mode 100644
index 0000000..51bbedd
--- /dev/null
+++ b/src/components/page/edit.vue
@@ -0,0 +1,88 @@
+<template>
+ <div v-loading="loading">
+ <Form :config="config" v-model="formData" v-model:visible="layoutVisible" :wrapper="wrapper" :title="isUpdate?'修改':'添加'" @submit="submit">
+ <template v-for="item in config.filter(item => item.slot)" :key="item.prop" #[`${item.slot!}`]="data">
+ <slot :name="item.slot" :model="data.model" :prop="data.prop"></slot>
+ </template>
+ </Form>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+import { usePageApi } from '/@/api/page';
+import Form from '/@/components/form/index.vue';
+import { ColumnConfig } from '../form/model/form';
+import { ElMessage } from 'element-plus';
+import { EventSettingRef } from './model';
+interface Props {
+ type: string;
+ wrapper?: 'div' | 'dialog' | 'drawer';
+ visible: boolean;
+ modelValue?: EmptyObjectType;
+ config: ColumnConfig[];
+}
+interface Emits {
+ (e: 'update:visible', val: boolean): void;
+ (e: 'update:modelValue', val: EmptyObjectType): void;
+ (e: 'submitSuccess'): void;
+}
+const props = withDefaults(defineProps<Props>(), {
+ modelValue: () => ({})
+});
+const emits = defineEmits<Emits>();
+const layoutVisible = computed({
+ get () {
+ return props.visible
+ },
+ set (val) {
+ emits('update:visible', val)
+ }
+})
+const loading = ref(false);
+const formData = computed({
+ get () {
+ return props.modelValue || {}
+ },
+ set (val) {
+ emits('update:modelValue', val)
+ }
+});
+const isUpdate = ref(false);
+const pageApi = usePageApi();
+
+const handleAdd = () => {
+ if (isUpdate.value) {
+ formData.value = {}
+ }
+ isUpdate.value = false;
+ layoutVisible.value = true;
+}
+const handleEdit = (id: number) => {
+ formData.value = {}
+ isUpdate.value = true;
+ layoutVisible.value = true;
+ loading.value = true
+ pageApi.getTableDetail(props.type, id).then(res => {
+ loading.value = false
+ formData.value = res.data
+ }).catch(() => {
+ loading.value = false
+ })
+}
+const submit = () => {
+ const submitApi = isUpdate.value ? pageApi.setTableItem : pageApi.addTableItem
+ submitApi(props.type, formData.value).then(() => {
+ ElMessage.success('保存成功!')
+ emits('submitSuccess')
+ })
+}
+defineExpose({
+ handleAdd,
+ handleEdit
+})
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/components/page/hook/useGetColumnsForm.ts b/src/components/page/hook/useGetColumnsForm.ts
new file mode 100644
index 0000000..eac8b1f
--- /dev/null
+++ b/src/components/page/hook/useGetColumnsForm.ts
@@ -0,0 +1,64 @@
+import { ref, Ref, watch } from "vue";
+import { ColumnConfig } from "../../form/model/form";
+import { TableColumn } from "../../table/type";
+import { EventSettingRef } from "../model";
+import { ColumnKind, usePageApi } from "/@/api/page";
+import { getFormConfigByFields, toCamelCase } from "/@/utils/other";
+interface Props {
+ type: string;
+ searchData?: EmptyObjectType;
+}
+interface Emits {
+ (e: 'update:searchData', val: EmptyObjectType): void;
+ (e: 'setting', val: EventSettingRef): void;
+}
+
+export default function useGetColumnsForm (props: Props, emits: Emits) {
+ const pageApi = usePageApi()
+
+ const editForm = ref({});
+
+ const searchForm = ref<EmptyObjectType>(props.searchData || {});
+ watch(() => props.searchData, (val) => {
+ searchForm.value = val || {}
+ })
+ watch(searchForm, (val) => {
+ emits('update:searchData', val)
+ })
+
+ const editConfig = ref([]) as Ref<ColumnConfig[]>;
+ const addConfig = ref([]) as Ref<ColumnConfig[]>;
+ const search = ref([]) as Ref<ColumnConfig[]>;
+ const columns = ref([]) as Ref<TableColumn[]>;
+ const col = { xs: 24, sm: 12, md: 8, lg: 8, xl: 6 }
+ pageApi.getColumns(props.type, ColumnKind.SEARCH).then(res => {
+ search.value = getFormConfigByFields(res.data, () => ({
+ required: false,
+ col
+ }))
+ emits('setting', { type: ColumnKind.SEARCH, config: search, formData: searchForm })
+ })
+ pageApi.getColumns(props.type, ColumnKind.LIST).then(res => {
+ columns.value = getFormConfigByFields(res.data, (item) => ({
+ prop: toCamelCase(item.name),
+ }))
+ emits('setting', { type: ColumnKind.LIST, config: columns })
+ })
+ pageApi.getColumns(props.type, ColumnKind.EDIT).then(res => {
+ editConfig.value = getFormConfigByFields(res.data)
+ emits('setting', { type: ColumnKind.EDIT, config: editConfig, formData: editForm })
+ })
+ pageApi.getColumns(props.type, ColumnKind.ADD).then(res => {
+ addConfig.value = getFormConfigByFields(res.data)
+ emits('setting', { type: ColumnKind.ADD, config: addConfig, formData: editForm })
+ })
+
+ return {
+ searchForm,
+ editForm,
+ editConfig,
+ addConfig,
+ search,
+ columns
+ }
+}
\ No newline at end of file
diff --git a/src/components/page/index.vue b/src/components/page/index.vue
new file mode 100644
index 0000000..4a2534e
--- /dev/null
+++ b/src/components/page/index.vue
@@ -0,0 +1,139 @@
+<template>
+ <div class="table-demo-container layout-padding">
+ <div class="table-demo-padding layout-padding-view layout-padding-auto">
+ <Table
+ ref="tableRef"
+ :data="data"
+ :config="config"
+ v-model:columns="columns"
+ :search="search"
+ :param="param"
+ :pager-visible="pagerVisible"
+ v-model:search-data="searchForm"
+ class="table-demo"
+ @del="onTableDelRow"
+ @add="onTableAdd"
+ @edit="onTableEdit"
+ @search="onSearch"
+ @sortHeader="onSortHeader">
+ <template v-for="item in search.filter(v => v.slot)" :key="item.prop" #[`${item.slot}`]="data">
+ <slot :name="item.slot" :model="data.model" :prop="data.prop"></slot>
+ </template>
+ <template v-for="item in columns.filter(v => v.slot)" :key="item.prop" #[`${item.slot}`]="data">
+ <slot :name="item.slot" :scope="data.scope"></slot>
+ </template>
+ </Table>
+ </div>
+ <Edit ref="editEl" v-model:visible="editVisible" :type="type" wrapper="drawer" :config="isUpdate ? editConfig : addConfig" :key="type" v-model="editForm" :isUpdate="isUpdate" @submit-success="getTableData">
+ <template v-for="item in editConfig.filter(item => item.slot)" :key="item.prop" #[`${item.slot}`]="data">
+ <slot :name="item.slot" :model="data.model" :prop="data.prop"></slot>
+ </template>
+ </Edit>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { defineAsyncComponent, ref } from 'vue';
+import { ElMessage } from 'element-plus';
+import { usePageApi } from '../../api/page';
+import Edit from './edit.vue';
+import { TableColumn } from '../table/type';
+import { EventSettingRef } from './model';
+import useGetColumnsForm from './hook/useGetColumnsForm';
+
+interface Props {
+ type: string;
+ searchData?: EmptyObjectType;
+}
+interface Emits {
+ (e: 'update:searchData', val: EmptyObjectType): void;
+ (e: 'setting', val: EventSettingRef): void;
+}
+const props = withDefaults(defineProps<Props>(), {
+ searchData: () => ({})
+});
+const emits = defineEmits<Emits>();
+const pageApi = usePageApi()
+const editVisible = ref(false);
+// 引入组件
+const Table = defineAsyncComponent(() => import('/@/components/table/index.vue'));
+
+// 初始化配置项数据与表单数据
+const { searchForm, editForm, editConfig, addConfig, search, columns } = useGetColumnsForm(props, emits)
+
+// 定义变量内容
+const tableRef = ref<RefType>();
+const isUpdate = ref(false);
+const pagerVisible = ref(false);
+const data = ref<EmptyObjectType[]>([]);
+const editEl = ref<InstanceType<typeof Edit>>();
+const config = ref<TableConfigType>({
+ total: 0, // 列表总数
+ loading: true, // loading 加载
+ isBorder: false, // 是否显示表格边框
+ isSerialNo: false, // 是否显示表格序号
+ isSelection: true, // 是否显示表格多选
+ isOperate: true, // 是否显示表格操作栏
+})
+const param = ref({
+ pageIndex: 1,
+ pageSize: 20,
+})
+
+// 初始化列表数据
+const getTableData = () => {
+ config.value.loading = true;
+ data.value = [];
+ pageApi.getTableData(props.type, { ...param.value, ...searchForm.value }).then(res => {
+ if (Array.isArray(res.data)) {
+ data.value = res.data || []
+ }
+ if (res.page) {
+ pagerVisible.value = true
+ config.value.total = res.page.totalCount
+ }
+ config.value.loading = false;
+ }).catch(() => {
+ config.value.loading = false;
+ })
+};
+
+// 删除当前项回调
+const onTableDelRow = (item: EmptyObjectType) => {
+ pageApi.delTableItem(props.type, item.id).then(() =>{
+ ElMessage.success(`删除成功!`);
+ getTableData();
+ })
+ getTableData();
+};
+const onTableAdd = () => {
+ editEl.value?.handleAdd();
+}
+const onTableEdit = (item: EmptyObjectType) => {
+ editEl.value?.handleEdit(item.id);
+}
+// 分页改变时回调
+const onSearch = (page: TableDemoPageType) => {
+ param.value.pageIndex = page.pageIndex;
+ param.value.pageSize = page.pageSize;
+ getTableData();
+};
+// 拖动显示列排序回调
+const onSortHeader = (data: TableColumn[]) => {
+ columns.value = data;
+};
+getTableData();
+
+</script>
+
+<style scoped lang="scss">
+.table-demo-container {
+ .table-demo-padding {
+ padding: 15px;
+ .table-demo {
+ flex: 1;
+ overflow: hidden;
+ }
+ }
+}
+</style>
diff --git a/src/components/page/model/index.ts b/src/components/page/model/index.ts
new file mode 100644
index 0000000..b635ab8
--- /dev/null
+++ b/src/components/page/model/index.ts
@@ -0,0 +1,44 @@
+import { Ref } from "vue";
+import { ColumnConfig } from "../../form/model/form";
+import { TableColumn } from "../../table/type";
+import { ColumnKind } from "/@/api/page";
+
+export interface TableDemoState {
+ tableData: {
+ data: EmptyObjectType[];
+ header: TableColumn[];
+ config: {
+ total: number;
+ loading: boolean;
+ isBorder: boolean;
+ isSelection: boolean;
+ isSerialNo: boolean;
+ isOperate: boolean;
+ };
+ search: ColumnConfig[];
+ param: {
+ pageNum: number;
+ pageSize: number;
+ };
+ };
+}
+
+type EventSettingRefConfig<T> = T extends ColumnKind.LIST ? Array<TableColumn> : Array<ColumnConfig>
+
+export interface EventSettingRef {
+ type: ColumnKind;
+ config: Ref<EventSettingRefConfig<EventSettingRef['type']>>;
+ formData?: Ref<EmptyObjectType>;
+}
+
+// type EventSettingPropsList = {
+// in: ColumnKind.LIST
+// } & TableColumn
+// type EventSettingPropsForm = {
+// in: ColumnKind.ADD | ColumnKind.DETAIL | ColumnKind.EDIT | ColumnKind.SEARCH
+// } & ColumnConfig
+// type EventSettingPropsCommon = ({in?: ColumnKind[]} & TableColumn) | ({ in?: ColumnKind[]} & ColumnConfig);
+
+export interface EventSettingProps {
+ columns?: Array<({ in?: ColumnKind | Array<ColumnKind> } & TableColumn) | ({ in?: ColumnKind | Array<ColumnKind> } & ColumnConfig)>
+}
diff --git a/src/components/radioGroup/index.vue b/src/components/radioGroup/index.vue
new file mode 100644
index 0000000..9627e07
--- /dev/null
+++ b/src/components/radioGroup/index.vue
@@ -0,0 +1,26 @@
+<template>
+ <el-radio-group>
+ <el-radio v-for="item in myOptions" :key="item[props.valueKey]" v-bind="item" :label="item[props.valueKey]">
+ {{item[props.labelKey]}}
+ </el-radio>
+ </el-radio-group>
+
+</template>
+
+<script setup lang="ts">
+import useOptions from '/@/hook/useOptions';
+interface Props {
+ options?: Array<EmptyObjectType>;
+ valueKey?: string;
+ labelKey?: string;
+ resultKey?: string;
+ api?: () => Promise<EmptyObjectType | Array<EmptyObjectType>>;
+ url?: string;
+}
+const props = withDefaults(defineProps<Props>(), {
+ valueKey: 'id',
+ labelKey: 'name',
+ resultKey: 'data',
+});
+const { myOptions } = useOptions(props)
+</script>
diff --git a/src/components/select/index.vue b/src/components/select/index.vue
new file mode 100644
index 0000000..5085aac
--- /dev/null
+++ b/src/components/select/index.vue
@@ -0,0 +1,33 @@
+<template>
+ <el-select v-bind="$attrs">
+ <el-option v-for="item in myOptions"
+ :key="item[valueKey]"
+ :label="item[labelKey]"
+ :disabled="item.disabled"
+ :value="item[valueKey]">
+ </el-option>
+ </el-select>
+</template>
+
+<script setup lang="ts">
+import useOptions from '/@/hook/useOptions';
+interface Props {
+ options?: Array<EmptyObjectType>;
+ valueKey?: string;
+ labelKey?: string;
+ resultKey?: string;
+ api?: () => Promise<EmptyObjectType | Array<EmptyObjectType>>;
+ url?: string;
+}
+const props = withDefaults(defineProps<Props>(), {
+ valueKey: 'id',
+ labelKey: 'name',
+ resultKey: 'data',
+});
+const { myOptions } = useOptions(props)
+
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/components/svgIcon/index.vue b/src/components/svgIcon/index.vue
new file mode 100644
index 0000000..576ee4c
--- /dev/null
+++ b/src/components/svgIcon/index.vue
@@ -0,0 +1,63 @@
+<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>
+ <Icon v-else-if="getIconName?.indexOf(':') !== -1" :icon="getIconName" :style="setIconSvgStyle"/>
+ <i v-else :class="getIconName" :style="setIconSvgStyle" />
+</template>
+
+<script setup lang="ts" name="svgIcon">
+import { computed } from 'vue';
+// 定义父组件传过来的值
+const props = defineProps({
+ // svg 图标组件名字
+ name: {
+ type: String,
+ },
+ // svg 大小
+ size: {
+ type: Number,
+ default: () => 14,
+ },
+ // svg 颜色
+ color: {
+ type: String,
+ },
+});
+
+// 在线链接、本地引入地址前缀
+// https://gitee.com/lyt-top/vue-next-admin/issues/I62OVL
+const linesString = ['https', 'http', '/src', '/assets', 'data:image', 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('')}`;
+});
+</script>
diff --git a/src/components/table/index.vue b/src/components/table/index.vue
new file mode 100644
index 0000000..5cfc9a7
--- /dev/null
+++ b/src/components/table/index.vue
@@ -0,0 +1,328 @@
+<template>
+ <div class="table-container">
+ <Search :search="search" @search="onSearch" v-model="searchDataRef">
+ <template #handle-after>
+ <el-button size="default" type="primary" @click="onAdd">添加 </el-button>
+ </template>
+ <template v-for="item in search.filter(item => item.slot)" :key="item.prop" #[`${item.slot}`]="data">
+ <slot :name="item.slot" :model="data.model" :prop="data.prop"></slot>
+ </template>
+ </Search>
+ <el-table
+ :data="data"
+ :border="setBorder"
+ v-bind="$attrs"
+ row-key="id"
+ stripe
+ style="width: 100%"
+ v-loading="config.loading"
+ @selection-change="onSelectionChange">
+ <el-table-column type="selection" :reserve-selection="true" width="40" fixed="left" v-if="config.isSelection && setHeader.length" />
+ <el-table-column type="index" label="序号" width="60" v-if="config.isSerialNo && setHeader.length" />
+ <template v-for="(item, index) in setHeader" :key="index">
+ <el-table-column
+ show-overflow-tooltip
+ :prop="item.prop"
+ :width="item.width"
+ :label="item.label"
+ v-if="item.if === undefined || item.if"
+ >
+ <template v-slot="scope">
+ <slot v-if="item.slot" :name="item.slot" :scope="scope" :model="scope.row" :prop="item.prop"></slot>
+ <template v-else-if="item.component === 'upload'">
+ <img :src="scope.row[item.prop]" width="50px" height="50px" />
+ </template>
+ <template v-else-if="item.component === 'switch'">
+ <el-tag :type="scope.row[item.prop] ? '' : 'info'" effect="dark">
+ <Icon v-if="scope.row[item.prop]" icon="material-symbols:check" class="text-lg"></Icon>
+ <Icon v-else icon="material-symbols:close" class="text-lg"></Icon>
+ </el-tag>
+ </template>
+ <template v-else>
+ {{ scope.row[item.prop] }}
+ </template>
+ </template>
+ </el-table-column>
+ </template>
+ <el-table-column label="操作" width="100" fixed="right" v-if="config.isOperate && setHeader.length">
+ <template v-slot="scope">
+ <el-button text type="primary" @click="onEdit(scope.row)">修改</el-button>
+ <el-popconfirm title="确定删除吗?" @confirm="onDel(scope.row)">
+ <template #reference>
+ <el-button text type="danger">删除</el-button>
+ </template>
+ </el-popconfirm>
+ </template>
+ </el-table-column>
+ <template #empty>
+ <el-empty description="暂无数据" />
+ </template>
+ <slot></slot>
+ </el-table>
+ <div class="table-footer mt15">
+ <el-pagination
+ v-if="pagerVisible"
+ v-model:current-page="state.page.pageIndex"
+ v-model:page-size="state.page.pageSize"
+ :pager-count="5"
+ :page-sizes="[10, 20, 30]"
+ :total="config.total"
+ layout="total, sizes, prev, pager, next, jumper"
+ background
+ @size-change="onHandleSizeChange"
+ @current-change="onHandleCurrentChange"
+ >
+ </el-pagination>
+ <div class="table-footer-tool">
+ <SvgIcon name="iconfont icon-yunxiazai_o" :size="22" title="导出" @click="onImportTable" />
+ <SvgIcon name="iconfont icon-shuaxin" :size="22" title="刷新" @click="onRefreshTable" />
+ <el-popover
+ placement="top-end"
+ trigger="click"
+ transition="el-zoom-in-top"
+ popper-class="table-tool-popper"
+ :width="300"
+ :persistent="false"
+ @show="onSetTable"
+ >
+ <template #reference>
+ <SvgIcon name="iconfont icon-quanjushezhi_o" :size="22" title="设置" />
+ </template>
+ <template #default>
+ <div class="tool-box">
+ <el-tooltip content="拖动进行排序" placement="top-start">
+ <SvgIcon name="fa fa-question-circle-o" :size="17" class="ml11" color="#909399" />
+ </el-tooltip>
+ <el-checkbox
+ v-model="state.checkListAll"
+ :indeterminate="state.checkListIndeterminate"
+ class="ml10 mr1"
+ label="列显示"
+ @change="onCheckAllChange"
+ />
+ <el-checkbox v-model="getConfig.isSerialNo" class="ml12 mr1" label="序号" />
+ <el-checkbox v-model="getConfig.isSelection" class="ml12 mr1" label="多选" />
+ </div>
+ <el-scrollbar>
+ <draggable
+ class="tool-sortable"
+ v-model="tableColumns"
+ item-key="prop">
+ <template #item="{element}">
+ <div class="tool-sortable-item">
+ <i class="fa fa-arrows-alt handle cursor-pointer"></i>
+ <el-checkbox v-model="element.isCheck" size="default" class="ml12 mr8" :label="element.label" @change="onCheckChange" />
+ </div>
+ </template>
+ </draggable>
+ <!-- <div ref="toolSetRef" class="tool-sortable">
+ <div class="tool-sortable-item" v-for="v in columns" :key="v.prop" :data-key="v.prop">
+ <i class="fa fa-arrows-alt handle cursor-pointer"></i>
+ <el-checkbox v-model="v.isCheck" size="default" class="ml12 mr8" :label="v.label" @change="onCheckChange" />
+ </div>
+ </div> -->
+ </el-scrollbar>
+ </template>
+ </el-popover>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script setup lang="ts" name="netxTable">
+import { reactive, computed, nextTick, watch, Ref } from 'vue';
+import { ElMessage } from 'element-plus';
+import table2excel from 'js-table2excel';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+import '/@/theme/tableTool.scss';
+import Search from './search.vue';
+import { ColumnConfig } from '../form/model/form';
+import { TableColumn } from './type';
+import draggable from 'vuedraggable'
+import { useVModel } from '@vueuse/core';
+// import useVModel from '/@/hook/useVModel';
+interface Param {
+ pageIndex?: number;
+ pageSize?: number;
+}
+interface Props {
+ data: EmptyObjectType[];
+ columns: TableColumn[];
+ config: TableConfigType;
+ search: ColumnConfig[];
+ param: Param;
+ pagerVisible: boolean;
+ searchData: EmptyObjectType;
+}
+// 定义父组件传过来的值
+const props = withDefaults(defineProps<Props>(), {
+ data: () => [],
+ columns: () => [],
+ config: () => ({
+ total: 0, // 列表总数
+ loading: true, // loading 加载
+ isBorder: false, // 是否显示表格边框
+ isSerialNo: false, // 是否显示表格序号
+ isSelection: true, // 是否显示表格多选
+ isOperate: true, // 是否显示表格操作栏
+ }),
+ search: () => [],
+ param: () => ({
+ pageIndex: 1,
+ pageSize: 10,
+ }),
+ pagerVisible: true,
+ searchData: () => ({})
+});
+
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['del', 'edit', 'add', 'search', 'sortHeader', 'update:searchData', 'update:columns']);
+const tableColumns = useVModel(props, 'columns', emit) as Ref<TableColumn[]>;
+// 定义变量内容
+// const toolSetRef = ref();
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+const state = reactive({
+ page: props.param,
+ selectlist: [] as EmptyObjectType[],
+ checkListAll: true,
+ checkListIndeterminate: false,
+});
+// const searchDataRef = useVModel(props, 'searchData', emit);
+const searchDataRef = computed({
+ get () {
+ return props.searchData || {}
+ },
+ set (val) {
+ emit('update:searchData', val)
+ }
+})
+
+// 设置边框显示/隐藏
+const setBorder = computed(() => {
+ return props.config.isBorder ? true : false;
+});
+// 获取父组件 配置项(必传)
+const getConfig = computed(() => {
+ return props.config;
+});
+// 设置 tool columns 数据
+const setHeader = computed(() => {
+ return props.columns.filter((v) => v.isCheck);
+});
+watch(() => props.columns, (val) => {
+ val.forEach(item => {
+ if (item.isCheck === undefined) {
+ item.isCheck = true
+ }
+ })
+})
+// tool 列显示全选改变时
+const onCheckAllChange = <T>(val: T) => {
+ if (val) props.columns.forEach((v) => (v.isCheck = true));
+ else props.columns.forEach((v) => (v.isCheck = false));
+ state.checkListIndeterminate = false;
+};
+// tool 列显示当前项改变时
+const onCheckChange = () => {
+ const headers = props.columns.filter((v) => v.isCheck).length;
+ state.checkListAll = headers === props.columns.length;
+ state.checkListIndeterminate = headers > 0 && headers < props.columns.length;
+};
+// 表格多选改变时,用于导出
+const onSelectionChange = (val: EmptyObjectType[]) => {
+ state.selectlist = val;
+};
+const onEdit = (row: EmptyObjectType) => {
+ emit('edit', row);
+}
+// 删除当前项
+const onDel = (row: EmptyObjectType) => {
+ emit('del', row);
+};
+const onAdd = () => {
+ emit('add');
+}
+// 分页改变
+const onHandleSizeChange = (val: number) => {
+ state.page.pageSize = val;
+ state.page.pageIndex = 1
+ emit('search', state.page);
+};
+// 分页改变
+const onHandleCurrentChange = (val: number) => {
+ state.page.pageIndex = val;
+ emit('search', state.page);
+};
+// 搜索时,分页还原成默认
+const pageReset = () => {
+ state.page.pageIndex = 1;
+ emit('search', state.page);
+};
+// 导出
+const onImportTable = () => {
+ if (state.selectlist.length <= 0) return ElMessage.warning('请先选择要导出的数据');
+ table2excel(props.columns, state.selectlist, `${themeConfig.value.globalTitle} ${new Date().toLocaleString()}`);
+};
+// 刷新
+const onRefreshTable = () => {
+ emit('search', state.page);
+};
+// 设置
+const onSetTable = () => {
+ nextTick(() => {
+ // const sortable = Sortable.create(toolSetRef.value, {
+ // handle: '.handle',
+ // dataIdAttr: 'data-key',
+ // animation: 150,
+ // onEnd: () => {
+ // const headerList: EmptyObjectType[] = [];
+ // sortable.toArray().forEach((val) => {
+ // props.columns.forEach((v) => {
+ // if (v.prop === val) headerList.push({ ...v });
+ // });
+ // });
+ // emit('sortHeader', headerList);
+ // },
+ // });
+ });
+};
+
+const onSearch = (data: EmptyObjectType) => {
+ state.page = Object.assign({}, state.page, { ...data });
+ pageReset();
+};
+
+// 暴露变量
+defineExpose({
+ pageReset,
+});
+</script>
+
+<style scoped lang="scss">
+.table-container {
+ display: flex;
+ flex-direction: column;
+ .el-table {
+ flex: 1;
+ }
+ .table-footer {
+ display: flex;
+ .table-footer-tool {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ i {
+ margin-right: 10px;
+ cursor: pointer;
+ color: var(--el-text-color-regular);
+ &:last-of-type {
+ margin-right: 0;
+ }
+ }
+ }
+ }
+}
+</style>
diff --git a/src/components/table/search.vue b/src/components/table/search.vue
new file mode 100644
index 0000000..64246df
--- /dev/null
+++ b/src/components/table/search.vue
@@ -0,0 +1,109 @@
+<template>
+ <div class="table-search-container" v-if="props.search.length > 0">
+ <Form ref="formRef" v-model="formData" :config="config" class="table-form" :handleVisible="false">
+ <template #form-after>
+ <el-col class="!flex-1 !max-w-none">
+ <el-form-item class="table-form-btn" :label-width="search.length <= 1 ? '10px' : '100px'">
+ <template #label v-if="search.length > 1">
+ <div class="table-form-btn-toggle ml10" @click="state.isToggle = !state.isToggle">
+ <span>{{ state.isToggle ? '收起筛选' : '展开筛选' }}</span>
+ <SvgIcon :name="state.isToggle ? 'ele-ArrowUp' : 'ele-ArrowDown'" />
+ </div>
+ </template>
+ <div class="flex justify-between w-full">
+ <div>
+ <el-button size="default" type="primary" @click="onSearch">查询 </el-button>
+ <el-button size="default" type="info" class="ml10" @click="onReset"> 重置 </el-button>
+ </div>
+ <div class="ml-2.5">
+ <slot name="handle-after"></slot>
+ </div>
+ </div>
+ </el-form-item>
+ </el-col>
+ </template>
+ <template v-for="item in config.filter(item => item.slot)" :key="item.prop" #[`${item.slot!}`]="data">
+ <slot :name="item.slot" :model="data.model" :prop="data.prop"></slot>
+ </template>
+ </Form>
+ </div>
+</template>
+
+<script setup lang="ts" name="makeTableDemoSearch">
+import { reactive, ref, onMounted, computed } from 'vue';
+import Form from '/@/components/form/index.vue'
+import { ColumnConfig } from '../form/model/form';
+interface Props {
+ search: ColumnConfig[];
+ modelValue: EmptyObjectType;
+}
+interface Emits {
+ (e: 'search', val: EmptyObjectType): void;
+ (e: 'update:modelValue', val: EmptyObjectType): void;
+}
+// 定义父组件传过来的值
+const props = withDefaults(defineProps<Props>(), {
+ search: () => [],
+});
+// 定义子组件向父组件传值/事件
+const emits = defineEmits<Emits>();
+
+const formData = computed({
+ get () {
+ return props.modelValue
+ },
+ set (val) {
+ emits('update:modelValue', val)
+ }
+})
+const config = computed(() => {
+ return props.search.map((item, index) => ({
+ ...item,
+ show: index === 0 || state.isToggle
+ }))
+})
+
+// 定义变量内容
+const formRef = ref<InstanceType<typeof Form>>();
+const state = reactive({
+ // form: {},
+ isToggle: false,
+});
+
+// 查询
+const onSearch = () => {
+ if (!formRef.value) return;
+ emits('search', formData.value);
+};
+// 重置
+const onReset = () => {
+ if (!formRef.value) return;
+ formRef.value?.formEl?.resetFields();
+ emits('search', formData.value);
+};
+// 初始化 form 字段,取自父组件 search.prop
+const initFormField = () => {
+ if (props.search.length <= 0) return false;
+ props.search.forEach((v) => (formData.value[v.prop] = ''));
+};
+// 页面加载时
+onMounted(() => {
+ initFormField();
+});
+</script>
+
+<style scoped lang="scss">
+.table-search-container {
+ display: flex;
+ .table-form {
+ flex: 1;
+ .table-form-btn-toggle {
+ white-space: nowrap;
+ user-select: none;
+ display: flex;
+ align-items: center;
+ color: var(--el-color-primary);
+ }
+ }
+}
+</style>
diff --git a/src/components/table/type.ts b/src/components/table/type.ts
new file mode 100644
index 0000000..27481c6
--- /dev/null
+++ b/src/components/table/type.ts
@@ -0,0 +1,27 @@
+import { FormRule } from "@form-create/element-ui";
+import { ColumnProp, FormType } from "../form/model/form";
+
+export interface TableColumn {
+ // 字段名
+ prop: string;
+ // 字段中文名
+ label?: string;
+ // 组件
+ component?: keyof FormType;
+ // 宽度
+ width?: string | number;
+ // 是否勾选显示
+ isCheck?: boolean;
+ // 自定义组件插槽
+ slot?: string;
+ // 是否必填
+ required?: boolean;
+ // 参数
+ props?: ColumnProp<TableColumn['component']>;
+ // 规则
+ rules?: FormRule[];
+ // 排序下标
+ index?: number;
+ // 是否渲染
+ if?: boolean;
+}
diff --git a/src/directive/authDirective.ts b/src/directive/authDirective.ts
new file mode 100644
index 0000000..5971e64
--- /dev/null
+++ b/src/directive/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/directive/customDirective.ts b/src/directive/customDirective.ts
new file mode 100644
index 0000000..c67350f
--- /dev/null
+++ b/src/directive/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/directive/index.ts b/src/directive/index.ts
new file mode 100644
index 0000000..e2e1c57
--- /dev/null
+++ b/src/directive/index.ts
@@ -0,0 +1,18 @@
+import type { App } from 'vue';
+import { authDirective } from '/@/directive/authDirective';
+import { wavesDirective, dragDirective } from '/@/directive/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/hook/useOptions.ts b/src/hook/useOptions.ts
new file mode 100644
index 0000000..33b63b2
--- /dev/null
+++ b/src/hook/useOptions.ts
@@ -0,0 +1,30 @@
+import { ref, watch } from "vue";
+import { usePageApi } from "../api/page";
+
+interface Props {
+ options?: Array<EmptyObjectType>;
+ valueKey?: string;
+ labelKey?: string;
+ resultKey?: string;
+ api?: () => Promise<EmptyObjectType | Array<EmptyObjectType>>;
+ url?: string;
+}
+
+export default function useOptions (props: Props) {
+ const myOptions = ref(props.options);
+ watch(() => props.options, (val) => {
+ myOptions.value = val
+ })
+ if (props.api) {
+ props.api().then(res => {
+ myOptions.value = props.resultKey ? res[props.resultKey] : res
+ })
+ } else if (props.url) {
+ usePageApi().getTableData(props.url, { pageIndex: 0 }).then(res => {
+ myOptions.value = props.resultKey ? res[props.resultKey] : res
+ })
+ }
+ return {
+ myOptions
+ }
+}
\ No newline at end of file
diff --git a/src/hook/usePageSetting.ts b/src/hook/usePageSetting.ts
new file mode 100644
index 0000000..18de975
--- /dev/null
+++ b/src/hook/usePageSetting.ts
@@ -0,0 +1,82 @@
+import { reactive, unref } from "vue";
+import { ColumnConfig } from "../components/form/model/form";
+import { TableColumn } from "../components/table/type";
+import { EventSettingProps, EventSettingRef } from "../components/page/model";
+import { ColumnKind } from "/@/api/page";
+import { deepMerge } from "/@/utils/other";
+// 各区域配置项(响应式)
+interface UseColumns {
+ table?: TableColumn[];
+ search?: ColumnConfig[];
+ add?: ColumnConfig[];
+ edit?: ColumnConfig[];
+ detail?: ColumnConfig[];
+}
+// 各区域表单值(响应式)
+interface UseForms {
+ // 搜索区域表单
+ search?: EmptyObjectType;
+ // 添加、修改、详情表单
+ data?: EmptyObjectType;
+}
+/**
+ * 页面配置
+ * @param newSettings 配置规则
+ * @returns setting: 回调方法; columns: 配置; forms: 表单;
+ */
+export default function usePageSetting (newSettings: EventSettingProps) {
+ const columns: UseColumns = reactive({
+ table: undefined,
+ search: undefined,
+ add: undefined,
+ edit: undefined,
+ detail: undefined,
+ })
+ const forms: UseForms = reactive({
+ search: undefined,
+ data: undefined
+ })
+ // 回调方法
+ const setting = (oldSetting: EventSettingRef) => {
+ if (oldSetting.type === ColumnKind.SEARCH) {
+ columns.search = oldSetting.config as unknown as ColumnConfig[];
+ forms.search = oldSetting.formData;
+ } else if (oldSetting.type === ColumnKind.LIST) {
+ columns.table = oldSetting.config as unknown as TableColumn[]
+ } else if (oldSetting.type === ColumnKind.ADD) {
+ columns.add = oldSetting.config as unknown as ColumnConfig[]
+ forms.data = oldSetting.formData;
+ } else if (oldSetting.type === ColumnKind.EDIT) {
+ columns.edit = oldSetting.config as unknown as ColumnConfig[]
+ forms.data = oldSetting.formData;
+ } else if (oldSetting.type === ColumnKind.DETAIL) {
+ columns.detail = oldSetting.config as unknown as ColumnConfig[]
+ forms.data = oldSetting.formData;
+ }
+ if (newSettings.columns) {
+ let newArr = newSettings.columns.filter(item => item.in === undefined || item.in === oldSetting.type || (Array.isArray(item.in) && item.in.some(v => v === oldSetting.type)))
+ let oldArrVal: Array<ColumnConfig | TableColumn> = unref(oldSetting.config)
+ newArr.forEach((newItem) => {
+ let oldItem = oldArrVal.find(v => v.prop === newItem.prop)
+ if (oldItem) {
+ // 合并配置
+ oldItem = deepMerge(oldItem, newItem)
+ } else if (newItem.in) {
+ // 追加配置
+ oldArrVal.push(newItem)
+ }
+ })
+ // 排序
+ let sortArr = oldArrVal.filter(item => item.index !== undefined).sort((item1, item2) => item1.index! - item2.index!)
+ oldArrVal = oldArrVal.filter(item => item.index === undefined)
+ sortArr.forEach(item => {
+ oldArrVal.splice(item.index!, 0, item)
+ })
+ }
+ }
+ return {
+ setting,
+ columns,
+ forms
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/index.ts b/src/i18n/index.ts
new file mode 100644
index 0000000..2b9072a
--- /dev/null
+++ b/src/i18n/index.ts
@@ -0,0 +1,68 @@
+import { createI18n } from 'vue-i18n';
+import pinia from '/@/stores/index';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+
+// 定义语言国际化内容
+
+/**
+ * 说明:
+ * 须在 pages 下新建文件夹(建议 `要国际化界面目录` 与 `i18n 目录` 相同,方便查找),
+ * 注意国际化定义的字段,不要与原有的定义字段相同。
+ * 1、/src/i18n/lang 下的 ts 为框架的国际化内容
+ * 2、/src/i18n/pages 下的 ts 为各界面的国际化内容
+ */
+
+// element plus 自带国际化
+import enLocale from 'element-plus/lib/locale/lang/en';
+import zhcnLocale from 'element-plus/lib/locale/lang/zh-cn';
+import zhtwLocale from 'element-plus/lib/locale/lang/zh-tw';
+
+// 定义变量内容
+const messages = {};
+const element = { en: enLocale, 'zh-cn': zhcnLocale, 'zh-tw': zhtwLocale };
+const itemize = { en: [], 'zh-cn': [], 'zh-tw': [] };
+const modules: Record<string, any> = import.meta.glob('./**/*.ts', { eager: true });
+
+// 对自动引入的 modules 进行分类 en、zh-cn、zh-tw
+// https://vitejs.cn/vite3-cn/guide/features.html#glob-import
+for (const path in modules) {
+ const key = path.match(/(\S+)\/(\S+).ts/);
+ if (itemize[key![2]]) itemize[key![2]].push(modules[path].default);
+ else itemize[key![2]] = modules[path];
+}
+
+// 合并数组对象(非标准数组对象,数组中对象的每项 key、value 都不同)
+function mergeArrObj<T>(list: T, key: string) {
+ let obj = {};
+ list[key].forEach((i: EmptyObjectType) => {
+ obj = Object.assign({}, obj, i);
+ });
+ return obj;
+}
+
+// 处理最终格式
+for (const key in itemize) {
+ messages[key] = {
+ name: key,
+ el: element[key].el,
+ message: mergeArrObj(itemize, key),
+ };
+}
+
+// 读取 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({
+ legacy: false,
+ 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..83d1129
--- /dev/null
+++ b/src/i18n/lang/en.ts
@@ -0,0 +1,192 @@
+// 定义内容
+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',
+ makeTableDemo: 'table 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',
+ layoutIframeViewOne: 'IframeViewOne',
+ layoutIframeViewTwo: 'IframeViewTwo',
+ },
+ 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',
+ twoMenuBarActiveColor: 'Menu Highlight Color',
+ twoIsMenuBarColorGradual: 'Menu gradient',
+ twoColumnsMenuBar: 'Column menu background',
+ twoColumnsMenuBarColor: 'Default font color bar menu',
+ twoIsColumnsMenuBarColorGradual: 'Column gradient',
+ twoIsColumnsMenuHoverPreload: 'Column Menu Hover Preload',
+ 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!',
+ },
+ upgrade: {
+ title: 'New version',
+ msg: 'The new version is available, please update it now! Dont worry, the update is fast!',
+ desc: 'Prompt: Update will restore the default configuration',
+ btnOne: 'Cruel refusal',
+ btnTwo: 'Update now',
+ btnTwoLoading: 'Updating',
+ },
+};
diff --git a/src/i18n/lang/zh-cn.ts b/src/i18n/lang/zh-cn.ts
new file mode 100644
index 0000000..e0713b9
--- /dev/null
+++ b/src/i18n/lang/zh-cn.ts
@@ -0,0 +1,192 @@
+// 定义内容
+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 演示',
+ makeTableDemo: '表格封装演示',
+ paramsIndex: '路由参数',
+ paramsCommon: '普通路由',
+ paramsDynamic: '动态路由',
+ paramsCommonDetails: '普通路由详情',
+ paramsDynamicDetails: '动态路由详情',
+ chartIndex: '大数据图表',
+ visualizingIndex: '数据可视化',
+ visualizingLinkDemo1: '数据可视化演示1',
+ visualizingLinkDemo2: '数据可视化演示2',
+ personal: '个人中心',
+ tools: '工具类集合',
+ layoutLinkView: '外链',
+ layoutIframeViewOne: '内嵌 iframe1',
+ layoutIframeViewTwo: '内嵌 iframe2',
+ },
+ 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: '菜单默认字体颜色',
+ twoMenuBarActiveColor: '菜单高亮背景色',
+ twoIsMenuBarColorGradual: '菜单背景渐变',
+ twoColumnsMenuBar: '分栏菜单背景',
+ twoColumnsMenuBarColor: '分栏菜单默认字体颜色',
+ twoIsColumnsMenuBarColorGradual: '分栏菜单背景渐变',
+ twoIsColumnsMenuHoverPreload: '分栏菜单鼠标悬停预加载',
+ 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: '复制失败!',
+ },
+ upgrade: {
+ title: '新版本升级',
+ msg: '新版本来啦,马上更新尝鲜吧!不用担心,更新很快的哦!',
+ desc: '提示:更新会还原默认配置',
+ btnOne: '残忍拒绝',
+ btnTwo: '马上更新',
+ btnTwoLoading: '更新中',
+ },
+};
diff --git a/src/i18n/lang/zh-tw.ts b/src/i18n/lang/zh-tw.ts
new file mode 100644
index 0000000..35e406f
--- /dev/null
+++ b/src/i18n/lang/zh-tw.ts
@@ -0,0 +1,192 @@
+// 定义内容
+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 演示',
+ makeTableDemo: '表格封裝演示',
+ paramsIndex: '路由參數',
+ paramsCommon: '普通路由',
+ paramsDynamic: '動態路由',
+ paramsCommonDetails: '普通路由詳情',
+ paramsDynamicDetails: '動態路由詳情',
+ chartIndex: '大資料圖表',
+ visualizingIndex: '數據視覺化',
+ visualizingLinkDemo1: '數據視覺化演示1',
+ visualizingLinkDemo2: '數據視覺化演示2',
+ personal: '個人中心',
+ tools: '工具類集合',
+ layoutLinkView: '外鏈',
+ layoutIframeViewOne: '内嵌 iframe1',
+ layoutIframeViewTwo: '内嵌 iframe2',
+ },
+ 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: '選單默認字體顏色',
+ twoMenuBarActiveColor: '選單高亮背景色',
+ twoIsMenuBarColorGradual: '選單背景漸變',
+ twoColumnsMenuBar: '分欄選單背景',
+ twoColumnsMenuBarColor: '分欄選單默認字體顏色',
+ twoIsColumnsMenuBarColorGradual: '分欄選單背景漸變',
+ twoIsColumnsMenuHoverPreload: '分欄選單滑鼠懸停預加載',
+ 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: '複製失敗!',
+ },
+ upgrade: {
+ title: '新版本陞級',
+ msg: '新版本來啦,馬上更新嘗鮮吧! 不用擔心,更新很快的哦!',
+ desc: '提示:更新會還原默認配寘',
+ btnOne: '殘忍拒絕',
+ btnTwo: '馬上更新',
+ btnTwoLoading: '更新中',
+ },
+};
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..d3f43ae
--- /dev/null
+++ b/src/i18n/pages/login/zh-cn.ts
@@ -0,0 +1,28 @@
+// 定义内容
+export default {
+ label: {
+ one1: '用户名登录',
+ two2: '手机号登录',
+ },
+ link: {
+ one3: '第三方登录',
+ two4: '友情链接',
+ },
+ account: {
+ accountPlaceholder1: '用户名',
+ accountPlaceholder2: '密码',
+ 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..8b5e248
--- /dev/null
+++ b/src/layout/component/aside.vue
@@ -0,0 +1,165 @@
+<template>
+ <div class="h100" v-show="!isTagsViewCurrenFull">
+ <el-aside class="layout-aside !shadow-none" :class="setCollapseStyle">
+ <Logo v-if="setShowLogo" class="aside-logo" />
+ <el-scrollbar class="flex-auto" ref="layoutAsideScrollbarRef" @mouseenter="onAsideEnterLeave(true)" @mouseleave="onAsideEnterLeave(false)">
+ <Vertical :menuList="state.menuList" />
+ </el-scrollbar>
+ </el-aside>
+ </div>
+</template>
+
+<script setup lang="ts" name="layoutAside">
+import { defineAsyncComponent, reactive, computed, watch, onBeforeMount, ref } 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 mittBus from '/@/utils/mitt';
+
+// 引入组件
+const Logo = defineAsyncComponent(() => import('/@/layout/logo/index.vue'));
+const Vertical = defineAsyncComponent(() => import('/@/layout/navMenu/vertical.vue'));
+
+// 定义变量内容
+const layoutAsideScrollbarRef = ref();
+const stores = useRoutesList();
+const storesThemeConfig = useThemeConfig();
+const storesTagsViewRoutes = useTagsViewRoutes();
+const { routesList } = storeToRefs(stores);
+const { themeConfig } = storeToRefs(storesThemeConfig);
+const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
+const state = reactive<AsideState>({
+ 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'];
+ }
+ }
+});
+// 设置显示/隐藏 logo
+const setShowLogo = computed(() => {
+ let { layout, isShowLogo } = themeConfig.value;
+ return (isShowLogo && layout === 'defaults') || (isShowLogo && layout === 'columns');
+});
+// 关闭移动端蒙版
+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', '');
+};
+// 设置/过滤路由(非静态路由/是否显示在菜单中)
+const setFilterRoutes = () => {
+ if (themeConfig.value.layout === 'columns') return false;
+ state.menuList = filterRoutesFun(routesList.value);
+};
+// 路由过滤递归函数
+const filterRoutesFun = <T extends RouteItem>(arr: T[]): T[] => {
+ return arr
+ .filter((item: T) => !item.meta?.isHide)
+ .map((item: T) => {
+ 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) mittBus.emit('restoreDefault');
+ // 开启 `分栏菜单鼠标悬停预加载` 才设置,防止 columnsAside.vue 监听 pinia.state
+ if (themeConfig.value.isColumnsMenuHoverPreload) stores.setColumnsMenuHover(bool);
+};
+// 页面加载前
+onBeforeMount(() => {
+ initMenuFixed(document.body.clientWidth);
+ setFilterRoutes();
+ // 此界面不需要取消监听(mittBus.off('setSendColumnsChildren))
+ // 因为切换布局时有的监听需要使用,取消了监听,某些操作将不生效
+ mittBus.on('setSendColumnsChildren', (res: MittMenu) => {
+ state.menuList = res.children;
+ });
+ // 开启经典布局分割菜单时,设置菜单数据
+ mittBus.on('setSendClassicChildren', (res: MittMenu) => {
+ let { layout, isClassicSplitMenu } = themeConfig.value;
+ if (layout === 'classic' && isClassicSplitMenu) {
+ state.menuList = [];
+ state.menuList = res.children;
+ }
+ });
+ // 开启经典布局分割菜单时,重新处理菜单数据
+ mittBus.on('getBreadcrumbIndexSetFilterRoutes', () => {
+ setFilterRoutes();
+ });
+ // 监听窗口大小改变时(适配移动端)
+ mittBus.on('layoutMobileResize', (res: LayoutMobileResize) => {
+ initMenuFixed(res.clientWidth);
+ closeLayoutAsideMobileMode();
+ });
+});
+// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
+watch(themeConfig.value, (val) => {
+ if (val.isShowLogoChange !== val.isShowLogo) {
+ if (layoutAsideScrollbarRef.value) layoutAsideScrollbarRef.value.update();
+ }
+});
+// 监听 pinia 值的变化,动态赋值给菜单中
+watch(
+ pinia.state,
+ (val) => {
+ let { layout, isClassicSplitMenu } = val.themeConfig.themeConfig;
+ if (layout === 'classic' && isClassicSplitMenu) return false;
+ setFilterRoutes();
+ },
+ {
+ deep: true,
+ }
+);
+</script>
+<style scoped lang="scss">
+.aside-logo {
+ &:deep(span) {
+ color: var(--next-bg-menuBarColor);
+ }
+}
+</style>
\ No newline at end of file
diff --git a/src/layout/component/columnsAside.vue b/src/layout/component/columnsAside.vue
new file mode 100644
index 0000000..d6ceedc
--- /dev/null
+++ b/src/layout/component/columnsAside.vue
@@ -0,0 +1,281 @@
+<template>
+ <div class="layout-columns-aside">
+ <el-scrollbar>
+ <ul @mouseleave="onColumnsAsideMenuMouseleave()">
+ <li
+ v-for="(v, k) in state.columnsAsideList"
+ :key="k"
+ @click="onColumnsAsideMenuClick(v)"
+ @mouseenter="onColumnsAsideMenuMouseenter(v, k)"
+ :ref="
+ (el) => {
+ if (el) columnsAsideOffsetTopRefs[k] = el;
+ }
+ "
+ :class="{ 'layout-columns-active': state.liIndex === k, 'layout-columns-hover': state.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 setup lang="ts" name="layoutColumnsAside">
+import { reactive, ref, onMounted, nextTick, watch, onUnmounted } 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';
+import mittBus from '/@/utils/mitt';
+
+// 定义变量内容
+const columnsAsideOffsetTopRefs = ref<RefType>([]);
+const columnsAsideActiveRef = ref();
+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) => {
+ if (k === undefined) return false;
+ state.liIndex = k;
+ columnsAsideActiveRef.value.style.top = `${columnsAsideOffsetTopRefs.value[k].offsetTop + state.difference}px`;
+};
+// 菜单高亮点击事件
+const onColumnsAsideMenuClick = async (v: RouteItem) => {
+ let { path, redirect } = v;
+ if (redirect) router.push(redirect);
+ else router.push(path);
+ // 一个路由设置自动收起菜单
+ // https://gitee.com/lyt-top/vue-next-admin/issues/I6HW7H
+ if (!v.children) themeConfig.value.isCollapse = true;
+ else if (v.children.length > 1) themeConfig.value.isCollapse = false;
+};
+// 鼠标移入时,显示当前的子级菜单
+const onColumnsAsideMenuMouseenter = (v: RouteRecordRaw, k: number) => {
+ if (!themeConfig.value.isColumnsMenuHoverPreload) return false;
+ let { path } = v;
+ state.liOldPath = path;
+ state.liOldIndex = k;
+ state.liHoverIndex = k;
+ mittBus.emit('setSendColumnsChildren', setSendChildren(path));
+ stores.setColumnsMenuHover(false);
+ stores.setColumnsNavHover(true);
+};
+// 鼠标移走时,显示原来的子级菜单
+const onColumnsAsideMenuMouseleave = async () => {
+ if (!themeConfig.value.isColumnsMenuHoverPreload) return false;
+ await stores.setColumnsNavHover(false);
+ // 添加延时器,防止拿到的 store.state.routesList 值不是最新的
+ setTimeout(() => {
+ if (!isColumnsMenuHover && !isColumnsNavHover) mittBus.emit('restoreDefault');
+ }, 100);
+};
+// 设置高亮动态位置
+const onColumnsAsideDown = (k: number) => {
+ nextTick(() => {
+ setColumnsAsideMove(k);
+ });
+};
+// 设置/过滤路由(非静态路由/是否显示在菜单中)
+const setFilterRoutes = () => {
+ state.columnsAsideList = filterRoutesFun(routesList.value);
+ const resData: MittMenu = setSendChildren(route.path);
+ if (Object.keys(resData).length <= 0) return false;
+ onColumnsAsideDown(resData.item?.k);
+ // 刷新时,初始化一个路由设置自动收起菜单
+ // https://gitee.com/lyt-top/vue-next-admin/issues/I6HW7H
+ resData.children.length <= 1 ? (themeConfig.value.isCollapse = true) : (themeConfig.value.isCollapse = false);
+ mittBus.emit('setSendColumnsChildren', resData);
+};
+// 传送当前子级数据到菜单中
+const setSendChildren = (path: string) => {
+ const currentPathSplit = path.split('/');
+ let currentData: MittMenu = { children: [] };
+ state.columnsAsideList.map((v: RouteItem, 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 = <T extends RouteItem>(arr: T[]): T[] => {
+ return arr
+ .filter((item: T) => !item.meta?.isHide)
+ .map((item: T) => {
+ 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: RouteItem) => v.path === routeFirst);
+ if (!currentSplitRoute) return false;
+ // 延迟拿值,防止取不到
+ setTimeout(() => {
+ onColumnsAsideDown(currentSplitRoute.k);
+ }, 0);
+};
+// 页面加载时
+onMounted(() => {
+ setFilterRoutes();
+ // 销毁变量,防止鼠标再次移入时,保留了上次的记录
+ mittBus.on('restoreDefault', () => {
+ state.liOldIndex = null;
+ state.liOldPath = null;
+ });
+});
+// 页面卸载时
+onUnmounted(() => {
+ mittBus.off('restoreDefault', () => {});
+});
+// 路由更新时
+onBeforeRouteUpdate((to) => {
+ setColumnsMenuHighlight(to.path);
+ mittBus.emit('setSendColumnsChildren', setSendChildren(to.path));
+});
+// 监听布局配置信息的变化,动态增加菜单高亮位置移动像素
+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;
+ mittBus.emit('setSendColumnsChildren', setSendChildren(route.path));
+ } else {
+ state.liHoverIndex = state.liOldIndex;
+ if (!state.liOldPath) return false;
+ mittBus.emit('setSendColumnsChildren', setSendChildren(state.liOldPath));
+ }
+ },
+ {
+ deep: true,
+ }
+);
+</script>
+
+<style scoped lang="scss">
+.layout-columns-aside {
+ width: 70px;
+ height: 100%;
+ background: var(--next-bg-columnsMenuBar);
+ ul {
+ position: relative;
+ .layout-columns-active,
+ .layout-columns-active a {
+ 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);
+ }
+ }
+ li {
+ color: var(--next-bg-columnsMenuBarColor);
+ width: 100%;
+ height: 50px;
+ text-align: center;
+ display: flex;
+ cursor: pointer;
+ position: relative;
+ z-index: 1;
+ &:hover {
+ @extend .layout-columns-hover;
+ }
+ .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);
+ }
+ }
+ .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..29aa179
--- /dev/null
+++ b/src/layout/component/header.vue
@@ -0,0 +1,18 @@
+<template>
+ <el-header class="layout-header" v-show="!isTagsViewCurrenFull">
+ <NavBarsIndex />
+ </el-header>
+</template>
+
+<script setup lang="ts" name="layoutHeader">
+import { defineAsyncComponent } from 'vue';
+import { storeToRefs } from 'pinia';
+import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
+
+// 引入组件
+const NavBarsIndex = defineAsyncComponent(() => import('/@/layout/navBars/index.vue'));
+
+// 定义变量内容
+const storesTagsViewRoutes = useTagsViewRoutes();
+const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
+</script>
diff --git a/src/layout/component/main.vue b/src/layout/component/main.vue
new file mode 100644
index 0000000..36cec94
--- /dev/null
+++ b/src/layout/component/main.vue
@@ -0,0 +1,65 @@
+<template>
+ <el-main class="layout-main" :style="isFixedHeader ? `height: calc(100% - ${setMainHeight})` : `minHeight: calc(100% - ${setMainHeight})`">
+ <el-scrollbar
+ ref="layoutMainScrollbarRef"
+ class="layout-main-scroll layout-backtop-header-fixed"
+ wrap-class="layout-main-scroll"
+ view-class="layout-main-scroll"
+ >
+ <LayoutParentView />
+ <LayoutFooter v-if="isFooter" />
+ </el-scrollbar>
+ <el-backtop :target="setBacktopClass" />
+ </el-main>
+</template>
+
+<script setup lang="ts" name="layoutMain">
+import { defineAsyncComponent, onMounted, computed, ref } from 'vue';
+import { useRoute } from 'vue-router';
+import { storeToRefs } from 'pinia';
+import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
+import { useThemeConfig } from '/@/stores/themeConfig';
+import { NextLoading } from '/@/utils/loading';
+
+// 引入组件
+const LayoutParentView = defineAsyncComponent(() => import('/@/layout/routerView/parent.vue'));
+const LayoutFooter = defineAsyncComponent(() => import('/@/layout/footer/index.vue'));
+
+// 定义变量内容
+const layoutMainScrollbarRef = ref();
+const route = useRoute();
+const storesTagsViewRoutes = useTagsViewRoutes();
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
+
+// 设置 footer 显示/隐藏
+const isFooter = computed(() => {
+ return themeConfig.value.isFooter && !route.meta.isIframe;
+});
+// 设置 header 固定
+const isFixedHeader = computed(() => {
+ return themeConfig.value.isFixedHeader;
+});
+// 设置 Backtop 回到顶部
+const setBacktopClass = computed(() => {
+ if (themeConfig.value.isFixedHeader) return `.layout-backtop-header-fixed .el-scrollbar__wrap`;
+ else return `.layout-backtop .el-scrollbar__wrap`;
+});
+// 设置主内容区的高度
+const setMainHeight = computed(() => {
+ if (isTagsViewCurrenFull.value) return '0px';
+ const { isTagsview, layout } = themeConfig.value;
+ if (isTagsview && layout !== 'classic') return '85px';
+ else return '51px';
+});
+// 页面加载前
+onMounted(() => {
+ NextLoading.done(600);
+});
+
+// 暴露变量
+defineExpose({
+ layoutMainScrollbarRef,
+});
+</script>
diff --git a/src/layout/footer/index.vue b/src/layout/footer/index.vue
new file mode 100644
index 0000000..97cffbf
--- /dev/null
+++ b/src/layout/footer/index.vue
@@ -0,0 +1,25 @@
+<template>
+ <div class="layout-footer pb15">
+ <div class="layout-footer-warp">
+ <div>vue-next-admin,Made by lyt with ❤️</div>
+ <div class="mt5">深圳市 xxx 公司版权所有</div>
+ </div>
+ </div>
+</template>
+
+<script setup lang="ts" name="layoutFooter">
+// 此处需有内容(注释也得),否则缓存将失败
+</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 0.3s ease;
+ }
+}
+</style>
diff --git a/src/layout/index.vue b/src/layout/index.vue
new file mode 100644
index 0000000..f4ee956
--- /dev/null
+++ b/src/layout/index.vue
@@ -0,0 +1,50 @@
+<template>
+ <component :is="layouts[themeConfig.layout]" />
+</template>
+
+<script setup lang="ts" name="layout">
+import { onBeforeMount, onUnmounted, defineAsyncComponent } from 'vue';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+import { Local } from '/@/utils/storage';
+import mittBus from '/@/utils/mitt';
+
+// 引入组件
+const layouts: any = {
+ 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')),
+};
+
+// 定义变量内容
+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;
+ mittBus.emit('layoutMobileResize', {
+ layout: 'defaults',
+ clientWidth,
+ });
+ } else {
+ 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);
+});
+</script>
diff --git a/src/layout/lockScreen/index.vue b/src/layout/lockScreen/index.vue
new file mode 100644
index 0000000..a565e5d
--- /dev/null
+++ b/src/layout/lockScreen/index.vue
@@ -0,0 +1,352 @@
+<template>
+ <div v-show="state.isShowLockScreen">
+ <div class="layout-lock-screen-mask"></div>
+ <div class="layout-lock-screen-img" :class="{ 'layout-lock-screen-filter': state.isShowLoockLogin }"></div>
+ <div class="layout-lock-screen">
+ <div
+ class="layout-lock-screen-date"
+ ref="layoutLockScreenDateRef"
+ @mousedown="onDownPc"
+ @mousemove="onMovePc"
+ @mouseup="onEnd"
+ @touchstart.stop="onDownApp"
+ @touchmove.stop="onMoveApp"
+ @touchend.stop="onEnd"
+ >
+ <div class="layout-lock-screen-date-box">
+ <div class="layout-lock-screen-date-box-time">
+ {{ state.time.hm }}<span class="layout-lock-screen-date-box-minutes">{{ state.time.s }}</span>
+ </div>
+ <div class="layout-lock-screen-date-box-info">{{ state.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="state.isShowLoockLogin" class="layout-lock-screen-login">
+ <div class="layout-lock-screen-login-box">
+ <div class="layout-lock-screen-login-box-img">
+ <img src="https://img2.baidu.com/it/u=1978192862,2048448374&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=500" />
+ </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="state.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 setup lang="ts" name="layoutLockScreen">
+import { nextTick, onMounted, reactive, ref, onUnmounted } from 'vue';
+import { formatDate } from '/@/utils/formatTime';
+import { Local } from '/@/utils/storage';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+
+// 定义变量内容
+const layoutLockScreenDateRef = ref<HtmlType>();
+const layoutLockScreenInputRef = ref();
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+const state = reactive({
+ transparency: 1,
+ downClientY: 0,
+ moveDifference: 0,
+ isShowLoockLogin: false,
+ isFlags: false,
+ querySelectorEl: '' as HtmlType,
+ time: {
+ hm: '',
+ s: '',
+ mdq: '',
+ },
+ setIntervalTime: 0,
+ isShowLockScreen: false,
+ isShowLockScreenIntervalTime: 0,
+ lockScreenPassword: '',
+});
+
+// 鼠标按下 pc
+const onDownPc = (down: MouseEvent) => {
+ state.isFlags = true;
+ state.downClientY = down.clientY;
+};
+// 鼠标按下 app
+const onDownApp = (down: TouchEvent) => {
+ state.isFlags = true;
+ state.downClientY = down.touches[0].clientY;
+};
+// 鼠标移动 pc
+const onMovePc = (move: MouseEvent) => {
+ state.moveDifference = move.clientY - state.downClientY;
+ onMove();
+};
+// 鼠标移动 app
+const onMoveApp = (move: TouchEvent) => {
+ state.moveDifference = move.touches[0].clientY - state.downClientY;
+ onMove();
+};
+// 鼠标移动事件
+const onMove = () => {
+ if (state.isFlags) {
+ const el = <HTMLElement>state.querySelectorEl;
+ const opacitys = (state.transparency -= 1 / 200);
+ 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 = layoutLockScreenDateRef.value;
+ });
+};
+// 时间初始化
+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);
+});
+</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;
+ }
+ }
+ }
+ }
+}
+:deep(.el-input-group__append) {
+ background: var(--el-color-white);
+ padding: 0px 15px;
+}
+: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..dc5810b
--- /dev/null
+++ b/src/layout/logo/index.vue
@@ -0,0 +1,77 @@
+<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 setup lang="ts" name="layoutLogo">
+import { computed } from 'vue';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+import logoMini from '/@/assets/logo-mini.png';
+
+// 定义变量内容
+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;
+};
+</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);
+ // color: #26a59a;
+ font-size: 16px;
+ cursor: pointer;
+ animation: logoAnimation 0.3s ease-in-out;
+ span {
+ white-space: nowrap;
+ display: inline-block;
+ // color: var(--next-bg-menuBarColor);
+ }
+ // &: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..56d3b8e
--- /dev/null
+++ b/src/layout/main/classic.vue
@@ -0,0 +1,71 @@
+<template>
+ <el-container class="layout-container flex-center">
+ <LayoutHeader />
+ <el-container class="layout-mian-height-50">
+ <LayoutAside />
+ <div class="flex-center layout-backtop">
+ <LayoutTagsView v-if="isTagsview" />
+ <LayoutMain ref="layoutMainRef" />
+ </div>
+ </el-container>
+ </el-container>
+</template>
+
+<script setup lang="ts" name="layoutClassic">
+import { defineAsyncComponent, computed, ref, watch, nextTick, onMounted } from 'vue';
+import { useRoute } from 'vue-router';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+
+// 引入组件
+const LayoutAside = defineAsyncComponent(() => import('/@/layout/component/aside.vue'));
+const LayoutHeader = defineAsyncComponent(() => import('/@/layout/component/header.vue'));
+const LayoutMain = defineAsyncComponent(() => import('/@/layout/component/main.vue'));
+const LayoutTagsView = defineAsyncComponent(() => import('/@/layout/navBars/tagsView/tagsView.vue'));
+
+// 定义变量内容
+const layoutMainRef = ref<InstanceType<typeof LayoutMain>>();
+const route = useRoute();
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+
+// 判断是否显示 tasgview
+const isTagsview = computed(() => {
+ return themeConfig.value.isTagsview;
+});
+// 重置滚动条高度,更新子级 scrollbar
+const updateScrollbar = () => {
+ layoutMainRef.value?.layoutMainScrollbarRef.update();
+};
+// 重置滚动条高度,由于组件是异步引入的
+const initScrollBarHeight = () => {
+ nextTick(() => {
+ setTimeout(() => {
+ updateScrollbar();
+ // '!' not null 断言操作符,不执行运行时检查
+ layoutMainRef.value!.layoutMainScrollbarRef.wrapRef.scrollTop = 0;
+ }, 500);
+ });
+};
+// 页面加载时
+onMounted(() => {
+ initScrollBarHeight();
+});
+// 监听路由的变化,切换界面时,滚动条置顶
+watch(
+ () => route.path,
+ () => {
+ initScrollBarHeight();
+ }
+);
+// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
+watch(
+ themeConfig,
+ () => {
+ updateScrollbar();
+ },
+ {
+ deep: true,
+ }
+);
+</script>
diff --git a/src/layout/main/columns.vue b/src/layout/main/columns.vue
new file mode 100644
index 0000000..e838729
--- /dev/null
+++ b/src/layout/main/columns.vue
@@ -0,0 +1,71 @@
+<template>
+ <el-container class="layout-container">
+ <ColumnsAside />
+ <el-container class="layout-columns-warp layout-container-view h100">
+ <LayoutAside />
+ <el-scrollbar ref="layoutScrollbarRef" class="layout-backtop">
+ <LayoutHeader />
+ <LayoutMain ref="layoutMainRef" />
+ </el-scrollbar>
+ </el-container>
+ </el-container>
+</template>
+
+<script setup lang="ts" name="layoutColumns">
+import { defineAsyncComponent, watch, onMounted, nextTick, ref } from 'vue';
+import { useRoute } from 'vue-router';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+
+// 引入组件
+const LayoutAside = defineAsyncComponent(() => import('/@/layout/component/aside.vue'));
+const LayoutHeader = defineAsyncComponent(() => import('/@/layout/component/header.vue'));
+const LayoutMain = defineAsyncComponent(() => import('/@/layout/component/main.vue'));
+const ColumnsAside = defineAsyncComponent(() => import('/@/layout/component/columnsAside.vue'));
+
+// 定义变量内容
+const layoutScrollbarRef = ref<RefType>('');
+const layoutMainRef = ref<InstanceType<typeof LayoutMain>>();
+const route = useRoute();
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+
+// 重置滚动条高度
+const updateScrollbar = () => {
+ // 更新父级 scrollbar
+ layoutScrollbarRef.value.update();
+ // 更新子级 scrollbar
+ layoutMainRef.value && layoutMainRef.value!.layoutMainScrollbarRef.update();
+};
+// 重置滚动条高度,由于组件是异步引入的
+const initScrollBarHeight = () => {
+ nextTick(() => {
+ setTimeout(() => {
+ updateScrollbar();
+ layoutScrollbarRef.value.wrapRef.scrollTop = 0;
+ layoutMainRef.value!.layoutMainScrollbarRef.wrapRef.scrollTop = 0;
+ }, 500);
+ });
+};
+// 页面加载时
+onMounted(() => {
+ initScrollBarHeight();
+});
+// 监听路由的变化,切换界面时,滚动条置顶
+watch(
+ () => route.path,
+ () => {
+ initScrollBarHeight();
+ }
+);
+// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
+watch(
+ themeConfig,
+ () => {
+ updateScrollbar();
+ },
+ {
+ deep: true,
+ }
+);
+</script>
diff --git a/src/layout/main/defaults.vue b/src/layout/main/defaults.vue
new file mode 100644
index 0000000..5a9a16c
--- /dev/null
+++ b/src/layout/main/defaults.vue
@@ -0,0 +1,71 @@
+<template>
+ <el-container class="layout-container">
+ <LayoutAside />
+ <el-container class="layout-container-view h100">
+ <el-scrollbar ref="layoutScrollbarRef" class="layout-backtop">
+ <LayoutHeader />
+ <LayoutMain ref="layoutMainRef" />
+ </el-scrollbar>
+ </el-container>
+ </el-container>
+</template>
+
+<script setup lang="ts" name="layoutDefaults">
+import { defineAsyncComponent, watch, onMounted, nextTick, ref } from 'vue';
+import { useRoute } from 'vue-router';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+import { NextLoading } from '/@/utils/loading';
+
+// 引入组件
+const LayoutAside = defineAsyncComponent(() => import('/@/layout/component/aside.vue'));
+const LayoutHeader = defineAsyncComponent(() => import('/@/layout/component/header.vue'));
+const LayoutMain = defineAsyncComponent(() => import('/@/layout/component/main.vue'));
+
+// 定义变量内容
+const layoutScrollbarRef = ref<RefType>('');
+const layoutMainRef = ref<InstanceType<typeof LayoutMain>>();
+const route = useRoute();
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+
+// 重置滚动条高度
+const updateScrollbar = () => {
+ // 更新父级 scrollbar
+ layoutScrollbarRef.value.update();
+ // 更新子级 scrollbar
+ layoutMainRef.value!.layoutMainScrollbarRef.update();
+};
+// 重置滚动条高度,由于组件是异步引入的
+const initScrollBarHeight = () => {
+ nextTick(() => {
+ setTimeout(() => {
+ updateScrollbar();
+ layoutScrollbarRef.value.wrapRef.scrollTop = 0;
+ layoutMainRef.value!.layoutMainScrollbarRef.wrapRef.scrollTop = 0;
+ }, 500);
+ });
+};
+// 页面加载时
+onMounted(() => {
+ initScrollBarHeight();
+ NextLoading.done(600);
+});
+// 监听路由的变化,切换界面时,滚动条置顶
+watch(
+ () => route.path,
+ () => {
+ initScrollBarHeight();
+ }
+);
+// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
+watch(
+ themeConfig,
+ () => {
+ updateScrollbar();
+ },
+ {
+ deep: true,
+ }
+);
+</script>
diff --git a/src/layout/main/transverse.vue b/src/layout/main/transverse.vue
new file mode 100644
index 0000000..1cd7773
--- /dev/null
+++ b/src/layout/main/transverse.vue
@@ -0,0 +1,58 @@
+<template>
+ <el-container class="layout-container flex-center layout-backtop">
+ <LayoutHeader />
+ <LayoutMain ref="layoutMainRef" />
+ </el-container>
+</template>
+
+<script setup lang="ts" name="layoutTransverse">
+import { defineAsyncComponent, ref, watch, nextTick, onMounted } from 'vue';
+import { useRoute } from 'vue-router';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+
+// 引入组件
+const LayoutHeader = defineAsyncComponent(() => import('/@/layout/component/header.vue'));
+const LayoutMain = defineAsyncComponent(() => import('/@/layout/component/main.vue'));
+
+// 定义变量内容
+const layoutMainRef = ref<InstanceType<typeof LayoutMain>>();
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+const route = useRoute();
+
+// 重置滚动条高度,更新子级 scrollbar
+const updateScrollbar = () => {
+ layoutMainRef.value!.layoutMainScrollbarRef.update();
+};
+// 重置滚动条高度,由于组件是异步引入的
+const initScrollBarHeight = () => {
+ nextTick(() => {
+ setTimeout(() => {
+ updateScrollbar();
+ layoutMainRef.value!.layoutMainScrollbarRef.wrapRef.scrollTop = 0;
+ }, 500);
+ });
+};
+// 页面加载时
+onMounted(() => {
+ initScrollBarHeight();
+});
+// 监听路由的变化,切换界面时,滚动条置顶
+watch(
+ () => route.path,
+ () => {
+ initScrollBarHeight();
+ }
+);
+// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
+watch(
+ themeConfig,
+ () => {
+ updateScrollbar();
+ },
+ {
+ deep: true,
+ }
+);
+</script>
diff --git a/src/layout/navBars/breadcrumb/breadcrumb.vue b/src/layout/navBars/breadcrumb/breadcrumb.vue
new file mode 100644
index 0000000..7dfaca6
--- /dev/null
+++ b/src/layout/navBars/breadcrumb/breadcrumb.vue
@@ -0,0 +1,146 @@
+<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 state.breadcrumbList" :key="!v.meta.tagsViewName ? v.meta.title : v.meta.tagsViewName">
+ <span v-if="k === state.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 setup lang="ts" name="layoutBreadcrumb">
+import { reactive, computed, onMounted } 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';
+
+// 定义变量内容
+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: RouteItem) => {
+ 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: RouteItems) => {
+ arr.forEach((item: RouteItem) => {
+ state.routeSplit.forEach((v: string, k: number, arrs: string[]) => {
+ 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(<RouteToFrom>route);
+};
+// 页面加载时
+onMounted(() => {
+ initRouteSplit(route.path);
+});
+// 路由更新时
+onBeforeRouteUpdate((to) => {
+ initRouteSplit(to.path);
+});
+</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;
+ }
+ :deep(.el-breadcrumb__separator) {
+ opacity: 0.7;
+ color: var(--next-bg-topBarColor);
+ }
+ :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..080dad5
--- /dev/null
+++ b/src/layout/navBars/breadcrumb/closeFull.vue
@@ -0,0 +1,53 @@
+<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 setup lang="ts" name="layoutCloseFull">
+import { storeToRefs } from 'pinia';
+import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
+
+// 定义变量内容
+const stores = useTagsViewRoutes();
+const { isTagsViewCurrenFull } = storeToRefs(stores);
+
+// 关闭当前全屏
+const onCloseFullscreen = () => {
+ stores.setCurrenFullscreen(false);
+};
+</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;
+ :deep(i) {
+ position: absolute;
+ left: 10px;
+ top: 35px;
+ color: #333333;
+ transition: all 0.3s ease;
+ }
+ }
+ &:hover {
+ transition: all 0.3s ease;
+ :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..29bd1bc
--- /dev/null
+++ b/src/layout/navBars/breadcrumb/index.vue
@@ -0,0 +1,107 @@
+<template>
+ <div class="layout-navbars-breadcrumb-index">
+ <Logo v-if="setIsShowLogo" />
+ <Breadcrumb />
+ <Horizontal :menuList="state.menuList" v-if="isLayoutTransverse" />
+ <User />
+ </div>
+</template>
+
+<script setup lang="ts" name="layoutBreadcrumbIndex">
+import { defineAsyncComponent, computed, reactive, onMounted, onUnmounted } from 'vue';
+import { useRoute } from 'vue-router';
+import { storeToRefs } from 'pinia';
+import { useRoutesList } from '/@/stores/routesList';
+import { useThemeConfig } from '/@/stores/themeConfig';
+import mittBus from '/@/utils/mitt';
+
+// 引入组件
+const Breadcrumb = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/breadcrumb.vue'));
+const User = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/user.vue'));
+const Logo = defineAsyncComponent(() => import('/@/layout/logo/index.vue'));
+const Horizontal = defineAsyncComponent(() => import('/@/layout/navMenu/horizontal.vue'));
+
+// 定义变量内容
+const stores = useRoutesList();
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+const { routesList } = storeToRefs(stores);
+const route = useRoute();
+const state = reactive({
+ menuList: [] as RouteItems,
+});
+
+// 设置 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);
+ mittBus.emit('setSendClassicChildren', resData);
+ } else {
+ state.menuList = filterRoutesFun(routesList.value);
+ }
+};
+// 设置了分割菜单时,删除底下 children
+const delClassicChildren = <T extends ChilType>(arr: T[]): T[] => {
+ arr.map((v: T) => {
+ if (v.children) delete v.children;
+ });
+ return arr;
+};
+// 路由过滤递归函数
+const filterRoutesFun = <T extends RouteItem>(arr: T[]): T[] => {
+ return arr
+ .filter((item: T) => !item.meta?.isHide)
+ .map((item: T) => {
+ item = Object.assign({}, item);
+ if (item.children) item.children = filterRoutesFun(item.children);
+ return item;
+ });
+};
+// 传送当前子级数据到菜单中
+const setSendClassicChildren = (path: string) => {
+ const currentPathSplit = path.split('/');
+ let currentData: MittMenu = { children: [] };
+ filterRoutesFun(routesList.value).map((v: RouteItem, 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;
+};
+// 页面加载时
+onMounted(() => {
+ setFilterRoutes();
+ mittBus.on('getBreadcrumbIndexSetFilterRoutes', () => {
+ setFilterRoutes();
+ });
+});
+// 页面卸载时
+onUnmounted(() => {
+ mittBus.off('getBreadcrumbIndexSetFilterRoutes', () => {});
+});
+</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..624d997
--- /dev/null
+++ b/src/layout/navBars/breadcrumb/search.vue
@@ -0,0 +1,124 @@
+<template>
+ <div class="layout-search-dialog">
+ <el-dialog v-model="state.isShowSearch" destroy-on-close :show-close="false">
+ <template #footer>
+ <el-autocomplete
+ v-model="state.menuQuery"
+ :fetch-suggestions="menuSearch"
+ :placeholder="$t('message.user.searchPlaceholder')"
+ ref="layoutMenuAutocompleteRef"
+ @select="onHandleSelect"
+ :fit-input-width="true"
+ >
+ <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>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup lang="ts" name="layoutBreadcrumbSearch">
+import { reactive, ref, nextTick } from 'vue';
+import { useRouter } from 'vue-router';
+import { useI18n } from 'vue-i18n';
+import { storeToRefs } from 'pinia';
+import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
+
+// 定义变量内容
+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 = (queryString: string) => {
+ return (restaurant: RouteItem) => {
+ 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: RouteItem) => {
+ if (!v.meta?.isHide) state.tagsViewList.push({ ...v });
+ });
+};
+// 当前菜单选中时
+const onHandleSelect = (item: RouteItem) => {
+ 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();
+};
+
+// 暴露变量
+defineExpose({
+ openSearch,
+});
+</script>
+
+<style scoped lang="scss">
+.layout-search-dialog {
+ position: relative;
+ :deep(.el-dialog) {
+ .el-dialog__header,
+ .el-dialog__body {
+ display: none;
+ }
+ .el-dialog__footer {
+ position: absolute;
+ left: 50%;
+ transform: translateX(-50%);
+ top: -53vh;
+ }
+ }
+ :deep(.el-autocomplete) {
+ width: 560px;
+ position: absolute;
+ top: 150px;
+ 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..45421c5
--- /dev/null
+++ b/src/layout/navBars/breadcrumb/setings.vue
@@ -0,0 +1,824 @@
+<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">
+ <div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.twoMenuBarActiveColor') }}</div>
+ <div class="layout-breadcrumb-seting-bar-flex-value">
+ <el-color-picker
+ v-model="getThemeConfig.menuBarActiveColor"
+ size="default"
+ show-alpha
+ @change="onBgColorPickerChange('menuBarActiveColor')"
+ />
+ </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>
+ <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.twoIsColumnsMenuHoverPreload') }}</div>
+ <div class="layout-breadcrumb-seting-bar-flex-value">
+ <el-switch
+ v-model="getThemeConfig.isColumnsMenuHoverPreload"
+ size="small"
+ @change="onColumnsMenuHoverPreloadChange"
+ :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: state.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="state.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"></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 setup lang="ts" name="layoutBreadcrumbSeting">
+import { nextTick, onUnmounted, onMounted, computed, reactive } from 'vue';
+import { ElMessage } from 'element-plus';
+import { useI18n } from 'vue-i18n';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+import { useChangeColor } from '/@/utils/theme';
+import { verifyAndSpace } from '/@/utils/toolsValidate';
+import { Local } from '/@/utils/storage';
+import Watermark from '/@/utils/watermark';
+import commonFunction from '/@/utils/commonFunction';
+import other from '/@/utils/other';
+import mittBus from '/@/utils/mitt';
+
+// 定义变量内容
+const { locale } = useI18n();
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+const { copyText } = commonFunction();
+const { getLightColor, getDarkColor } = useChangeColor();
+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}`, themeConfig.value[bg]);
+ if (bg === 'menuBar') {
+ document.documentElement.style.setProperty(`--next-bg-menuBar-light-1`, 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);
+};
+// 2、分栏设置 ->
+const onColumnsMenuHoverPreloadChange = () => {
+ setLocalThemeConfig();
+};
+// 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();
+ 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 = () => {
+ mittBus.emit('openOrCloseSortable');
+ setLocalThemeConfig();
+};
+// 4、界面显示 --> 开启 TagsView 共用
+const onShareTagsViewChange = () => {
+ 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 = 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: string) => {
+ 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('menuBarActiveColor');
+ onBgColorPickerChange('topBar');
+ onBgColorPickerChange('topBarColor');
+ onBgColorPickerChange('columnsMenuBar');
+ onBgColorPickerChange('columnsMenuBarColor');
+};
+// 关闭弹窗时,初始化变量。变量用于处理 layoutScrollbarRef.value.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();
+ // @ts-ignore
+ Local.set('version', __NEXT_VERSION__);
+};
+// 初始化菜单样式等
+const initSetStyle = () => {
+ // 2、菜单 / 顶栏 --> 顶栏背景渐变
+ onTopBarGradualChange();
+ // 2、菜单 / 顶栏 --> 菜单背景渐变
+ onMenuBarGradualChange();
+ // 2、菜单 / 顶栏 --> 分栏菜单背景渐变
+ onColumnsMenuBarGradualChange();
+};
+onMounted(() => {
+ nextTick(() => {
+ // 判断当前布局是否不相同,不相同则初始化当前布局的样式,防止监听窗口大小改变时,布局配置logo、菜单背景等部分布局失效问题
+ if (!Local.get('frequency')) initLayoutChangeFun();
+ Local.set('frequency', 1);
+ // 监听窗口大小改变,非默认布局,设置成默认布局(适配移动端)
+ mittBus.on('layoutMobileResize', (res: LayoutMobileResize) => {
+ 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')) locale.value = Local.get('themeConfig').globalI18n;
+ // 初始化菜单样式等
+ initSetStyle();
+ }, 100);
+ });
+});
+onUnmounted(() => {
+ mittBus.off('layoutMobileResize', () => {});
+});
+
+// 暴露变量
+defineExpose({
+ openDrawer,
+});
+</script>
+
+<style scoped lang="scss">
+.layout-breadcrumb-seting-bar {
+ height: calc(100vh - 50px);
+ padding: 0 15px;
+ :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..9337211
--- /dev/null
+++ b/src/layout/navBars/breadcrumb/user.vue
@@ -0,0 +1,258 @@
+<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="state.disabledSize === 'large'">{{ $t('message.user.dropdownLarge') }}</el-dropdown-item>
+ <el-dropdown-item command="default" :disabled="state.disabledSize === 'default'">{{ $t('message.user.dropdownDefault') }}</el-dropdown-item>
+ <el-dropdown-item command="small" :disabled="state.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="state.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="state.disabledI18n === 'zh-cn'">简体中文</el-dropdown-item>
+ <el-dropdown-item command="en" :disabled="state.disabledI18n === 'en'">English</el-dropdown-item>
+ <el-dropdown-item command="zh-tw" :disabled="state.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="state.isScreenfull ? $t('message.user.title6') : $t('message.user.title5')"
+ :class="!state.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 setup lang="ts" name="layoutBreadcrumbUser">
+import { defineAsyncComponent, ref, computed, reactive, onMounted } 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 mittBus from '/@/utils/mitt';
+import { Session, Local } from '/@/utils/storage';
+
+// 引入组件
+const UserNews = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/userNews.vue'));
+const Search = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/search.vue'));
+
+// 定义变量内容
+const { locale, t } = useI18n();
+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 = () => {
+ 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 () => {
+ // 清除缓存/token等
+ Session.clear();
+ // 使用 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);
+ initI18nOrSize('globalComponentSize', 'disabledSize');
+ window.location.reload();
+};
+// 语言切换
+const onLanguageChange = (lang: string) => {
+ Local.remove('themeConfig');
+ themeConfig.value.globalI18n = lang;
+ Local.set('themeConfig', themeConfig.value);
+ locale.value = lang;
+ other.useTitle();
+ initI18nOrSize('globalI18n', 'disabledI18n');
+};
+// 初始化组件大小/i18n
+const initI18nOrSize = (value: string, attr: string) => {
+ state[attr] = Local.get('themeConfig')[value];
+};
+// 页面加载时
+onMounted(() => {
+ if (Local.get('themeConfig')) {
+ initI18nOrSize('globalComponentSize', 'disabledSize');
+ initI18nOrSize('globalI18n', 'disabledI18n');
+ }
+});
+</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;
+ }
+ }
+ }
+ :deep(.el-dropdown) {
+ color: var(--next-bg-topBarColor);
+ }
+ :deep(.el-badge) {
+ height: 40px;
+ line-height: 40px;
+ display: flex;
+ align-items: center;
+ }
+ :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..340d880
--- /dev/null
+++ b/src/layout/navBars/breadcrumb/userNews.vue
@@ -0,0 +1,107 @@
+<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="state.newsList.length > 0" @click="onAllReadClick">{{ $t('message.user.newBtn') }}</div>
+ </div>
+ <div class="content-box">
+ <template v-if="state.newsList.length > 0">
+ <div class="content-box-item" v-for="(v, k) in state.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="state.newsList.length > 0">{{ $t('message.user.newGo') }}</div>
+ </div>
+</template>
+
+<script setup lang="ts" name="layoutBreadcrumbUserNews">
+import { reactive } from 'vue';
+
+// 定义变量内容
+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');
+};
+</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;
+ }
+ }
+ :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..aa8edb9
--- /dev/null
+++ b/src/layout/navBars/index.vue
@@ -0,0 +1,35 @@
+<template>
+ <div class="layout-navbars-container">
+ <BreadcrumbIndex />
+ <TagsView v-if="setShowTagsView" />
+ </div>
+</template>
+
+<script setup lang="ts" name="layoutNavBars">
+import { defineAsyncComponent, computed } from 'vue';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+
+// 引入组件
+const BreadcrumbIndex = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/index.vue'));
+const TagsView = defineAsyncComponent(() => import('/@/layout/navBars/tagsView/tagsView.vue'));
+
+// 定义变量内容
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+
+// 是否显示 tagsView
+const setShowTagsView = computed(() => {
+ let { layout, isTagsview } = themeConfig.value;
+ return layout !== 'classic' && isTagsview;
+});
+</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..92a228d
--- /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="state.isShow"
+ >
+ <ul class="el-dropdown-menu">
+ <template v-for="(v, k) in state.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: `${state.arrowLeft}px` }"></div>
+ </div>
+ </transition>
+</template>
+
+<script setup lang="ts" name="layoutTagsViewContextmenu">
+import { computed, reactive, onMounted, onUnmounted, watch } from 'vue';
+
+// 定义父组件传过来的值
+const props = defineProps({
+ dropdown: {
+ type: Object,
+ default: () => {
+ return {
+ x: 0,
+ y: 0,
+ };
+ },
+ },
+});
+
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['currentContextmenuClick']);
+
+// 定义变量内容
+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: RouteItem) => {
+ 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,
+ }
+);
+
+// 暴露变量
+defineExpose({
+ openContextmenu,
+});
+</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..4383cc0
--- /dev/null
+++ b/src/layout/navBars/tagsView/tagsView.vue
@@ -0,0 +1,726 @@
+<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 state.tagsViewList"
+ :key="k"
+ class="layout-navbars-tagsview-ul-li"
+ :data-url="v.url"
+ :class="{ 'is-active': isActive(v) }"
+ @contextmenu.prevent="onContextmenu(v, $event)"
+ @mousedown="onMousedownMenu(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="state.dropdown" ref="contextmenuRef" @currentContextmenuClick="onCurrentContextmenuClick" />
+ </div>
+</template>
+
+<script setup lang="ts" name="layoutTagsView">
+import { defineAsyncComponent, reactive, onMounted, computed, ref, nextTick, onBeforeUpdate, onBeforeMount, onUnmounted, watch } 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 mittBus from '/@/utils/mitt';
+
+// 引入组件
+const Contextmenu = defineAsyncComponent(() => import('/@/layout/navBars/tagsView/contextmenu.vue'));
+
+// 定义变量内容
+const tagsRefs = ref<RefType>([]);
+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: RouteItem) => {
+ return other.setTagsViewNameI18n(v);
+ };
+});
+// 设置 tagsView 高亮
+const isActive = (v: RouteItem) => {
+ 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);
+};
+// 获取 pinia 中的 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();
+};
+// pinia 中获取路由信息:如果是设置了固定的(isAffix),进行初始化显示
+const initTagsView = async () => {
+ if (Session.get('tagsViewList') && getThemeConfig.value.isCacheTagsView) {
+ state.tagsViewList = await Session.get('tagsViewList');
+ } else {
+ await state.tagsViewRoutesList.map((v: RouteItem) => {
+ if (v.meta?.isAffix && !v.meta.isHide) {
+ v.url = setTagsViewHighlight(v);
+ state.tagsViewList.push({ ...v });
+ storesKeepALiveNames.addCachedView(v);
+ }
+ });
+ await addTagsView(route.path, <RouteToFrom>route);
+ }
+ // 初始化当前元素(li)的下标
+ getTagsRefsIndex(getThemeConfig.value.isShareTagsView ? state.routePath : state.routeActive);
+};
+// 处理可开启多标签详情,单标签详情(动态路由(xxx/:id/:name"),普通路由处理)
+const solveAddTagsView = async (path: string, to?: RouteToFrom) => {
+ let isDynamicPath = to?.meta?.isDynamic ? to.meta.isDynamicPath : path;
+ let current = state.tagsViewList.filter(
+ (v: RouteItem) =>
+ 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: RouteItem) => 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?: RouteToFrom) => {
+ 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?: RouteToFrom) => {
+ // 防止拿取不到路由信息
+ nextTick(async () => {
+ // 修复:https://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G
+ let item: RouteItem;
+ if (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: RouteItem) => v.path === to?.meta?.isDynamicPath)) {
+ // 防止首次进入界面时(登录进入) tagsViewList 不存浏览器中
+ addBrowserSetSession(state.tagsViewList);
+ return false;
+ }
+ item = state.tagsViewRoutesList.find((v: RouteItem) => 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: RouteItem) => v.path === path)) {
+ // 防止首次进入界面时(登录进入) tagsViewList 不存浏览器中
+ addBrowserSetSession(state.tagsViewList);
+ return false;
+ }
+ item = state.tagsViewRoutesList.find((v: RouteItem) => v.path === path);
+ }
+ if (!item) return false;
+ if (item?.meta?.isLink && !item.meta.isIframe) return false;
+ if (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 decodeURIPath = decodeURI(fullPath);
+ let item: RouteToFrom = {};
+ state.tagsViewList.forEach((v: RouteItem) => {
+ v.transUrl = transUrlParams(v);
+ if (v.transUrl) {
+ if (v.transUrl === transUrlParams(v)) item = v;
+ } else {
+ if (v.path === decodeURIPath) item = v;
+ }
+ });
+ if (!item) return false;
+ await storesKeepALiveNames.delCachedView(item);
+ mittBus.emit('onTagsViewRefreshRouterView', fullPath);
+ if (item.meta?.isKeepAlive) storesKeepALiveNames.addCachedView(item);
+};
+// 3、关闭当前 tagsView:如果是设置了固定的(isAffix),不可以关闭
+const closeCurrentTagsView = (path: string) => {
+ state.tagsViewList.map((v: RouteItem, k: number, arr: RouteItems) => {
+ 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: RouteItem) => {
+ if (v.meta?.isAffix && !v.meta.isHide) {
+ v.url = setTagsViewHighlight(v);
+ storesKeepALiveNames.delOthersCachedViews(v);
+ state.tagsViewList.push({ ...v });
+ }
+ });
+ addTagsView(path, <RouteToFrom>route);
+ addBrowserSetSession(state.tagsViewList);
+ }
+};
+// 5、关闭全部 tagsView:如果是设置了固定的(isAffix),不进行关闭
+const closeAllTagsView = () => {
+ if (Session.get('tagsViewList')) {
+ storesKeepALiveNames.delAllCachedViews();
+ state.tagsViewList = [];
+ Session.get('tagsViewList').map((v: RouteItem) => {
+ 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: RouteItem) => (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 非当前页演示时,操作异常
+// https://gitee.com/lyt-top/vue-next-admin/issues/I61VS9
+const getCurrentRouteItem = (item: RouteItem): any => {
+ let resItem: RouteToFrom = {};
+ state.tagsViewList.forEach((v: RouteItem) => {
+ v.transUrl = transUrlParams(v);
+ if (v.transUrl) {
+ // 动态路由、普通路由带参数
+ if (v.transUrl === transUrlParams(v) && v.transUrl === item.commonUrl) resItem = v;
+ } else {
+ // 路由不带参数
+ if (v.path === decodeURI(item.path)) resItem = v;
+ }
+ });
+ if (!resItem) return null;
+ else return resItem;
+};
+// 当前项右键菜单点击
+const onCurrentContextmenuClick = async (item: RouteItem) => {
+ item.commonUrl = transUrlParams(item);
+ if (!getCurrentRouteItem(item)) return ElMessage({ type: 'warning', message: '请正确输入路径及完整参数(query、params)' });
+ const { path, name, params, query, meta, url } = getCurrentRouteItem(item);
+ 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: RouteItem, e: MouseEvent) => {
+ const { clientX, clientY } = e;
+ state.dropdown.x = clientX;
+ state.dropdown.y = clientY;
+ contextmenuRef.value.openContextmenu(v);
+};
+// 鼠标按下时,判断是鼠标中键就关闭当前 tasgview
+const onMousedownMenu = (v: RouteItem, e: MouseEvent) => {
+ if (!v.meta?.isAffix && e.button === 1) {
+ const item = Object.assign({}, { contextMenuClickId: 1, ...v });
+ onCurrentContextmenuClick(item);
+ }
+};
+// 当前的 tagsView 项点击时
+const onTagsClick = (v: RouteItem, k: number) => {
+ state.tagsRefsIndex = k;
+ router.push(v);
+};
+// 处理 url,地址栏链接有参数时,tagsview 右键菜单刷新功能失效问题,感谢 @ZzZz-RIPPER、@dejavuuuuu
+// https://gitee.com/lyt-top/vue-next-admin/issues/I5K3YO
+// https://gitee.com/lyt-top/vue-next-admin/issues/I61VS9
+const transUrlParams = (v: RouteItem) => {
+ let params = v.query && Object.keys(v.query).length > 0 ? v.query : v.params;
+ if (!params) return '';
+ let path = '';
+ for (let [key, value] of Object.entries(params)) {
+ if (v.meta?.isDynamic) path += `/${value}`;
+ else path += `&${key}=${value}`;
+ }
+ // 判断是否是动态路由(xxx/:id/:name")isDynamic
+ if (v.meta?.isDynamic) {
+ /**
+ *
+ * isFnClick 用于判断是通过方法调用,还是直接右键菜单点击(此处只针对动态路由)
+ * 原因:
+ * 1、右键菜单点击时,路由的 path 还是原始定义的路由格式,如:/params/dynamic/details/:t/:id/:tagsViewName
+ * 2、通过事件调用时,路由的 path 不是原始定义的路由格式,如:/params/dynamic/details/vue-next-admin/111/我是动态路由测试tagsViewName(非国际化)
+ *
+ * 所以右侧菜单点击时,需要处理路径拼接 v.path.split(':')[0],得到路径 + 参数的完整路径
+ */
+ return v.isFnClick ? decodeURI(v.path) : `${v.path.split(':')[0]}${path.replace(/^\//, '')}`;
+ } else {
+ return `${v.path}${path.replace(/^&/, '?')}`;
+ }
+};
+// 处理 tagsView 高亮(多标签详情时使用,单标签详情未使用)
+const setTagsViewHighlight = (v: RouteToFrom) => {
+ 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 onHandleScroll = (e: WheelEventType) => {
+ scrollbarRef.value.$refs.wrapRef.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 = tagsRefs.value[0];
+ // 最后 li
+ let liLast = tagsRefs.value[tagsRefs.value.length - 1];
+ // 当前滚动条的值
+ let scrollRefs = scrollbarRef.value.$refs.wrapRef;
+ // 当前滚动条滚动宽度
+ let scrollS = scrollRefs.scrollWidth;
+ // 当前滚动条偏移宽度
+ let offsetW = scrollRefs.offsetWidth;
+ // 当前滚动条偏移距离
+ let scrollL = scrollRefs.scrollLeft;
+ // 上一个 tags li dom
+ let liPrevTag = tagsRefs.value[state.tagsRefsIndex - 1];
+ // 下一个 tags li dom
+ let liNextTag = tagsRefs.value[state.tagsRefsIndex + 1];
+ // 上一个 tags li dom 的偏移距离
+ let beforePrevL = 0;
+ // 下一个 tags li dom 的偏移距离
+ let afterNextL = 0;
+ 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;
+ }
+ }
+ // 更新滚动条,防止不出现
+ scrollbarRef.value.update();
+ });
+};
+// 获取 tagsView 的下标:用于处理 tagsView 点击时的横向滚动
+const getTagsRefsIndex = (path: string | unknown) => {
+ nextTick(async () => {
+ // await 使用该写法,防止拿取不到 tagsViewList 列表数据不完整
+ let tagsViewList = await state.tagsViewList;
+ state.tagsRefsIndex = tagsViewList.findIndex((v: RouteItem) => {
+ 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: RouteItem[] = [];
+ state.sortable.toArray().map((val: string) => {
+ state.tagsViewList.map((v: RouteItem) => {
+ 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 当前页全屏
+ mittBus.on('onCurrentContextmenuClick', (data: RouteItem) => {
+ // 通过方法点击关闭 tagsView
+ data.isFnClick = true;
+ onCurrentContextmenuClick(data);
+ });
+ // 监听布局配置界面开启/关闭拖拽
+ mittBus.on('openOrCloseSortable', () => {
+ initSortable();
+ });
+ // 监听布局配置开启 TagsView 共用,为了演示还原默认值
+ mittBus.on('openShareTagsView', () => {
+ if (getThemeConfig.value.isShareTagsView) {
+ router.push('/home');
+ state.tagsViewList = [];
+ state.tagsViewRoutesList.map((v: RouteItem) => {
+ if (v.meta?.isAffix && !v.meta.isHide) {
+ v.url = setTagsViewHighlight(v);
+ state.tagsViewList.push({ ...v });
+ }
+ });
+ }
+ });
+});
+// 页面卸载时
+onUnmounted(() => {
+ // 取消非本页面调用监听
+ mittBus.off('onCurrentContextmenuClick', () => {});
+ // 取消监听布局配置界面开启/关闭拖拽
+ mittBus.off('openOrCloseSortable', () => {});
+ // 取消监听布局配置开启 TagsView 共用
+ 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, <RouteToFrom>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,
+ }
+);
+</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;
+ :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-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNzAiIGhlaWdodD0iNzAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZmlsbD0ibm9uZSI+CgogPGc+CiAgPHRpdGxlPkxheWVyIDE8L3RpdGxlPgogIDxwYXRoIHRyYW5zZm9ybT0icm90YXRlKC0wLjEzMzUwNiA1MC4xMTkyIDUwKSIgaWQ9InN2Z18xIiBkPSJtMTAwLjExOTE5LDEwMGMtNTUuMjI4LDAgLTEwMCwtNDQuNzcyIC0xMDAsLTEwMGwwLDEwMGwxMDAsMHoiIG9wYWNpdHk9InVuZGVmaW5lZCIgc3Ryb2tlPSJudWxsIiBmaWxsPSIjRjhFQUU3Ii8+CiAgPHBhdGggZD0ibS0wLjYzNzY2LDcuMzEyMjhjMC4xMTkxOSwwIDAuMjE3MzcsMC4wNTc5NiAwLjQ3Njc2LDAuMTE5MTljMC4yMzIsMC4wNTQ3NyAwLjI3MzI5LDAuMDM0OTEgMC4zNTc1NywwLjExOTE5YzAuMDg0MjgsMC4wODQyOCAwLjM1NzU3LDAgMC40NzY3NiwwbDAuMTE5MTksMGwwLjIzODM4LDAiIGlkPSJzdmdfMiIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiAgPHBhdGggZD0ibTI4LjkyMTM0LDY5LjA1MjQ0YzAsMC4xMTkxOSAwLDAuMjM4MzggMCwwLjM1NzU3bDAsMC4xMTkxOWwwLDAuMTE5MTkiIGlkPSJzdmdfMyIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiAgPHJlY3QgaWQ9InN2Z180IiBoZWlnaHQ9IjAiIHdpZHRoPSIxLjMxMTA4IiB5PSI2LjgzNTUyIiB4PSItMC4wNDE3MSIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiAgPHJlY3QgaWQ9InN2Z181IiBoZWlnaHQ9IjEuNzg3ODQiIHdpZHRoPSIwLjExOTE5IiB5PSI2OC40NTY1IiB4PSIyOC45MjEzNCIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiAgPHJlY3QgaWQ9InN2Z182IiBoZWlnaHQ9IjQuODg2NzciIHdpZHRoPSIxOS4wNzAzMiIgeT0iNTEuMjkzMjEiIHg9IjM2LjY2ODY2IiBzdHJva2U9Im51bGwiIGZpbGw9Im5vbmUiLz4KIDwvZz4KPC9zdmc+'),
+ url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNzAiIGhlaWdodD0iNzAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZmlsbD0ibm9uZSI+CiA8Zz4KICA8dGl0bGU+TGF5ZXIgMTwvdGl0bGU+CiAgPHBhdGggdHJhbnNmb3JtPSJyb3RhdGUoLTg5Ljc2MjQgNy4zMzAxNCA1NS4xMjUyKSIgc3Ryb2tlPSJudWxsIiBpZD0ic3ZnXzEiIGZpbGw9IiNGOEVBRTciIGQ9Im02Mi41NzQ0OSwxMTcuNTIwODZjLTU1LjIyOCwwIC0xMDAsLTQ0Ljc3MiAtMTAwLC0xMDBsMCwxMDBsMTAwLDB6IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPgogIDxwYXRoIGQ9Im0tMC42Mzc2Niw3LjMxMjI4YzAuMTE5MTksMCAwLjIxNzM3LDAuMDU3OTYgMC40NzY3NiwwLjExOTE5YzAuMjMyLDAuMDU0NzcgMC4yNzMyOSwwLjAzNDkxIDAuMzU3NTcsMC4xMTkxOWMwLjA4NDI4LDAuMDg0MjggMC4zNTc1NywwIDAuNDc2NzYsMGwwLjExOTE5LDBsMC4yMzgzOCwwIiBpZD0ic3ZnXzIiIHN0cm9rZT0ibnVsbCIgZmlsbD0ibm9uZSIvPgogIDxwYXRoIGQ9Im0yOC45MjEzNCw2OS4wNTI0NGMwLDAuMTE5MTkgMCwwLjIzODM4IDAsMC4zNTc1N2wwLDAuMTE5MTlsMCwwLjExOTE5IiBpZD0ic3ZnXzMiIHN0cm9rZT0ibnVsbCIgZmlsbD0ibm9uZSIvPgogIDxyZWN0IGlkPSJzdmdfNCIgaGVpZ2h0PSIwIiB3aWR0aD0iMS4zMTEwOCIgeT0iNi44MzU1MiIgeD0iLTAuMDQxNzEiIHN0cm9rZT0ibnVsbCIgZmlsbD0ibm9uZSIvPgogIDxyZWN0IGlkPSJzdmdfNSIgaGVpZ2h0PSIxLjc4Nzg0IiB3aWR0aD0iMC4xMTkxOSIgeT0iNjguNDU2NSIgeD0iMjguOTIxMzQiIHN0cm9rZT0ibnVsbCIgZmlsbD0ibm9uZSIvPgogIDxyZWN0IGlkPSJzdmdfNiIgaGVpZ2h0PSI0Ljg4Njc3IiB3aWR0aD0iMTkuMDcwMzIiIHk9IjUxLjI5MzIxIiB4PSIzNi42Njg2NiIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiA8L2c+Cjwvc3ZnPg=='),
+ url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><rect rx='8' width='100%' height='100%' fill='%23F8EAE7'/></svg>");
+ -webkit-mask-size: 18px 30px, 20px 30px, calc(100% - 30px) calc(100% + 17px);
+ -webkit-mask-position: right bottom, left bottom, center top;
+ -webkit-mask-repeat: no-repeat;
+ }
+ .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..1463376
--- /dev/null
+++ b/src/layout/navMenu/horizontal.vue
@@ -0,0 +1,159 @@
+<template>
+ <div class="el-menu-horizontal-warp">
+ <el-scrollbar @wheel.native.prevent="onElMenuHorizontalScroll" ref="elMenuHorizontalScrollRef">
+ <el-menu router :default-active="state.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 v-if="val.meta.icon" class="iconfont" :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 v-if="val.meta.icon" class="iconfont" :name="val.meta.icon" />
+ {{ $t(val.meta.title) }}
+ </template>
+ <template #title v-else>
+ <a class="w100" @click.prevent="onALinkClick(val)">
+ <SvgIcon v-if="val.meta.icon" class="iconfont" :name="val.meta.icon" />
+ {{ $t(val.meta.title) }}
+ </a>
+ </template>
+ </el-menu-item>
+ </template>
+ </template>
+ </el-menu>
+ </el-scrollbar>
+ </div>
+</template>
+
+<script setup lang="ts" name="navMenuHorizontal">
+import { defineAsyncComponent, reactive, computed, onMounted, nextTick, onBeforeMount, ref } from 'vue';
+import { useRoute, onBeforeRouteUpdate, RouteRecordRaw } from 'vue-router';
+import { storeToRefs } from 'pinia';
+import { useRoutesList } from '/@/stores/routesList';
+import { useThemeConfig } from '/@/stores/themeConfig';
+import other from '/@/utils/other';
+import mittBus from '/@/utils/mitt';
+
+// 引入组件
+const SubItem = defineAsyncComponent(() => import('/@/layout/navMenu/subItem.vue'));
+
+// 定义父组件传过来的值
+const props = defineProps({
+ // 菜单列表
+ menuList: {
+ type: Array<RouteRecordRaw>,
+ default: () => [],
+ },
+});
+
+// 定义变量内容
+const elMenuHorizontalScrollRef = ref();
+const stores = useRoutesList();
+const storesThemeConfig = useThemeConfig();
+const { routesList } = storeToRefs(stores);
+const { themeConfig } = storeToRefs(storesThemeConfig);
+const route = useRoute();
+const state = reactive({
+ defaultActive: '' as string | undefined,
+});
+
+// 获取父级菜单数据
+const menuLists = computed(() => {
+ return <RouteItems>props.menuList;
+});
+// 设置横向滚动条可以鼠标滚轮滚动
+const onElMenuHorizontalScroll = (e: WheelEventType) => {
+ const eventDelta = e.wheelDelta || -e.deltaY * 40;
+ elMenuHorizontalScrollRef.value.$refs.wrapRef.scrollLeft = elMenuHorizontalScrollRef.value.$refs.wrapRef.scrollLeft + eventDelta / 4;
+};
+// 初始化数据,页面刷新时,滚动条滚动到对应位置
+const initElMenuOffsetLeft = () => {
+ nextTick(() => {
+ let els = <HTMLElement>document.querySelector('.el-menu.el-menu--horizontal li.is-active');
+ if (!els) return false;
+ elMenuHorizontalScrollRef.value.$refs.wrapRef.scrollLeft = els.offsetLeft;
+ });
+};
+// 路由过滤递归函数
+const filterRoutesFun = <T extends RouteItem>(arr: T[]): T[] => {
+ return arr
+ .filter((item: T) => !item.meta?.isHide)
+ .map((item: T) => {
+ item = Object.assign({}, item);
+ if (item.children) item.children = filterRoutesFun(item.children);
+ return item;
+ });
+};
+// 传送当前子级数据到菜单中
+const setSendClassicChildren = (path: string) => {
+ const currentPathSplit = path.split('/');
+ let currentData: MittMenu = { children: [] };
+ 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: RouteToFrom) => {
+ const { path, meta } = currentRoute;
+ if (themeConfig.value.layout === 'classic') {
+ 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;
+ }
+};
+// 打开外部链接
+const onALinkClick = (val: RouteItem) => {
+ other.handleOpenLink(val);
+};
+// 页面加载前
+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) {
+ mittBus.emit('setSendClassicChildren', setSendClassicChildren(to.path));
+ }
+});
+</script>
+
+<style scoped lang="scss">
+.el-menu-horizontal-warp {
+ flex: 1;
+ overflow: hidden;
+ margin-right: 30px;
+ :deep(.el-scrollbar__bar.is-vertical) {
+ display: none;
+ }
+ :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..9cc08b1
--- /dev/null
+++ b/src/layout/navMenu/subItem.vue
@@ -0,0 +1,49 @@
+<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 v-if="val.meta.icon" class="iconfont" :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 v-if="val.meta.icon" class="iconfont" :name="val.meta.icon" />
+ <span>{{ $t(val.meta.title) }}</span>
+ </template>
+ <template v-else>
+ <a class="w100" @click.prevent="onALinkClick(val)">
+ <SvgIcon v-if="val.meta.icon" class="iconfont" :name="val.meta.icon" />
+ {{ $t(val.meta.title) }}
+ </a>
+ </template>
+ </el-menu-item>
+ </template>
+ </template>
+</template>
+
+<script setup lang="ts" name="navMenuSubItem">
+import { computed } from 'vue';
+import { RouteRecordRaw } from 'vue-router';
+import other from '/@/utils/other';
+
+// 定义父组件传过来的值
+const props = defineProps({
+ // 菜单列表
+ chil: {
+ type: Array<RouteRecordRaw>,
+ default: () => [],
+ },
+});
+
+// 获取父级菜单数据
+const chils = computed(() => {
+ return <RouteItems>props.chil;
+});
+// 打开外部链接
+const onALinkClick = (val: RouteItem) => {
+ other.handleOpenLink(val);
+};
+</script>
diff --git a/src/layout/navMenu/vertical.vue b/src/layout/navMenu/vertical.vue
new file mode 100644
index 0000000..25264c9
--- /dev/null
+++ b/src/layout/navMenu/vertical.vue
@@ -0,0 +1,102 @@
+<template>
+ <el-menu
+ router
+ :default-active="state.defaultActive"
+ background-color="transparent"
+ :collapse="state.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 v-if="val.meta.icon" class="iconfont" :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 v-if="val.meta.icon" class="iconfont" :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 class="w100" @click.prevent="onALinkClick(val)">{{ $t(val.meta.title) }}</a>
+ </template>
+ </el-menu-item>
+ </template>
+ </template>
+ </el-menu>
+</template>
+
+<script setup lang="ts" name="navMenuVertical">
+import { defineAsyncComponent, reactive, computed, onMounted, watch } from 'vue';
+import { useRoute, onBeforeRouteUpdate, RouteRecordRaw } from 'vue-router';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+import other from '/@/utils/other';
+
+// 引入组件
+const SubItem = defineAsyncComponent(() => import('/@/layout/navMenu/subItem.vue'));
+
+// 定义父组件传过来的值
+const props = defineProps({
+ // 菜单列表
+ menuList: {
+ type: Array<RouteRecordRaw>,
+ default: () => [],
+ },
+});
+
+// 定义变量内容
+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 <RouteItems>props.menuList;
+});
+// 获取布局配置信息
+const getThemeConfig = computed(() => {
+ return themeConfig.value;
+});
+// 菜单高亮(详情时,父级高亮)
+const setParentHighlight = (currentRoute: RouteToFrom) => {
+ 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;
+};
+// 打开外部链接
+const onALinkClick = (val: RouteItem) => {
+ other.handleOpenLink(val);
+};
+// 页面加载时
+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;
+});
+// 设置菜单的收起/展开
+watch(
+ themeConfig.value,
+ () => {
+ document.body.clientWidth <= 1000 ? (state.isCollapse = false) : (state.isCollapse = themeConfig.value.isCollapse);
+ },
+ {
+ immediate: true,
+ }
+);
+</script>
diff --git a/src/layout/routerView/iframes.vue b/src/layout/routerView/iframes.vue
new file mode 100644
index 0000000..8e1f958
--- /dev/null
+++ b/src/layout/routerView/iframes.vue
@@ -0,0 +1,101 @@
+<template>
+ <div class="layout-padding layout-padding-unset layout-iframe">
+ <div class="layout-padding-auto layout-padding-view">
+ <div class="w100" v-for="v in setIframeList" :key="v.path" v-loading="v.meta.loading" element-loading-background="white">
+ <transition-group :name="name">
+ <iframe
+ :src="v.meta.isLink"
+ :key="v.path"
+ frameborder="0"
+ height="100%"
+ width="100%"
+ style="position: absolute"
+ :data-url="v.path"
+ v-show="getRoutePath === v.path"
+ ref="iframeRef"
+ />
+ </transition-group>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script setup lang="ts" name="layoutIframeView">
+import { computed, watch, ref, nextTick } from 'vue';
+import { useRoute } from 'vue-router';
+
+// 定义父组件传过来的值
+const props = defineProps({
+ // 刷新 iframe
+ refreshKey: {
+ type: String,
+ default: () => '',
+ },
+ // 过渡动画 name
+ name: {
+ type: String,
+ default: () => 'slide-right',
+ },
+ // iframe 列表
+ list: {
+ type: Array,
+ default: () => [],
+ },
+});
+
+// 定义变量内容
+const iframeRef = ref();
+const route = useRoute();
+
+// 处理 list 列表,当打开时,才进行加载
+const setIframeList = computed(() => {
+ return (<RouteItems>props.list).filter((v: RouteItem) => v.meta?.isIframeOpen);
+});
+// 获取 iframe 当前路由 path
+const getRoutePath = computed(() => {
+ return route.path;
+});
+// 关闭 iframe loading
+const closeIframeLoading = (val: string, item: RouteItem) => {
+ nextTick(() => {
+ if (!iframeRef.value) return false;
+ iframeRef.value.forEach((v: HTMLElement) => {
+ if (v.dataset.url === val) {
+ v.onload = () => {
+ if (item.meta?.isIframeOpen && item.meta.loading) item.meta.loading = false;
+ };
+ }
+ });
+ });
+};
+// 监听路由变化,初始化 iframe 数据,防止多个 iframe 时,切换不生效
+watch(
+ () => route.fullPath,
+ (val) => {
+ const item: any = props.list.find((v: any) => v.path === val);
+ if (!item) return false;
+ if (!item.meta.isIframeOpen) item.meta.isIframeOpen = true;
+ closeIframeLoading(val, item);
+ },
+ {
+ immediate: true,
+ }
+);
+// 监听 iframe refreshKey 变化,用于 tagsview 右键菜单刷新
+watch(
+ () => props.refreshKey,
+ () => {
+ const item: any = props.list.find((v: any) => v.path === route.path);
+ if (!item) return false;
+ if (item.meta.isIframeOpen) item.meta.isIframeOpen = false;
+ setTimeout(() => {
+ item.meta.isIframeOpen = true;
+ item.meta.loading = true;
+ closeIframeLoading(route.fullPath, item);
+ });
+ },
+ {
+ deep: true,
+ }
+);
+</script>
diff --git a/src/layout/routerView/link.vue b/src/layout/routerView/link.vue
new file mode 100644
index 0000000..ccdc3a4
--- /dev/null
+++ b/src/layout/routerView/link.vue
@@ -0,0 +1,93 @@
+<template>
+ <div class="layout-padding layout-link-container">
+ <div class="layout-padding-auto layout-padding-view">
+ <div class="layout-link-warp">
+ <i class="layout-link-icon iconfont icon-xingqiu"></i>
+ <div class="layout-link-msg">页面 "{{ $t(state.title) }}" 已在新窗口中打开</div>
+ <el-button class="mt30" round size="default" @click="onGotoFullPage">
+ <i class="iconfont icon-lianjie"></i>
+ <span>立即前往体验</span>
+ </el-button>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script setup lang="ts" name="layoutLinkView">
+import { reactive, watch } from 'vue';
+import { useRoute } from 'vue-router';
+import { verifyUrl } from '/@/utils/toolsValidate';
+
+// 定义变量内容
+const route = useRoute();
+const state = reactive<LinkViewState>({
+ title: '',
+ isLink: '',
+});
+
+// 立即前往
+const onGotoFullPage = () => {
+ const { origin, pathname } = window.location;
+ if (verifyUrl(<string>state.isLink)) window.open(state.isLink);
+ else window.open(`${origin}${pathname}#${state.isLink}`);
+};
+// 监听路由的变化,设置内容
+watch(
+ () => route.path,
+ () => {
+ state.title = <string>route.meta.title;
+ state.isLink = <string>route.meta.isLink;
+ },
+ {
+ immediate: true,
+ }
+);
+</script>
+
+<style scoped lang="scss">
+.layout-link-container {
+ .layout-link-warp {
+ margin: auto;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ i.layout-link-icon {
+ position: relative;
+ font-size: 100px;
+ color: var(--el-color-primary);
+ &::after {
+ content: '';
+ position: absolute;
+ left: 50px;
+ top: 0;
+ width: 15px;
+ height: 100px;
+ background: linear-gradient(
+ rgba(255, 255, 255, 0.01),
+ rgba(255, 255, 255, 0.01),
+ rgba(255, 255, 255, 0.01),
+ rgba(255, 255, 255, 0.05),
+ rgba(255, 255, 255, 0.05),
+ rgba(255, 255, 255, 0.05),
+ rgba(235, 255, 255, 0.5),
+ rgba(255, 255, 255, 0.05),
+ rgba(255, 255, 255, 0.05),
+ rgba(255, 255, 255, 0.05),
+ rgba(255, 255, 255, 0.01),
+ rgba(255, 255, 255, 0.01),
+ rgba(255, 255, 255, 0.01)
+ );
+ transform: rotate(-15deg);
+ animation: toRight 5s linear infinite;
+ }
+ }
+ .layout-link-msg {
+ font-size: 12px;
+ color: var(--next-bg-topBarColor);
+ opacity: 0.7;
+ margin-top: 15px;
+ }
+ }
+}
+</style>
diff --git a/src/layout/routerView/parent.vue b/src/layout/routerView/parent.vue
new file mode 100644
index 0000000..4124f7f
--- /dev/null
+++ b/src/layout/routerView/parent.vue
@@ -0,0 +1,108 @@
+<template>
+ <div class="layout-parent">
+ <router-view v-slot="{ Component }">
+ <transition :name="setTransitionName" mode="out-in">
+ <keep-alive :include="getKeepAliveNames">
+ <component :is="Component" :key="state.refreshRouterViewKey" class="w100" v-show="!isIframePage" />
+ </keep-alive>
+ </transition>
+ </router-view>
+ <transition :name="setTransitionName" mode="out-in">
+ <Iframes class="w100" v-show="isIframePage" :refreshKey="state.iframeRefreshKey" :name="setTransitionName" :list="state.iframeList" />
+ </transition>
+ </div>
+</template>
+
+<script setup lang="ts" name="layoutParentView">
+import { defineAsyncComponent, computed, reactive, onBeforeMount, onUnmounted, nextTick, watch, onMounted } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+import { storeToRefs } from 'pinia';
+import { useKeepALiveNames } from '/@/stores/keepAliveNames';
+import { useThemeConfig } from '/@/stores/themeConfig';
+import { Session } from '/@/utils/storage';
+import mittBus from '/@/utils/mitt';
+
+// 引入组件
+const Iframes = defineAsyncComponent(() => import('/@/layout/routerView/iframes.vue'));
+
+// 定义变量内容
+const route = useRoute();
+const router = useRouter();
+const storesKeepAliveNames = useKeepALiveNames();
+const storesThemeConfig = useThemeConfig();
+const { keepAliveNames, cachedViews } = storeToRefs(storesKeepAliveNames);
+const { themeConfig } = storeToRefs(storesThemeConfig);
+const state = reactive<ParentViewState>({
+ refreshRouterViewKey: '', // 非 iframe tagsview 右键菜单刷新时
+ iframeRefreshKey: '', // iframe tagsview 右键菜单刷新时
+ keepAliveNameList: [],
+ iframeList: [],
+});
+
+// 设置主界面切换动画
+const setTransitionName = computed(() => {
+ return themeConfig.value.animation;
+});
+// 获取组件缓存列表(name值)
+const getKeepAliveNames = computed(() => {
+ return themeConfig.value.isTagsview ? cachedViews.value : state.keepAliveNameList;
+});
+// 设置 iframe 显示/隐藏
+const isIframePage = computed(() => {
+ return route.meta.isIframe;
+});
+// 获取 iframe 组件列表(未进行渲染)
+const getIframeListRoutes = async () => {
+ router.getRoutes().forEach((v) => {
+ if (v.meta.isIframe) {
+ v.meta.isIframeOpen = false;
+ v.meta.loading = true;
+ state.iframeList.push({ ...v });
+ }
+ });
+};
+// 页面加载前,处理缓存,页面刷新时路由缓存处理
+onBeforeMount(() => {
+ state.keepAliveNameList = keepAliveNames.value;
+ mittBus.on('onTagsViewRefreshRouterView', (fullPath: string) => {
+ state.keepAliveNameList = keepAliveNames.value.filter((name: string) => route.name !== name);
+ state.refreshRouterViewKey = '';
+ state.iframeRefreshKey = '';
+ nextTick(() => {
+ state.refreshRouterViewKey = fullPath;
+ state.iframeRefreshKey = fullPath;
+ state.keepAliveNameList = keepAliveNames.value;
+ });
+ });
+});
+// 页面加载时
+onMounted(() => {
+ getIframeListRoutes();
+ // https://gitee.com/lyt-top/vue-next-admin/issues/I58U75
+ // https://gitee.com/lyt-top/vue-next-admin/issues/I59RXK
+ // https://gitee.com/lyt-top/vue-next-admin/pulls/40
+ nextTick(() => {
+ setTimeout(() => {
+ if (themeConfig.value.isCacheTagsView) {
+ let tagsViewArr: RouteItem[] = Session.get('tagsViewList') || [];
+ cachedViews.value = tagsViewArr.filter((item) => item.meta?.isKeepAlive).map((item) => item.name as string);
+ }
+ }, 0);
+ });
+});
+// 页面卸载时
+onUnmounted(() => {
+ mittBus.off('onTagsViewRefreshRouterView', () => {});
+});
+// 监听路由变化,防止 tagsView 多标签时,切换动画消失
+// https://toscode.gitee.com/lyt-top/vue-next-admin/pulls/38/files
+watch(
+ () => route.fullPath,
+ () => {
+ state.refreshRouterViewKey = decodeURI(route.fullPath);
+ },
+ {
+ immediate: true,
+ }
+);
+</script>
diff --git a/src/layout/sponsors/index.vue b/src/layout/sponsors/index.vue
new file mode 100644
index 0000000..6f85895
--- /dev/null
+++ b/src/layout/sponsors/index.vue
@@ -0,0 +1,108 @@
+<template>
+ <div class="sponsors-container" title="点击前往体验" v-show="state.sponsors.isShow" @click="onSponsorsClick">
+ <el-carousel height="240px" indicator-position="none" :arrow="setCarouselShow" @change="onCarouselChange">
+ <el-carousel-item v-for="(v, k) in state.sponsors.list" :key="k">
+ <img :src="v.url" class="sponsors-img" />
+ <div class="sponsors-text" v-html="v.text"></div>
+ </el-carousel-item>
+ </el-carousel>
+ <div class="sponsors-close">
+ <SvgIcon name="ele-Close" :size="12" title="关闭赞助商" @click.stop="onCloseSponsors" />
+ </div>
+ </div>
+</template>
+
+<script setup lang="ts" name="layoutSponsors">
+import { reactive, computed, onMounted } from 'vue';
+import sponsorsOne from '/@/assets/ccflowRightNextAdmin.png';
+
+// 定义变量内容
+const state = reactive({
+ sponsors: {
+ list: [
+ {
+ url: sponsorsOne,
+ text: `驰骋BPM系统包含表单引擎+流程引擎+权限控制,方便集成,配置灵活,功能强大,适合中国国情的工作流引擎.演示:http://demo.ccflow.org。右上角点star方可加群: 1060674395`,
+ link: 'http://www.ccflow.org/',
+ },
+ ],
+ isShow: false,
+ index: 0,
+ },
+});
+
+// 设置轮播图箭头显示
+const setCarouselShow = computed(() => {
+ return state.sponsors.list.length <= 1 ? 'never' : 'hover';
+});
+// 关闭赞助商
+const onCloseSponsors = () => {
+ state.sponsors.isShow = false;
+};
+// 轮播图改变时
+const onCarouselChange = (e: number) => {
+ state.sponsors.index = e;
+};
+// 当前项内容点击
+const onSponsorsClick = () => {
+ window.open(state.sponsors.list[state.sponsors.index].link);
+};
+// 延迟显示,防止影响其它界面加载
+const delayShow = () => {
+ setTimeout(() => {
+ state.sponsors.isShow = true;
+ }, 3000);
+};
+// 页面加载时
+onMounted(() => {
+ delayShow();
+});
+</script>
+
+<style scoped lang="scss">
+.sponsors-container {
+ position: fixed;
+ right: 15px;
+ bottom: 15px;
+ z-index: 3;
+ width: 200px;
+ background-color: var(--next-bg-main-color);
+ box-shadow: var(--el-box-shadow-lighter);
+ border-radius: 5px;
+ overflow: hidden;
+ cursor: pointer;
+ .sponsors-img {
+ width: 100%;
+ height: 80px;
+ }
+ .sponsors-text {
+ padding: 10px;
+ color: var(--el-text-color-regular);
+ font-size: var(--el-dialog-content-font-size);
+ }
+ .sponsors-close {
+ width: 60px;
+ height: 60px;
+ border-radius: 100%;
+ background: rgba(0, 0, 0, 0.05);
+ transition: all 0.3s ease;
+ position: absolute;
+ right: -35px;
+ bottom: -35px;
+ :deep(i) {
+ position: absolute;
+ left: 9px;
+ top: 9px;
+ color: #afafaf;
+ transition: all 0.3s ease;
+ }
+ &:hover {
+ transition: all 0.3s ease;
+ :deep(i) {
+ color: var(--el-color-primary);
+ transition: all 0.3s ease;
+ }
+ }
+ }
+}
+</style>
diff --git a/src/layout/upgrade/index.vue b/src/layout/upgrade/index.vue
new file mode 100644
index 0000000..6dd350d
--- /dev/null
+++ b/src/layout/upgrade/index.vue
@@ -0,0 +1,151 @@
+<template>
+ <div class="upgrade-dialog">
+ <el-dialog
+ v-model="state.isUpgrade"
+ width="300px"
+ destroy-on-close
+ :show-close="false"
+ :close-on-click-modal="false"
+ :close-on-press-escape="false"
+ >
+ <div class="upgrade-title">
+ <div class="upgrade-title-warp">
+ <span class="upgrade-title-warp-txt">{{ $t('message.upgrade.title') }}</span>
+ <span class="upgrade-title-warp-version">v{{ state.version }}</span>
+ </div>
+ </div>
+ <div class="upgrade-content">
+ {{ getThemeConfig.globalTitle }} {{ $t('message.upgrade.msg') }}
+ <div class="mt5">
+ <el-link type="primary" class="font12" href="https://gitee.com/lyt-top/vue-next-admin/blob/master/CHANGELOG.md" target="_black">
+ CHANGELOG.md
+ </el-link>
+ </div>
+ <div class="upgrade-content-desc mt5">{{ $t('message.upgrade.desc') }}</div>
+ </div>
+ <div class="upgrade-btn">
+ <el-button round size="default" type="info" text @click="onCancel">{{ $t('message.upgrade.btnOne') }}</el-button>
+ <el-button type="primary" round size="default" @click="onUpgrade" :loading="state.isLoading">{{ state.btnTxt }}</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup lang="ts" name="layoutUpgrade">
+import { reactive, computed, onMounted } from 'vue';
+import { useI18n } from 'vue-i18n';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+import { Local } from '/@/utils/storage';
+
+// 定义变量内容
+const { t } = useI18n();
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+const state = reactive({
+ isUpgrade: false,
+ // @ts-ignore
+ version: __NEXT_VERSION__,
+ isLoading: false,
+ btnTxt: '',
+});
+
+// 获取布局配置信息
+const getThemeConfig = computed(() => {
+ return themeConfig.value;
+});
+// 残忍拒绝
+const onCancel = () => {
+ state.isUpgrade = false;
+};
+// 马上更新
+const onUpgrade = () => {
+ state.isLoading = true;
+ state.btnTxt = t('message.upgrade.btnTwoLoading');
+ setTimeout(() => {
+ Local.clear();
+ window.location.reload();
+ Local.set('version', state.version);
+ }, 2000);
+};
+// 延迟显示,防止刷新时界面显示太快
+const delayShow = () => {
+ setTimeout(() => {
+ state.isUpgrade = true;
+ }, 2000);
+};
+// 页面加载时
+onMounted(() => {
+ delayShow();
+ setTimeout(() => {
+ state.btnTxt = t('message.upgrade.btnTwo');
+ }, 200);
+});
+</script>
+
+<style scoped lang="scss">
+.upgrade-dialog {
+ :deep(.el-dialog) {
+ .el-dialog__body {
+ padding: 0 !important;
+ }
+ .el-dialog__header {
+ display: none !important;
+ }
+ .upgrade-title {
+ text-align: center;
+ height: 130px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+ &::after {
+ content: '';
+ position: absolute;
+ background-color: var(--el-color-primary-light-1);
+ width: 130%;
+ height: 130px;
+ border-bottom-left-radius: 100%;
+ border-bottom-right-radius: 100%;
+ }
+ .upgrade-title-warp {
+ z-index: 1;
+ position: relative;
+ .upgrade-title-warp-txt {
+ color: var(--next-color-white);
+ font-size: 22px;
+ letter-spacing: 3px;
+ }
+ .upgrade-title-warp-version {
+ color: var(--next-color-white);
+ background-color: var(--el-color-primary-light-4);
+ font-size: 12px;
+ position: absolute;
+ display: flex;
+ top: -2px;
+ right: -50px;
+ padding: 2px 4px;
+ border-radius: 2px;
+ }
+ }
+ }
+ .upgrade-content {
+ padding: 20px;
+ line-height: 22px;
+ .upgrade-content-desc {
+ color: var(--el-color-info-light-5);
+ font-size: 12px;
+ }
+ }
+ .upgrade-btn {
+ border-top: 1px solid var(--el-border-color-lighter, #ebeef5);
+ display: flex;
+ justify-content: space-around;
+ padding: 15px 20px;
+ .el-button {
+ width: 100%;
+ }
+ }
+ }
+}
+</style>
diff --git a/src/main.ts b/src/main.ts
new file mode 100644
index 0000000..3561d5c
--- /dev/null
+++ b/src/main.ts
@@ -0,0 +1,26 @@
+import { createApp } from 'vue';
+import pinia from '/@/stores/index';
+import App from './App.vue';
+import router from './router';
+import { directive } from '/@/directive/index';
+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 '/@/theme/tailwind.scss';
+import VueGridLayout from 'vue-grid-layout';
+import { Icon } from '@iconify/vue';
+import formCreate from '@form-create/element-ui';
+import install from '@form-create/element-ui/auto-import';
+import page from '/@/components/page/index.vue';
+
+formCreate.use(install);
+const app = createApp(App);
+
+directive(app);
+other.elSvg(app);
+app.component('Icon', Icon);
+app.component('Page', page);
+app.use(pinia).use(router).use(ElementPlus, { i18n: i18n.global.t }).use(i18n).use(VueGridLayout).use(formCreate).mount('#app');
diff --git a/src/model/api/common.ts b/src/model/api/common.ts
new file mode 100644
index 0000000..7465214
--- /dev/null
+++ b/src/model/api/common.ts
@@ -0,0 +1,22 @@
+export interface ApiResult<T> {
+ code: number;
+ data: T,
+ message: string;
+ page: Page;
+}
+
+// export interface ApiPagerResult<T> extends ApiResult<T> {
+// pager: Pager;
+// }
+
+export interface PageProps {
+ pageIndex?: number;
+ pageSize?: number;
+}
+
+export interface Page {
+ pageIndex: number;
+ pageSize: number;
+ totalCount: number;
+ longTotalCount: string;
+}
diff --git a/src/model/api/login.ts b/src/model/api/login.ts
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/model/api/login.ts
diff --git a/src/model/api/menu.ts b/src/model/api/menu.ts
new file mode 100644
index 0000000..f82f337
--- /dev/null
+++ b/src/model/api/menu.ts
@@ -0,0 +1,21 @@
+export interface Menu {
+ id: number;
+ name: string;
+ displayName: string;
+ parentID: number;
+ url: string;
+ icon?: string;
+ visible: boolean;
+ newWindow: boolean;
+ permissions: Permissions;
+ children: Menu[];
+}
+
+interface Permissions {
+ '1'?: string;
+ '2'?: string;
+ '4'?: string;
+ '8'?: string;
+ '16'?: string;
+ '32'?: string;
+}
diff --git a/src/model/api/page.ts b/src/model/api/page.ts
new file mode 100644
index 0000000..df0afb7
--- /dev/null
+++ b/src/model/api/page.ts
@@ -0,0 +1,16 @@
+export interface Column {
+ name: string;
+ displayName: string;
+ description: string;
+ category: string;
+ typeName: string;
+ itemType?: any;
+ length: number;
+ precision: number;
+ scale: number;
+ nullable: boolean;
+ primaryKey: boolean;
+ readonly: boolean;
+ mapField: string;
+ groupView?: any;
+}
\ No newline at end of file
diff --git a/src/model/api/user.ts b/src/model/api/user.ts
new file mode 100644
index 0000000..8b96648
--- /dev/null
+++ b/src/model/api/user.ts
@@ -0,0 +1,52 @@
+export interface UserInfo {
+ id: number;
+ name: string;
+ password: string;
+ displayName: string;
+ sex: string;
+ mail: string;
+ mobile: string;
+ code?: any;
+ avatar: string;
+ roleID: number;
+ roleIds?: any;
+ roleName: string;
+ roleNames: string;
+ departmentID: number;
+ online: boolean;
+ enable: boolean;
+ logins: number;
+ lastLogin: string;
+ lastLoginIP: string;
+ registerTime: string;
+ registerIP?: any;
+ ex1: number;
+ ex2: number;
+ ex3: number;
+ ex4?: any;
+ ex5?: any;
+ ex6?: any;
+ updateUser?: any;
+ updateUserID: number;
+ updateIP: string;
+ updateTime: string;
+ remark?: any;
+ permission: string;
+}
+
+export type Login = {
+ token: string;
+}
+
+export interface GetMenuTreeItem {
+ children: GetMenuTreeItem[]
+ displayName: string;
+ icon: string;
+ id: number;
+ name: string;
+ newWindow: boolean;
+ parentID: number;
+ permissions: Object;
+ url: string;
+ visible: boolean;
+}
diff --git a/src/router/backEnd.ts b/src/router/backEnd.ts
new file mode 100644
index 0000000..c49358a
--- /dev/null
+++ b/src/router/backEnd.ts
@@ -0,0 +1,253 @@
+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';
+import { Menu } from '../model/api/menu';
+import { toCamelCase } from '../utils/other';
+import { Component, h, shallowRef } from 'vue';
+
+
+// 后端控制路由
+
+// 引入 api 请求接口
+const menuApi = useMenuApi();
+
+/**
+ * 获取目录下的 .vue、.tsx 全部文件
+ * @method import.meta.glob
+ * @link 参考:https://cn.vitejs.dev/guide/features.html#json
+ */
+// const layouModules: any = import.meta.glob('../layout/routerView/*.{vue,tsx}');
+// const viewsModules: any = import.meta.glob('../views/**/*.{vue,tsx}');
+// const dynamicViewsModules: Record<string, Function> = Object.assign({}, { ...layouModules }, { ...viewsModules });
+const modules = import.meta.glob('../views/modules/**/**.vue')
+
+/**
+ * 后端控制路由:初始化方法,防止刷新时路由丢失
+ * @method NextLoading 界面 loading 动画开始执行
+ * @method useUserInfo().setUserInfos() 触发初始化用户信息 pinia
+ * @method useRequestOldRoutes().setRequestOldRoutes() 存储接口原始路由(未处理component),根据需求选择使用
+ * @method setAddRoute 添加动态路由
+ * @method setFilterMenuAndCacheTagsViewRoutes 设置路由到 pinia routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
+ */
+export async function initBackEndControlRoutes() {
+ // 界面 loading 动画开始执行
+ if (window.nextLoading === undefined) NextLoading.start();
+ // 无 token 停止执行下一步
+ if (!Session.get('token')) return false;
+ // 触发初始化用户信息 pinia
+ // https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP
+ await useUserInfo().setUserInfos();
+ // 获取路由菜单数据
+ const res = await menuApi.getMenu();
+ // 无登录权限时,添加判断
+ // https://gitee.com/lyt-top/vue-next-admin/issues/I64HVO
+ if (res.data.length <= 0) return Promise.resolve(true);
+ // 存储接口原始路由(未处理component),根据需求选择使用
+ useRequestOldRoutes().setRequestOldRoutes(JSON.parse(JSON.stringify(res.data)));
+ // 处理路由(component),替换 dynamicRoutes(/@/router/route)第一个顶级 children 的路由
+ dynamicRoutes[0].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: 'fa:home',
+ },
+ },
+ {
+ path: '/personal',
+ name: 'personal',
+ component: () => import('/@/views/personal/index.vue'),
+ meta: {
+ title: 'message.router.personal',
+ isLink: '',
+ isHide: true,
+ isKeepAlive: true,
+ isAffix: false,
+ isIframe: false,
+ roles: ['admin', 'common'],
+ icon: 'iconfont icon-gerenzhongxin',
+ },
+ },
+ ...await backEndComponent(res.data)
+ ];
+ // 添加动态路由
+ await setAddRoute();
+ // 设置路由到 pinia routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
+ await setFilterMenuAndCacheTagsViewRoutes();
+}
+
+/**
+ * 设置路由到 pinia routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
+ * @description 用于左侧菜单、横向菜单的显示
+ * @description 用于 tagsView、菜单搜索中:未过滤隐藏的(isHide)
+ */
+export async function setFilterMenuAndCacheTagsViewRoutes() {
+ const storesRoutesList = useRoutesList(pinia);
+ storesRoutesList.setRoutesList(dynamicRoutes[0].children as any);
+ setCacheTagsViewRoutes();
+}
+
+/**
+ * 缓存多级嵌套数组处理后的一维数组
+ * @description 用于 tagsView、菜单搜索中:未过滤隐藏的(isHide)
+ */
+export function setCacheTagsViewRoutes() {
+ const storesTagsView = useTagsViewRoutes(pinia);
+ storesTagsView.setTagsViewRoutes(formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes))[0].children);
+}
+
+/**
+ * 处理路由格式及添加捕获所有路由或 404 Not found 路由
+ * @description 替换 dynamicRoutes(/@/router/route)第一个顶级 children 的路由
+ * @returns 返回替换后的路由数组
+ */
+export function setFilterRouteEnd() {
+ let filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes));
+ // notFoundAndNoPower 防止 404、401 不在 layout 布局中,不设置的话,404、401 界面将全屏显示
+ // 关联问题 No match found for location with path 'xxx'
+ filterRouteEnd[0].children = [...filterRouteEnd[0].children, ...notFoundAndNoPower];
+ return filterRouteEnd;
+}
+
+/**
+ * 添加动态路由
+ * @method router.addRoute
+ * @description 此处循环为 dynamicRoutes(/@/router/route)第一个顶级 children 的路由一维数组,非多级嵌套
+ * @link 参考:https://next.router.vuejs.org/zh/api/#addroute
+ */
+export async function setAddRoute() {
+ await setFilterRouteEnd().forEach((route: RouteRecordRaw) => {
+ router.addRoute(route);
+ });
+}
+
+/**
+ * 请求后端路由菜单接口
+ * @description isRequestRoutes 为 true,则开启后端控制路由
+ * @returns 返回后端路由菜单数据
+ */
+export function getBackEndControlRoutes() {
+ // 模拟 admin 与 test
+ const stores = useUserInfo(pinia);
+ const { userInfos } = storeToRefs(stores);
+ const auth = userInfos.value.roles[0];
+ // 管理员 admin
+ if (auth === 'admin') return menuApi.getAdminMenu();
+ // 其它用户 test
+ else return menuApi.getTestMenu();
+}
+
+/**
+ * 将指定组件设置自定义名称
+ *
+ * @param {String} name 组件自定义名称
+ * @param {Component | Promise<Component>} component
+ * @return {Component}
+ */
+ export function createCustomComponent (name: string, component: Component) {
+ return {
+ name,
+ setup () {
+ const component = shallowRef();
+ return {
+ component
+ }
+ },
+ async created () {
+ if (component instanceof Promise) {
+ try {
+ const module = await component
+ this.component = module?.default
+ } catch (error) {
+ // console.error(`can not resolve component ${name}, error:`, error)
+ }
+ return
+ }
+ this.component = component
+ },
+ render () {
+ return this.component ? h(this.component) : null
+ },
+ } as Component
+}
+
+
+/**
+ * 重新请求后端路由菜单接口
+ * @description 用于菜单管理界面刷新菜单(未进行测试)
+ * @description 路径:/src/views/system/menu/component/addMenu.vue
+ */
+export async function setBackEndControlRefreshRoutes() {
+ await getBackEndControlRoutes();
+}
+
+/**
+ * 后端路由 component 转换
+ * @param routes 后端返回的路由表数组
+ * @returns 返回处理成函数后的 component
+ */
+export function backEndComponent(routes: Menu[]): Array<RouteRecordRaw> {
+ if (!routes) return [];
+ return routes.map((item) => {
+ // if (item.component) item.component = dynamicImport(dynamicViewsModules, item.component as string);
+ // item.children && backEndComponent(item.children);
+ const url = item.url.split('/').map(v => toCamelCase(v)).join('/')
+ const component = modules[`../views/modules${url}.vue`] || modules[`../views/modules${url}/index.vue`]
+ return {
+ path: url,
+ name: item.name,
+ // component: component || dynamicImport(dynamicViewsModules, 'modules/index') as never,
+ component: component || createCustomComponent(item.name, import('../views/modules/index.vue')),
+ props: { type: url },
+ meta: {
+ title: item.displayName,
+ isLink: "",
+ isHide: false,
+ isKeepAlive: true,
+ isAffix: false,
+ isIframe: item.newWindow,
+ // roles
+ icon: item.icon ? item.icon.replace(/^fa-/, 'fa:') : ''
+ },
+ children: backEndComponent(item.children)
+ };
+ });
+}
+
+/**
+ * 后端路由 component 转换函数
+ * @param dynamicViewsModules 获取目录下的 .vue、.tsx 全部文件
+ * @param component 当前要处理项 component
+ * @returns 返回处理成函数后的 component
+ */
+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..21337b6
--- /dev/null
+++ b/src/router/frontEnd.ts
@@ -0,0 +1,153 @@
+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';
+
+// 前端控制路由
+
+/**
+ * 前端控制路由:初始化方法,防止刷新时路由丢失
+ * @method NextLoading 界面 loading 动画开始执行
+ * @method useUserInfo(pinia).setUserInfos() 触发初始化用户信息 pinia
+ * @method setAddRoute 添加动态路由
+ * @method setFilterMenuAndCacheTagsViewRoutes 设置递归过滤有权限的路由到 pinia routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
+ */
+export async function initFrontEndControlRoutes() {
+ // 界面 loading 动画开始执行
+ if (window.nextLoading === undefined) NextLoading.start();
+ // 无 token 停止执行下一步
+ if (!Session.get('token')) return false;
+ // 触发初始化用户信息 pinia
+ // https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP
+ await useUserInfo(pinia).setUserInfos();
+ // 无登录权限时,添加判断
+ // https://gitee.com/lyt-top/vue-next-admin/issues/I64HVO
+ if (useUserInfo().userInfos.roles.length <= 0) return Promise.resolve(true);
+ // 添加动态路由
+ await setAddRoute();
+ // 设置递归过滤有权限的路由到 pinia routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
+ await setFilterMenuAndCacheTagsViewRoutes();
+}
+
+/**
+ * 添加动态路由
+ * @method router.addRoute
+ * @description 此处循环为 dynamicRoutes(/@/router/route)第一个顶级 children 的路由一维数组,非多级嵌套
+ * @link 参考:https://next.router.vuejs.org/zh/api/#addroute
+ */
+export async function setAddRoute() {
+ await setFilterRouteEnd().forEach((route: RouteRecordRaw) => {
+ router.addRoute(route);
+ });
+}
+
+/**
+ * 删除/重置路由
+ * @method router.removeRoute
+ * @description 此处循环为 dynamicRoutes(/@/router/route)第一个顶级 children 的路由一维数组,非多级嵌套
+ * @link 参考:https://next.router.vuejs.org/zh/api/#push
+ */
+export async function frontEndsResetRoute() {
+ await setFilterRouteEnd().forEach((route: RouteRecordRaw) => {
+ const routeName: any = route.name;
+ router.hasRoute(routeName) && router.removeRoute(routeName);
+ });
+}
+
+/**
+ * 获取有当前用户权限标识的路由数组,进行对原路由的替换
+ * @description 替换 dynamicRoutes(/@/router/route)第一个顶级 children 的路由
+ * @returns 返回替换后的路由数组
+ */
+export function setFilterRouteEnd() {
+ let filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes));
+ // notFoundAndNoPower 防止 404、401 不在 layout 布局中,不设置的话,404、401 界面将全屏显示
+ // 关联问题 No match found for location with path 'xxx'
+ filterRouteEnd[0].children = [...setFilterRoute(filterRouteEnd[0].children), ...notFoundAndNoPower];
+ return filterRouteEnd;
+}
+
+/**
+ * 获取当前用户权限标识去比对路由表(未处理成多级嵌套路由)
+ * @description 这里主要用于动态路由的添加,router.addRoute
+ * @link 参考:https://next.router.vuejs.org/zh/api/#addroute
+ * @param chil dynamicRoutes(/@/router/route)第一个顶级 children 的下路由集合
+ * @returns 返回有当前用户权限标识的路由数组
+ */
+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;
+}
+
+/**
+ * 缓存多级嵌套数组处理后的一维数组
+ * @description 用于 tagsView、菜单搜索中:未过滤隐藏的(isHide)
+ */
+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);
+}
+
+/**
+ * 设置递归过滤有权限的路由到 pinia routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
+ * @description 用于左侧菜单、横向菜单的显示
+ * @description 用于 tagsView、菜单搜索中:未过滤隐藏的(isHide)
+ */
+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();
+}
+
+/**
+ * 判断路由 `meta.roles` 中是否包含当前登录用户权限字段
+ * @param roles 用户权限标识,在 userInfos(用户信息)的 roles(登录页登录时缓存到浏览器)数组
+ * @param route 当前循环时的路由项
+ * @returns 返回对比后有权限的路由项
+ */
+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;
+}
+
+/**
+ * 获取当前用户权限标识去比对路由表,设置递归过滤有权限的路由
+ * @param routes 当前路由 children
+ * @param roles 用户权限标识,在 userInfos(用户信息)的 roles(登录页登录时缓存到浏览器)数组
+ * @returns 返回有权限的路由数组 `meta.roles` 中控制
+ */
+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..a92deab
--- /dev/null
+++ b/src/router/index.ts
@@ -0,0 +1,137 @@
+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, notFoundAndNoPower } from '/@/router/route';
+import { initFrontEndControlRoutes } from '/@/router/frontEnd';
+import { initBackEndControlRoutes } from '/@/router/backEnd';
+
+/**
+ * 1、前端控制路由时:isRequestRoutes 为 false,需要写 roles,需要走 setFilterRoute 方法。
+ * 2、后端控制路由时:isRequestRoutes 为 true,不需要写 roles,不需要走 setFilterRoute 方法),
+ * 相关方法已拆解到对应的 `backEnd.ts` 与 `frontEnd.ts`(他们互不影响,不需要同时改 2 个文件)。
+ * 特别说明:
+ * 1、前端控制:路由菜单由前端去写(无菜单管理界面,有角色管理界面),角色管理中有 roles 属性,需返回到 userInfo 中。
+ * 2、后端控制:路由菜单由后端返回(有菜单管理界面、有角色管理界面)
+ */
+
+// 读取 `/src/stores/themeConfig.ts` 是否开启后端控制路由配置
+const storesThemeConfig = useThemeConfig(pinia);
+const { themeConfig } = storeToRefs(storesThemeConfig);
+const { isRequestRoutes } = themeConfig.value;
+
+/**
+ * 创建一个可以被 Vue 应用程序使用的路由实例
+ * @method createRouter(options: RouterOptions): Router
+ * @link 参考:https://next.router.vuejs.org/zh/api/#createrouter
+ */
+export const router = createRouter({
+ history: createWebHashHistory(),
+ /**
+ * 说明:
+ * 1、notFoundAndNoPower 默认添加 404、401 界面,防止一直提示 No match found for location with path 'xxx'
+ * 2、backEnd.ts(后端控制路由)、frontEnd.ts(前端控制路由) 中也需要加 notFoundAndNoPower 404、401 界面。
+ * 防止 404、401 不在 layout 布局中,不设置的话,404、401 界面将全屏显示
+ */
+ routes: [...notFoundAndNoPower, ...staticRoutes],
+});
+
+/**
+ * 路由多级嵌套数组处理成一维数组
+ * @param arr 传入路由菜单数据数组
+ * @returns 返回处理后的一维路由菜单数组
+ */
+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;
+}
+
+/**
+ * 一维数组处理成多级嵌套数组(只保留二级:也就是二级以上全部处理成只有二级,keep-alive 支持二级缓存)
+ * @description isKeepAlive 处理 `name` 值,进行缓存。顶级关闭,全部不缓存
+ * @link 参考:https://v3.cn.vuejs.org/api/built-in-components.html#keep-alive
+ * @param arr 处理后的一维路由菜单数组
+ * @returns 返回将一维数组重新处理成 `定义动态路由(dynamicRoutes)` 的格式
+ */
+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;
+}
+
+// 路由加载前
+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();
+ // 解决刷新时,一直跳 404 页面问题,关联问题 No match found for location with path 'xxx'
+ // to.query 防止页面刷新时,普通路由带参数时,参数丢失。动态路由(xxx/:id/:name")isDynamic 无需处理
+ next({ path: to.path, query: to.query });
+ } else {
+ // https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP
+ await initFrontEndControlRoutes();
+ next({ path: to.path, query: to.query });
+ }
+ } 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..95e6c84
--- /dev/null
+++ b/src/router/route.ts
@@ -0,0 +1,1230 @@
+import { RouteRecordRaw } from 'vue-router';
+
+/**
+ * 建议:路由 path 路径与文件夹名称相同,找文件可浏览器地址找,方便定位文件位置
+ *
+ * 路由meta对象参数说明
+ * meta: {
+ * title: 菜单栏及 tagsView 栏、菜单搜索名称(国际化)
+ * isLink: 是否超链接菜单,开启外链条件,`1、isLink: 链接地址不为空 2、isIframe:false`
+ * isHide: 是否隐藏此路由
+ * isKeepAlive: 是否缓存组件状态
+ * isAffix: 是否固定在 tagsView 栏上
+ * isIframe: 是否内嵌窗口,开启条件,`1、isIframe:true 2、isLink:链接地址不为空`
+ * roles: 当前路由权限标识,取角色管理。控制路由显示、隐藏。超级管理员:admin 普通角色:common
+ * icon: 菜单、tagsView 图标,阿里:加 `iconfont xxx`,fontawesome:加 `fa xxx`
+ * }
+ */
+
+// 扩展 RouteMeta 接口
+declare module 'vue-router' {
+ interface RouteMeta {
+ title?: string;
+ isLink?: string;
+ isHide?: boolean;
+ isKeepAlive?: boolean;
+ isAffix?: boolean;
+ isIframe?: boolean;
+ roles?: string[];
+ icon?: string;
+ }
+}
+
+/**
+ * 定义动态路由
+ * 前端添加路由,请在顶级节点的 `children 数组` 里添加
+ * @description 未开启 isRequestRoutes 为 true 时使用(前端控制路由),开启时第一个顶级 children 的路由将被替换成接口请求回来的路由数据
+ * @description 各字段请查看 `/@/views/system/menu/component/addMenu.vue 下的 ruleForm`
+ * @returns 返回路由菜单数据
+ */
+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',
+ },
+ },
+ {
+ path: '/personal',
+ name: 'personal',
+ component: () => import('/@/views/personal/index.vue'),
+ meta: {
+ title: 'message.router.personal',
+ isLink: '',
+ isHide: false,
+ isKeepAlive: true,
+ isAffix: false,
+ isIframe: false,
+ roles: ['admin', 'common'],
+ icon: 'iconfont icon-gerenzhongxin',
+ },
+ },
+ // {
+ // path: '/system',
+ // name: 'system',
+ // component: () => import('/@/layout/routerView/parent.vue'),
+ // redirect: '/system/menu',
+ // meta: {
+ // title: 'message.router.system',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'iconfont icon-xitongshezhi',
+ // },
+ // children: [
+ // {
+ // path: '/system/menu',
+ // name: 'systemMenu',
+ // component: () => import('/@/views/system/menu/index.vue'),
+ // meta: {
+ // title: 'message.router.systemMenu',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'iconfont icon-caidan',
+ // },
+ // },
+ // {
+ // path: '/system/role',
+ // name: 'systemRole',
+ // component: () => import('/@/views/system/role/index.vue'),
+ // meta: {
+ // title: 'message.router.systemRole',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'ele-ColdDrink',
+ // },
+ // },
+ // {
+ // path: '/system/user',
+ // name: 'systemUser',
+ // component: () => import('/@/views/system/user/index.vue'),
+ // meta: {
+ // title: 'message.router.systemUser',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'iconfont icon-icon-',
+ // },
+ // },
+ // {
+ // path: '/system/dept',
+ // name: 'systemDept',
+ // component: () => import('/@/views/system/dept/index.vue'),
+ // meta: {
+ // title: 'message.router.systemDept',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'ele-OfficeBuilding',
+ // },
+ // },
+ // {
+ // path: '/system/dic',
+ // name: 'systemDic',
+ // component: () => import('/@/views/system/dic/index.vue'),
+ // meta: {
+ // title: 'message.router.systemDic',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'ele-SetUp',
+ // },
+ // },
+ // ],
+ // },
+ // {
+ // path: '/limits',
+ // name: 'limits',
+ // component: () => import('/@/layout/routerView/parent.vue'),
+ // redirect: '/limits/frontEnd',
+ // meta: {
+ // title: 'message.router.limits',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-quanxian',
+ // },
+ // children: [
+ // {
+ // path: '/limits/frontEnd',
+ // name: 'limitsFrontEnd',
+ // component: () => import('/@/layout/routerView/parent.vue'),
+ // redirect: '/limits/frontEnd/page',
+ // meta: {
+ // title: 'message.router.limitsFrontEnd',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: '',
+ // },
+ // children: [
+ // {
+ // path: '/limits/frontEnd/page',
+ // name: 'limitsFrontEndPage',
+ // component: () => import('/@/views/limits/frontEnd/page/index.vue'),
+ // meta: {
+ // title: 'message.router.limitsFrontEndPage',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: '',
+ // },
+ // },
+ // {
+ // path: '/limits/frontEnd/btn',
+ // name: 'limitsFrontEndBtn',
+ // component: () => import('/@/views/limits/frontEnd/btn/index.vue'),
+ // meta: {
+ // title: 'message.router.limitsFrontEndBtn',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: '',
+ // },
+ // },
+ // ],
+ // },
+ // {
+ // path: '/limits/backEnd',
+ // name: 'limitsBackEnd',
+ // component: () => import('/@/layout/routerView/parent.vue'),
+ // meta: {
+ // title: 'message.router.limitsBackEnd',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: '',
+ // },
+ // children: [
+ // {
+ // path: '/limits/backEnd/page',
+ // name: 'limitsBackEndEndPage',
+ // component: () => import('/@/views/limits/backEnd/page/index.vue'),
+ // meta: {
+ // title: 'message.router.limitsBackEndEndPage',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: '',
+ // },
+ // },
+ // ],
+ // },
+ // ],
+ // },
+ // {
+ // path: '/menu',
+ // name: 'menu',
+ // component: () => import('/@/layout/routerView/parent.vue'),
+ // redirect: '/menu/menu1',
+ // meta: {
+ // title: 'message.router.menu',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-caidan',
+ // },
+ // children: [
+ // {
+ // path: '/menu/menu1',
+ // name: 'menu1',
+ // component: () => import('/@/layout/routerView/parent.vue'),
+ // redirect: '/menu/menu1/menu11',
+ // meta: {
+ // title: 'message.router.menu1',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-caidan',
+ // },
+ // children: [
+ // {
+ // path: '/menu/menu1/menu11',
+ // name: 'menu11',
+ // component: () => import('/@/views/menu/menu1/menu11/index.vue'),
+ // meta: {
+ // title: 'message.router.menu11',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-caidan',
+ // },
+ // },
+ // {
+ // path: '/menu/menu1/menu12',
+ // name: 'menu12',
+ // component: () => import('/@/layout/routerView/parent.vue'),
+ // redirect: '/menu/menu1/menu12/menu121',
+ // meta: {
+ // title: 'message.router.menu12',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-caidan',
+ // },
+ // children: [
+ // {
+ // path: '/menu/menu1/menu12/menu121',
+ // name: 'menu121',
+ // component: () => import('/@/views/menu/menu1/menu12/menu121/index.vue'),
+ // meta: {
+ // title: 'message.router.menu121',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-caidan',
+ // },
+ // },
+ // {
+ // path: '/menu/menu1/menu12/menu122',
+ // name: 'menu122',
+ // component: () => import('/@/views/menu/menu1/menu12/menu122/index.vue'),
+ // meta: {
+ // title: 'message.router.menu122',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-caidan',
+ // },
+ // },
+ // ],
+ // },
+ // {
+ // path: '/menu/menu1/menu13',
+ // name: 'menu13',
+ // component: () => import('/@/views/menu/menu1/menu13/index.vue'),
+ // meta: {
+ // title: 'message.router.menu13',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-caidan',
+ // },
+ // },
+ // ],
+ // },
+ // {
+ // path: '/menu/menu2',
+ // name: 'menu2',
+ // component: () => import('/@/views/menu/menu2/index.vue'),
+ // meta: {
+ // title: 'message.router.menu2',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-caidan',
+ // },
+ // },
+ // ],
+ // },
+ // {
+ // path: '/fun',
+ // name: 'funIndex',
+ // component: () => import('/@/layout/routerView/parent.vue'),
+ // redirect: '/fun/tagsView',
+ // meta: {
+ // title: 'message.router.funIndex',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-crew_feature',
+ // },
+ // children: [
+ // {
+ // path: '/fun/tagsView',
+ // name: 'funTagsView',
+ // component: () => import('/@/views/fun/tagsView/index.vue'),
+ // meta: {
+ // title: 'message.router.funTagsView',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'ele-Pointer',
+ // },
+ // },
+ // {
+ // path: '/fun/countup',
+ // name: 'funCountup',
+ // component: () => import('/@/views/fun/countup/index.vue'),
+ // meta: {
+ // title: 'message.router.funCountup',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'ele-Odometer',
+ // },
+ // },
+ // {
+ // path: '/fun/wangEditor',
+ // name: 'funWangEditor',
+ // component: () => import('/@/views/fun/wangEditor/index.vue'),
+ // meta: {
+ // title: 'message.router.funWangEditor',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-fuwenbenkuang',
+ // },
+ // },
+ // {
+ // path: '/fun/cropper',
+ // name: 'funCropper',
+ // component: () => import('/@/views/fun/cropper/index.vue'),
+ // meta: {
+ // title: 'message.router.funCropper',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-caijian',
+ // },
+ // },
+ // {
+ // path: '/fun/qrcode',
+ // name: 'funQrcode',
+ // component: () => import('/@/views/fun/qrcode/index.vue'),
+ // meta: {
+ // title: 'message.router.funQrcode',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-ico',
+ // },
+ // },
+ // {
+ // path: '/fun/echartsMap',
+ // name: 'funEchartsMap',
+ // component: () => import('/@/views/fun/echartsMap/index.vue'),
+ // meta: {
+ // title: 'message.router.funEchartsMap',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-ditu',
+ // },
+ // },
+ // {
+ // path: '/fun/printJs',
+ // name: 'funPrintJs',
+ // component: () => import('/@/views/fun/printJs/index.vue'),
+ // meta: {
+ // title: 'message.router.funPrintJs',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'ele-Printer',
+ // },
+ // },
+ // {
+ // path: '/fun/clipboard',
+ // name: 'funClipboard',
+ // component: () => import('/@/views/fun/clipboard/index.vue'),
+ // meta: {
+ // title: 'message.router.funClipboard',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'ele-DocumentCopy',
+ // },
+ // },
+ // {
+ // path: '/fun/gridLayout',
+ // name: 'funGridLayout',
+ // component: () => import('/@/views/fun/gridLayout/index.vue'),
+ // meta: {
+ // title: 'message.router.funGridLayout',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-tuodong',
+ // },
+ // },
+ // {
+ // path: '/fun/splitpanes',
+ // name: 'funSplitpanes',
+ // component: () => import('/@/views/fun/splitpanes/index.vue'),
+ // meta: {
+ // title: 'message.router.funSplitpanes',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon--chaifenlie',
+ // },
+ // },
+ // ],
+ // },
+ // {
+ // path: '/pages',
+ // name: 'pagesIndex',
+ // component: () => import('/@/layout/routerView/parent.vue'),
+ // redirect: '/pages/filtering',
+ // meta: {
+ // title: 'message.router.pagesIndex',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-fuzhiyemian',
+ // },
+ // children: [
+ // {
+ // path: '/pages/filtering',
+ // name: 'pagesFiltering',
+ // component: () => import('/@/views/pages/filtering/index.vue'),
+ // meta: {
+ // title: 'message.router.pagesFiltering',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'ele-Sell',
+ // },
+ // /**
+ // * 注意此处详情写法:
+ // * 1、嵌套进父级里时,面包屑显示为:首页/页面/过滤筛选组件/过滤筛选组件详情
+ // * 2、不嵌套进父级时,面包屑显示为:首页/页面/过滤筛选组件/过滤筛选组件详情
+ // * 3、想要父级不高亮,面包屑显示为:首页/页面/过滤筛选组件详情,设置路径为:/pages/filteringDetails
+ // */
+ // children: [
+ // {
+ // path: '/pages/filtering/details',
+ // name: 'pagesFilteringDetails',
+ // component: () => import('/@/views/pages/filtering/details.vue'),
+ // meta: {
+ // title: 'message.router.pagesFilteringDetails',
+ // isLink: '',
+ // isHide: true,
+ // isKeepAlive: false,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'ele-Sunny',
+ // },
+ // },
+ // ],
+ // },
+ // {
+ // path: '/pages/filtering/details1',
+ // name: 'pagesFilteringDetails1',
+ // component: () => import('/@/views/pages/filtering/details1.vue'),
+ // meta: {
+ // title: 'message.router.pagesFilteringDetails1',
+ // isLink: '',
+ // isHide: true,
+ // isKeepAlive: false,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'ele-Sunny',
+ // },
+ // },
+ // {
+ // path: '/pages/iocnfont',
+ // name: 'pagesIocnfont',
+ // component: () => import('/@/views/pages/iocnfont/index.vue'),
+ // meta: {
+ // title: 'message.router.pagesIocnfont',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'ele-Present',
+ // },
+ // },
+ // {
+ // path: '/pages/element',
+ // name: 'pagesElement',
+ // component: () => import('/@/views/pages/element/index.vue'),
+ // meta: {
+ // title: 'message.router.pagesElement',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'ele-Eleme',
+ // },
+ // },
+ // {
+ // path: '/pages/awesome',
+ // name: 'pagesAwesome',
+ // component: () => import('/@/views/pages/awesome/index.vue'),
+ // meta: {
+ // title: 'message.router.pagesAwesome',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'ele-SetUp',
+ // },
+ // },
+ // {
+ // path: '/pages/formAdapt',
+ // name: 'pagesFormAdapt',
+ // component: () => import('/@/views/pages/formAdapt/index.vue'),
+ // meta: {
+ // title: 'message.router.pagesFormAdapt',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-biaodan',
+ // },
+ // },
+ // {
+ // path: '/pages/tableRules',
+ // name: 'pagesTableRules',
+ // component: () => import('/@/views/pages/tableRules/index.vue'),
+ // meta: {
+ // title: 'message.router.pagesTableRules',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-jiliandongxuanzeqi',
+ // },
+ // },
+ // {
+ // path: '/pages/formI18n',
+ // name: 'pagesFormI18n',
+ // component: () => import('/@/views/pages/formI18n/index.vue'),
+ // meta: {
+ // title: 'message.router.pagesFormI18n',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-diqiu',
+ // },
+ // },
+ // {
+ // path: '/pages/formRules',
+ // name: 'pagesFormRules',
+ // component: () => import('/@/views/pages/formRules/index.vue'),
+ // meta: {
+ // title: 'message.router.pagesFormRules',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-shuxing',
+ // },
+ // },
+ // {
+ // path: '/pages/listAdapt',
+ // name: 'pagesListAdapt',
+ // component: () => import('/@/views/pages/listAdapt/index.vue'),
+ // meta: {
+ // title: 'message.router.pagesListAdapt',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-chazhaobiaodanliebiao',
+ // },
+ // },
+ // {
+ // path: '/pages/waterfall',
+ // name: 'pagesWaterfall',
+ // component: () => import('/@/views/pages/waterfall/index.vue'),
+ // meta: {
+ // title: 'message.router.pagesWaterfall',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-zidingyibuju',
+ // },
+ // },
+ // {
+ // path: '/pages/steps',
+ // name: 'pagesSteps',
+ // component: () => import('/@/views/pages/steps/index.vue'),
+ // meta: {
+ // title: 'message.router.pagesSteps',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-step',
+ // },
+ // },
+ // {
+ // path: '/pages/preview',
+ // name: 'pagesPreview',
+ // component: () => import('/@/views/pages/preview/index.vue'),
+ // meta: {
+ // title: 'message.router.pagesPreview',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-15tupianyulan',
+ // },
+ // },
+ // {
+ // path: '/pages/waves',
+ // name: 'pagesWaves',
+ // component: () => import('/@/views/pages/waves/index.vue'),
+ // meta: {
+ // title: 'message.router.pagesWaves',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-bolangneng',
+ // },
+ // },
+ // {
+ // path: '/pages/tree',
+ // name: 'pagesTree',
+ // component: () => import('/@/views/pages/tree/index.vue'),
+ // meta: {
+ // title: 'message.router.pagesTree',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-shuxingtu',
+ // },
+ // },
+ // {
+ // path: '/pages/drag',
+ // name: 'pagesDrag',
+ // component: () => import('/@/views/pages/drag/index.vue'),
+ // meta: {
+ // title: 'message.router.pagesDrag',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'ele-Pointer',
+ // },
+ // },
+ // {
+ // path: '/pages/lazyImg',
+ // name: 'pagesLazyImg',
+ // component: () => import('/@/views/pages/lazyImg/index.vue'),
+ // meta: {
+ // title: 'message.router.pagesLazyImg',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'ele-PictureFilled',
+ // },
+ // },
+ // {
+ // path: '/pages/dynamicForm',
+ // name: 'pagesDynamicForm',
+ // component: () => import('/@/views/pages/dynamicForm/index.vue'),
+ // meta: {
+ // title: 'message.router.pagesDynamicForm',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'iconfont icon-wenducanshu-05',
+ // },
+ // },
+ // {
+ // path: '/pages/workflow',
+ // name: 'pagesWorkflow',
+ // component: () => import('/@/views/pages/workflow/index.vue'),
+ // meta: {
+ // title: 'message.router.pagesWorkflow',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'ele-Connection',
+ // },
+ // },
+ // ],
+ // },
+ // {
+ // path: '/make',
+ // name: 'makeIndex',
+ // component: () => import('/@/layout/routerView/parent.vue'),
+ // redirect: '/make/selector',
+ // meta: {
+ // title: 'message.router.makeIndex',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'iconfont icon-siweidaotu',
+ // },
+ // children: [
+ // {
+ // path: '/make/selector',
+ // name: 'makeSelector',
+ // component: () => import('/@/views/make/selector/index.vue'),
+ // meta: {
+ // title: 'message.router.makeSelector',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-xuanzeqi',
+ // },
+ // },
+ // {
+ // path: '/make/noticeBar',
+ // name: 'makeNoticeBar',
+ // component: () => import('/@/views/make/noticeBar/index.vue'),
+ // meta: {
+ // title: 'message.router.makeNoticeBar',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'ele-Bell',
+ // },
+ // },
+ // {
+ // path: '/make/svgDemo',
+ // name: 'makeSvgDemo',
+ // component: () => import('/@/views/make/svgDemo/index.vue'),
+ // meta: {
+ // title: 'message.router.makeSvgDemo',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'fa fa-thumbs-o-up',
+ // },
+ // },
+ // {
+ // path: '/make/tableDemo',
+ // name: 'makeTableDemo',
+ // component: () => import('/@/views/make/tableDemo/index.vue'),
+ // meta: {
+ // title: 'message.router.makeTableDemo',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-shuju',
+ // },
+ // },
+ // ],
+ // },
+ // {
+ // path: '/params',
+ // name: 'paramsIndex',
+ // component: () => import('/@/layout/routerView/parent.vue'),
+ // redirect: '/params/common',
+ // meta: {
+ // title: 'message.router.paramsIndex',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'iconfont icon-zhongduancanshu',
+ // },
+ // children: [
+ // {
+ // path: '/params/common',
+ // name: 'paramsCommon',
+ // component: () => import('/@/views/params/common/index.vue'),
+ // meta: {
+ // title: 'message.router.paramsCommon',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'iconfont icon-putong',
+ // },
+ // },
+ // {
+ // path: '/params/common/details',
+ // name: 'paramsCommonDetails',
+ // component: () => import('/@/views/params/common/details.vue'),
+ // meta: {
+ // title: 'message.router.paramsCommonDetails',
+ // isLink: '',
+ // isHide: true,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'ele-Comment',
+ // },
+ // },
+ // {
+ // path: '/params/dynamic',
+ // name: 'paramsDynamic',
+ // component: () => import('/@/views/params/dynamic/index.vue'),
+ // meta: {
+ // title: 'message.router.paramsDynamic',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'iconfont icon-dongtai',
+ // },
+ // },
+ // /**
+ // * tagsViewName 为要设置不同的 "tagsView 名称" 字段
+ // * 如若需设置不同 "tagsView 名称",tagsViewName 字段必须要有
+ // */
+ // {
+ // path: '/params/dynamic/details/:t/:id/:tagsViewName',
+ // name: 'paramsDynamicDetails',
+ // component: () => import('/@/views/params/dynamic/details.vue'),
+ // meta: {
+ // title: 'message.router.paramsDynamicDetails',
+ // isLink: '',
+ // isHide: true,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'ele-Lightning',
+ // },
+ // },
+ // ],
+ // },
+ // {
+ // path: '/visualizing',
+ // name: 'visualizingIndex',
+ // component: () => import('/@/layout/routerView/parent.vue'),
+ // redirect: '/visualizing/visualizingLinkDemo1',
+ // meta: {
+ // title: 'message.router.visualizingIndex',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'ele-ChatLineRound',
+ // },
+ // /**
+ // * 打开内置全屏
+ // * component 都为 `() => import('/@/layout/routerView/link.vue')`
+ // * isLink 链接为内置的路由地址,地址为 staticRoutes 中定义
+ // */
+ // children: [
+ // {
+ // path: '/visualizing/visualizingLinkDemo1',
+ // name: 'visualizingLinkDemo1',
+ // component: () => import('/@/layout/routerView/link.vue'),
+ // meta: {
+ // title: 'message.router.visualizingLinkDemo1',
+ // isLink: '/visualizingDemo1',
+ // isHide: false,
+ // isKeepAlive: false,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'iconfont icon-caozuo-wailian',
+ // },
+ // },
+ // {
+ // path: '/visualizing/visualizingLinkDemo2',
+ // name: 'visualizingLinkDemo2',
+ // component: () => import('/@/layout/routerView/link.vue'),
+ // meta: {
+ // title: 'message.router.visualizingLinkDemo2',
+ // isLink: '/visualizingDemo2',
+ // isHide: false,
+ // isKeepAlive: false,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'iconfont icon-caozuo-wailian',
+ // },
+ // },
+ // ],
+ // },
+ // {
+ // path: '/chart',
+ // name: 'chartIndex',
+ // component: () => import('/@/views/chart/index.vue'),
+ // meta: {
+ // title: 'message.router.chartIndex',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-ico_shuju',
+ // },
+ // },
+ // {
+ // path: '/tools',
+ // name: 'tools',
+ // component: () => import('/@/views/tools/index.vue'),
+ // meta: {
+ // title: 'message.router.tools',
+ // isLink: '',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin', 'common'],
+ // icon: 'iconfont icon-gongju',
+ // },
+ // },
+ // {
+ // path: '/link',
+ // name: 'layoutLinkView',
+ // component: () => import('/@/layout/routerView/link.vue'),
+ // meta: {
+ // title: 'message.router.layoutLinkView',
+ // isLink: 'https://element-plus.gitee.io/#/zh-CN/component/installation',
+ // isHide: false,
+ // isKeepAlive: false,
+ // isAffix: false,
+ // isIframe: false,
+ // roles: ['admin'],
+ // icon: 'iconfont icon-caozuo-wailian',
+ // },
+ // },
+ // {
+ // path: '/iframesOne',
+ // name: 'layoutIframeViewOne',
+ // component: () => import('/@/layout/routerView/iframes.vue'),
+ // meta: {
+ // title: 'message.router.layoutIframeViewOne',
+ // isLink: 'https://nodejs.org/zh-cn/',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: true,
+ // isIframe: true,
+ // roles: ['admin'],
+ // icon: 'iconfont icon-neiqianshujuchucun',
+ // },
+ // },
+ // {
+ // path: '/iframesTwo',
+ // name: 'layoutIframeViewTwo',
+ // component: () => import('/@/layout/routerView/iframes.vue'),
+ // meta: {
+ // title: 'message.router.layoutIframeViewTwo',
+ // isLink: 'https://undraw.co/illustrations',
+ // isHide: false,
+ // isKeepAlive: true,
+ // isAffix: true,
+ // isIframe: true,
+ // roles: ['admin'],
+ // icon: 'iconfont icon-neiqianshujuchucun',
+ // },
+ // },
+ ],
+ },
+];
+
+/**
+ * 定义404、401界面
+ * @link 参考:https://next.router.vuejs.org/zh/guide/essentials/history-mode.html#netlify
+ */
+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,
+ },
+ },
+];
+
+/**
+ * 定义静态路由(默认路由)
+ * 此路由不要动,前端添加路由的话,请在 `dynamicRoutes 数组` 中添加
+ * @description 前端控制直接改 dynamicRoutes 中的路由,后端控制不需要修改,请求接口路由数据时,会覆盖 dynamicRoutes 第一个顶级 children 的内容(全屏,不包含 layout 中的路由出口)
+ * @returns 返回路由菜单数据
+ */
+export const staticRoutes: Array<RouteRecordRaw> = [
+ {
+ path: '/login',
+ name: 'login',
+ component: () => import('/@/views/login/index.vue'),
+ meta: {
+ title: '登录',
+ },
+ },
+ /**
+ * 提示:写在这里的为全屏界面,不建议写在这里
+ * 请写在 `dynamicRoutes` 路由数组中
+ */
+];
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/keepAliveNames.ts b/src/stores/keepAliveNames.ts
new file mode 100644
index 0000000..981198f
--- /dev/null
+++ b/src/stores/keepAliveNames.ts
@@ -0,0 +1,35 @@
+import { defineStore } from 'pinia';
+
+/**
+ * 路由缓存列表
+ * @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 (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..b14ecc2
--- /dev/null
+++ b/src/stores/requestOldRoutes.ts
@@ -0,0 +1,16 @@
+import { defineStore } from 'pinia';
+
+/**
+ * 后端返回原始路由(未处理时)
+ * @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..5e3a249
--- /dev/null
+++ b/src/stores/routesList.ts
@@ -0,0 +1,26 @@
+import { defineStore } from 'pinia';
+
+/**
+ * 路由列表
+ * @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..cfb3e39
--- /dev/null
+++ b/src/stores/tagsViewRoutes.ts
@@ -0,0 +1,23 @@
+import { defineStore } from 'pinia';
+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..0213a49
--- /dev/null
+++ b/src/stores/themeConfig.ts
@@ -0,0 +1,157 @@
+import { defineStore } from 'pinia';
+
+/**
+ * 布局配置
+ * 修复: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: (): ThemeConfigState => ({
+ // themeConfig: {
+ // // 是否开启布局配置抽屉
+ // isDrawer: false,
+
+ // /**
+ // * 全局主题
+ // */
+ // // 默认 primary 主题颜色
+ // primary: '#409eff',
+ // // 是否开启深色模式
+ // isIsDark: false,
+
+ // /**
+ // * 顶栏设置
+ // */
+ // // 默认顶栏导航背景颜色
+ // topBar: '#ffffff',
+ // // 默认顶栏导航字体颜色
+ // topBarColor: '#606266',
+ // // 是否开启顶栏背景颜色渐变
+ // isTopBarColorGradual: false,
+
+ // /**
+ // * 菜单设置
+ // */
+ // // 默认菜单导航背景颜色
+ // menuBar: '#545c64',
+ // // 默认菜单导航字体颜色
+ // menuBarColor: '#eaeaea',
+ // // 默认菜单高亮背景色
+ // menuBarActiveColor: 'rgba(0, 0, 0, 0.2)',
+ // // 是否开启菜单背景颜色渐变
+ // isMenuBarColorGradual: false,
+
+ // /**
+ // * 分栏设置
+ // */
+ // // 默认分栏菜单背景颜色
+ // columnsMenuBar: '#545c64',
+ // // 默认分栏菜单字体颜色
+ // columnsMenuBarColor: '#e6e6e6',
+ // // 是否开启分栏菜单背景颜色渐变
+ // isColumnsMenuBarColorGradual: false,
+ // // 是否开启分栏菜单鼠标悬停预加载(预览菜单)
+ // isColumnsMenuHoverPreload: false,
+
+ // /**
+ // * 界面设置
+ // */
+ // // 是否开启菜单水平折叠效果
+ // isCollapse: false,
+ // // 是否开启菜单手风琴效果
+ // isUniqueOpened: true,
+ // // 是否开启固定 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: true,
+ // // 水印文案
+ // wartermarkText: 'vue-next-admin',
+
+ // /**
+ // * 其它设置
+ // */
+ // // 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: false,
+
+ // /**
+ // * 全局网站标题 / 副标题
+ // */
+ // // 网站主标题(菜单导航、浏览器当前网页标题)
+ // globalTitle: 'vue-next-admin',
+ // // 网站副标题(登录页顶部文字)
+ // globalViceTitle: 'vueNextAdmin',
+ // // 网站副标题(登录页顶部文字)
+ // globalViceTitleMsg: '专注、免费、开源、维护、解疑',
+ // // 默认初始语言,可选值"<zh-cn|en|zh-tw>",默认 zh-cn
+ // globalI18n: 'zh-cn',
+ // // 默认全局组件大小,可选值"<large|'default'|small>",默认 'large'
+ // globalComponentSize: 'large',
+ // },
+ themeConfig: {"isDrawer":false,"primary":"#523DFF","isIsDark":false,"topBar":"#ffffff","topBarColor":"#606266","isTopBarColorGradual":false,"menuBar":"#FCFCFC","menuBarColor":"#454545","menuBarActiveColor":"rgba(255, 255, 255, 1)","isMenuBarColorGradual":false,"columnsMenuBar":"#545c64","columnsMenuBarColor":"#e6e6e6","isColumnsMenuBarColorGradual":false,"isColumnsMenuHoverPreload":false,"isCollapse":false,"isUniqueOpened":true,"isFixedHeader":true,"isFixedHeaderChange":false,"isClassicSplitMenu":false,"isLockScreen":false,"lockScreenTime":29,"isShowLogo":true,"isShowLogoChange":false,"isBreadcrumb":false,"isTagsview":true,"isBreadcrumbIcon":false,"isTagsviewIcon":false,"isCacheTagsView":false,"isSortableTagsView":true,"isShareTagsView":false,"isFooter":false,"isGrayscale":false,"isInvert":false,"isWartermark":false,"wartermarkText":"新生命平台","tagsStyle":"tags-style-one","animation":"slide-right","columnsAsideStyle":"columns-round","columnsAsideLayout":"columns-vertical","layout":"classic","isRequestRoutes":true,"globalTitle":"新生命平台","globalViceTitle":"新生命平台","globalViceTitleMsg":"","globalI18n":"zh-cn","globalComponentSize":"default"}
+ }),
+ actions: {
+ setThemeConfig(data: ThemeConfigState) {
+ this.themeConfig = data.themeConfig;
+ },
+ },
+});
diff --git a/src/stores/userInfo.ts b/src/stores/userInfo.ts
new file mode 100644
index 0000000..17eecde
--- /dev/null
+++ b/src/stores/userInfo.ts
@@ -0,0 +1,50 @@
+import { defineStore } from 'pinia';
+import Cookies from 'js-cookie';
+import { Session } from '/@/utils/storage';
+import { useUserApi } from '../api/user';
+const userApi = useUserApi();
+
+/**
+ * 用户信息
+ * @methods setUserInfos 设置用户信息
+ */
+export const useUserInfo = defineStore('userInfo', {
+ state: (): UserInfosState => ({
+ userInfos: {
+ userName: '',
+ photo: '',
+ time: 0,
+ roles: [],
+ authBtnList: [],
+ },
+ }),
+ actions: {
+ async setUserInfos() {
+ // 存储用户信息到浏览器缓存
+ if (Session.get('userInfo')) {
+ this.userInfos = Session.get('userInfo');
+ } else {
+ const userInfos: any = await this.getApiUserInfo();
+ this.userInfos = userInfos;
+ }
+ },
+ // 模拟接口数据
+ // https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP
+ async getApiUserInfo() {
+ return new Promise((resolve) => {
+ userApi.info().then(res => {
+ let defaultBtnRoles: Array<string> = res.data.permission.split(',');
+ // let defaultAuthBtnList: Array<string> = [];
+ const userInfos = {
+ userName: res.data.name,
+ photo: res.data.avatar,
+ time: new Date().getTime(),
+ // roles: [],
+ authBtnList: defaultBtnRoles,
+ };
+ resolve(userInfos);
+ })
+ });
+ },
+ },
+});
diff --git a/src/theme/app.scss b/src/theme/app.scss
new file mode 100644
index 0000000..ef9d351
--- /dev/null
+++ b/src/theme/app.scss
@@ -0,0 +1,324 @@
+/* 初始化样式
+------------------------------- */
+* {
+ 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-pd {
+ padding: 15px !important;
+ }
+ .layout-flex {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ }
+ .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;
+ height: auto !important;
+ }
+ .layout-main {
+ padding: 0 !important;
+ overflow: hidden;
+ width: 100%;
+ background-color: var(--next-bg-main-color);
+ display: flex;
+ flex-direction: column;
+ // 内层 el-scrollbar样式,用于界面高度自适应(main.vue)
+ .layout-main-scroll {
+ @extend .layout-flex;
+ .layout-parent {
+ @extend .layout-flex;
+ position: relative;
+ }
+ }
+ }
+ // 用于界面高度自适应
+ .layout-padding {
+ @extend .layout-pd;
+ position: absolute;
+ left: 0;
+ top: 0;
+ height: 100%;
+ overflow: hidden;
+ @extend .layout-flex;
+ &-auto {
+ height: inherit;
+ @extend .layout-flex;
+ }
+ &-view {
+ background: var(--el-color-white);
+ width: 100%;
+ height: 100%;
+ border-radius: 4px;
+ border: 1px solid var(--el-border-color-light, #ebeef5);
+ overflow: hidden;
+ }
+ }
+ // 用于界面高度自适应,主视图区 main 的内边距,用于 iframe
+ .layout-padding-unset {
+ padding: 0 !important;
+ &-view {
+ border-radius: 0 !important;
+ border: none !important;
+ }
+ }
+ // 用于设置 iframe loading 时的高度(loading 垂直居中显示)
+ .layout-iframe {
+ .el-loading-parent--relative {
+ height: 100%;
+ }
+ }
+ .el-scrollbar {
+ width: 100%;
+ }
+ .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-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..b3609cd
--- /dev/null
+++ b/src/theme/common/transition.scss
@@ -0,0 +1,147 @@
+/* 页面切换动画
+------------------------------- */
+.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;
+ }
+}
+
+/* 登录页动画
+------------------------------- */
+@keyframes loginLeft {
+ 0% {
+ left: -100%;
+ }
+ 50%,
+ 100% {
+ left: 100%;
+ }
+}
+@keyframes loginTop {
+ 0% {
+ top: -100%;
+ }
+ 50%,
+ 100% {
+ top: 100%;
+ }
+}
+@keyframes loginRight {
+ 0% {
+ right: -100%;
+ }
+ 50%,
+ 100% {
+ right: 100%;
+ }
+}
+@keyframes loginBottom {
+ 0% {
+ bottom: -100%;
+ }
+ 50%,
+ 100% {
+ bottom: 100%;
+ }
+}
+
+/* 左右左 link.vue
+------------------------------- */
+@keyframes toRight {
+ 0% {
+ left: -5px;
+ }
+ 50% {
+ left: 100%;
+ }
+ 100% {
+ left: -5px;
+ }
+}
diff --git a/src/theme/dark.scss b/src/theme/dark.scss
new file mode 100644
index 0000000..ef7534b
--- /dev/null
+++ b/src/theme/dark.scss
@@ -0,0 +1,249 @@
+/* 深色模式样式
+------------------------------- */
+[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-menuBarActiveColor: var(--next-color-hover-rgba) !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%);
+ --el-fill-color-lighter: var(--next-color-hover-rgba) !important;
+
+ // 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);
+ }
+ /*深色模式时分页高亮问题*/
+ .el-pagination.is-background .btn-next.is-active,
+ .el-pagination.is-background .btn-prev.is-active,
+ .el-pagination.is-background .el-pager li.is-active {
+ color: var(--next-color-white) !important;
+ }
+
+ // 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;
+ }
+ }
+
+ // loading
+ .el-loading-mask {
+ background-color: var(--next-bg-main) !important;
+ }
+}
diff --git a/src/theme/element.scss b/src/theme/element.scss
new file mode 100644
index 0000000..fa4e78b
--- /dev/null
+++ b/src/theme/element.scss
@@ -0,0 +1,333 @@
+@import 'mixins/index.scss';
+
+/* Button 按钮
+------------------------------- */
+// 第三方字体图标大小
+.el-button:not(.is-circle) 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-autocomplete-suggestion__wrap {
+ max-height: 280px !important;
+}
+
+/* Form 表单
+------------------------------- */
+.el-form {
+ // 用于修改弹窗时表单内容间隔太大问题,如系统设置的新增菜单弹窗里的表单内容
+ // .el-form-item:last-of-type {
+ // margin-bottom: 0 !important;
+ // }
+ // 修复行内表单最后一个 el-form-item 位置下移问题
+ &.el-form--inline {
+ .el-form-item--large.el-form-item:last-of-type {
+ margin-bottom: 22px !important;
+ }
+ .el-form-item--default.el-form-item:last-of-type,
+ .el-form-item--small.el-form-item:last-of-type {
+ margin-bottom: 18px !important;
+ }
+ }
+ // https://gitee.com/lyt-top/vue-next-admin/issues/I5K1PM
+ .el-form-item .el-form-item__label .el-icon {
+ margin-right: 0px;
+ }
+}
+
+/* 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-bg-menuBarActiveColor) !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-menu-item:hover {
+ @extend .el-menu-hover-bg-color;
+}
+.el-sub-menu.is-active.is-opened .el-sub-menu__title {
+ background-color: unset !important;
+}
+
+.el-menu>.el-sub-menu.is-active[aria-expanded="false"]>.el-sub-menu__title {
+ color: var(--el-color-primary);
+ background-color: var(--next-bg-menuBarActiveColor) !important;
+}
+.el-sub-menu__title:hover,
+.el-menu-item:hover,
+.el-sub-menu.is-active.is-opened .el-sub-menu__title:hover {
+ color: var(--el-color-primary-light-3);
+ background-color: var(--next-bg-menuBarActiveColor) !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;
+}
+/*修复Select 选择器高度问题*/
+.el-select-dropdown__wrap {
+ max-height: 274px !important;
+}
+/*修复Cascader 级联选择器高度问题*/
+.el-cascader-menu__wrap.el-scrollbar__wrap {
+ height: 204px !important;
+}
+/*用于界面高度自适应(main.vue),区分 scrollbar__view,防止其它使用 scrollbar 的地方出现滚动条消失*/
+.layout-container-view .el-scrollbar__view {
+ height: 100%;
+}
+/*防止分栏布局二级菜单很多时,滚动条消失问题*/
+.layout-columns-warp .layout-aside .el-scrollbar__view {
+ height: unset !important;
+}
+
+/* Pagination 分页
+------------------------------- */
+.el-pagination__editor {
+ margin-right: 8px;
+}
+/*深色模式时分页高亮问题*/
+.el-pagination.is-background .btn-next.is-active,
+.el-pagination.is-background .btn-prev.is-active,
+.el-pagination.is-background .el-pager li.is-active {
+ background-color: var(--el-color-primary) !important;
+ color: var(--el-color-white) !important;
+}
+
+/* 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..569f614
--- /dev/null
+++ b/src/theme/iconSelector.scss
@@ -0,0 +1,31 @@
+/* Popover 弹出框(图标选择器)
+------------------------------- */
+.icon-selector-popper {
+ padding: 0 !important;
+ .icon-selector-warp {
+ height: 260px;
+ overflow: hidden;
+ position: relative;
+ .icon-selector-warp-title {
+ position: absolute;
+ height: 40px;
+ line-height: 40px;
+ left: 15px;
+ }
+ .el-tabs__header {
+ display: flex;
+ justify-content: flex-end;
+ padding: 0 15px;
+ border-bottom: 1px solid var(--el-border-color-light);
+ margin: 0 !important;
+ .el-tabs__nav-wrap {
+ &::after {
+ height: 0 !important;
+ }
+ .el-tabs__item {
+ padding: 0 5px !important;
+ }
+ }
+ }
+ }
+}
diff --git a/src/theme/index.scss b/src/theme/index.scss
new file mode 100644
index 0000000..f5d59ae
--- /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 './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..eb1d883
--- /dev/null
+++ b/src/theme/media/form.scss
@@ -0,0 +1,31 @@
+@import './index.scss';
+
+/* 页面宽度小于576px
+------------------------------- */
+@media screen and (max-width: $xs) {
+ .el-form-item__label {
+ width: 100% !important;
+ text-align: left !important;
+ // 移动端 label 右对齐问题
+ justify-content: flex-start !important;
+ }
+ .el-form-item__content {
+ margin-left: 0 !important;
+ }
+ .el-form-item {
+ // 响应式表单时,登录页需要重新处理
+ display: unset !important;
+ }
+ // 表格演示中的表单筛选
+ .table-form-btn {
+ display: flex !important;
+ .el-form-item__label {
+ width: auto !important;
+ }
+ }
+ // 表格演示中的表单筛选最大高度,适配移动端
+ .table-search-container {
+ max-height: 160px;
+ overflow: auto;
+ }
+}
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..df8ce56
--- /dev/null
+++ b/src/theme/media/layout.scss
@@ -0,0 +1,59 @@
+@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;
+ }
+ }
+ // pagination 分页中的工具栏
+ .table-footer-tool {
+ display: none !important;
+ }
+}
diff --git a/src/theme/media/login.scss b/src/theme/media/login.scss
new file mode 100644
index 0000000..29cdbb0
--- /dev/null
+++ b/src/theme/media/login.scss
@@ -0,0 +1,74 @@
+@import './index.scss';
+
+/* 页面宽度小于1200px
+------------------------------- */
+@media screen and (max-width: $lg) and (min-width: $xs) {
+ .login-container {
+ .login-left {
+ .login-left-img {
+ top: 90% !important;
+ left: 12% !important;
+ width: 30% !important;
+ height: 18% !important;
+ }
+ }
+ .login-right {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ }
+ }
+}
+
+/* 页面宽度小于576px
+------------------------------- */
+@media screen and (max-width: $xs) {
+ .login-container {
+ .login-left {
+ display: none;
+ }
+ .login-right {
+ width: 100% !important;
+ .login-right-warp {
+ width: 100% !important;
+ height: 100% !important;
+ border: none !important;
+ .login-right-warp-mian {
+ .el-form-item {
+ display: flex !important;
+ }
+ .login-right-warp-main-title {
+ font-size: 20px !important;
+ }
+ }
+ .login-right-warp-one {
+ &::after {
+ right: 0 !important;
+ }
+ }
+ .login-right-warp-two {
+ &::before {
+ bottom: 1px !important;
+ }
+ }
+ }
+ }
+ }
+}
+
+/* 页面宽度小于375px
+------------------------------- */
+@media screen and (max-width: $us) {
+ .login-container {
+ .login-right {
+ .login-right-warp {
+ .login-right-warp-mian {
+ .login-right-warp-main-title {
+ font-size: 18px !important;
+ }
+ }
+ }
+ }
+ }
+}
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..37af75f
--- /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,
+ .table-footer {
+ justify-content: 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..bbc3c61
--- /dev/null
+++ b/src/theme/other.scss
@@ -0,0 +1,36 @@
+/* wangeditor 富文本编辑器
+------------------------------- */
+.editor-container {
+ z-index: 10; // 用于 wangeditor 点击全屏时
+ .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/tableTool.scss b/src/theme/tableTool.scss
new file mode 100644
index 0000000..d5ab55e
--- /dev/null
+++ b/src/theme/tableTool.scss
@@ -0,0 +1,27 @@
+.table-tool-popper {
+ padding: 0 !important;
+ .tool-box {
+ display: flex;
+ border-bottom: 1px solid var(--el-border-color-lighter);
+ box-sizing: border-box;
+ color: var(--el-text-color-primary);
+ height: 40px;
+ align-items: center;
+ }
+ .tool-sortable {
+ max-height: 303px;
+ .tool-sortable-item {
+ display: flex;
+ box-sizing: border-box;
+ color: var(--el-text-color-primary);
+ align-items: center;
+ padding: 0 12px;
+ &:hover {
+ background: var(--el-fill-color-lighter);
+ }
+ i {
+ opacity: 0.7;
+ }
+ }
+ }
+}
diff --git a/src/theme/tailwind.scss b/src/theme/tailwind.scss
new file mode 100644
index 0000000..bd6213e
--- /dev/null
+++ b/src/theme/tailwind.scss
@@ -0,0 +1,3 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
\ No newline at end of file
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/types/axios.d.ts b/src/types/axios.d.ts
new file mode 100644
index 0000000..bcd0a21
--- /dev/null
+++ b/src/types/axios.d.ts
@@ -0,0 +1,13 @@
+/* eslint-disable */
+import * as axios from 'axios';
+
+// 扩展 axios 数据返回类型,可自行扩展
+declare module 'axios' {
+ export interface AxiosResponse<T = any> {
+ code: number;
+ data: T;
+ message: string;
+ type?: string;
+ [key: string]: T;
+ }
+}
diff --git a/src/types/global.d.ts b/src/types/global.d.ts
new file mode 100644
index 0000000..a46b866
--- /dev/null
+++ b/src/types/global.d.ts
@@ -0,0 +1,111 @@
+// 申明外部 npm 插件模块
+declare module 'vue-grid-layout';
+declare module 'qrcodejs2-fixes';
+declare module 'splitpanes';
+declare module 'js-cookie';
+declare module '@wangeditor/editor-for-vue';
+declare module 'js-table2excel';
+declare module 'qs';
+
+// 声明一个模块,防止引入文件时报错
+declare module '*.json';
+declare module '*.png';
+declare module '*.jpg';
+declare module '*.scss';
+declare module '*.ts';
+declare module '*.js';
+
+// 声明文件,*.vue 后缀的文件交给 vue 模块来处理
+declare module '*.vue' {
+ import type { DefineComponent } from 'vue';
+ const component: DefineComponent<{}, {}, any>;
+ export default component;
+}
+
+// 声明文件,定义全局变量
+/* eslint-disable */
+declare interface Window {
+ nextLoading: boolean;
+}
+
+// 声明路由当前项类型
+declare type RouteItem<T = any> = {
+ path: string;
+ name?: string | symbol | undefined | null;
+ redirect?: string;
+ k?: T;
+ meta?: {
+ title?: string;
+ isLink?: string;
+ isHide?: boolean;
+ isKeepAlive?: boolean;
+ isAffix?: boolean;
+ isIframe?: boolean;
+ roles?: string[];
+ icon?: string;
+ isDynamic?: boolean;
+ isDynamicPath?: string;
+ isIframeOpen?: string;
+ loading?: boolean;
+ };
+ children: T[];
+ query?: { [key: string]: T };
+ params?: { [key: string]: T };
+ contextMenuClickId?: string | number;
+ commonUrl?: string;
+ isFnClick?: boolean;
+ url?: string;
+ transUrl?: string;
+ title?: string;
+ id?: string | number;
+};
+
+// 声明路由 to from
+declare interface RouteToFrom<T = any> extends RouteItem {
+ path?: string;
+ children?: T[];
+}
+
+// 声明路由当前项类型集合
+declare type RouteItems<T extends RouteItem = any> = T[];
+
+// 声明 ref
+declare type RefType<T = any> = T | null;
+
+// 声明 HTMLElement
+declare type HtmlType = HTMLElement | string | undefined | null;
+
+// 申明 children 可选
+declare type ChilType<T = any> = {
+ children?: T[];
+};
+
+// 申明 数组
+declare type EmptyArrayType<T = any> = T[];
+
+// 申明 对象
+declare type EmptyObjectType<T = any> = {
+ [key: string]: T;
+};
+
+// 申明 select option
+declare type SelectOptionType = {
+ value: string | number;
+ label: string | number;
+};
+
+// 鼠标滚轮滚动类型
+declare interface WheelEventType extends WheelEvent {
+ wheelDelta: number;
+}
+
+// table 数据格式公共类型
+declare interface TableType<T = any> {
+ total: number;
+ loading: boolean;
+ param: {
+ pageNum: number;
+ pageSize: number;
+ [key: string]: T;
+ };
+}
diff --git a/src/types/layout.d.ts b/src/types/layout.d.ts
new file mode 100644
index 0000000..82904ef
--- /dev/null
+++ b/src/types/layout.d.ts
@@ -0,0 +1,59 @@
+// aside
+declare type AsideState = {
+ menuList: RouteRecordRaw[];
+ clientWidth: number;
+};
+
+// columnsAside
+declare type ColumnsAsideState<T = any> = {
+ columnsAsideList: T[];
+ liIndex: number;
+ liOldIndex: null | number;
+ liHoverIndex: null | number;
+ liOldPath: null | string;
+ difference: number;
+ routeSplit: string[];
+};
+
+// navBars breadcrumb
+declare type BreadcrumbState<T = any> = {
+ breadcrumbList: T[];
+ routeSplit: string[];
+ routeSplitFirst: string;
+ routeSplitIndex: number;
+};
+
+// navBars search
+declare type SearchState<T = any> = {
+ isShowSearch: boolean;
+ menuQuery: string;
+ tagsViewList: T[];
+};
+
+// navBars tagsView
+declare type TagsViewState<T = any> = {
+ routeActive: string | T;
+ routePath: string | unknown;
+ dropdown: {
+ x: string | number;
+ y: string | number;
+ };
+ sortable: T;
+ tagsRefsIndex: number;
+ tagsViewList: T[];
+ tagsViewRoutesList: T[];
+};
+
+// navBars parent
+declare type ParentViewState<T = any> = {
+ refreshRouterViewKey: string;
+ iframeRefreshKey: string;
+ keepAliveNameList: string[];
+ iframeList: T[];
+};
+
+// navBars link
+declare type LinkViewState = {
+ title: string;
+ isLink: string;
+};
diff --git a/src/types/mitt.d.ts b/src/types/mitt.d.ts
new file mode 100644
index 0000000..b68b80d
--- /dev/null
+++ b/src/types/mitt.d.ts
@@ -0,0 +1,38 @@
+/**
+ * mitt 事件类型定义
+ *
+ * @method openSetingsDrawer 打开布局设置弹窗
+ * @method restoreDefault 分栏布局,鼠标移入、移出数据显示
+ * @method setSendColumnsChildren 分栏布局,鼠标移入、移出菜单数据传入到 navMenu 下的菜单中
+ * @method setSendClassicChildren 经典布局,开启切割菜单时,菜单数据传入到 navMenu 下的菜单中
+ * @method getBreadcrumbIndexSetFilterRoutes 布局设置弹窗,开启切割菜单时,菜单数据传入到 navMenu 下的菜单中
+ * @method layoutMobileResize 浏览器窗口改变时,用于适配移动端界面显示
+ * @method openOrCloseSortable 布局设置弹窗,开启 TagsView 拖拽
+ * @method openShareTagsView 布局设置弹窗,开启 TagsView 共用
+ * @method onTagsViewRefreshRouterView tagsview 刷新界面
+ * @method onCurrentContextmenuClick tagsview 右键菜单每项点击时
+ */
+declare type MittType<T = any> = {
+ openSetingsDrawer?: string;
+ restoreDefault?: string;
+ setSendColumnsChildren: T;
+ setSendClassicChildren: T;
+ getBreadcrumbIndexSetFilterRoutes?: string;
+ layoutMobileResize: T;
+ openOrCloseSortable?: string;
+ openShareTagsView?: string;
+ onTagsViewRefreshRouterView?: T;
+ onCurrentContextmenuClick?: T;
+};
+
+// mitt 参数类型定义
+declare type LayoutMobileResize = {
+ layout: string;
+ clientWidth: number;
+};
+
+// mitt 参数菜单类型
+declare type MittMenu = {
+ children: RouteRecordRaw[];
+ item?: RouteItem;
+};
diff --git a/src/types/pinia.d.ts b/src/types/pinia.d.ts
new file mode 100644
index 0000000..09c6e47
--- /dev/null
+++ b/src/types/pinia.d.ts
@@ -0,0 +1,91 @@
+/**
+ * pinia 类型定义
+ */
+
+// 用户信息
+declare interface UserInfosState<T = any> {
+ userInfos: {
+ authBtnList: string[];
+ photo: string;
+ roles: string[];
+ time: number;
+ userName: string;
+ [key: string]: T;
+ };
+}
+
+// 路由缓存列表
+declare interface KeepAliveNamesState {
+ keepAliveNames: string[];
+ cachedViews: string[];
+}
+
+// 后端返回原始路由(未处理时)
+declare interface RequestOldRoutesState {
+ requestOldRoutes: string[];
+}
+
+// TagsView 路由列表
+declare interface TagsViewRoutesState<T = any> {
+ tagsViewRoutes: T[];
+ isTagsViewCurrenFull: Boolean;
+}
+
+// 路由列表
+declare interface RoutesListState<T = any> {
+ routesList: T[];
+ isColumnsMenuHover: Boolean;
+ isColumnsNavHover: Boolean;
+}
+
+// 布局配置
+declare interface ThemeConfigState {
+ themeConfig: {
+ isDrawer: boolean;
+ primary: string;
+ topBar: string;
+ topBarColor: string;
+ isTopBarColorGradual: boolean;
+ menuBar: string;
+ menuBarColor: string;
+ menuBarActiveColor: string;
+ isMenuBarColorGradual: boolean;
+ columnsMenuBar: string;
+ columnsMenuBarColor: string;
+ isColumnsMenuBarColorGradual: boolean;
+ isColumnsMenuHoverPreload: 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;
+ globalViceTitleMsg: string;
+ globalI18n: string;
+ globalComponentSize: string;
+ };
+}
diff --git a/src/types/views.d.ts b/src/types/views.d.ts
new file mode 100644
index 0000000..d41ad4f
--- /dev/null
+++ b/src/types/views.d.ts
@@ -0,0 +1,332 @@
+// import { FormConfig } from "../components/form/model/form";
+
+/**
+ * views personal
+ */
+type NewInfo = {
+ title: string;
+ date: string;
+ link: string;
+};
+type Recommend = {
+ title: string;
+ msg: string;
+ icon: string;
+ bg: string;
+ iconColor: string;
+};
+declare type PersonalState = {
+ newsInfoList: NewInfo[];
+ recommendList: Recommend[];
+ personalForm: {
+ name: string;
+ email: string;
+ autograph: string;
+ occupation: string;
+ phone: string;
+ sex: string;
+ };
+};
+
+/**
+ * views visualizing
+ */
+declare type Demo2State<T = any> = {
+ time: {
+ txt: string;
+ fun: number;
+ };
+ dropdownList: T[];
+ dropdownActive: string;
+ skyList: T[];
+ dBtnList: T[];
+ chartData4Index: number;
+ dBtnActive: number;
+ earth3DBtnList: T[];
+ chartData4List: T[];
+ myCharts: T[];
+};
+
+/**
+ * views params
+ */
+declare type ParamsState = {
+ value: string;
+ tagsViewName: string;
+ tagsViewNameIsI18n: boolean;
+};
+
+/**
+ * views system
+ */
+// role
+declare interface RowRoleType {
+ roleName: string;
+ roleSign: string;
+ describe: string;
+ sort: number;
+ status: boolean;
+ createTime: string;
+}
+
+interface SysRoleTableType extends TableType {
+ data: RowRoleType[];
+}
+
+declare interface SysRoleState {
+ tableData: SysRoleTableType;
+}
+
+declare type TreeType = {
+ id: number;
+ label: string;
+ children?: TreeType[];
+};
+
+// user
+declare type RowUserType<T = any> = {
+ userName: string;
+ userNickname: string;
+ roleSign: string;
+ department: string[];
+ phone: string;
+ email: string;
+ sex: string;
+ password: string;
+ overdueTime: T;
+ status: boolean;
+ describe: string;
+ createTime: T;
+};
+
+interface SysUserTableType extends TableType {
+ data: RowUserType[];
+}
+
+declare interface SysUserState {
+ tableData: SysUserTableType;
+}
+
+declare type DeptTreeType = {
+ deptName: string;
+ createTime: string;
+ status: boolean;
+ sort: number;
+ describe: string;
+ id: number | string;
+ children?: DeptTreeType[];
+};
+
+// dept
+declare interface RowDeptType extends DeptTreeType {
+ deptLevel: string[];
+ person: string;
+ phone: string;
+ email: string;
+}
+
+interface SysDeptTableType extends TableType {
+ data: DeptTreeType[];
+}
+
+declare interface SysDeptState {
+ tableData: SysDeptTableType;
+}
+
+// dic
+type ListType = {
+ id: number;
+ label: string;
+ value: string;
+};
+
+declare interface RowDicType {
+ dicName: string;
+ fieldName: string;
+ describe: string;
+ status: boolean;
+ createTime: string;
+ list: ListType[];
+}
+
+interface SysDicTableType extends TableType {
+ data: RowDicType[];
+}
+
+declare interface SysDicState {
+ tableData: SysDicTableType;
+}
+
+/**
+ * views pages
+ */
+// filtering
+declare type FilteringChilType = {
+ id: number | string;
+ label: string;
+ active: boolean;
+};
+
+declare type FilterListType = {
+ img: string;
+ title: string;
+ evaluate: string;
+ collection: string;
+ price: string;
+ monSales: string;
+ id: number | string;
+ loading?: boolean;
+};
+
+declare type FilteringRowType = {
+ title: string;
+ isMore: boolean;
+ isShowMore: boolean;
+ id: number | string;
+ children: FilteringChilType[];
+};
+
+// tableRules
+declare type TableRulesHeaderType = {
+ prop: string;
+ width: string | number;
+ label: string;
+ isRequired?: boolean;
+ isTooltip?: boolean;
+ type: string;
+};
+
+declare type TableRulesState = {
+ tableData: {
+ data: EmptyObjectType[];
+ header: TableRulesHeaderType[];
+ option: SelectOptionType[];
+ };
+};
+
+declare type TableRulesOneProps = {
+ name: string;
+ email: string;
+ autograph: string;
+ occupation: string;
+};
+
+// tree
+declare type RowTreeType = {
+ id: number;
+ label: string;
+ label1: string;
+ label2: string;
+ isShow: boolean;
+ children?: RowTreeType[];
+};
+
+// workflow index
+declare type NodeListState = {
+ id: string | number;
+ nodeId: string | undefined;
+ class: HTMLElement | string;
+ left: number | string;
+ top: number | string;
+ icon: string;
+ name: string;
+};
+
+declare type LineListState = {
+ sourceId: string;
+ targetId: string;
+ label: string;
+};
+
+declare type XyState = {
+ x: string | number;
+ y: string | number;
+};
+
+declare type WorkflowState<T = any> = {
+ leftNavList: T[];
+ dropdownNode: XyState;
+ dropdownLine: XyState;
+ isShow: boolean;
+ jsPlumb: T;
+ jsPlumbNodeIndex: null | number;
+ jsplumbDefaults: T;
+ jsplumbMakeSource: T;
+ jsplumbMakeTarget: T;
+ jsplumbConnect: T;
+ jsplumbData: {
+ nodeList: NodeListState[];
+ lineList: LineListState[];
+ };
+};
+
+// workflow drawer
+declare type WorkflowDrawerNodeState<T = any> = {
+ node: { [key: string]: T };
+ nodeRules: T;
+ form: T;
+ tabsActive: string;
+ loading: {
+ extend: boolean;
+ };
+};
+
+declare type WorkflowDrawerLabelType = {
+ type: string;
+ label: string;
+};
+
+declare type WorkflowDrawerState<T = any> = {
+ isOpen: boolean;
+ nodeData: {
+ type: string;
+ };
+ jsplumbConn: T;
+};
+
+/**
+ * views make
+ */
+// tableDemo
+declare type TableDemoPageType = {
+ pageIndex: number;
+ pageSize: number;
+};
+
+declare type TableSearchType = {
+ label: string;
+ prop: string;
+ placeholder?: string;
+ required: boolean;
+ type: string;
+ options?: SelectOptionType[];
+};
+
+interface TableConfigType {
+ total: number;
+ loading: boolean;
+ isBorder: boolean;
+ isSerialNo: boolean;
+ isSelection: boolean;
+ isOperate: boolean;
+}
+
+// declare type TableDemoState = {
+// tableData: {
+// data: EmptyObjectType[];
+// header: TableHeaderType[];
+// config: {
+// total: number;
+// loading: boolean;
+// isBorder: boolean;
+// isSelection: boolean;
+// isSerialNo: boolean;
+// isOperate: boolean;
+// };
+// search: FormConfig[];
+// param: {
+// pageNum: number;
+// pageSize: number;
+// };
+// };
+// };
diff --git a/src/utils/arrayOperation.ts b/src/utils/arrayOperation.ts
new file mode 100644
index 0000000..08c8c31
--- /dev/null
+++ b/src/utils/arrayOperation.ts
@@ -0,0 +1,65 @@
+/**
+ * 判断两数组字符串是否相同(用于按钮权限验证),数组字符串中存在相同时会自动去重(按钮权限标识不会重复)
+ * @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 = news.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<T>(a: T, b: T): boolean {
+ 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: EmptyArrayType, attr?: string) {
+ if (!Object.keys(arr).length) {
+ return arr;
+ } else {
+ if (attr) {
+ const obj: EmptyObjectType = {};
+ return arr.reduce((cur: EmptyArrayType[], item: EmptyArrayType) => {
+ obj[item[attr]] ? '' : (obj[item[attr]] = true && item[attr] && cur.push(item));
+ return cur;
+ }, []);
+ } else {
+ return [...new Set(arr)];
+ }
+ }
+}
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..c78fe69
--- /dev/null
+++ b/src/utils/commonFunction.ts
@@ -0,0 +1,66 @@
+// 通用函数
+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: EmptyArrayType, column: number, cellValue: string) => {
+ return cellValue ? `${cellValue}%` : '-';
+ };
+ // 列表日期时间格式化
+ const dateFormatYMD = (row: EmptyArrayType, column: number, cellValue: string) => {
+ if (!cellValue) return '-';
+ return formatDate(new Date(cellValue), 'YYYY-mm-dd');
+ };
+ // 列表日期时间格式化
+ const dateFormatYMDHMS = (row: EmptyArrayType, column: number, cellValue: string) => {
+ if (!cellValue) return '-';
+ return formatDate(new Date(cellValue), 'YYYY-mm-dd HH:MM:SS');
+ };
+ // 列表日期时间格式化
+ const dateFormatHMS = (row: EmptyArrayType, column: number, cellValue: string) => {
+ 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: string = '0', scale: number = 4) => {
+ return Number.parseFloat(value).toFixed(scale);
+ };
+ // 小数格式化
+ const scale2Format = (value: string = '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/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..5fd020c
--- /dev/null
+++ b/src/utils/loading.ts
@@ -0,0 +1,44 @@
+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: (time: number = 0) => {
+ nextTick(() => {
+ setTimeout(() => {
+ window.nextLoading = false;
+ const el = <HTMLElement>document.querySelector('.loading-next');
+ el?.parentNode?.removeChild(el);
+ }, time);
+ });
+ },
+};
diff --git a/src/utils/mitt.ts b/src/utils/mitt.ts
new file mode 100644
index 0000000..8e73d4c
--- /dev/null
+++ b/src/utils/mitt.ts
@@ -0,0 +1,8 @@
+// https://www.npmjs.com/package/mitt
+import mitt, { Emitter } from 'mitt';
+
+// 类型
+const emitter: Emitter<MittType> = mitt<MittType>();
+
+// 导出
+export default emitter;
diff --git a/src/utils/other.ts b/src/utils/other.ts
new file mode 100644
index 0000000..e201a85
--- /dev/null
+++ b/src/utils/other.ts
@@ -0,0 +1,289 @@
+import { nextTick, defineAsyncComponent } 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 { verifyUrl } from '/@/utils/toolsValidate';
+import { Column } from '../model/api/page';
+import { ColumnConfig } from '../components/form/model/form';
+import { TableColumn } from '../components/table/type';
+import { h } from 'vue'
+
+// 引入组件
+const SvgIcon = defineAsyncComponent(() => import('/@/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 = <string>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: string = '';
+ const { query, params, meta } = item;
+ // 修复tagsViewName匹配到其他含下列单词的路由
+ // https://gitee.com/lyt-top/vue-next-admin/pulls/44/files
+ const pattern = /^\{("(zh-cn|en|zh-tw)":"[^,]+",?){1,3}}$/;
+ if (query?.tagsViewName || params?.tagsViewName) {
+ if (pattern.test(query?.tagsViewName) || pattern.test(params?.tagsViewName)) {
+ // 国际化
+ const urlTagsParams = (query?.tagsViewName && JSON.parse(query?.tagsViewName)) || (params?.tagsViewName && JSON.parse(params?.tagsViewName));
+ tagsViewName = urlTagsParams[i18n.global.locale.value];
+ } else {
+ // 非国际化
+ tagsViewName = query?.tagsViewName || params?.tagsViewName;
+ }
+ } else {
+ // 非自定义 tagsView 名称
+ tagsViewName = i18n.global.t(meta.title);
+ }
+ return tagsViewName;
+}
+
+/**
+ * 图片懒加载
+ * @param el dom 目标元素
+ * @param arr 列表数据
+ * @description data-xxx 属性用于存储页面或应用程序的私有自定义数据
+ */
+export const lazyImg = (el: string, arr: EmptyArrayType) => {
+ 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: EmptyObjectType) {
+ let newObj: EmptyObjectType;
+ 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: EmptyArrayType) {
+ 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;
+}
+
+/**
+ * 打开外部链接
+ * @param val 当前点击项菜单
+ */
+export function handleOpenLink(val: RouteItem) {
+ const { origin, pathname } = window.location;
+ router.push(val.path);
+ if (verifyUrl(<string>val.meta?.isLink)) window.open(val.meta?.isLink);
+ else window.open(`${origin}${pathname}#${val.meta?.isLink}`);
+}
+/**
+ * 字符串转小驼峰
+ * @param str 转换的字符串
+ */
+export function toCamelCase(str = '') {
+ return str.replace(/^[A-Z]*/, (str) => str.toLowerCase())
+ .replace(/[-_](\w)/g, (_, p1) => {
+ return p1.toUpperCase();
+ }).replace(/^\w/, function(match) {
+ return match.toLowerCase();
+ });
+}
+/**
+ * 通过表配置获取表单配置
+ * @param fields 配置项列表
+ */
+export function getFormConfigByFields (fields: Column[] = [], fun?: (item: Column) => EmptyObjectType) {
+ const propTypes = {
+ Int32: 'inputNumber',
+ Int64: 'inputNumber',
+ String: 'input',
+ Boolean: 'switch',
+ DateTime: 'datePicker'
+ }
+ const propProps = {
+ DateTime: {
+ type: 'datetime'
+ }
+ }
+ return fields.map(item => ({
+ component: propTypes[item.typeName],
+ label: item.displayName,
+ prop: toCamelCase(item.mapField || item.name),
+ props: propProps[item.typeName],
+ ...(fun ? fun(item) : {})
+ }))
+}
+
+export function is(val: unknown, type: string) {
+ return toString.call(val) === `[object ${type}]`;
+}
+
+export function isObject(val: any): val is Record<any, any> {
+ return val !== null && is(val, 'Object');
+}
+// 深度合并
+export function deepMerge<T = any>(src: any = {}, ...targets: Array<any>): T {
+ let key: string;
+ targets.forEach((target) => {
+ for (key in target) {
+ src[key] = isObject(src[key]) ? deepMerge(src[key], target[key]) : (src[key] = target[key]);
+ }
+ });
+ return src;
+}
+
+/**
+ * 统一批量导出
+ * @method elSvg 导出全局注册 element plus svg 图标
+ * @method useTitle 设置浏览器标题国际化
+ * @method setTagsViewNameI18n 设置 自定义 tagsView 名称、 自定义 tagsView 名称国际化
+ * @method lazyImg 图片懒加载
+ * @method globalComponentSize() element plus 全局组件大小
+ * @method deepClone 对象深克隆
+ * @method isMobile 判断是否是移动端
+ * @method handleEmpty 判断数组对象中所有属性是否为空,为空则删除当前行对象
+ * @method handleOpenLink 打开外部链接
+ */
+const other = {
+ elSvg: (app: App) => {
+ elSvg(app);
+ },
+ useTitle: () => {
+ useTitle();
+ },
+ setTagsViewNameI18n(route: RouteToFrom) {
+ return setTagsViewNameI18n(route);
+ },
+ lazyImg: (el: string, arr: EmptyArrayType) => {
+ lazyImg(el, arr);
+ },
+ globalComponentSize: () => {
+ return globalComponentSize();
+ },
+ deepClone: (obj: EmptyObjectType) => {
+ return deepClone(obj);
+ },
+ isMobile: () => {
+ return isMobile();
+ },
+ handleEmpty: (list: EmptyArrayType) => {
+ return handleEmpty(list);
+ },
+ handleOpenLink: (val: RouteItem) => {
+ handleOpenLink(val);
+ },
+ toCamelCase: (str: string) => {
+ return toCamelCase(str);
+ },
+ getFormConfigByFields (fields: Column[]) {
+ return getFormConfigByFields(fields);
+ },
+ deepMerge (src: any = {}, ...targets: Array<any>) {
+ return deepMerge(src, ...targets)
+ }
+};
+
+// 统一批量导出
+export default other;
diff --git a/src/utils/request.ts b/src/utils/request.ts
new file mode 100644
index 0000000..3e33dce
--- /dev/null
+++ b/src/utils/request.ts
@@ -0,0 +1,81 @@
+import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
+import { ElMessage, ElMessageBox } from 'element-plus';
+import { Session } from '/@/utils/storage';
+import qs from 'qs';
+import { ApiResult } from '../model/api/common';
+
+// 配置新建一个 axios 实例
+const service: AxiosInstance = axios.create({
+ baseURL: import.meta.env.VITE_API_URL,
+ timeout: 50000,
+ headers: { 'Content-Type': 'application/json' },
+ paramsSerializer: {
+ serialize(params) {
+ return qs.stringify(params, { allowDots: true });
+ },
+ },
+});
+
+// 添加请求拦截器
+service.interceptors.request.use(
+ (config) => {
+ // 在发送请求之前做些什么 token
+ if (Session.get('token')) {
+ config.headers!['Authorization'] = `${Session.get('token')}`;
+ }
+ return config;
+ },
+ (error) => {
+ // 对请求错误做些什么
+ return Promise.reject(error);
+ }
+);
+
+// 添加响应拦截器
+service.interceptors.response.use(
+ (response) => {
+ ElMessage
+ // 对响应数据做点什么
+ const res = response.data;
+ if (res.code && res.code !== 0) {
+ // `token` 过期或者账号已在别处登录
+ if (res.code === 401 || res.code === 4001) {
+ Session.clear(); // 清除浏览器全部临时缓存
+ window.location.href = '/'; // 去登录页
+ ElMessageBox.alert('你已被登出,请重新登录', '提示', {})
+ .then(() => {})
+ .catch(() => {});
+ } else if (res.message) {
+ ElMessage.error(res.message)
+ }
+ return Promise.reject(service.interceptors.response);
+ } else {
+ return response;
+ }
+ },
+ (error) => {
+ // 对响应错误做点什么
+ if (error.response.status === 401) {
+ Session.clear(); // 清除浏览器全部临时缓存
+ window.location.href = '/'; // 去登录页
+ } else 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);
+ }
+);
+
+// 导出 axios 实例
+// export default service;
+
+export default <T> (config: AxiosRequestConfig) => {
+ // 指定promise实例成功之后的回调函数的第一个参数的类型为Response<T>
+ return service<ApiResult<T>>(config).then(res => {
+ return res.data
+ })
+}
diff --git a/src/utils/setIconfont.ts b/src/utils/setIconfont.ts
new file mode 100644
index 0000000..6f4270e
--- /dev/null
+++ b/src/utils/setIconfont.ts
@@ -0,0 +1,48 @@
+// 字体图标 url
+const cssCdnUrlList: Array<string> = [
+ '//at.alicdn.com/t/c/font_2298093_rnp72ifj3ba.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..09213b4
--- /dev/null
+++ b/src/utils/storage.ts
@@ -0,0 +1,64 @@
+import Cookies from 'js-cookie';
+
+/**
+ * window.localStorage 浏览器永久缓存
+ * @method set 设置永久缓存
+ * @method get 获取永久缓存
+ * @method remove 移除永久缓存
+ * @method clear 移除全部永久缓存
+ */
+export const Local = {
+ // 查看 v2.4.3版本更新日志
+ setKey(key: string) {
+ // @ts-ignore
+ return `${__NEXT_NAME__}:${key}`;
+ },
+ // 设置永久缓存
+ set<T>(key: string, val: T) {
+ window.localStorage.setItem(Local.setKey(key), JSON.stringify(val));
+ },
+ // 获取永久缓存
+ get(key: string) {
+ let json = <string>window.localStorage.getItem(Local.setKey(key));
+ return JSON.parse(json);
+ },
+ // 移除永久缓存
+ remove(key: string) {
+ window.localStorage.removeItem(Local.setKey(key));
+ },
+ // 移除全部永久缓存
+ clear() {
+ window.localStorage.clear();
+ },
+};
+
+/**
+ * window.sessionStorage 浏览器临时缓存
+ * @method set 设置临时缓存
+ * @method get 获取临时缓存
+ * @method remove 移除临时缓存
+ * @method clear 移除全部临时缓存
+ */
+export const Session = {
+ // 设置临时缓存
+ set<T>(key: string, val: T) {
+ if (key === 'token') return Cookies.set(key, val);
+ window.sessionStorage.setItem(Local.setKey(key), JSON.stringify(val));
+ },
+ // 获取临时缓存
+ get(key: string) {
+ if (key === 'token') return Cookies.get(key);
+ let json = <string>window.sessionStorage.getItem(Local.setKey(key));
+ return JSON.parse(json);
+ },
+ // 移除临时缓存
+ remove(key: string) {
+ if (key === 'token') return Cookies.remove(key);
+ window.sessionStorage.removeItem(Local.setKey(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..398053a
--- /dev/null
+++ b/src/utils/theme.ts
@@ -0,0 +1,63 @@
+import { ElMessage } from 'element-plus';
+
+/**
+ * 颜色转换函数
+ * @method hexToRgb hex 颜色转 rgb 颜色
+ * @method rgbToHex rgb 颜色转 Hex 颜色
+ * @method getDarkColor 加深颜色值
+ * @method getLightColor 变浅颜色值
+ */
+export function useChangeColor() {
+ // str 颜色值字符串
+ const hexToRgb = (str: string): any => {
+ let hexs: any = '';
+ let reg = /^\#?[0-9A-Fa-f]{6}$/;
+ if (!reg.test(str)) {
+ ElMessage.warning('输入错误的hex');
+ return '';
+ }
+ str = str.replace('#', '');
+ hexs = str.match(/../g);
+ for (let i = 0; i < 3; i++) hexs[i] = parseInt(hexs[i], 16);
+ return hexs;
+ };
+ // r 代表红色 | g 代表绿色 | b 代表蓝色
+ const rgbToHex = (r: any, g: any, b: any): string => {
+ let reg = /^\d{1,3}$/;
+ if (!reg.test(r) || !reg.test(g) || !reg.test(b)) {
+ ElMessage.warning('输入错误的rgb颜色值');
+ return '';
+ }
+ 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('')}`;
+ };
+ // color 颜色值字符串 | level 变浅的程度,限0-1之间
+ const getDarkColor = (color: string, level: number): string => {
+ let reg = /^\#?[0-9A-Fa-f]{6}$/;
+ if (!reg.test(color)) {
+ ElMessage.warning('输入错误的hex颜色值');
+ return '';
+ }
+ let rgb = useChangeColor().hexToRgb(color);
+ for (let i = 0; i < 3; i++) rgb[i] = Math.floor(rgb[i] * (1 - level));
+ return useChangeColor().rgbToHex(rgb[0], rgb[1], rgb[2]);
+ };
+ // color 颜色值字符串 | level 加深的程度,限0-1之间
+ const getLightColor = (color: string, level: number): string => {
+ let reg = /^\#?[0-9A-Fa-f]{6}$/;
+ if (!reg.test(color)) {
+ ElMessage.warning('输入错误的hex颜色值');
+ return '';
+ }
+ let rgb = useChangeColor().hexToRgb(color);
+ for (let i = 0; i < 3; i++) rgb[i] = Math.floor((255 - rgb[i]) * level + rgb[i]);
+ return useChangeColor().rgbToHex(rgb[0], rgb[1], rgb[2]);
+ };
+ return {
+ hexToRgb,
+ rgbToHex,
+ getDarkColor,
+ getLightColor,
+ };
+}
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/watermark.ts b/src/utils/watermark.ts
new file mode 100644
index 0000000..aba49e7
--- /dev/null
+++ b/src/utils/watermark.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 = <CanvasRenderingContext2D>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 = '0px';
+ 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/error/401.vue b/src/views/error/401.vue
new file mode 100644
index 0000000..5441840
--- /dev/null
+++ b/src/views/error/401.vue
@@ -0,0 +1,91 @@
+<template>
+ <div class="error layout-padding">
+ <div class="layout-padding-auto layout-padding-view">
+ <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" size="default" 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>
+ </div>
+</template>
+
+<script setup lang="ts" name="noPower">
+import { Session } from '/@/utils/storage';
+
+const onSetAuth = () => {
+ // https://gitee.com/lyt-top/vue-next-admin/issues/I5C3JS
+ // 清除缓存/token等
+ Session.clear();
+ // 使用 reload 时,不需要调用 resetRoute() 重置路由
+ window.location.reload();
+};
+</script>
+
+<style scoped lang="scss">
+.error {
+ height: 100%;
+ .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..0b7d899
--- /dev/null
+++ b/src/views/error/404.vue
@@ -0,0 +1,91 @@
+<template>
+ <div class="error layout-padding">
+ <div class="layout-padding-auto layout-padding-view">
+ <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" size="default" 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>
+ </div>
+</template>
+
+<script setup lang="ts" name="notFound">
+import { useRouter } from 'vue-router';
+
+// 定义变量内容
+const router = useRouter();
+
+// 返回首页
+const onGoHome = () => {
+ router.push('/');
+};
+</script>
+
+<style scoped lang="scss">
+.error {
+ height: 100%;
+ .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..d351e1e
--- /dev/null
+++ b/src/views/home/index.vue
@@ -0,0 +1,633 @@
+<template>
+ <div class="home-container layout-pd">
+ <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 state.homeOne"
+ :key="k"
+ :class="{ 'home-media home-media-lg': k > 1, 'home-media-sm': k === 1 }"
+ >
+ <div class="home-card-item flex">
+ <div class="flex-margin flex w100" :class="` home-one-animation${k}`">
+ <div class="flex-auto">
+ <span class="font30">{{ v.num1 }}</span>
+ <span class="ml5 font16" :style="{ color: v.color1 }">{{ v.num2 }}%</span>
+ <div class="mt10">{{ v.num3 }}</div>
+ </div>
+ <div class="home-card-item-icon flex" :style="{ background: `var(${v.color2})` }">
+ <i class="flex-margin font32" :class="v.num4" :style="{ color: `var(${v.color3})` }"></i>
+ </div>
+ </div>
+ </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%" ref="homeLineRef"></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%" ref="homePieRef"></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 class="home-card-item-title">快捷导航工具</div>
+ <div class="home-monitor">
+ <div class="flex-warp">
+ <div class="flex-warp-item" v-for="(v, k) in state.homeThree" :key="k">
+ <div class="flex-warp-item-box" :class="`home-animation${k}`">
+ <div class="flex-margin">
+ <i :class="v.icon" :style="{ color: v.iconColor }"></i>
+ <span class="pl5">{{ v.label }}</span>
+ <div class="mt10">{{ v.value }}</div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </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%" ref="homeBarRef"></div>
+ </div>
+ </el-col>
+ </el-row>
+ </div>
+</template>
+
+<script setup lang="ts" name="home">
+import { reactive, onMounted, ref, watch, nextTick, onActivated, markRaw } from 'vue';
+import * as echarts from 'echarts';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
+
+// 定义变量内容
+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({
+ global: {
+ homeChartOne: null,
+ homeChartTwo: null,
+ homeCharThree: null,
+ dispose: [null, '', undefined],
+ } as any,
+ homeOne: [
+ {
+ num1: '125,12',
+ num2: '-12.32',
+ num3: '订单统计信息',
+ num4: 'fa fa-meetup',
+ color1: '#FF6462',
+ color2: '--next-color-primary-lighter',
+ color3: '--el-color-primary',
+ },
+ {
+ num1: '653,33',
+ num2: '+42.32',
+ num3: '月度计划信息',
+ num4: 'iconfont icon-ditu',
+ color1: '#6690F9',
+ color2: '--next-color-success-lighter',
+ color3: '--el-color-success',
+ },
+ {
+ num1: '125,65',
+ num2: '+17.32',
+ num3: '年度计划信息',
+ num4: 'iconfont icon-zaosheng',
+ color1: '#6690F9',
+ color2: '--next-color-warning-lighter',
+ color3: '--el-color-warning',
+ },
+ {
+ num1: '520,43',
+ num2: '-10.01',
+ num3: '访问统计信息',
+ num4: 'fa fa-github-alt',
+ color1: '#FF6462',
+ color2: '--next-color-danger-lighter',
+ color3: '--el-color-danger',
+ },
+ ],
+ homeThree: [
+ {
+ icon: 'iconfont icon-yangan',
+ label: '浅粉红',
+ value: '2.1%OBS/M',
+ iconColor: '#F72B3F',
+ },
+ {
+ icon: 'iconfont icon-wendu',
+ label: '深红(猩红)',
+ value: '30℃',
+ iconColor: '#91BFF8',
+ },
+ {
+ icon: 'iconfont icon-shidu',
+ label: '淡紫红',
+ value: '57%RH',
+ iconColor: '#88D565',
+ },
+ {
+ icon: 'iconfont icon-shidu',
+ label: '弱紫罗兰红',
+ value: '107w',
+ iconColor: '#88D565',
+ },
+ {
+ icon: 'iconfont icon-zaosheng',
+ label: '中紫罗兰红',
+ value: '57DB',
+ iconColor: '#FBD4A0',
+ },
+ {
+ icon: 'iconfont icon-zaosheng',
+ label: '紫罗兰',
+ value: '57PV',
+ iconColor: '#FBD4A0',
+ },
+ {
+ icon: 'iconfont icon-zaosheng',
+ label: '暗紫罗兰',
+ value: '517Cpd',
+ iconColor: '#FBD4A0',
+ },
+ {
+ icon: 'iconfont icon-zaosheng',
+ label: '幽灵白',
+ value: '12kg',
+ iconColor: '#FBD4A0',
+ },
+ {
+ icon: 'iconfont icon-zaosheng',
+ label: '海军蓝',
+ value: '64fm',
+ iconColor: '#FBD4A0',
+ },
+ ],
+ myCharts: [] as EmptyArrayType,
+ charts: {
+ theme: '',
+ bgColor: '',
+ color: '#303133',
+ },
+});
+
+// 折线图
+const initLineChart = () => {
+ if (!state.global.dispose.some((b: any) => b === state.global.homeChartOne)) state.global.homeChartOne.dispose();
+ state.global.homeChartOne = markRaw(echarts.init(homeLineRef.value, state.charts.theme));
+ const option = {
+ backgroundColor: state.charts.bgColor,
+ title: {
+ text: '政策补贴额度',
+ x: 'left',
+ textStyle: { fontSize: '15', color: state.charts.color },
+ },
+ grid: { top: 70, right: 20, bottom: 30, left: 30 },
+ tooltip: { trigger: 'axis' },
+ legend: { data: ['预购队列', '最新成交价'], right: 0 },
+ xAxis: {
+ data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
+ },
+ yAxis: [
+ {
+ type: 'value',
+ name: '价格',
+ splitLine: { show: true, lineStyle: { type: 'dashed', color: '#f5f5f5' } },
+ },
+ ],
+ series: [
+ {
+ name: '预购队列',
+ type: 'line',
+ symbolSize: 6,
+ symbol: 'circle',
+ smooth: true,
+ data: [0, 41.1, 30.4, 65.1, 53.3, 53.3, 53.3, 41.1, 30.4, 65.1, 53.3, 10],
+ lineStyle: { color: '#fe9a8b' },
+ itemStyle: { color: '#fe9a8b', borderColor: '#fe9a8b' },
+ areaStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: '#fe9a8bb3' },
+ { offset: 1, color: '#fe9a8b03' },
+ ]),
+ },
+ },
+ {
+ name: '最新成交价',
+ type: 'line',
+ symbolSize: 6,
+ symbol: 'circle',
+ smooth: true,
+ data: [0, 24.1, 7.2, 15.5, 42.4, 42.4, 42.4, 24.1, 7.2, 15.5, 42.4, 0],
+ lineStyle: { color: '#9E87FF' },
+ itemStyle: { color: '#9E87FF', borderColor: '#9E87FF' },
+ areaStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: '#9E87FFb3' },
+ { offset: 1, color: '#9E87FF03' },
+ ]),
+ },
+ emphasis: {
+ itemStyle: {
+ color: {
+ type: 'radial',
+ x: 0.5,
+ y: 0.5,
+ r: 0.5,
+ colorStops: [
+ { offset: 0, color: '#9E87FF' },
+ { offset: 0.4, color: '#9E87FF' },
+ { offset: 0.5, color: '#fff' },
+ { offset: 0.7, color: '#fff' },
+ { offset: 0.8, color: '#fff' },
+ { offset: 1, color: '#fff' },
+ ],
+ },
+ borderColor: '#9E87FF',
+ borderWidth: 2,
+ },
+ },
+ },
+ ],
+ };
+ state.global.homeChartOne.setOption(option);
+ state.myCharts.push(state.global.homeChartOne);
+};
+// 饼图
+const initPieChart = () => {
+ if (!state.global.dispose.some((b: any) => b === state.global.homeChartTwo)) state.global.homeChartTwo.dispose();
+ state.global.homeChartTwo = markRaw(echarts.init(homePieRef.value, state.charts.theme));
+ var getname = ['房屋及结构物', '专用设备', '通用设备', '文物和陈列品', '图书、档案'];
+ var getvalue = [34.2, 38.87, 17.88, 9.05, 2.05];
+ var data = [];
+ for (var i = 0; i < getname.length; i++) {
+ data.push({ name: getname[i], value: getvalue[i] });
+ }
+ const colorList = ['#51A3FC', '#36C78B', '#FEC279', '#968AF5', '#E790E8'];
+ const option = {
+ backgroundColor: state.charts.bgColor,
+ title: {
+ text: '房屋建筑工程',
+ x: 'left',
+ textStyle: { fontSize: '15', color: state.charts.color },
+ },
+ tooltip: { trigger: 'item', formatter: '{b} <br/> {c}%' },
+ graphic: {
+ elements: [
+ {
+ type: 'image',
+ z: -1,
+ style: {
+ image: themeConfig.value.isIsDark
+ ? ''
+ : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAK0AAACtCAYAAADCr/9DAAAcoElEQVR4Xu19e7wcRZn28/ZM90xXzzknOYEkIAEiBAUUFyFc4wKCCAt8gHhBUEDFG8K3Iri6+3ETL0hQ9FthvYC4gAb0cwFRQcUlKiIIbpRbEBGUREJIyHWmq2e6Z+r9fjU5iQnJOWcuPV195nT/l5yq93nep57p6amueouQXV0rwMzW6tWrS4XCsFvPVQWIyAphKweR3ShUGw2EAwMIAfhE1OgacJIHoEme/7jpM3O+UgnnWFZuDpF6pQJ2JtDOBJ4JwgxmmgbwEABr3GAAM1Ah8CqAVgC8nEBLFWgJQz1Liv7sefZTRBS0EGvSNslMu9nQL1u2TEyZsv3rARygwK8nxuvIwh7McBJ0iL4T/xXgR8DW75nxcL2ef2jKFFqTIIdUQ01q02qTDg5v/wZLqSMZ9I8AtGHtFI6YAmExFO4jsu6N3Ny9Q0SrU8gzEUqTzrSrV8ud7aJ1okW54wg4jJmLiSgdL4i+Gz8Moh9xQ91ZKhUeizd8uqNNCtNKya9QqnYqWdbbAcwF0Fd5M/AnZv5/UFgwMFBYnG7Ldc+urwZvczmY2Q6CxolMfDaYjwKQ616uCRHhd2BcX63at0ybRusnBOM2SfadaYOAd2Wun8PgMwFMb1OPvmlORBUGfw8K13qes6hvEuunr0nfD/dn4gsJdAqAfD8NUpe5MBF+wWR9QRRydxMRdxnPePcJf6etBNGRFvNFDBxuXM20EyA8QWx9xnVz3yMilXa6o/GbsKYNgugNivlzAOZNVPGN8SY8rpgvK7nObRPxzjvhTFsu1/ay8rgKTP9kbND7BZixyLLoQte1F06klCaMadetWzecz7uXg/DB7Jk1bovRD3JW42PFYvHZuCP3Il7qTcvMJKvRe8D0eYC374UIWcymAlUwf14I5/NEVEuzJqk27bp11Tm2bV3HwGFpFrGfuDHwlKLG+wdd97605pVK0+q7axBE/8zAZwGItIrXx7wUA9esWfXiJ2fNmpW6FWepM63v8w6M6EYivKmPTTExUiM8wQ2cXio5j6SJcKpMu96vnZQj6zqAt0uTSJOcS41B/+a5+S+lZXosFaZduJDzcw+MPk/Ax/rpLV1/mZ1+FLn5M6aQ+XW9xk1bLvN0ykXfpeyN1kTw+F9Y4WTTjwtGTavXC4DodoB3mggjlnFsrun0AT5LiML3TelhzLRS1t7KoBuz2QFTQ98VrgLzJZ5X0LM7iV9GTCtl+FEGvtjiZsDERckAW1SAcN1DD9rnHHEE1VvsEUuzxE1bkbX5BPp4LOyzIOYVYP6hEM7biaiaFJnETKtrA8hq9DUw3p9UchlOMgro9bpu0T5BLzxPAjER0zJzTlajG8A4I4mkMozkFSDggWq1cuzw8PC6XqP33LT6DhtUo/9kxrt7nUwW37gCD/iVtUdPnz69p3fcnpvW98PrQXifcTkzAokoQET3rnpp+fG9XLPQU9NKGX2RwfotV3ZNIgWY+S5POCcRUdSLtHtm2oqMLiTwVb0gncVMvwIM3Oq59mm9WK/QE9NKWX8HQy2YZPOwzIz1ROQDqqbvMrp4HYAiQLqKjS5SN1lqLzQ/VQSeL0ThE3F/xGI3rZTRwQzWe44KcZM1Ha9ZS4D5CRAeJcZitqxnuK6WAOGLnue9RDT6JLv+QVoul4cLhYHpzPVZjQbvRkSvAngfxdiHCMOm8+sBPoNwtuc6N8QZO1bTrpJyVhH2wwDPiJOkqVjMWG0R7mELv2LLvt+z8Vivtl5Xq9XdmfOHKqh5YD4GoL5Yj0GEEExHCmH/Oq5xjM20upCbDCK9RWP/uMiZiEOEv0DXxYJ1h+vmHzJVBLlcq72GFE4gJl1/7B9MaBEj5ouE+v5CiL/FETM20/p+eJ3+KoiDVNIxGCgT4RZifEsI58Gk8cfDq1Z5j7oK30OwzgR4h/Hap/TvDwjXPiyOGYVYTFsJwncT46aUijUqLQKeZsaXhLBvTuoVZDca6R92QdA4iaEuAHBQN7FM9CXQ1ULYmntXV9emXVetzrHZ+h9mDHTFJMHOzHiEiS8vuc4dvXpG7XU6UkaHKlaXENHRvcaKMT6DreM9L39XNzG7Mq3+5Mugfj/AB3RDIqm+uo6rBesi1819vxfzh0nlsTmOlNE8Bl8xccpD0YvCzb+WiFZ2qldXpvWD6FIwX9YpeFL9mLHWIvq06+avISJ9ykzfXXpuHFBXMrBL2pMj0B1C2Cd3yrNj01Yq4T+QhYdSekbBZnrwf4Hr53me90KnIk2UfsuXL/dKg8OXE/DPaX+RwcTvKrmF73SibUembS41DCJtWH2wRiovZqxQxB8aFIXbU0mwh6R8358L2P8Jwl49hOkyNL2kGvm9Bgbaf0zoyLRSRh9jsN4uk86L+W6lnLMGBvRZXZPz0vPmQRB9gYFz0rotnwg3C9dpe41126aVUu7EyD8JoJRCOzT0M7YQzmf75YdWtxo3N5ASfROMwW5j9aA/W0RHtltqtAPThrcwcGoPEugyJK1hhXeWSvZPuwzUd911Td9cnu5gxpzUJUd4/KEH7X3b2RzZlmmljA5hsH6H3Fa/3gvFf1UNHDcZjiPqVEtmHg6C6HYG9CF/6boYH/E85z9aJdWy+Zp1YoPoAQAHtho8iXbM/Aewc0ypRC8mgTeRMZi5IGW4AERvSVkeK4Vr707U2hFSLZtWytopDDJWVWQUkR8Urn0sEa1N2SCkls7IJlP9jKuPrErPxfwZzytc3Aqhlkw7sv37cTD2bCVoQm30AoyjJ8KagYT0aBlmZDyvB+M9LXfqfcOKatR2GxgYGHfGpyXTVoLaacTU0URwj3JdFNb8I6dOnZrdYTsUWBvXD6LvUIp+VOvtWUIU/mW8lMY1bTM5GT5ORCm5y/KzquEc1Mmk9HhiTLa/66NYfRn9OC0FrPW3Zj0KZg8ODr401liMa9r1snZyDnRbOgaUXmpYjUMHi8U/pYPPxGfBzEO+jO4nwt6pyIb5cs8rXNqVaaUMf8PAwSlIqG4RHeW69i9TwKWvKAQB76K4/rt0VGCnVcLN70xEcjSRx7zTShkexICe5jJ+sVIXlErFq40T6VMClWp0FCn+SRoW2ijGOQOe89VOTbuAgXeaHye+zRMFfVBzdvVQAd+vXQyiy3sI0VJoZiwuec6ojyuj3mnL5fL0XL6whNn0VnD6Wz3Kv25oiFa3lHHWqGMF9ByuH0QLCXhDx0Fi6qiIDh8Y5VFwVNNWZPXjBGt+TBw6DaMXVLzJde3/7jRA1q89BfTzbYOjxwhmt08RsEAI5/RtsR/VtH4QLjb+MoFwvec6WT3b9nzXdWvfDz8CwjVdB+ouQBDW7B2nTt36bec2TeuH4f6o4+HuMLvszbw8FM6eU7NXtF0K2X735huzDTUsDmm/d4w9GB/0POcbL4+4TdNWZO0qAl0YI3zboSyyznLdvD5IJLsMKDCynep3JmcTGPhlSTiHj2va5rm01egvzAY3yDEeFsI+MFvIbcCtm0H6fvh1ED5gkIWSHM3a3vOWbc5hqzvtSAG53xgkCovo8OwlgskR2IDt+/4OIPvPRo/NYpzrec61Y5u2Gs1nxeZOn2H83POc7DBn855tMpCydhWbfFQk3OO5zhYFSba60/p++BgIrzGlGYEOFcI2eqc3lXsacZl5uyCI/sqAZ4hfrbzenjZzpq77u+HawrRSylmM/HMGt9Pc7wlnniFxMthRFPD98BoQPmJMIMs6wSvmf7RN0/p++H4QtppiSIwsWyd7Xv6OxPAyoJYUqFZ5t4aKnjI4k/AfnnA2fWi2uNNWZKhPA9f1UA1cvES4zuyJWhDOgGCJQvoy+gHA/ytR0I2PA4Q/Cdd51bbvtDL6G8CvMEFM1yvwvMKnjGBnoOMq4PvV40HWD8dt2JsGrBr2zI3FVzbdadcGwWybc8/2BnPcqKpWrc8eHhZLxm2ZNTCiQHNDpAyXgshIUWcCv0WMlLjaZNogqJ+uWH3bhCIE/EII5wgT2Blm6wpIGV3N4PNb7xFfSwJ9QQi7ORW7ybS+rF8DKDO/ENss1hCfFFmkdhQw+eKJQPcLYTdnljYzbajnRk1sq2GCPUsIer4dAbO2ySuwoWBL/XlD5z74wrUH9Q/1pmlHVvWsh5kJ5Ec94bwu+SHIEDtRwPfDb4Lw3k76dtsnZ6lXF4vFp5qmXVutvtJW1jPdBu2kP4Pnl3pwql8nXLI+4ytQlrVTLdAt47eMvwWBTxGicFvTtL5fPx6kjExnsEXHlIpZpcP4h7g3ESuVykyyHL3qatzyA7EzILrYc+3PNIErsno+wTKx07UhXHsqEZVjTzAL2DMFpAyfZmD3ngGMFphxk+c5Z47cacNrQc2K0YlezHii5DnGFuckmmwfgckgvJkZ7zKQUnNtygbTyuiHAB+fNAkiLBDutjevJc0lw2tdASnD8xlI/JuZQH8Twp614fHADx8hwj6t046nJYE+KYR9ZTzRsihJKVCpRG8ii3+WFN5mOPpxsrjxTrsC4O0TJ8HqRM8r3pk4bgbYlQJS8ixGZOSVO8HeiRYu5PwBB0Y1AFZXmXTQmRXvUyoVHuuga9bFoAIj8/oBACdxGoz9SFeSsXIFI6XfhWsPZEWREx/2WAB9WXsaoMRnEFipN1O1Wt2joSy9wDfZi7HW85ypyYJmaHEpUJGhLp+01fbuuOKPFofA7yDfD/cHJV+YQx+uXBJ/X9jb62Sz+PEqYGzDAOMDVC4Hh1m53C/iTamlaL/1hHNQSy2zRqlTwA/Cr4HxwaSJ6XN/qVKpHkOWdbcB8IVCOG9MGjfDi0cBKcOrGUh8ba2eJiXfrx4HsjbtdIwnpRaiEP3Ec+1jW2iZNUmhAhVZu0IbKHFqRBeR79dOBJGBHbB8pycKJyaedAYYiwK+X7sMRGOejRAL0MuDEF1m7k7L/GPPKyT+6rgnQk7CoL5f+xSILkk8deZLTZr2p55XOCbxpDPAWBSoyNqVBBr3zK9YwDYLwuB/pSCIjlDM98YdvIV4v/aEY7xMegs8sybbUEDK8N8ZOC9pcQh0AZk6wYYZj5U8J/FFOkmL3K94MghvYsa7E8/PwoepVqu9pt4gA+//6QVP2DsmnnQGGIsCfhDdBebEZ3+Y+F0kJe/EiJbGkkl7QerNZWZEjfa6Za3ToIAvw0UA9k2aCyt1LC1btkwMTdluUxnFJElUg/rO06YJEx+YJNPsS6yKH75EhGmJJ8eYO7KeNtR7tEpJExjrrKikuWR4rSuwevXqoUKxZOQEeIvs2U3TyiB8mtnARjULH/SKW59e0rp8WUsTCvh+OBeEh0xgN5ezamBTy8wAXOsJ51wTyWeYnStQCcKziPGtziN02pPWeMIeHtkjVruRiM7oNFSn/Ri4ryScf+y0f9bPjAIVGf5fAv63AfRmNaINz7RBdAmYE68NS4SKW2zWPagbECCD7FABX4b6ZHoDy0rpdk/Yb2maNgjqpylW3+kwh+66Mfb3POd/uguS9U5KAWZ2ZRDpH2GJ7w8ji64SRftfNtxpw3A/1KFP50v8YqjzS6L45cSBM8COFAiC6DDFbGLTgC7E9D7PdW7YWDVRyCDSVRNzHWXSRSdmvrvkFf6pixBZ1wQVKPu1T1tEFyUIuQmKgIOFcB7cVERMBuEfmbHpMIYESQXCtYeJqJogZgbVoQK+DPVB3/t32L2bbg2/Yk+ZPp0qfzetDG9h4NRuonbcl9UJnldMfvdEx4QnZ0cp5U4j58wlXyMD/FRJFF6tld9k2oqMLiTwVUaGg3CT5zpnGsHOQFtWwFQNL02Qwd8uiUJzVdkm066Xcl4O+ftaziDGhsxYv3LF8zNmz56dPSLEqGvcoXwZPgjgwLjjthKPoM4TonjNFqZl5uLIVEahlSBxt2HFp5VKBSMVpuPOpR/jlcu1Pa0cPWGkmLIWNI/Xe47z+y1Mq/9RkeGvCDCym4CBhaVsS3lq/S5l9EUGf8wMQVor3Py0jad5blGC3A+iT4E5+c1qG5TgRl3tOThYTL5Ek5mRmDCoS5cudYenzVwC8HZmSNOdnrA37dx+2Snk0TwGG3mu1WJYhK+7rvMhM8JkqKMpYPqgbwLOE8JpPs9u9XjAzHlfRiuJMMXQEAaqUdt1YGBghSH8DPZlCuiynn4QLSYYmcNvsqlHao+hoeLT2zSt/k8pw1sZeIep0dPTbkIUEt+abCrftONWgtppxGRmXcqGX31PCeE052fHMG3tnQxaYFBMySrcrVQqLTfIIYPecChiLqhGi5mxhylBNi6SGdO0zFwKqvUXmVmYIgpY13oiny0ONzcATWTfD84G5a4zSYPyOEg4zm/HNO0GsrXvg+gUg2TrqsH7DgwUHjfIYVJDr1y5ckB4g08BtIMpIYjwnFu0ZxMRj2taKetvY6jvmSLbxCX6uefabzLKYRKDSxnNZ3DzqHpTF4GuFMLeqjLjNo+K1NvKB4e2e4EIg6YIa1yLcIbrOjeb5DAZsf0w3Bf15sbFvMn8VYNfu61v21HPNy374TcswvtNkmbGKk/YexLRSpM8JhO2nvaUQaSfIV9vNG/Gw57nHLAtDqOaVsrwAAa2eAA2kgTznZ6X1bFNSvuyX/uUZaKE58sTHKO8wJgnSfsy1Hu3zH7idDKMD3ue87WkBm6y4qyX8tA88r9gw48FAK3zK2t2mj59eqWtO61uHAThexTjhhQMomSFQ0sl5w8p4NKXFJh5uyCIfsfALilI8CuecEbdoj7mnZaZCzKoPwfwjBQk8qxw7f2JaE0KuPQVBf0SQVbrPwHzUSlIrFGP1KuHhop/Ho3LmKbVnfwguhjMl6cgGT0Ndo8o5o8joigVfPqEhJTRlxj80XSkw7d7ovCWsbiMa9p163g4b0fPmShQt03ijBs8z3lfOgSe+CykDM9l4CtpyYSAA4VwxqwTNq5pdTIVWZtPIKMTzVuIyvxpzyuYWveblvHtmoeUtVMY9F0TpQO2RZ4Z95Q85+jxEmvJtCOHPj8LwBsvYFJ/14dUCGGb2YiZVJI9xPH96rEg63YARrZXbXtWgOYJYd8/Xtotmbb5bOvXPgeifx0vYIJ/Z333F8L+YoKYfQGlDUtW7r90iaPUJMR8t9di0ZaWTbuGeYoTRM8AGE5NopoI0WWeaydePC9VGrRBpixrp1horo9NzR0WgGKF/Vqd0mzZtBuebcOPEvClNjRKpinjq0LY52XnN4wtd9kPP2xR80dX4uWvxmTGuNHznLNaNUtbpn3iCXZ2mR0+TqA5rQIk1o75LimdU7ffnnQp/uzaTAE9D+sH0XwCDO2mHXM4fIL9KiHo+VYHrS3T6qDVanRMQ3Hip5a3lBDjSaX4lIGBwpMttZ8EjZh5WFbDBWB6cxrTZaJ/K7n2Fe1wa9u0OriU0W0MPrkdoKTaMlC2wB8QonBrUphpxZEyOoShFgCUhlezW8nE4Kc819mHiMJ2NOzQtHInhbzeoTnQDliSbQm42XXtc4lIlzCdVNfChZw/4KD6RWD+P6bXxI4hPCuiNw64dtu1bjsyrSbi++E5IFybcjcsgWWd4xXzP045z9joVSo1fef6JshIOc7W8yBc77lOR+u1OzYtM+vDoO9l4PDWmZppyeDvWmhcIIRo+WHfDNPOUVes4JIohZcQSK8hsDuPlEjPpbVq5bXDw8PrOkHr2LQabE0Q7Gqr3COmt+W0kjgRlRnqqvK6NVfPnDnTyAmVrfBst82GFVrRmVD8GZC5TYht8FYW0dGua/93G322aNqVaXWkShCeQYwbOyWQfD9eTqDPua593USuPq4rv1SC8K0W0aVg7JW8jp0hMvDlknDO76z3hl5dm7ZpXBl+m4DTuyGSdF9mvEjgaxqN2lcHBwdXJY3fKZ4uyVqR0Rk5C+czY4vKK53GTLDfomXPP3fInDlzat1gxmJavUfeKw09NAFFBBH5DL6FGNcLsWVRiG6Ejbvvump195yiswnWewHePu74vY7HjHWNnJo7VPx7Ta5OMWMxrQav1Wp7N5T1oK5Q0ykZ0/0Y/Eci61ZVV99LwwsKn3lHDqK3EfB2AAfH9c1oQGdW4LcOiMJtcWDHZlpNRsra20bWZ8YaN45E247BeJKI7lIW7vEK+d/oH3Jtx2izw9NPP12Y8YpXzM1x7kgiOpaBubr8Q5th0tec+bOeV4jtGKfYzeX7tU/D0DlTPRytBoBHwc0t9Y8Q0aNRJP84NDS0ulPMFStWlDxvyhzLsvZpsNrHAh3AYH3UUbHTmOnsR3cKN3/yxirecXCM3bQj87e6XKj+Suv3S88z/oWZl1sWrVSMVcRcgYUqM+o5siwFFJnZI8I0KF1Jm2YwsCsRJtxzaQeD+YfyenvezJkU6xRj7KbViW0odz7j5wAO6SDRrEtfKMBLwPWDPc9bFnc6PTGtJrmWeWpehvcR0d5xk87ipV6Bl/I5PqxQKCzuBdOemVaT9X1/R7Ls+5jxyl6Qz2KmUoG1YBzpec6iXrHrqWmbd9y1wWzbsX4J0KxeJZHFTYcCRFQB481C2L/pJaOem1aTX7euunvepnsz4/ZyKM3G1i9pGnWcMDBgL+w1k0RMq5MIAp6tONTG3bXXSWXxk1VAz2ETcLzr2r9KAjkx0+pk9CnWinM/I6I9k0guw0hCAVpVBx83lOAr8ERNqyVk5mkyiH4E4KAkJM0weqkAL1ENHDsw0JtZgtGYJ27aEeO6MqgvAPikXkqaxe6pAr8H28d7HsU+DzseayOmHTGuFQThlQy6YAIvBBlP3z79O93pV9acPlrR414nbcy0GxPTi8gt0NdSVaKn16pP3PgM5iuEcC6Ocy1Bu3IYN60m7PvhfiD+fjaz0O7wJdder4dl4vfGtbywG+apMK1OQL/2tYPwWwBtOiK9m8SyvrEqsChn2e8oFmnU6tyxoo0TLDWm3cizLMNzLWA+gPRU9EtyRNKFpRj4d8+1P9FuQY1eppE60+pky+XaXlaObgKwXy+Tz2KPqcBSVvTeUsnWq/VSdaXStCOzC3k/qF9A4Euzu26inlEgfF0U7U+mtTpPak27cZiq1erudWV9g4AjEh26yQjGeLJB9Q8MCvHrNKefetOO3HXJ98PTybKuAHinNAs6EbkxYz2YP/fCC0u+3O327iTynxCm3SgEMwtZrX8C3DwdO/uh1r1DGmgWWoku8jzvhe7DJRNhQpl2oyRS8iwmfb4ZdPXotNetSmYk20NhgH/Mii5utWR8e+F723pCmvbvz7v8ykYjuoQIp5s/z7W3AxVbdKKfEvMl453VFRteDwJNaNNuZt7dGxx9HIwz+m8LdiyjrgC6k8BXCuE8GEtEg0H6wrQb9SuXebqVr38IjA8BvINBXVMBrauiE3Bjo66+MjhY/FMqSMVAoq9Mu9kPNrsShCdZZJ0N5iNTd5pLDAM3TohFYFwnpf2dfjw4pS9Nu/mASilnKcq9i0CngfGa3vvFGMJSBt+KHL5dKhQeNcYiAeC+N+3mGpZrtb0shVNY0UlE2Heir+Mlwp9B9AMo3Oa6+QeIiBPwjHGISWXazdX2fd4RiI4lwlEMvBHAdOOjMQ4B/YwK5vssop/V6/zTwcHCH9POuRf8Jq1pXy5muVzb08rTPCg+CBbNBUNvvsz3QvQWYzIB+hDthxXUb4mt+4WwF2WnUsZUCbzFQZhQzZr1yGbM2Jsb2Nti3pMZc0C0GzN2IcKUGJPxwVgComcY/Azp9/+NxuJ6PXi004M0YuSWylDZnbaDYdGFo2u12g5K5WbUWW1nWTTFYgwo6OqIVgEKNpPKE6MGywqJEQJcY4ZPZK1pEK9GXa1Qylk+NEQdlwvtgHpfdPn/ixNifr4QLGYAAAAASUVORK5CYII=',
+ width: 230,
+ height: 230,
+ },
+ left: '16.5%',
+ top: 'center',
+ },
+ ],
+ },
+ legend: {
+ type: 'scroll',
+ orient: 'vertical',
+ right: '0%',
+ left: '65%',
+ top: 'center',
+ itemWidth: 14,
+ itemHeight: 14,
+ data: getname,
+ textStyle: {
+ rich: {
+ name: {
+ fontSize: 14,
+ fontWeight: 400,
+ width: 200,
+ height: 35,
+ padding: [0, 0, 0, 60],
+ color: state.charts.color,
+ },
+ rate: {
+ fontSize: 15,
+ fontWeight: 500,
+ height: 35,
+ width: 40,
+ padding: [0, 0, 0, 30],
+ color: state.charts.color,
+ },
+ },
+ },
+ },
+ series: [
+ {
+ type: 'pie',
+ radius: ['82', themeConfig.value.isIsDark ? '50' : '102'],
+ center: ['32%', '50%'],
+ itemStyle: {
+ color: function (params: any) {
+ return colorList[params.dataIndex];
+ },
+ },
+ label: { show: false },
+ labelLine: { show: false },
+ data: data,
+ },
+ ],
+ };
+ state.global.homeChartTwo.setOption(option);
+ state.myCharts.push(state.global.homeChartTwo);
+};
+// 柱状图
+const initBarChart = () => {
+ if (!state.global.dispose.some((b: any) => b === state.global.homeCharThree)) state.global.homeCharThree.dispose();
+ state.global.homeCharThree = markRaw(echarts.init(homeBarRef.value, state.charts.theme));
+ const option = {
+ backgroundColor: state.charts.bgColor,
+ title: {
+ text: '地热开发利用',
+ x: 'left',
+ textStyle: { fontSize: '15', color: state.charts.color },
+ },
+ tooltip: { trigger: 'axis' },
+ legend: { data: ['供温', '回温', '压力值(Mpa)'], right: 0 },
+ grid: { top: 70, right: 80, bottom: 30, left: 80 },
+ xAxis: [
+ {
+ type: 'category',
+ data: ['1km', '2km', '3km', '4km', '5km', '6km'],
+ boundaryGap: true,
+ axisTick: { show: false },
+ },
+ ],
+ yAxis: [
+ {
+ name: '供回温度(℃)',
+ nameLocation: 'middle',
+ nameTextStyle: { padding: [3, 4, 50, 6] },
+ splitLine: { show: true, lineStyle: { type: 'dashed', color: '#f5f5f5' } },
+ axisLine: { show: false },
+ axisTick: { show: false },
+ axisLabel: { color: state.charts.color, formatter: '{value} ' },
+ },
+ {
+ name: '压力值(Mpa)',
+ nameLocation: 'middle',
+ nameTextStyle: { padding: [50, 4, 5, 6] },
+ splitLine: { show: false },
+ axisLine: { show: false },
+ axisTick: { show: false },
+ axisLabel: { color: state.charts.color, formatter: '{value} ' },
+ },
+ ],
+ series: [
+ {
+ name: '供温',
+ type: 'line',
+ smooth: true,
+ showSymbol: true,
+ // 矢量画五角星
+ symbol: 'path://M150 0 L80 175 L250 75 L50 75 L220 175 Z',
+ symbolSize: 12,
+ yAxisIndex: 0,
+ areaStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: 'rgba(250,180,101,0.3)' },
+ { offset: 1, color: 'rgba(250,180,101,0)' },
+ ]),
+ shadowColor: 'rgba(250,180,101,0.2)',
+ shadowBlur: 20,
+ },
+ itemStyle: { color: '#FF8000' },
+ // data中可以使用对象,value代表相应的值,另外可加入自定义的属性
+ data: [
+ { value: 1, stationName: 's1' },
+ { value: 3, stationName: 's2' },
+ { value: 4, stationName: 's3' },
+ { value: 9, stationName: 's4' },
+ { value: 3, stationName: 's5' },
+ { value: 2, stationName: 's6' },
+ ],
+ },
+ {
+ name: '回温',
+ type: 'line',
+ smooth: true,
+ showSymbol: true,
+ symbol: 'emptyCircle',
+ symbolSize: 12,
+ yAxisIndex: 0,
+ areaStyle: {
+ color: new echarts.graphic.LinearGradient(
+ 0,
+ 0,
+ 0,
+ 1,
+ [
+ { offset: 0, color: 'rgba(199, 237, 250,0.5)' },
+ { offset: 1, color: 'rgba(199, 237, 250,0.2)' },
+ ],
+ false
+ ),
+ },
+ itemStyle: {
+ color: '#3bbc86',
+ },
+ data: [
+ { value: 31, stationName: 's1' },
+ { value: 36, stationName: 's2' },
+ { value: 54, stationName: 's3' },
+ { value: 24, stationName: 's4' },
+ { value: 73, stationName: 's5' },
+ { value: 22, stationName: 's6' },
+ ],
+ },
+ {
+ name: '压力值(Mpa)',
+ type: 'bar',
+ barWidth: 30,
+ yAxisIndex: 1,
+ itemStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: 'rgba(108,80,243,0.3)' },
+ { offset: 1, color: 'rgba(108,80,243,0)' },
+ ]),
+ //柱状图圆角
+ borderRadius: [30, 30, 0, 0],
+ },
+ data: [
+ { value: 11, stationName: 's1' },
+ { value: 34, stationName: 's2' },
+ { value: 54, stationName: 's3' },
+ { value: 39, stationName: 's4' },
+ { value: 63, stationName: 's5' },
+ { value: 24, stationName: 's6' },
+ ],
+ },
+ ],
+ };
+ state.global.homeCharThree.setOption(option);
+ state.myCharts.push(state.global.homeCharThree);
+};
+// 批量设置 echarts resize
+const initEchartsResizeFun = () => {
+ nextTick(() => {
+ for (let i = 0; i < state.myCharts.length; i++) {
+ setTimeout(() => {
+ state.myCharts[i].resize();
+ }, i * 1000);
+ }
+ });
+};
+// 批量设置 echarts resize
+const initEchartsResize = () => {
+ window.addEventListener('resize', initEchartsResizeFun);
+};
+// 页面加载时
+onMounted(() => {
+ initEchartsResize();
+});
+// 由于页面缓存原因,keep-alive
+onActivated(() => {
+ initEchartsResizeFun();
+});
+// 监听 pinia 中的 tagsview 开启全屏变化,重新 resize 图表,防止不出现/大小不变等
+watch(
+ () => isTagsViewCurrenFull.value,
+ () => {
+ initEchartsResizeFun();
+ }
+);
+// 监听 pinia 中是否开启深色主题
+watch(
+ () => themeConfig.value.isIsDark,
+ (isIsDark) => {
+ nextTick(() => {
+ state.charts.theme = isIsDark ? 'dark' : '';
+ state.charts.bgColor = isIsDark ? 'transparent' : '';
+ state.charts.color = isIsDark ? '#dadada' : '#303133';
+ setTimeout(() => {
+ initLineChart();
+ }, 500);
+ setTimeout(() => {
+ initPieChart();
+ }, 700);
+ setTimeout(() => {
+ initBarChart();
+ }, 1000);
+ });
+ },
+ {
+ deep: true,
+ immediate: true,
+ }
+);
+</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/4) + 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..7f29d74
--- /dev/null
+++ b/src/views/login/component/account.vue
@@ -0,0 +1,181 @@
+<template>
+ <el-form size="large" class="login-content-form">
+ <el-form-item class="login-animation1">
+ <el-input text :placeholder="$t('message.account.accountPlaceholder1')" v-model="state.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="state.isShowPassword ? 'text' : 'password'"
+ :placeholder="$t('message.account.accountPlaceholder2')"
+ v-model="state.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="state.isShowPassword ? 'icon-yincangmima' : 'icon-xianshimima'"
+ @click="state.isShowPassword = !state.isShowPassword"
+ >
+ </i>
+ </template>
+ </el-input>
+ </el-form-item>
+ <el-form-item class="login-animation3">
+ <el-col :span="15">
+ <el-input
+ text
+ maxlength="4"
+ :placeholder="$t('message.account.accountPlaceholder3')"
+ v-model="state.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" v-waves>1234</el-button>
+ </el-col>
+ </el-form-item>
+ <el-form-item class="login-animation4">
+ <el-button type="primary" class="login-content-submit" round v-waves @click="onSignIn" :loading="state.loading.signIn">
+ <span>{{ $t('message.account.accountBtnText') }}</span>
+ </el-button>
+ </el-form-item>
+ </el-form>
+</template>
+
+<script setup lang="ts" name="loginAccount">
+import { reactive, 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 { useUserApi } from '/@/api/user';
+
+// 定义变量内容
+const { t } = useI18n();
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+const route = useRoute();
+const router = useRouter();
+const userApi = useUserApi();
+const state = reactive({
+ isShowPassword: false,
+ ruleForm: {
+ userName: '',
+ password: '',
+ code: '',
+ },
+ loading: {
+ signIn: false,
+ },
+});
+
+// 时间获取
+const currentTime = computed(() => {
+ return formatAxis(new Date());
+});
+// 登录
+const onSignIn = async () => {
+ state.loading.signIn = true;
+ // 存储 token 到浏览器缓存
+ // 模拟数据,对接接口时,记得删除多余代码及对应依赖的引入。用于 `/src/stores/userInfo.ts` 中不同用户登录判断(模拟数据)
+ userApi.signIn(state.ruleForm).then(async res => {
+ // console.log(res.data.token)
+ Session.set('token', res.data.token);
+ Cookies.set('userName', state.ruleForm.userName);
+ if (!themeConfig.value.isRequestRoutes) {
+ // 前端控制路由,2、请注意执行顺序
+ const isNoPower = await initFrontEndControlRoutes();
+ signInSuccess(isNoPower);
+ } else {
+ // 模拟后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
+ // 添加完动态路由,再进行 router 跳转,否则可能报错 No match found for location with path "/"
+ const isNoPower = await initBackEndControlRoutes();
+ // 执行完 initBackEndControlRoutes,再执行 signInSuccess
+ signInSuccess(isNoPower);
+ }
+ }).catch(() => {
+ state.loading.signIn = false;
+ })
+};
+// 登录成功后的跳转
+const signInSuccess = (isNoPower: boolean | undefined) => {
+ if (isNoPower) {
+ ElMessage.warning('抱歉,您没有登录权限');
+ Session.clear();
+ } else {
+ // 初始化登录成功时间问候语
+ let currentTimeInfo = currentTime.value;
+ // 登录成功,跳到转首页
+ // 如果是复制粘贴的路径,非首页/登录页,那么登录成功后重定向到对应的路径中
+ if (route.query?.redirect) {
+ 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('/');
+ }
+ // 登录成功提示
+ const signInText = t('message.signInText');
+ ElMessage.success(`${currentTimeInfo},${signInText}`);
+ // 添加 loading,防止第一次进入界面时出现短暂空白
+ NextLoading.start();
+ }
+ state.loading.signIn = false;
+};
+</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/component/mobile.vue b/src/views/login/component/mobile.vue
new file mode 100644
index 0000000..6f47b55
--- /dev/null
+++ b/src/views/login/component/mobile.vue
@@ -0,0 +1,70 @@
+<template>
+ <el-form size="large" class="login-content-form">
+ <el-form-item class="login-animation1">
+ <el-input text :placeholder="$t('message.mobile.placeholder1')" v-model="state.ruleForm.userName" clearable autocomplete="off">
+ <template #prefix>
+ <i class="iconfont icon-dianhua el-input__icon"></i>
+ </template>
+ </el-input>
+ </el-form-item>
+ <el-form-item class="login-animation2">
+ <el-col :span="15">
+ <el-input text maxlength="4" :placeholder="$t('message.mobile.placeholder2')" v-model="state.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 v-waves class="login-content-code">{{ $t('message.mobile.codeText') }}</el-button>
+ </el-col>
+ </el-form-item>
+ <el-form-item class="login-animation3">
+ <el-button round type="primary" v-waves class="login-content-submit">
+ <span>{{ $t('message.mobile.btnText') }}</span>
+ </el-button>
+ </el-form-item>
+ <div class="font12 mt30 login-animation4 login-msg">{{ $t('message.mobile.msgText') }}</div>
+ </el-form>
+</template>
+
+<script setup lang="ts" name="loginMobile">
+import { reactive } from 'vue';
+
+// 定义变量内容
+const state = reactive({
+ ruleForm: {
+ userName: '',
+ code: '',
+ },
+});
+</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-code {
+ width: 100%;
+ padding: 0;
+ }
+ .login-content-submit {
+ width: 100%;
+ letter-spacing: 2px;
+ font-weight: 300;
+ margin-top: 15px;
+ }
+ .login-msg {
+ color: var(--el-text-color-placeholder);
+ }
+}
+</style>
diff --git a/src/views/login/component/scan.vue b/src/views/login/component/scan.vue
new file mode 100644
index 0000000..c719bf0
--- /dev/null
+++ b/src/views/login/component/scan.vue
@@ -0,0 +1,63 @@
+<template>
+ <div class="login-scan-container">
+ <div ref="qrcodeRef"></div>
+ <div class="font12 mt20 login-msg">
+ <i class="iconfont icon-saoyisao mr5"></i>
+ <span>{{ $t('message.scan.text') }}</span>
+ </div>
+ </div>
+</template>
+
+<script setup lang="ts" name="loginScan">
+import { ref, onMounted, nextTick } from 'vue';
+import QRCode from 'qrcodejs2-fixes';
+
+// 定义变量内容
+const qrcodeRef = ref<HTMLElement | null>(null);
+
+// 初始化生成二维码
+const initQrcode = () => {
+ nextTick(() => {
+ (<HTMLElement>qrcodeRef.value).innerHTML = '';
+ new QRCode(qrcodeRef.value, {
+ text: `https://qm.qq.com/cgi-bin/qm/qr?k=RdUY97Vx0T0vZ_1OOu-X1yFNkWgDwbjC&jump_from=webapi`,
+ width: 260,
+ height: 260,
+ colorDark: '#000000',
+ colorLight: '#ffffff',
+ });
+ });
+};
+// 页面加载时
+onMounted(() => {
+ initQrcode();
+});
+</script>
+
+<style scoped lang="scss">
+.login-scan-animation {
+ opacity: 0;
+ animation-name: error-num;
+ animation-duration: 0.5s;
+ animation-fill-mode: forwards;
+}
+.login-scan-container {
+ padding: 0 20px 20px;
+ display: flex;
+ flex-direction: column;
+ text-align: center;
+ @extend .login-scan-animation;
+ animation-delay: 0.1s;
+ :deep(img) {
+ margin: auto;
+ }
+ .login-msg {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--el-text-color-placeholder);
+ @extend .login-scan-animation;
+ animation-delay: 0.2s;
+ }
+}
+</style>
diff --git a/src/views/login/index.vue b/src/views/login/index.vue
new file mode 100644
index 0000000..111539d
--- /dev/null
+++ b/src/views/login/index.vue
@@ -0,0 +1,254 @@
+<template>
+ <div class="login-container flex">
+ <div class="login-left">
+ <div class="login-left-logo">
+ <img :src="logoMini" />
+ <div class="login-left-logo-text">
+ <span>{{ getThemeConfig.globalViceTitle }}</span>
+ <span class="login-left-logo-text-msg">{{ getThemeConfig.globalViceTitleMsg }}</span>
+ </div>
+ </div>
+ <div class="login-left-img">
+ <img :src="loginMain" />
+ </div>
+ <img :src="loginBg" class="login-left-waves" />
+ </div>
+ <div class="login-right flex">
+ <div class="login-right-warp flex-margin">
+ <span class="login-right-warp-one"></span>
+ <span class="login-right-warp-two"></span>
+ <div class="login-right-warp-mian">
+ <div class="login-right-warp-main-title">{{ getThemeConfig.globalTitle }} 欢迎您!</div>
+ <div class="login-right-warp-main-form">
+ <div v-if="!state.isScan">
+ <el-tabs v-model="state.tabsActiveName">
+ <el-tab-pane :label="$t('message.label.one1')" name="account">
+ <Account />
+ </el-tab-pane>
+ <el-tab-pane :label="$t('message.label.two2')" name="mobile">
+ <Mobile />
+ </el-tab-pane>
+ </el-tabs>
+ </div>
+ <Scan v-if="state.isScan" />
+ <div class="login-content-main-sacn" @click="state.isScan = !state.isScan">
+ <i class="iconfont" :class="state.isScan ? 'icon-diannao1' : 'icon-barcode-qr'"></i>
+ <div class="login-content-main-sacn-delta"></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script setup lang="ts" name="loginIndex">
+import { defineAsyncComponent, onMounted, reactive, computed } from 'vue';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+import { NextLoading } from '/@/utils/loading';
+import logoMini from '/@/assets/logo-mini.png';
+import loginMain from '/@/assets/login-main.svg';
+import loginBg from '/@/assets/login-bg.svg';
+
+// 引入组件
+const Account = defineAsyncComponent(() => import('/@/views/login/component/account.vue'));
+const Mobile = defineAsyncComponent(() => import('/@/views/login/component/mobile.vue'));
+const Scan = defineAsyncComponent(() => import('/@/views/login/component/scan.vue'));
+
+// 定义变量内容
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+const state = reactive({
+ tabsActiveName: 'account',
+ isScan: false,
+});
+
+// 获取布局配置信息
+const getThemeConfig = computed(() => {
+ return themeConfig.value;
+});
+// 页面加载时
+onMounted(() => {
+ NextLoading.done();
+});
+</script>
+
+<style scoped lang="scss">
+.login-container {
+ height: 100%;
+ background: var(--el-color-white);
+ .login-left {
+ flex: 1;
+ position: relative;
+ background-color: rgba(211, 239, 255, 1);
+ margin-right: 100px;
+ .login-left-logo {
+ display: flex;
+ align-items: center;
+ position: absolute;
+ top: 50px;
+ left: 80px;
+ z-index: 1;
+ animation: logoAnimation 0.3s ease;
+ img {
+ width: 52px;
+ height: 52px;
+ }
+ .login-left-logo-text {
+ display: flex;
+ flex-direction: column;
+ span {
+ margin-left: 10px;
+ font-size: 28px;
+ color: #26a59a;
+ }
+ .login-left-logo-text-msg {
+ font-size: 12px;
+ color: #32a99e;
+ }
+ }
+ }
+ .login-left-img {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 100%;
+ height: 52%;
+ img {
+ width: 100%;
+ height: 100%;
+ animation: error-num 0.6s ease;
+ }
+ }
+ .login-left-waves {
+ position: absolute;
+ top: 0;
+ right: -100px;
+ }
+ }
+ .login-right {
+ width: 700px;
+ .login-right-warp {
+ border: 1px solid var(--el-color-primary-light-3);
+ border-radius: 3px;
+ width: 500px;
+ height: 500px;
+ position: relative;
+ overflow: hidden;
+ background-color: var(--el-color-white);
+ .login-right-warp-one,
+ .login-right-warp-two {
+ position: absolute;
+ display: block;
+ width: inherit;
+ height: inherit;
+ &::before,
+ &::after {
+ content: '';
+ position: absolute;
+ z-index: 1;
+ }
+ }
+ .login-right-warp-one {
+ &::before {
+ filter: hue-rotate(0deg);
+ top: 0px;
+ left: 0;
+ width: 100%;
+ height: 3px;
+ background: linear-gradient(90deg, transparent, var(--el-color-primary));
+ animation: loginLeft 3s linear infinite;
+ }
+ &::after {
+ filter: hue-rotate(60deg);
+ top: -100%;
+ right: 2px;
+ width: 3px;
+ height: 100%;
+ background: linear-gradient(180deg, transparent, var(--el-color-primary));
+ animation: loginTop 3s linear infinite;
+ animation-delay: 0.7s;
+ }
+ }
+ .login-right-warp-two {
+ &::before {
+ filter: hue-rotate(120deg);
+ bottom: 2px;
+ right: -100%;
+ width: 100%;
+ height: 3px;
+ background: linear-gradient(270deg, transparent, var(--el-color-primary));
+ animation: loginRight 3s linear infinite;
+ animation-delay: 1.4s;
+ }
+ &::after {
+ filter: hue-rotate(300deg);
+ bottom: -100%;
+ left: 0px;
+ width: 3px;
+ height: 100%;
+ background: linear-gradient(360deg, transparent, var(--el-color-primary));
+ animation: loginBottom 3s linear infinite;
+ animation-delay: 2.1s;
+ }
+ }
+ .login-right-warp-mian {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ .login-right-warp-main-title {
+ height: 130px;
+ line-height: 130px;
+ font-size: 27px;
+ text-align: center;
+ letter-spacing: 3px;
+ animation: logoAnimation 0.3s ease;
+ animation-delay: 0.3s;
+ color: var(--el-text-color-primary);
+ }
+ .login-right-warp-main-form {
+ flex: 1;
+ padding: 0 50px 50px;
+ .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-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: 1px;
+ top: 0px;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+</style>
diff --git a/src/views/modules/admin/user/index.vue b/src/views/modules/admin/user/index.vue
new file mode 100644
index 0000000..dd5ba08
--- /dev/null
+++ b/src/views/modules/admin/user/index.vue
@@ -0,0 +1,51 @@
+<template>
+ <Page v-bind="$attrs" @setting="setting">
+ <template #mail>
+ 测试
+ </template>
+ </Page>
+</template>
+
+<script setup lang="ts" name="User">
+import usePageSetting from '/@/hook/usePageSetting'
+import { ColumnKind, usePageApi } from '/@/api/page';
+const { setting, columns, forms } = usePageSetting({
+ columns: [
+ {
+ prop: 'sex',
+ component: 'radioGroup',
+ props: {
+ options: [{ id: 1, name: '男' }, { id: 2, name: '女' }]
+ },
+ },
+ {
+ prop: 'mail',
+ slot: 'mail',
+ },
+ {
+ prop: 'departmentID',
+ component: 'select',
+ props: {
+ api: () => usePageApi().getTableData('/admin/department', { pageIndex: 0 })
+ }
+ },
+ {
+ prop: 'roleID',
+ component: 'select',
+ props: {
+ url: '/admin/role'
+ }
+ },
+ {
+ in: [ColumnKind.ADD, ColumnKind.EDIT],
+ prop: 'name',
+ props: {
+ onChange: (val: string) => {
+ forms.data!.mail = val
+ columns.add!.find(item => item.prop === 'sex')!.if = !val
+ }
+ }
+ }
+ ]
+})
+</script>
diff --git a/src/views/modules/index.vue b/src/views/modules/index.vue
new file mode 100644
index 0000000..a85ffdc
--- /dev/null
+++ b/src/views/modules/index.vue
@@ -0,0 +1,8 @@
+<template>
+ <Page :type="route.path"></Page>
+</template>
+
+<script setup lang="ts">
+import { useRoute } from 'vue-router';
+const route = useRoute();
+</script>
diff --git a/src/views/personal/index.vue b/src/views/personal/index.vue
new file mode 100644
index 0000000..4ca238e
--- /dev/null
+++ b/src/views/personal/index.vue
@@ -0,0 +1,373 @@
+<template>
+ <div class="personal layout-pd">
+ <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://img2.baidu.com/it/u=1978192862,2048448374&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=500" />
+ </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 state.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 state.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="state.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="state.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="state.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="state.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="state.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="state.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="state.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 setup lang="ts" name="personal">
+import { reactive, computed } from 'vue';
+import { formatAxis } from '/@/utils/formatTime';
+import { newsInfoList, recommendList } from './mock';
+
+// 定义变量内容
+const state = reactive<PersonalState>({
+ newsInfoList,
+ recommendList,
+ personalForm: {
+ name: '',
+ email: '',
+ autograph: '',
+ occupation: '',
+ phone: '',
+ sex: '',
+ },
+});
+
+// 当前时间提示语
+const currentTime = computed(() => {
+ return formatAxis(new Date());
+});
+</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;
+ :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..ca261b6
--- /dev/null
+++ b/src/views/personal/mock.ts
@@ -0,0 +1,66 @@
+/**
+ * 消息通知
+ * @returns 返回模拟数据
+ */
+export const newsInfoList = [
+ {
+ 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 = [
+ {
+ 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/tailwind.config.js b/tailwind.config.js
new file mode 100644
index 0000000..12f8da6
--- /dev/null
+++ b/tailwind.config.js
@@ -0,0 +1,11 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: [
+ "./index.html",
+ "./src/**/*.{vue,js,ts,jsx,tsx}",
+ ],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..98f1fdc
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,75 @@
+{
+ "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. */,
+ "suppressImplicitAnyIndexErrors": true
+ },
+ "include": ["src/**/*.ts", "src/**/*.vue", "src/**/*.tsx", "src/**/*.d.ts"], // **Represents any directory, and * represents any file. Indicates that all files in the src directory will be compiled
+ "exclude": ["node_modules", "dist"] // Indicates the file directory that does not need to be compiled
+}
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 0000000..604cddb
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,66 @@
+import vue from '@vitejs/plugin-vue';
+import { resolve } from 'path';
+import { defineConfig, loadEnv, ConfigEnv } from 'vite';
+import vueSetupExtend from 'vite-plugin-vue-setup-extend';
+
+const pathResolve = (dir: string) => {
+ 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(), vueSetupExtend()],
+ root: process.cwd(),
+ resolve: { alias },
+ base: mode.command === 'serve' ? './' : env.VITE_PUBLIC_PATH,
+ 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: JSON.parse(env.VITE_OPEN),
+ hmr: true,
+ proxy: {
+ '/base-api': {
+ target: 'https://cube.newlifex.com',
+ ws: true,
+ changeOrigin: true,
+ rewrite: (path) => path.replace(/^\/base-api/, ''),
+ },
+ },
+ },
+ build: {
+ outDir: 'dist',
+ chunkSizeWarningLimit: 1500,
+ rollupOptions: {
+ output: {
+ entryFileNames: `assets/[name].[hash].js`,
+ chunkFileNames: `assets/[name].[hash].js`,
+ assetFileNames: `assets/[name].[hash].[ext]`,
+ compact: true,
+ manualChunks: {
+ vue: ['vue', 'vue-router', 'pinia'],
+ echarts: ['echarts'],
+ },
+ },
+ },
+ },
+ css: { preprocessorOptions: { css: { charset: false } } },
+ define: {
+ __VUE_I18N_LEGACY_API__: JSON.stringify(false),
+ __VUE_I18N_FULL_INSTALL__: JSON.stringify(false),
+ __INTLIFY_PROD_DEVTOOLS__: JSON.stringify(false),
+ __NEXT_VERSION__: JSON.stringify(process.env.npm_package_version),
+ __NEXT_NAME__: JSON.stringify(process.env.npm_package_name),
+ },
+ };
+});
+
+export default viteConfig;