From 873d54056dd559c1b17da0c471166cba90eef639 Mon Sep 17 00:00:00 2001 From: TheSmileCat <2098833867@qq.com> Date: Thu, 2 Feb 2023 16:07:38 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9B=E5=BB=BA=E4=BB=93=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 0 .env.build | 6 + .env.build-test | 8 + .env.serve-dev | 10 + .env.serve-test | 10 + .eslintignore | 6 + .eslintrc.json | 4 + .gitignore | 51 +++ .husky/commit-msg | 5 + .husky/pre-commit | 8 + .npmrc | 7 + .prettierrc | 10 + .vscode/extensions.json | 3 + .vscode/settings.json | 4 + README.md | 85 ++++ eslintrc/.eslintrc-auto-import.json | 116 ++++++ eslintrc/eslint-config.js | 200 ++++++++++ index.html | 13 + mock-prod-server.ts | 12 + mock/example.ts | 12 + mock/excel.ts | 56 +++ mock/table.ts | 31 ++ optimize-include.ts | 133 +++++++ package.json | 129 ++++++ public/favicon.ico | Bin 0 -> 209410 bytes src/App.vue | 45 +++ src/api/remote-search.ts | 17 + src/api/user.ts | 31 ++ src/assets/401_images/401.gif | Bin 0 -> 164227 bytes src/assets/404_images/404.png | Bin 0 -> 98071 bytes src/assets/404_images/404_cloud.png | Bin 0 -> 4766 bytes src/assets/layout/animation-image.gif | Bin 0 -> 6334 bytes src/assets/layout/login-bg.svg | 1 + src/assets/layout/login-front.svg | 6 + src/assets/layout/login-top.svg | 21 + src/assets/layout/login.svg | 1 + src/assets/layout/logo.png | Bin 0 -> 10543 bytes src/components/ElSvgIcon.vue | 36 ++ src/components/TestUnit.vue | 15 + src/components/__tests__/el-svgIcon.test.jsx | 236 +++++++++++ src/directives/button-codes.ts | 21 + src/directives/codes-permission.ts | 20 + src/directives/example/clickoutside.js | 21 + src/directives/example/copy.js | 31 ++ src/directives/example/debounce.js | 26 ++ src/directives/example/longpress.js | 45 +++ src/directives/example/watermark.js | 28 ++ src/directives/example/waves.css | 26 ++ src/directives/example/waves.js | 72 ++++ src/directives/index.ts | 26 ++ src/directives/lang.ts | 44 +++ src/directives/roles-permission.ts | 20 + src/hooks/use-common.ts | 47 +++ src/hooks/use-element.ts | 214 ++++++++++ src/hooks/use-error-log.ts | 32 ++ src/hooks/use-layout.ts | 44 +++ src/hooks/use-permission.ts | 184 +++++++++ src/hooks/use-self-router.ts | 43 ++ src/hooks/use-table.ts | 122 ++++++ src/icons/SvgIcon.vue | 45 +++ src/icons/common/404.svg | 0 src/icons/common/bug.svg | 1 + src/icons/common/chart.svg | 1 + src/icons/common/clipboard.svg | 1 + src/icons/common/component.svg | 1 + src/icons/common/dashboard.svg | 1 + src/icons/common/demo.svg | 1 + src/icons/common/documentation.svg | 1 + src/icons/common/drag.svg | 1 + src/icons/common/edit.svg | 1 + src/icons/common/education.svg | 1 + src/icons/common/email.svg | 1 + src/icons/common/example.svg | 1 + src/icons/common/excel.svg | 1 + src/icons/common/exit-fullscreen.svg | 1 + src/icons/common/eye-open.svg | 1 + src/icons/common/eye.svg | 1 + src/icons/common/form.svg | 1 + src/icons/common/fullscreen.svg | 1 + src/icons/common/guide.svg | 1 + src/icons/common/hamburger.svg | 2 + src/icons/common/icon.svg | 1 + src/icons/common/international.svg | 1 + src/icons/common/language.svg | 1 + src/icons/common/link.svg | 1 + src/icons/common/list.svg | 1 + src/icons/common/lock.svg | 1 + src/icons/common/message.svg | 1 + src/icons/common/money.svg | 1 + src/icons/common/nested.svg | 1 + src/icons/common/password.svg | 1 + src/icons/common/pdf.svg | 1 + src/icons/common/people.svg | 1 + src/icons/common/peoples.svg | 1 + src/icons/common/qq.svg | 1 + src/icons/common/search.svg | 1 + src/icons/common/shopping.svg | 1 + src/icons/common/sidebar-logo.svg | 2 + src/icons/common/size.svg | 1 + src/icons/common/skill.svg | 1 + src/icons/common/star.svg | 1 + src/icons/common/tab.svg | 1 + src/icons/common/table.svg | 1 + src/icons/common/theme.svg | 1 + src/icons/common/tree-table.svg | 1 + src/icons/common/tree.svg | 1 + src/icons/common/user.svg | 1 + src/icons/common/wechat.svg | 1 + src/icons/common/zip.svg | 0 src/icons/nav-bar/dashboard.svg | 1 + src/icons/nav-bar/example.svg | 1 + src/icons/nav-bar/eye-open.svg | 1 + src/icons/nav-bar/eye.svg | 1 + src/icons/nav-bar/form.svg | 1 + src/icons/nav-bar/language.svg | 1 + src/icons/nav-bar/link.svg | 1 + src/icons/nav-bar/nested.svg | 1 + src/icons/nav-bar/password.svg | 1 + src/icons/nav-bar/table.svg | 1 + src/icons/nav-bar/theme-icon.svg | 2 + src/icons/nav-bar/tree.svg | 1 + src/icons/nav-bar/user.svg | 1 + src/lang/en.ts | 123 ++++++ src/lang/index.ts | 19 + src/lang/zh.ts | 177 +++++++++ src/layout/app-main/Breadcrumb.vue | 86 ++++ src/layout/app-main/Hamburger.vue | 33 ++ src/layout/app-main/Navbar.vue | 129 ++++++ src/layout/app-main/TagsView.vue | 305 +++++++++++++++ src/layout/app-main/component/LangSelect.vue | 41 ++ src/layout/app-main/component/ScreenFull.vue | 57 +++ src/layout/app-main/component/ScreenLock.vue | 225 +++++++++++ src/layout/app-main/component/SizeSelect.vue | 39 ++ src/layout/app-main/component/ThemeSelect.vue | 52 +++ src/layout/app-main/index.vue | 120 ++++++ src/layout/index.vue | 68 ++++ src/layout/sidebar/Link.vue | 31 ++ src/layout/sidebar/Logo.vue | 78 ++++ src/layout/sidebar/MenuIcon.vue | 25 ++ src/layout/sidebar/SidebarItem.vue | 82 ++++ src/layout/sidebar/index.vue | 42 ++ src/lib/element-plus.ts | 8 + src/main.ts | 52 +++ src/permission.ts | 50 +++ src/plugins/vite-plugin-setup-extend/index.ts | 38 ++ src/router/index.ts | 222 +++++++++++ src/router/modules/basic-demo.ts | 100 +++++ src/router/modules/charts.ts | 42 ++ src/router/modules/directive.ts | 48 +++ src/router/modules/excel.ts | 23 ++ src/router/modules/guid.ts | 14 + src/router/modules/other.ts | 35 ++ src/router/modules/rich-text.ts | 17 + src/router/modules/table.ts | 23 ++ src/settings.ts | 115 ++++++ src/store/basic.ts | 112 ++++++ src/store/config.ts | 33 ++ src/store/tags-view.ts | 65 ++++ src/styles/index.scss | 69 ++++ src/styles/reset-elemenet-plus-style.scss | 4 + src/styles/scss-suger.scss | 274 +++++++++++++ src/styles/transition.scss | 44 +++ src/theme/base/custom/ct-css-vars.scss | 67 ++++ src/theme/base/element-plus/button.scss | 122 ++++++ src/theme/base/element-plus/checkbox.scss | 27 ++ src/theme/base/element-plus/css-vars.scss | 17 + src/theme/base/element-plus/form.scss | 20 + src/theme/base/element-plus/pagination.scss | 30 ++ src/theme/base/element-plus/redio.scss | 18 + src/theme/base/element-plus/table.scss | 17 + src/theme/base/element-plus/var.scss | 63 +++ src/theme/base/index.scss | 13 + src/theme/china-red/custom/ct-css-vars.scss | 90 +++++ src/theme/china-red/element-plus/button.scss | 123 ++++++ .../china-red/element-plus/checkbox.scss | 27 ++ .../china-red/element-plus/css-vars.scss | 17 + src/theme/china-red/element-plus/form.scss | 20 + .../china-red/element-plus/pagination.scss | 30 ++ src/theme/china-red/element-plus/redio.scss | 18 + src/theme/china-red/element-plus/table.scss | 17 + src/theme/china-red/element-plus/var.scss | 63 +++ src/theme/china-red/index.scss | 13 + src/theme/dark/custom/ct-css-vars.scss | 68 ++++ src/theme/dark/element-plus/button.scss | 123 ++++++ src/theme/dark/element-plus/checkbox.scss | 27 ++ src/theme/dark/element-plus/css-vars.css | 0 src/theme/dark/element-plus/css-vars.css.map | 1 + src/theme/dark/element-plus/css-vars.scss | 17 + src/theme/dark/element-plus/form.scss | 20 + src/theme/dark/element-plus/pagination.scss | 30 ++ src/theme/dark/element-plus/redio.scss | 18 + src/theme/dark/element-plus/table.scss | 17 + src/theme/dark/element-plus/var.scss | 63 +++ src/theme/dark/index.scss | 13 + src/theme/index.css | 0 src/theme/index.css.map | 1 + src/theme/index.scss | 11 + src/theme/lighting/custom/ct-css-vars.scss | 67 ++++ src/theme/lighting/element-plus/button.scss | 123 ++++++ src/theme/lighting/element-plus/checkbox.scss | 27 ++ src/theme/lighting/element-plus/css-vars.css | 0 .../lighting/element-plus/css-vars.css.map | 1 + src/theme/lighting/element-plus/css-vars.scss | 17 + src/theme/lighting/element-plus/form.scss | 20 + .../lighting/element-plus/pagination.scss | 30 ++ src/theme/lighting/element-plus/redio.scss | 18 + src/theme/lighting/element-plus/table.scss | 17 + src/theme/lighting/element-plus/var.scss | 63 +++ src/theme/lighting/index.scss | 13 + src/theme/mixins/_var.scss | 55 +++ src/theme/mixins/config.scss | 5 + src/theme/mixins/function.scss | 60 +++ src/theme/mixins/mixins.scss | 61 +++ src/theme/utils/change-theme.ts | 3 + src/theme/utils/index.ts | 1 + src/utils/axios-req.ts | 67 ++++ src/utils/bus.ts | 3 + src/utils/common-util.ts | 126 ++++++ src/utils/mock-axios-req.ts | 59 +++ src/views/basic-demo/hook/index.vue | 14 + src/views/basic-demo/keep-alive/index.vue | 58 +++ .../basic-demo/keep-alive/second-child.vue | 33 ++ .../basic-demo/keep-alive/tab-keep-alive.vue | 19 + .../basic-demo/keep-alive/third-child.vue | 30 ++ .../third-children/SecondChildren.vue | 10 + .../third-children/ThirdChildren.vue | 10 + .../keep-alive/third-keep-alive.vue | 19 + src/views/basic-demo/mock/index.vue | 17 + .../basic-demo/parent-children/Children.vue | 76 ++++ .../parent-children/SubChildren.vue | 34 ++ .../basic-demo/parent-children/index.vue | 54 +++ src/views/basic-demo/pinia/index.vue | 14 + src/views/basic-demo/svg-icon/index.vue | 18 + .../basic-demo/vue3-template/Vue3Template.vue | 39 ++ src/views/basic-demo/worker/index.vue | 45 +++ src/views/charts/components/Keyboard.vue | 158 ++++++++ src/views/charts/components/LineMarker.vue | 278 +++++++++++++ src/views/charts/components/MixChart.vue | 232 +++++++++++ src/views/charts/components/mixins/resize.js | 56 +++ src/views/charts/echarts-demo.vue | 356 +++++++++++++++++ src/views/charts/keyboard.vue | 17 + src/views/charts/line.vue | 17 + src/views/charts/mix-chart.vue | 17 + src/views/dashboard/index.vue | 51 +++ src/views/directive/clickoutside.vue | 35 ++ src/views/directive/copy.vue | 19 + src/views/directive/debounce.vue | 24 ++ src/views/directive/longpress.vue | 15 + src/views/directive/watermark.vue | 12 + src/views/directive/waves.vue | 17 + src/views/error-log/error-generator.vue | 79 ++++ src/views/error-log/index.vue | 148 +++++++ src/views/error-page/401.vue | 93 +++++ src/views/error-page/404.vue | 225 +++++++++++ src/views/excel/excel.js | 57 +++ src/views/excel/exportExcel.vue | 99 +++++ src/views/excel/importExcel.vue | 54 +++ src/views/guide/index.vue | 33 ++ src/views/guide/steps.ts | 45 +++ src/views/login/index.vue | 22 ++ src/views/login/login-alt.vue | 270 +++++++++++++ src/views/login/login-basic.vue | 253 ++++++++++++ src/views/login/login-lighting.vue | 252 ++++++++++++ src/views/nested/menu1/index.vue | 9 + src/views/nested/menu1/menu1-1/index.vue | 11 + src/views/nested/menu1/menu1-2/index.vue | 9 + .../nested/menu1/menu1-2/menu1-2-1/index.vue | 5 + .../nested/menu1/menu1-2/menu1-2-2/index.vue | 5 + src/views/nested/menu1/menu1-3/index.vue | 5 + src/views/nested/menu2/index.vue | 6 + src/views/other/count-to.vue | 24 ++ src/views/other/d3/component/NodeDetail.vue | 61 +++ src/views/other/d3/data.json | 269 +++++++++++++ src/views/other/d3/index.vue | 170 ++++++++ src/views/other/d3/useD3.js | 183 +++++++++ src/views/other/d3/useDatas.js | 109 ++++++ src/views/other/drag-pane.vue | 41 ++ src/views/other/signboard/component/index.vue | 89 +++++ src/views/other/signboard/index.vue | 58 +++ src/views/rbac-test/TestAddEdit.vue | 5 + src/views/rbac-test/TestButton.vue | 14 + src/views/rbac-test/TestDetail.vue | 5 + src/views/rbac-test/TestMenu.vue | 22 ++ src/views/redirect/index.tsx | 13 + src/views/rich-text/TinymceExample-bak.vue | 33 ++ src/views/rich-text/TinymceExample.vue | 7 + src/views/rich-text/tinymce/index.vue | 119 ++++++ src/views/roles-codes/button-permission.vue | 7 + src/views/roles-codes/code-index.vue | 4 + src/views/roles-codes/index.vue | 29 ++ src/views/roles-codes/role-index.vue | 3 + src/views/setting-switch/SettingSwitch.vue | 50 +++ src/views/setting-switch/index.vue | 50 +++ src/views/table/dynamic-table.vue | 90 +++++ src/views/table/vxe-table.vue | 368 ++++++++++++++++++ ts-out-dir/package.json | 124 ++++++ ts-out-dir/src/api/user.d.ts | 3 + ts-out-dir/src/api/user.js | 26 ++ ts-out-dir/src/directives/button-codes.d.ts | 5 + ts-out-dir/src/directives/button-codes.js | 22 ++ .../src/directives/codes-permission.d.ts | 5 + ts-out-dir/src/directives/codes-permission.js | 22 ++ ts-out-dir/src/directives/index.d.ts | 1 + ts-out-dir/src/directives/index.js | 8 + .../src/directives/roles-permission.d.ts | 5 + ts-out-dir/src/directives/roles-permission.js | 22 ++ ts-out-dir/src/hooks/use-common.d.ts | 10 + ts-out-dir/src/hooks/use-common.js | 31 ++ ts-out-dir/src/hooks/use-element.d.ts | 67 ++++ ts-out-dir/src/hooks/use-element.js | 158 ++++++++ ts-out-dir/src/hooks/use-error-log.d.ts | 1 + ts-out-dir/src/hooks/use-error-log.js | 28 ++ ts-out-dir/src/hooks/use-layout.d.ts | 2 + ts-out-dir/src/hooks/use-layout.js | 38 ++ ts-out-dir/src/hooks/use-permission.d.ts | 15 + ts-out-dir/src/hooks/use-permission.js | 146 +++++++ ts-out-dir/src/hooks/use-self-router.d.ts | 4 + ts-out-dir/src/hooks/use-self-router.js | 40 ++ ts-out-dir/src/hooks/use-table.d.ts | 15 + ts-out-dir/src/hooks/use-table.js | 106 +++++ ts-out-dir/src/lib/element-plus.d.ts | 1 + ts-out-dir/src/lib/element-plus.js | 7 + ts-out-dir/src/main.d.ts | 6 + ts-out-dir/src/main.js | 22 ++ ts-out-dir/src/permission.d.ts | 1 + ts-out-dir/src/permission.js | 44 +++ ts-out-dir/src/router/index.d.ts | 6 + ts-out-dir/src/router/index.js | 203 ++++++++++ ts-out-dir/src/settings.d.ts | 3 + ts-out-dir/src/settings.js | 21 + ts-out-dir/src/store/basic.d.ts | 41 ++ ts-out-dir/src/store/basic.js | 124 ++++++ ts-out-dir/src/store/tagsView.d.ts | 8 + ts-out-dir/src/store/tagsView.js | 59 +++ ts-out-dir/src/utils/axios-req.d.ts | 1 + ts-out-dir/src/utils/axios-req.js | 52 +++ ts-out-dir/src/utils/bus.d.ts | 2 + ts-out-dir/src/utils/bus.js | 2 + ts-out-dir/src/utils/common-util.d.ts | 16 + ts-out-dir/src/utils/common-util.js | 66 ++++ ts-out-dir/src/views/redirect/index.d.ts | 2 + ts-out-dir/src/views/redirect/index.jsx | 13 + tsconfig.base.json | 50 +++ tsconfig.json | 11 + typings/auto-imports.d.ts | 116 ++++++ typings/basic.d.ts | 66 ++++ typings/components.d.ts | 16 + typings/env.d.ts | 12 + typings/global.d.ts | 10 + typings/shims-vue.d.ts | 6 + vite.config.ts | 123 ++++++ vitest.config.ts | 19 + vitest.setup.ts | 5 + 353 files changed, 15014 insertions(+) create mode 100644 .editorconfig create mode 100644 .env.build create mode 100644 .env.build-test create mode 100644 .env.serve-dev create mode 100644 .env.serve-test create mode 100644 .eslintignore create mode 100644 .eslintrc.json create mode 100644 .gitignore create mode 100644 .husky/commit-msg create mode 100644 .husky/pre-commit create mode 100644 .npmrc create mode 100644 .prettierrc create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 README.md create mode 100644 eslintrc/.eslintrc-auto-import.json create mode 100644 eslintrc/eslint-config.js create mode 100644 index.html create mode 100644 mock-prod-server.ts create mode 100644 mock/example.ts create mode 100644 mock/excel.ts create mode 100644 mock/table.ts create mode 100644 optimize-include.ts create mode 100644 package.json create mode 100644 public/favicon.ico create mode 100644 src/App.vue create mode 100644 src/api/remote-search.ts create mode 100644 src/api/user.ts create mode 100644 src/assets/401_images/401.gif create mode 100644 src/assets/404_images/404.png create mode 100644 src/assets/404_images/404_cloud.png create mode 100644 src/assets/layout/animation-image.gif create mode 100644 src/assets/layout/login-bg.svg create mode 100644 src/assets/layout/login-front.svg create mode 100644 src/assets/layout/login-top.svg create mode 100644 src/assets/layout/login.svg create mode 100644 src/assets/layout/logo.png create mode 100644 src/components/ElSvgIcon.vue create mode 100644 src/components/TestUnit.vue create mode 100644 src/components/__tests__/el-svgIcon.test.jsx create mode 100644 src/directives/button-codes.ts create mode 100644 src/directives/codes-permission.ts create mode 100644 src/directives/example/clickoutside.js create mode 100644 src/directives/example/copy.js create mode 100644 src/directives/example/debounce.js create mode 100644 src/directives/example/longpress.js create mode 100644 src/directives/example/watermark.js create mode 100644 src/directives/example/waves.css create mode 100644 src/directives/example/waves.js create mode 100644 src/directives/index.ts create mode 100644 src/directives/lang.ts create mode 100644 src/directives/roles-permission.ts create mode 100644 src/hooks/use-common.ts create mode 100644 src/hooks/use-element.ts create mode 100644 src/hooks/use-error-log.ts create mode 100644 src/hooks/use-layout.ts create mode 100644 src/hooks/use-permission.ts create mode 100644 src/hooks/use-self-router.ts create mode 100644 src/hooks/use-table.ts create mode 100644 src/icons/SvgIcon.vue create mode 100644 src/icons/common/404.svg create mode 100644 src/icons/common/bug.svg create mode 100644 src/icons/common/chart.svg create mode 100644 src/icons/common/clipboard.svg create mode 100644 src/icons/common/component.svg create mode 100644 src/icons/common/dashboard.svg create mode 100644 src/icons/common/demo.svg create mode 100644 src/icons/common/documentation.svg create mode 100644 src/icons/common/drag.svg create mode 100644 src/icons/common/edit.svg create mode 100644 src/icons/common/education.svg create mode 100644 src/icons/common/email.svg create mode 100644 src/icons/common/example.svg create mode 100644 src/icons/common/excel.svg create mode 100644 src/icons/common/exit-fullscreen.svg create mode 100644 src/icons/common/eye-open.svg create mode 100644 src/icons/common/eye.svg create mode 100644 src/icons/common/form.svg create mode 100644 src/icons/common/fullscreen.svg create mode 100644 src/icons/common/guide.svg create mode 100644 src/icons/common/hamburger.svg create mode 100644 src/icons/common/icon.svg create mode 100644 src/icons/common/international.svg create mode 100644 src/icons/common/language.svg create mode 100644 src/icons/common/link.svg create mode 100644 src/icons/common/list.svg create mode 100644 src/icons/common/lock.svg create mode 100644 src/icons/common/message.svg create mode 100644 src/icons/common/money.svg create mode 100644 src/icons/common/nested.svg create mode 100644 src/icons/common/password.svg create mode 100644 src/icons/common/pdf.svg create mode 100644 src/icons/common/people.svg create mode 100644 src/icons/common/peoples.svg create mode 100644 src/icons/common/qq.svg create mode 100644 src/icons/common/search.svg create mode 100644 src/icons/common/shopping.svg create mode 100644 src/icons/common/sidebar-logo.svg create mode 100644 src/icons/common/size.svg create mode 100644 src/icons/common/skill.svg create mode 100644 src/icons/common/star.svg create mode 100644 src/icons/common/tab.svg create mode 100644 src/icons/common/table.svg create mode 100644 src/icons/common/theme.svg create mode 100644 src/icons/common/tree-table.svg create mode 100644 src/icons/common/tree.svg create mode 100644 src/icons/common/user.svg create mode 100644 src/icons/common/wechat.svg create mode 100644 src/icons/common/zip.svg create mode 100644 src/icons/nav-bar/dashboard.svg create mode 100644 src/icons/nav-bar/example.svg create mode 100644 src/icons/nav-bar/eye-open.svg create mode 100644 src/icons/nav-bar/eye.svg create mode 100644 src/icons/nav-bar/form.svg create mode 100644 src/icons/nav-bar/language.svg create mode 100644 src/icons/nav-bar/link.svg create mode 100644 src/icons/nav-bar/nested.svg create mode 100644 src/icons/nav-bar/password.svg create mode 100644 src/icons/nav-bar/table.svg create mode 100644 src/icons/nav-bar/theme-icon.svg create mode 100644 src/icons/nav-bar/tree.svg create mode 100644 src/icons/nav-bar/user.svg create mode 100644 src/lang/en.ts create mode 100644 src/lang/index.ts create mode 100644 src/lang/zh.ts create mode 100644 src/layout/app-main/Breadcrumb.vue create mode 100644 src/layout/app-main/Hamburger.vue create mode 100644 src/layout/app-main/Navbar.vue create mode 100644 src/layout/app-main/TagsView.vue create mode 100644 src/layout/app-main/component/LangSelect.vue create mode 100644 src/layout/app-main/component/ScreenFull.vue create mode 100644 src/layout/app-main/component/ScreenLock.vue create mode 100644 src/layout/app-main/component/SizeSelect.vue create mode 100644 src/layout/app-main/component/ThemeSelect.vue create mode 100644 src/layout/app-main/index.vue create mode 100644 src/layout/index.vue create mode 100644 src/layout/sidebar/Link.vue create mode 100644 src/layout/sidebar/Logo.vue create mode 100644 src/layout/sidebar/MenuIcon.vue create mode 100644 src/layout/sidebar/SidebarItem.vue create mode 100644 src/layout/sidebar/index.vue create mode 100644 src/lib/element-plus.ts create mode 100644 src/main.ts create mode 100644 src/permission.ts create mode 100644 src/plugins/vite-plugin-setup-extend/index.ts create mode 100644 src/router/index.ts create mode 100644 src/router/modules/basic-demo.ts create mode 100644 src/router/modules/charts.ts create mode 100644 src/router/modules/directive.ts create mode 100644 src/router/modules/excel.ts create mode 100644 src/router/modules/guid.ts create mode 100644 src/router/modules/other.ts create mode 100644 src/router/modules/rich-text.ts create mode 100644 src/router/modules/table.ts create mode 100644 src/settings.ts create mode 100644 src/store/basic.ts create mode 100644 src/store/config.ts create mode 100644 src/store/tags-view.ts create mode 100644 src/styles/index.scss create mode 100644 src/styles/reset-elemenet-plus-style.scss create mode 100644 src/styles/scss-suger.scss create mode 100644 src/styles/transition.scss create mode 100644 src/theme/base/custom/ct-css-vars.scss create mode 100644 src/theme/base/element-plus/button.scss create mode 100644 src/theme/base/element-plus/checkbox.scss create mode 100644 src/theme/base/element-plus/css-vars.scss create mode 100644 src/theme/base/element-plus/form.scss create mode 100644 src/theme/base/element-plus/pagination.scss create mode 100644 src/theme/base/element-plus/redio.scss create mode 100644 src/theme/base/element-plus/table.scss create mode 100644 src/theme/base/element-plus/var.scss create mode 100644 src/theme/base/index.scss create mode 100644 src/theme/china-red/custom/ct-css-vars.scss create mode 100644 src/theme/china-red/element-plus/button.scss create mode 100644 src/theme/china-red/element-plus/checkbox.scss create mode 100644 src/theme/china-red/element-plus/css-vars.scss create mode 100644 src/theme/china-red/element-plus/form.scss create mode 100644 src/theme/china-red/element-plus/pagination.scss create mode 100644 src/theme/china-red/element-plus/redio.scss create mode 100644 src/theme/china-red/element-plus/table.scss create mode 100644 src/theme/china-red/element-plus/var.scss create mode 100644 src/theme/china-red/index.scss create mode 100644 src/theme/dark/custom/ct-css-vars.scss create mode 100644 src/theme/dark/element-plus/button.scss create mode 100644 src/theme/dark/element-plus/checkbox.scss create mode 100644 src/theme/dark/element-plus/css-vars.css create mode 100644 src/theme/dark/element-plus/css-vars.css.map create mode 100644 src/theme/dark/element-plus/css-vars.scss create mode 100644 src/theme/dark/element-plus/form.scss create mode 100644 src/theme/dark/element-plus/pagination.scss create mode 100644 src/theme/dark/element-plus/redio.scss create mode 100644 src/theme/dark/element-plus/table.scss create mode 100644 src/theme/dark/element-plus/var.scss create mode 100644 src/theme/dark/index.scss create mode 100644 src/theme/index.css create mode 100644 src/theme/index.css.map create mode 100644 src/theme/index.scss create mode 100644 src/theme/lighting/custom/ct-css-vars.scss create mode 100644 src/theme/lighting/element-plus/button.scss create mode 100644 src/theme/lighting/element-plus/checkbox.scss create mode 100644 src/theme/lighting/element-plus/css-vars.css create mode 100644 src/theme/lighting/element-plus/css-vars.css.map create mode 100644 src/theme/lighting/element-plus/css-vars.scss create mode 100644 src/theme/lighting/element-plus/form.scss create mode 100644 src/theme/lighting/element-plus/pagination.scss create mode 100644 src/theme/lighting/element-plus/redio.scss create mode 100644 src/theme/lighting/element-plus/table.scss create mode 100644 src/theme/lighting/element-plus/var.scss create mode 100644 src/theme/lighting/index.scss create mode 100644 src/theme/mixins/_var.scss create mode 100644 src/theme/mixins/config.scss create mode 100644 src/theme/mixins/function.scss create mode 100644 src/theme/mixins/mixins.scss create mode 100644 src/theme/utils/change-theme.ts create mode 100644 src/theme/utils/index.ts create mode 100644 src/utils/axios-req.ts create mode 100644 src/utils/bus.ts create mode 100644 src/utils/common-util.ts create mode 100644 src/utils/mock-axios-req.ts create mode 100644 src/views/basic-demo/hook/index.vue create mode 100644 src/views/basic-demo/keep-alive/index.vue create mode 100644 src/views/basic-demo/keep-alive/second-child.vue create mode 100644 src/views/basic-demo/keep-alive/tab-keep-alive.vue create mode 100644 src/views/basic-demo/keep-alive/third-child.vue create mode 100644 src/views/basic-demo/keep-alive/third-children/SecondChildren.vue create mode 100644 src/views/basic-demo/keep-alive/third-children/ThirdChildren.vue create mode 100644 src/views/basic-demo/keep-alive/third-keep-alive.vue create mode 100644 src/views/basic-demo/mock/index.vue create mode 100644 src/views/basic-demo/parent-children/Children.vue create mode 100644 src/views/basic-demo/parent-children/SubChildren.vue create mode 100644 src/views/basic-demo/parent-children/index.vue create mode 100644 src/views/basic-demo/pinia/index.vue create mode 100644 src/views/basic-demo/svg-icon/index.vue create mode 100644 src/views/basic-demo/vue3-template/Vue3Template.vue create mode 100644 src/views/basic-demo/worker/index.vue create mode 100644 src/views/charts/components/Keyboard.vue create mode 100644 src/views/charts/components/LineMarker.vue create mode 100644 src/views/charts/components/MixChart.vue create mode 100644 src/views/charts/components/mixins/resize.js create mode 100644 src/views/charts/echarts-demo.vue create mode 100644 src/views/charts/keyboard.vue create mode 100644 src/views/charts/line.vue create mode 100644 src/views/charts/mix-chart.vue create mode 100644 src/views/dashboard/index.vue create mode 100644 src/views/directive/clickoutside.vue create mode 100644 src/views/directive/copy.vue create mode 100644 src/views/directive/debounce.vue create mode 100644 src/views/directive/longpress.vue create mode 100644 src/views/directive/watermark.vue create mode 100644 src/views/directive/waves.vue create mode 100644 src/views/error-log/error-generator.vue create mode 100644 src/views/error-log/index.vue create mode 100644 src/views/error-page/401.vue create mode 100644 src/views/error-page/404.vue create mode 100644 src/views/excel/excel.js create mode 100644 src/views/excel/exportExcel.vue create mode 100644 src/views/excel/importExcel.vue create mode 100644 src/views/guide/index.vue create mode 100644 src/views/guide/steps.ts create mode 100644 src/views/login/index.vue create mode 100644 src/views/login/login-alt.vue create mode 100644 src/views/login/login-basic.vue create mode 100644 src/views/login/login-lighting.vue create mode 100644 src/views/nested/menu1/index.vue create mode 100644 src/views/nested/menu1/menu1-1/index.vue create mode 100644 src/views/nested/menu1/menu1-2/index.vue create mode 100644 src/views/nested/menu1/menu1-2/menu1-2-1/index.vue create mode 100644 src/views/nested/menu1/menu1-2/menu1-2-2/index.vue create mode 100644 src/views/nested/menu1/menu1-3/index.vue create mode 100644 src/views/nested/menu2/index.vue create mode 100644 src/views/other/count-to.vue create mode 100644 src/views/other/d3/component/NodeDetail.vue create mode 100644 src/views/other/d3/data.json create mode 100644 src/views/other/d3/index.vue create mode 100644 src/views/other/d3/useD3.js create mode 100644 src/views/other/d3/useDatas.js create mode 100644 src/views/other/drag-pane.vue create mode 100644 src/views/other/signboard/component/index.vue create mode 100644 src/views/other/signboard/index.vue create mode 100644 src/views/rbac-test/TestAddEdit.vue create mode 100644 src/views/rbac-test/TestButton.vue create mode 100644 src/views/rbac-test/TestDetail.vue create mode 100644 src/views/rbac-test/TestMenu.vue create mode 100644 src/views/redirect/index.tsx create mode 100644 src/views/rich-text/TinymceExample-bak.vue create mode 100644 src/views/rich-text/TinymceExample.vue create mode 100644 src/views/rich-text/tinymce/index.vue create mode 100644 src/views/roles-codes/button-permission.vue create mode 100644 src/views/roles-codes/code-index.vue create mode 100644 src/views/roles-codes/index.vue create mode 100644 src/views/roles-codes/role-index.vue create mode 100644 src/views/setting-switch/SettingSwitch.vue create mode 100644 src/views/setting-switch/index.vue create mode 100644 src/views/table/dynamic-table.vue create mode 100644 src/views/table/vxe-table.vue create mode 100644 ts-out-dir/package.json create mode 100644 ts-out-dir/src/api/user.d.ts create mode 100644 ts-out-dir/src/api/user.js create mode 100644 ts-out-dir/src/directives/button-codes.d.ts create mode 100644 ts-out-dir/src/directives/button-codes.js create mode 100644 ts-out-dir/src/directives/codes-permission.d.ts create mode 100644 ts-out-dir/src/directives/codes-permission.js create mode 100644 ts-out-dir/src/directives/index.d.ts create mode 100644 ts-out-dir/src/directives/index.js create mode 100644 ts-out-dir/src/directives/roles-permission.d.ts create mode 100644 ts-out-dir/src/directives/roles-permission.js create mode 100644 ts-out-dir/src/hooks/use-common.d.ts create mode 100644 ts-out-dir/src/hooks/use-common.js create mode 100644 ts-out-dir/src/hooks/use-element.d.ts create mode 100644 ts-out-dir/src/hooks/use-element.js create mode 100644 ts-out-dir/src/hooks/use-error-log.d.ts create mode 100644 ts-out-dir/src/hooks/use-error-log.js create mode 100644 ts-out-dir/src/hooks/use-layout.d.ts create mode 100644 ts-out-dir/src/hooks/use-layout.js create mode 100644 ts-out-dir/src/hooks/use-permission.d.ts create mode 100644 ts-out-dir/src/hooks/use-permission.js create mode 100644 ts-out-dir/src/hooks/use-self-router.d.ts create mode 100644 ts-out-dir/src/hooks/use-self-router.js create mode 100644 ts-out-dir/src/hooks/use-table.d.ts create mode 100644 ts-out-dir/src/hooks/use-table.js create mode 100644 ts-out-dir/src/lib/element-plus.d.ts create mode 100644 ts-out-dir/src/lib/element-plus.js create mode 100644 ts-out-dir/src/main.d.ts create mode 100644 ts-out-dir/src/main.js create mode 100644 ts-out-dir/src/permission.d.ts create mode 100644 ts-out-dir/src/permission.js create mode 100644 ts-out-dir/src/router/index.d.ts create mode 100644 ts-out-dir/src/router/index.js create mode 100644 ts-out-dir/src/settings.d.ts create mode 100644 ts-out-dir/src/settings.js create mode 100644 ts-out-dir/src/store/basic.d.ts create mode 100644 ts-out-dir/src/store/basic.js create mode 100644 ts-out-dir/src/store/tagsView.d.ts create mode 100644 ts-out-dir/src/store/tagsView.js create mode 100644 ts-out-dir/src/utils/axios-req.d.ts create mode 100644 ts-out-dir/src/utils/axios-req.js create mode 100644 ts-out-dir/src/utils/bus.d.ts create mode 100644 ts-out-dir/src/utils/bus.js create mode 100644 ts-out-dir/src/utils/common-util.d.ts create mode 100644 ts-out-dir/src/utils/common-util.js create mode 100644 ts-out-dir/src/views/redirect/index.d.ts create mode 100644 ts-out-dir/src/views/redirect/index.jsx create mode 100644 tsconfig.base.json create mode 100644 tsconfig.json create mode 100644 typings/auto-imports.d.ts create mode 100644 typings/basic.d.ts create mode 100644 typings/components.d.ts create mode 100644 typings/env.d.ts create mode 100644 typings/global.d.ts create mode 100644 typings/shims-vue.d.ts create mode 100644 vite.config.ts create mode 100644 vitest.config.ts create mode 100644 vitest.setup.ts diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e69de29 diff --git a/.env.build b/.env.build new file mode 100644 index 0000000..43a43c7 --- /dev/null +++ b/.env.build @@ -0,0 +1,6 @@ +VITE_APP_ENV = 'prod' +#自动获取地址推荐 +VITE_APP_BASE_URL = 'https://github.jzfai.top/micro-service-api' + +#image or oss address +VITE_APP_IMAGE_URL = 'https://github.jzfai.top/gofast-image' diff --git a/.env.build-test b/.env.build-test new file mode 100644 index 0000000..d454976 --- /dev/null +++ b/.env.build-test @@ -0,0 +1,8 @@ +VITE_APP_ENV = 'test' +#自动获取地址推荐 +#VITE_APP_BASE_URL = '/micro-service-api' +VITE_APP_BASE_URL = 'https://github.jzfai.top/micro-service-api' +VITE_APP_BASE_WS_URL = '' + +#image or oss address +VITE_APP_IMAGE_URL = 'https://github.jzfai.top/gofast-image' diff --git a/.env.serve-dev b/.env.serve-dev new file mode 100644 index 0000000..a38d289 --- /dev/null +++ b/.env.serve-dev @@ -0,0 +1,10 @@ +#The defined variable must start with VITE_APP_ +VITE_APP_ENV = 'dev' +VITE_APP_BASE_URL = 'https://github.jzfai.top/micro-service-api' + +#image or oss address +VITE_APP_IMAGE_URL = 'https://github.jzfai.top/gofast-image' + +#proxy, use this to test proxy +#VITE_APP_BASE_URL = '/api' +#VITE_APP_PROXY_URL = 'https://github.jzfai.top/micro-service-api' diff --git a/.env.serve-test b/.env.serve-test new file mode 100644 index 0000000..ed14544 --- /dev/null +++ b/.env.serve-test @@ -0,0 +1,10 @@ +#The defined variable must start with VITE_APP_ +VITE_APP_ENV = 'test' +VITE_APP_BASE_URL = 'https://github.jzfai.top/micro-service-api' + + #image or oss address +VITE_APP_IMAGE_URL = 'https://github.jzfai.top/gofast-image' + +#proxy, use this to test proxy +#VITE_APP_BASE_URL = '/api' +#VITE_APP_PROXY_URL = 'https://github.jzfai.top/micro-service-api' diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..14f5b39 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,6 @@ +public +node_modules +.history +.husky +dist +*.d.ts diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..c7e7ebd --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,4 @@ +{ + "root": true, + "extends": ["./eslintrc/eslint-config.js", "./eslintrc/.eslintrc-auto-import.json"] +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b5e33a8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,51 @@ +# compiled output +/dist +/dist-ssr +/node_modules + +#lock +pnpm-lock.yaml + +# Logs +logs +*.log +npm-debug.log* +pnpm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# OS +.DS_Store + +# Tests +/coverage +/.nyc_output + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# Other +.history +*.local +yarn* +pnpm* + + +#.eslintrc-auto-import.json +#auto-imports.d.ts +#components.d.ts +stats.html diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100644 index 0000000..3b92648 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,5 @@ +#!/bin/sh +#. "$(dirname "$0")/_/husky.sh" +#在项目中我们会使用commit-msg这个git hook来校验我们commit时添加的备注信息是否符合规范。在以前的我们通常是这样配置: +#--no-install 参数表示强制npx使用项目中node_modules目录中的commitlint包(如果需要开启,注意:需要安装npx) +#npx --no-install commitlint --edit $1 diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..db96295 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,8 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +#推送之前运行eslint检查 +npm run lint +#推送之前运行单元测试检查 +#npm run test:unit + diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..daf66a1 --- /dev/null +++ b/.npmrc @@ -0,0 +1,7 @@ +shamefully-hoist=true +strict-peer-dependencies=false + +###aliyun address +registry = https://registry.npmmirror.com + + diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..454eec7 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "useTabs": false, + "tabWidth": 2, + "printWidth": 120, + "singleQuote": true, + "trailingComma": "none", + "bracketSpacing": true, + "semi": false, + "htmlWhitespaceSensitivity": "ignore" +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..0c87b22 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["johnsoncodehk.volar", "esbenp.prettier-vscode","dbaeumer.vscode-eslint"] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..4029450 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "editor.defaultFormatter": "esbenp.prettier-vscode", + "npm.packageManager": "yarn" +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..ffef565 --- /dev/null +++ b/README.md @@ -0,0 +1,85 @@ +# vue3-admin-plus + +The plus version of vue3-admin-ts , provide enterprise-class using demo + +suggestion the Node.js >= 16.0.0。 + + + +## Documents + +- [Official Documentation](https://github.jzfai.top/vue3-admin-doc/) + +- [中文官网](https://github.jzfai.top/vue3-admin-cn-doc/) + + + +## Online experience + +[Access address](https://github.jzfai.top/vue3-admin-plus) + +[国内体验地址](https://github.jzfai.top/vue3-admin-plus) + + + +## Related items + +The framework is available in js,ts, plus and electron versions +- js version:[vue3-admin-template](https://github.com/jzfai/vue3-admin-template.git) -- basic version +- ts version:[vue3-element-ts](https://github.com/jzfai/vue3-admin-ts.git) +- ts version for plus:[vue3-element-plus](https://github.com/jzfai/vue3-admin-plus.git) +- ts version for electron:[vue3-element-electron](https://github.com/jzfai/vue3-admin-electron.git) +- java Micro-service background data:[micro-service-plus](https://github.com/jzfai/micro-service-plus) + + +## Build Setup + +```bash +# clone the project +git clone https://github.com/jzfai/vue3-admin-plus.git + +# enter the project directory +cd vue3-admin-plus + +# pnpm address https://pnpm.io/zh/motivation +# install dependency(Recommend use pnpm) +# you can use "npm -g i pnpm@7.9.0" to install pnpm +pnpm i + +# develop +pnpm run dev +``` + + +## Build + +```bash +# build for test environment +pnpm run build-test + +# build for production environment +pnpm run build +``` + +## Others + +```bash +# preview the release environment effect +pnpm run preview + +# code format check +pnpm run lint + +``` + + +## Browsers support + +Note: Vue3 is not supported the Internet Explorer + + +## Discussion and Communication +[WeChat group](https://github.jzfai.top/file/images/wx-groud.png) + + + diff --git a/eslintrc/.eslintrc-auto-import.json b/eslintrc/.eslintrc-auto-import.json new file mode 100644 index 0000000..429c7b0 --- /dev/null +++ b/eslintrc/.eslintrc-auto-import.json @@ -0,0 +1,116 @@ +{ + "globals": { + "EffectScope": true, + "axiosReq": true, + "bus": true, + "buttonCodes": true, + "casHandleChange": true, + "clickoutside": true, + "cloneDeep": true, + "closeElLoading": true, + "codesPermission": true, + "commonUtil": true, + "computed": true, + "copy": true, + "copyValueToClipboard": true, + "createApp": true, + "customRef": true, + "debounce": true, + "defineAsyncComponent": true, + "defineComponent": true, + "directives": true, + "effectScope": true, + "elConfirm": true, + "elConfirmNoCancelBtn": true, + "elLoading": true, + "elMessage": true, + "elNotify": true, + "filterAsyncRouter": true, + "filterAsyncRouterByCodes": true, + "filterAsyncRoutesByMenuList": true, + "filterAsyncRoutesByRoles": true, + "freshRouter": true, + "getCurrentInstance": true, + "getCurrentScope": true, + "getLangInstance": true, + "getQueryParam": true, + "h": true, + "inject": true, + "isExternal": true, + "isProxy": true, + "isReactive": true, + "isReadonly": true, + "isRef": true, + "lang": true, + "langTitle": true, + "loginOutReq": true, + "loginReq": true, + "longpress": true, + "markRaw": true, + "mockAxiosReq": true, + "nextTick": true, + "onActivated": true, + "onBeforeMount": true, + "onBeforeRouteLeave": true, + "onBeforeRouteUpdate": true, + "onBeforeUnmount": true, + "onBeforeUpdate": true, + "onDeactivated": true, + "onErrorCaptured": true, + "onMounted": true, + "onRenderTracked": true, + "onRenderTriggered": true, + "onScopeDispose": true, + "onServerPrefetch": true, + "onUnmounted": true, + "onUpdated": true, + "progressClose": true, + "progressStart": true, + "provide": true, + "reactive": true, + "readonly": true, + "ref": true, + "resetRouter": true, + "resetState": true, + "resizeHandler": true, + "resolveComponent": true, + "resolveDirective": true, + "rolesPermission": true, + "routeInfo": true, + "routerBack": true, + "routerPush": true, + "routerReplace": true, + "searchUser": true, + "shallowReactive": true, + "shallowReadonly": true, + "shallowRef": true, + "sleepTimeout": true, + "storeToRefs": true, + "toRaw": true, + "toRef": true, + "toRefs": true, + "transactionList": true, + "triggerRef": true, + "unref": true, + "useAttrs": true, + "useBasicStore": true, + "useConfigStore": true, + "useCssModule": true, + "useCssVars": true, + "useElement": true, + "useErrorLog": true, + "useLink": true, + "useRoute": true, + "useRouter": true, + "useSlots": true, + "useTable": true, + "useTagsViewStore": true, + "userInfoReq": true, + "watch": true, + "watchEffect": true, + "watchPostEffect": true, + "watchSyncEffect": true, + "watermark": true, + "waves": true + } +} \ No newline at end of file diff --git a/eslintrc/eslint-config.js b/eslintrc/eslint-config.js new file mode 100644 index 0000000..34b37f7 --- /dev/null +++ b/eslintrc/eslint-config.js @@ -0,0 +1,200 @@ +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { defineConfig } = require('eslint-define-config') +module.exports = defineConfig({ + env: { + es6: true, + browser: true, + node: true + }, + globals: { + defineOptions: true, + $ref: true + }, + plugins: ['@typescript-eslint', 'prettier', 'unicorn'], + extends: [ + 'eslint:recommended', + 'plugin:import/recommended', + 'plugin:eslint-comments/recommended', + 'plugin:jsonc/recommended-with-jsonc', + 'plugin:markdown/recommended', + 'plugin:vue/vue3-recommended', + 'plugin:@typescript-eslint/recommended', + 'prettier' + ], + settings: { + 'import/resolver': { + node: { extensions: ['.js', '.mjs', '.ts', '.d.ts', '.tsx'] } + } + }, + overrides: [ + { + files: ['*.ts', '*.vue'], + rules: { + 'no-undef': 'off', + '@typescript-eslint/ban-types': 'off' + } + }, + { + files: ['*.js'], + rules: { + '@typescript-eslint/no-var-requires': 'off' + } + }, + { + files: ['*.vue'], + parser: 'vue-eslint-parser', + parserOptions: { + parser: '@typescript-eslint/parser', + extraFileExtensions: ['.vue'], + ecmaVersion: 'latest', + ecmaFeatures: { + jsx: true + } + }, + rules: { + 'no-undef': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-empty-function': 'off' + } + } + ], + rules: { + // js/ts + camelcase: ['error', { properties: 'never' }], + 'no-console': ['warn', { allow: ['error'] }], + 'no-debugger': 'warn', + 'no-constant-condition': ['error', { checkLoops: false }], + 'no-restricted-syntax': ['error', 'LabeledStatement', 'WithStatement'], + 'no-return-await': 'error', + 'no-var': 'error', + 'no-empty': ['error', { allowEmptyCatch: true }], + 'prefer-const': ['warn', { destructuring: 'all', ignoreReadBeforeAssign: true }], + 'prefer-arrow-callback': ['error', { allowNamedFunctions: false, allowUnboundThis: true }], + 'object-shorthand': ['error', 'always', { ignoreConstructors: false, avoidQuotes: true }], + 'prefer-rest-params': 'error', + 'prefer-spread': 'error', + 'prefer-template': 'error', + + 'no-redeclare': 'off', + '@typescript-eslint/no-redeclare': 'error', + // best-practice + 'array-callback-return': 'error', + 'block-scoped-var': 'error', + 'no-alert': 'warn', + 'no-case-declarations': 'error', + 'no-multi-str': 'error', + 'no-with': 'error', + 'no-void': 'error', + + 'sort-imports': [ + 'warn', + { + ignoreCase: false, + ignoreDeclarationSort: true, + ignoreMemberSort: false, + memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'], + allowSeparatedGroups: false + } + ], + // stylistic-issues + 'prefer-exponentiation-operator': 'error', + + // ts + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/no-non-null-asserted-optional-chain': 'off', + '@typescript-eslint/consistent-type-imports': ['error', { disallowTypeAnnotations: false }], + '@typescript-eslint/ban-ts-comment': ['off', { 'ts-ignore': false }], + '@typescript-eslint/no-empty-function': 'off', + // vue + 'vue/no-v-html': 'off', + 'vue/require-default-prop': 'off', + 'vue/require-explicit-emits': 'off', + 'vue/multi-word-component-names': 'off', + 'vue/prefer-import-from-vue': 'off', + 'vue/no-v-text-v-html-on-component': 'off', + 'vue/html-self-closing': [ + 'error', + { + html: { + void: 'always', + normal: 'always', + component: 'always' + }, + svg: 'always', + math: 'always' + } + ], + + // prettier + //fix lf error + 'prettier/prettier': 'off', + // import + // 'import/first': 'error', + // 'import/no-duplicates': 'error', + // 'import/order': [ + // 'error', + // { + // groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'], + // + // pathGroups: [ + // { + // pattern: 'vue', + // group: 'external', + // position: 'before' + // } + // ], + // pathGroupsExcludedImportTypes: ['type'] + // } + // ], + 'import/no-unresolved': 'off', + 'import/namespace': 'off', + 'import/default': 'off', + 'import/no-named-as-default': 'off', + 'import/no-named-as-default-member': 'off', + 'import/named': 'off', + + // eslint-plugin-eslint-comments + 'eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }], + + // unicorn + 'unicorn/custom-error-definition': 'error', + 'unicorn/error-message': 'error', + 'unicorn/escape-case': 'error', + 'unicorn/import-index': 'error', + 'unicorn/new-for-builtins': 'error', + 'unicorn/no-array-method-this-argument': 'error', + 'unicorn/no-array-push-push': 'error', + 'unicorn/no-console-spaces': 'error', + 'unicorn/no-for-loop': 'error', + 'unicorn/no-hex-escape': 'error', + 'unicorn/no-instanceof-array': 'error', + 'unicorn/no-invalid-remove-event-listener': 'error', + 'unicorn/no-new-array': 'error', + 'unicorn/no-new-buffer': 'error', + 'unicorn/no-unsafe-regex': 'off', + 'unicorn/number-literal-case': 'error', + 'unicorn/prefer-array-find': 'error', + 'unicorn/prefer-array-flat-map': 'error', + 'unicorn/prefer-array-index-of': 'error', + 'unicorn/prefer-array-some': 'error', + 'unicorn/prefer-date-now': 'error', + 'unicorn/prefer-dom-node-dataset': 'error', + 'unicorn/prefer-includes': 'error', + 'unicorn/prefer-keyboard-event-key': 'error', + 'unicorn/prefer-math-trunc': 'error', + 'unicorn/prefer-modern-dom-apis': 'error', + 'unicorn/prefer-negative-index': 'error', + 'unicorn/prefer-number-properties': 'error', + 'unicorn/prefer-optional-catch-binding': 'error', + 'unicorn/prefer-prototype-methods': 'error', + 'unicorn/prefer-query-selector': 'error', + 'unicorn/prefer-reflect-apply': 'error', + 'unicorn/prefer-string-slice': 'error', + 'unicorn/prefer-string-starts-ends-with': 'error', + 'unicorn/prefer-string-trim-start-end': 'error', + 'unicorn/prefer-type-error': 'error', + 'unicorn/throw-new-error': 'error' + } +}) diff --git a/index.html b/index.html new file mode 100644 index 0000000..b8226ee --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + + + + + + <%= title %> + + +
+ + + diff --git a/mock-prod-server.ts b/mock-prod-server.ts new file mode 100644 index 0000000..1f931f7 --- /dev/null +++ b/mock-prod-server.ts @@ -0,0 +1,12 @@ +import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer' +//https://cn.vitejs.dev/guide/features.html#glob-import +const modulesFiles = import.meta.glob('../mock/*', { eager: true }) +let modules = [] +for (const filePath in modulesFiles) { + //读取文件内容到 modules + modules = modules.concat(modulesFiles[filePath].default) +} +export function setupProdMockServer() { + //创建prod mock server + createProdMockServer([...modules]) +} diff --git a/mock/example.ts b/mock/example.ts new file mode 100644 index 0000000..4f04247 --- /dev/null +++ b/mock/example.ts @@ -0,0 +1,12 @@ +export default [ + { + url: '/getMapInfo', + method: 'get', + response: () => { + return { + code: 200, + title: 'mock请求测试' + } + } + } +] diff --git a/mock/excel.ts b/mock/excel.ts new file mode 100644 index 0000000..b4631a7 --- /dev/null +++ b/mock/excel.ts @@ -0,0 +1,56 @@ +import Mock from 'mockjs' + +const NameList: any = [] +const count = 100 + +for (let i = 0; i < count; i++) { + NameList.push( + Mock.mock({ + name: '@first' + }) + ) +} +NameList.push({ name: 'mock-Pan' }) + +export default [ + // username search + { + url: '/vue3-admin-plus/search/user', + method: 'get', + response: (config) => { + const { name } = config.query + const mockNameList = NameList.filter((item) => { + // @ts-ignore + const lowerCaseName = item.name.toLowerCase() + return !(name && !lowerCaseName.includes(name.toLowerCase())) + }) + return { + code: 20000, + data: { items: mockNameList } + } + } + }, + + // transaction list + { + url: '/vue3-admin-plus/transaction/list', + method: 'get', + response: () => { + return { + code: 20000, + data: { + total: 20, + 'items|20': [ + { + order_no: '@guid()', + timestamp: +Mock.Random.date('T'), + username: '@name()', + price: '@float(1000, 15000, 0, 2)', + 'status|1': ['success', 'pending'] + } + ] + } + } + } + } +] diff --git a/mock/table.ts b/mock/table.ts new file mode 100644 index 0000000..d5723e5 --- /dev/null +++ b/mock/table.ts @@ -0,0 +1,31 @@ +import Mock from 'mockjs' + +const data = Mock.mock({ + 'items|30': [ + { + id: '@id', + title: '@sentence(10, 20)', + 'status|1': ['published', 'draft', 'deleted'], + author: 'name', + display_time: '@datetime', + pageviews: '@integer(300, 5000)' + } + ] +}) + +export default [ + { + url: '/vue3-admin-template/table/list', + method: 'get', + response: () => { + const items = data.items + return { + code: 20000, + data: { + total: items.length, + items + } + } + } + } +] diff --git a/optimize-include.ts b/optimize-include.ts new file mode 100644 index 0000000..a29553c --- /dev/null +++ b/optimize-include.ts @@ -0,0 +1,133 @@ +// const fs = require('fs') +// const files = fs.readdirSync( +// 'D:\\github\\vue3-admin-ts\\node_modules\\.pnpm\\element-plus@2.2.9_vue@3.2.37\\node_modules\\element-plus\\es\\components\\' +// ) +// console.log(111, JSON.stringify(files)) +// console.log(console.dir(files)) +// console.log(console.dir(files.slice(20))) + +import { resolve } from 'path' + +const elementPlusComponentNameArr = [ + 'affix', + 'alert', + 'aside', + 'autocomplete', + 'avatar', + 'backtop', + 'badge', + 'base', + 'breadcrumb', + 'breadcrumb-item', + 'button', + 'button-group', + 'calendar', + 'card', + 'carousel', + 'carousel-item', + 'cascader', + 'cascader-panel', + 'check-tag', + 'checkbox', + 'checkbox-button', + 'checkbox-group', + 'col', + 'collapse', + 'collapse-item', + 'collapse-transition', + 'color-picker', + 'config-provider', + 'container', + 'date-picker', + 'descriptions', + 'descriptions-item', + 'dialog', + 'divider', + 'drawer', + 'dropdown', + 'dropdown-item', + 'dropdown-menu', + 'empty', + 'footer', + 'form', + 'form-item', + 'header', + 'icon', + 'image', + 'image-viewer', + 'infinite-scroll', + 'input', + 'input-number', + 'link', + 'loading', + 'main', + 'menu', + 'menu-item', + 'menu-item-group', + 'message', + 'message-box', + 'notification', + 'option', + 'option-group', + 'overlay', + 'page-header', + 'pagination', + 'popconfirm', + 'popover', + 'popper', + 'progress', + 'radio', + 'radio-button', + 'radio-group', + 'rate', + 'result', + 'row', + 'scrollbar', + 'select', + 'select-v2', + 'skeleton', + 'skeleton-item', + 'slider', + 'space', + 'step', + 'steps', + 'sub-menu', + 'switch', + 'tab-pane', + 'table', + 'table-column', + 'table-v2', + 'tabs', + 'tag', + 'teleport', + 'time-picker', + 'time-select', + 'timeline', + 'timeline-item', + 'tooltip', + 'transfer', + 'tree', + 'tree-select', + 'tree-v2', + 'upload', + 'virtual-list' +] + +export const pkgPath = resolve(__dirname, './package.json') + +// eslint-disable-next-line @typescript-eslint/no-var-requires +let { dependencies } = require(pkgPath) +dependencies = Object.keys(dependencies).filter((dep) => !dep.startsWith('@types/')) + +const EPDepsArr = () => { + const depsArr = [] as string[] + elementPlusComponentNameArr.forEach((feItem) => { + depsArr.push(`element-plus/es/components/${feItem}/style/index`) + }) + return depsArr +} + +export const optimizeElementPlus = EPDepsArr() +export const optimizeDependencies = dependencies + +export default [] diff --git a/package.json b/package.json new file mode 100644 index 0000000..b5fa43c --- /dev/null +++ b/package.json @@ -0,0 +1,129 @@ +{ + "name": "vue3-admin-plus", + "version": "2.0.2", + "license": "MIT", + "author": "kuanghua", + "packageManager": "pnpm@7.9.0", + "scripts": { + "dev": "vite --mode serve-dev", + "test": "vite --mode serve-test", + "build:test": "vite build --mode build-test", + "build": "vite build --mode build", + "preview:build": "npm run build && vite preview ", + "preview": "vite preview ", + "lint": "eslint --ext .js,.jsx,.vue,.ts,.tsx src --fix", + "prepare": "husky install", + "test:unit": "vue-cli-service test:unit", + "test:watchAll": "vue-cli-service test:unit --watchAll", + "test:cov": "vue-cli-service test:unit --coverage", + "test:majestic": "majestic", + "vitest": "vitest --ui", + "tsc-check": "tsc", + "coverage": "vitest run --coverage" + }, + "dependencies": { + "@element-plus/icons-vue": "^2.0.4", + "screenfull": "^6.0.2", + "axios": "^1.1.3", + "echarts": "^5.4.0", + "element-plus": "^2.2.9", + "js-error-collection": "^1.0.7", + "mitt": "3.0.0", + "moment-mini": "2.22.1", + "nprogress": "0.2.0", + "path-browserify": "^1.0.1", + "path-to-regexp": "^6.2.1", + "pinia": "^2.0.16", + "pinia-plugin-persistedstate": "2.3.0", + "vue": "^3.2.37", + "vue-clipboard3": "^2.0.0", + "vue-i18n": "9.1.10", + "vue-router": "^4.1.5", + "xlsx": "^0.18.5", + "d3": "7.2.1", + "splitpanes": "^3.1.1", + "vxe-table": "^4.3.5", + "xe-utils": "^3.5.6", + "tinymce": "^6.1.0", + "driver.js": "^0.9.8", + "sortablejs": "1.15.0" + }, + "devDependencies": { + "@babel/eslint-parser": "7.16.3", + "@tinymce/tinymce-vue": "^5.0.0", + "@types/mockjs": "1.0.6", + "@types/node": "^17.0.35", + "@types/path-browserify": "^1.0.0", + "@typescript-eslint/eslint-plugin": "5.30.0", + "@typescript-eslint/parser": "5.30.0", + "@vitejs/plugin-legacy": "^2.2.0", + "@vitejs/plugin-vue": "^2.3.3", + "@vitejs/plugin-vue-jsx": "^2.0.1", + "@vitest/coverage-c8": "^0.22.1", + "@vitest/ui": "^0.22.1", + "@vue/cli-plugin-unit-jest": "4.5.17", + "@vue/cli-service": "4.5.17", + "@vue/test-utils": "^2.0.2", + "@vueuse/core": "^8.7.5", + "eslint": "8.18.0", + "eslint-config-prettier": "8.5.0", + "eslint-define-config": "1.5.1", + "eslint-plugin-eslint-comments": "3.2.0", + "eslint-plugin-import": "2.26.0", + "eslint-plugin-jsonc": "^2.3.0", + "eslint-plugin-markdown": "^3.0.0", + "eslint-plugin-prettier": "4.1.0", + "eslint-plugin-unicorn": "^43.0.2", + "eslint-plugin-vue": "9.1.1", + "husky": "7.0.2", + "jsdom": "16.4.0", + "jsonc-eslint-parser": "^2.1.0", + "majestic": "1.8.1", + "mockjs": "1.1.0", + "prettier": "2.2.1", + "resize-observer-polyfill": "^1.5.1", + "rollup-plugin-visualizer": "^5.8.3", + "sass": "^1.52.1", + "svg-sprite-loader": "6.0.11", + "typescript": "^4.7.2", + "unocss": "^0.33.5", + "unplugin-auto-import": "^0.11.2", + "unplugin-vue-components": "^0.22.8", + "vite": "^4.0.2", + "vite-plugin-mkcert": "^1.7.2", + "vite-plugin-mock": "^2.9.6", + "vite-plugin-svg-icons": "^2.0.1", + "vitest": "^0.22.1", + "vue-tsc": "^0.34.16" + }, + "pnpm": { + "peerDependencyRules": { + "ignoreMissing": [ + "vite-plugin-mock", + "unplugin-auto-import", + "unplugin-vue-components", + "unocss", + "unplugin", + "vite-plugin-mock", + "@vitejs/plugin-legacy", + "@vitejs/plugin-vue", + "@vitejs/*", + "@babel/*", + "vite", + "vue", + "@unocss/vite", + "rollup", + "vue-jest" + ] + } + }, + "browserslist": [ + "> 1%", + "not ie 11", + "not op_mini all" + ], + "engines": { + "node": ">= 16 <18", + "pnpm": ">= 6 <8" + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..b3e50e381b8259ae9913fb5043a103d5d3960575 GIT binary patch literal 209410 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 z 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%0A*K7{ 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 literal 0 HcmV?d00001 diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..4c2f0fa --- /dev/null +++ b/src/App.vue @@ -0,0 +1,45 @@ + + + diff --git a/src/api/remote-search.ts b/src/api/remote-search.ts new file mode 100644 index 0000000..457e9ae --- /dev/null +++ b/src/api/remote-search.ts @@ -0,0 +1,17 @@ +import request from '@/utils/mock-axios-req' + +export function searchUser(name) { + return request({ + url: '/vue3-admin-plus/search/user', + method: 'get', + params: { name } + }) +} + +export function transactionList(query) { + return request({ + url: '/vue3-admin-plus/transaction/list', + method: 'get', + params: query + }) +} diff --git a/src/api/user.ts b/src/api/user.ts new file mode 100644 index 0000000..c003a5c --- /dev/null +++ b/src/api/user.ts @@ -0,0 +1,31 @@ +//获取用户信息 +import axiosReq from '@/utils/axios-req' +export const userInfoReq = (): Promise => { + return new Promise((resolve) => { + const reqConfig = { + url: '/basis-func/user/getUserInfo', + params: { plateFormId: 2 }, + method: 'post' + } + axiosReq(reqConfig).then(({ data }) => { + resolve(data) + }) + }) +} + +//登录 +export const loginReq = (subForm) => { + return axiosReq({ + url: '/basis-func/user/loginValid', + params: subForm, + method: 'post' + }) +} + +//退出登录 +export const loginOutReq = () => { + return axiosReq({ + url: '/basis-func/user/loginValid', + method: 'post' + }) +} diff --git a/src/assets/401_images/401.gif b/src/assets/401_images/401.gif new file mode 100644 index 0000000000000000000000000000000000000000..cd6e0d9433421b3f29d0ec0c40f755e354728000 GIT binary patch literal 164227 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⋘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 GY5fOuZZib{ literal 0 HcmV?d00001 diff --git a/src/assets/404_images/404.png b/src/assets/404_images/404.png new file mode 100644 index 0000000000000000000000000000000000000000..3d8e2305cc973ad2121403aee4bf08728f76c461 GIT binary patch literal 98071 zcmZsD1yoe)_qGfpFmxy&-5?DTB3;rUAxKDvbVzqeiAZ-S3L@QI(jWrT-5rArH4O2c zxq5&1-u3_1I%_Gcbl>@Z)@`}0ni zgTxS1Xz2Sp5LyN$jB+`(TK2go0$*ON+wYG~Qz71pR)(>+cvvo`d01{Xdj)u2?ZXzy zmA;x1Nzp_;m7?it6=)ebdFi9=K=7-zt#9B^kGF`IzK;CC(qMy@r8#>WqG2@cS5uox zXbf0B@c&#i)!^b0Mb!?4K=50dqjrDj)8Y7T(OQwKjh4xB0;y*hgfuAsToL#vtY-x2 zcDPC4UD@TJ&X)ylS~p2s{Vm(V1wS(C*u6kTtf;l}x2;9RDSK|B+2Q|vU# z5g|>`3ves^tw-x#pW$kM%4o{)rRUjP-bFAxh4kKaDr2nlD0Ny3>QcfT2w<51UE`{O zQGN&5UTB2YKA@#pXv;7`0|{yiD)FUE4eA?4@$j%fYDMKsqFQWUi?UOjnyuv<1_{u= zug?(m3a+6reFd6hu*h(3OM4>q*mTc~Pg?D7J-n+TvnsoY9 zWoxbD->+xD=K*Q$(+jLna6%I4kA`x*GDPIgI-Zm%UVn5!@S7kc4LW0oj3yb?d`)8c z7ej523IBV$9&o#~u-m;%@UGl)D|$=WY^|@KLU`Ac)l*@|602_{T4+M7IA6dbP#2AL)Eg1u&)lV@(b^iSAa}Wv>^6+>!0CyZsvtcv1&Qq&svN z+sZThYEIutRzAD;PdEXgWle?>lIf5kVEHlvET1a{;shO{ zn-EQLhR|g}l#-=7bY$DeCw*BaO6=ZCIRr)2d3ye8*IdkaiCqEbd9ba|DSo;7ROxl@(%P?=XHjX#v%4uLDStHz#?vp;8Jp~psBrurXiozhE0`(5iED>LBhfh5__U^oInU|$yP zEjDz&{zwWAxMdUZr8h#Q=vPr46k)9@kV_jypUZrWZ3!8{4Gc-ISvP>EqE52=OPg%cn3_A1Z+SuWO*0}uNWds4s zAhHbNeJ>FWsaCAW5waW9L4FA9Wr=FLpr*j>!WUNfY>TSb`i)Yththth%76Sc@)}q} z#=A@s1{4@Z>WAs!^^cH?WYrfik`9X{fiIcaicws{R=?W(`}oTdF7Taj4mNRDu&>;I z{4zufM6pn&*L_0n^uS2Kp2m8rj=vHajm%)0ZyNTcn@wug^UjqFs9J#iwD=khPyY|B zktqP6M89)9&wx(|%4a*P;&Jc6s(^o8=aRB(4Kgwpm-fAp_?~bxq0|4UPCxmP54Nw` zf8KveXS@t^YI)NG0{})#k;X3S`owvLhXtN)LG8zL?>f|k6Y<^+zeU_~P(n_T3cesZ z8M$)|qkPrp{Yt_1HBT1+ zO$}G`mF#sBF264SZO#=YiEgoZnB0y+E+=?at|BLr{=?)Ir}<1cztP~%gOtGG__6o( zMm~b3uxF~!@$Upjl>b=+yK-RE^|!b6=#XmBAb0Kk0yP63l$@RoTOm8=ocSwp{*zOYGx+e}se(;LO3e6?ei2{2&&Vv#NqBGgg!wJ(!R2P`LBb7c^&8 z?_}TM;6eYN3D70K&z~p#{=4r}rQ6HpW`vHNQ6cYvu$FmNk@Ifi=~0v3F+WPqS*X{> z2_Nn)^R~a;O-srktbEh9S&aNYACRic7*z#8+=w0Mna;iy>`*~9X)GjuDJ%2()!vdB zZ0%@0nm{d0Hybg!I$Csmq{VC#z5?Jn182ITfa?C@E(zU!0=cu06u$Y?}# z)Q!Vd5YFX{PI!wE)k>WaaQkvEERB9y_+J|{$ekI8#RaR>HTob-4E2h#JB02*h^Df6 z+hbAf6XDe)%Bk-yG^;-KiykYn{3G^*W_{J-^WXPidjIz05b`1L?_RQm-0y&O7;DB? znhfbMQX7`Q)xWCPdi9+!bnTwM4~5>a6{jc@y+8h6f(8CFuG-$*J2Knb^#~b_$kXV(?y&%;wLJv#A=pR$wIksq9h{$)&wK4AHHGojB6 z2(7_D+CMG$3c1i4)v3GYWLSQ5Fi4E)uPOqkT_=lR{&dUcQ=+q{7G%ZnFRo#YhBB7T zpTT4KG6XDdObk4tDsUWL!nCY;*QhBHa&fhy=Rzuuu@v+LHImBfsx)g-H;d=!^}p?a zgG^77#$I}a7(~GRLzx^(#GUa*ujinA+$hxZSd|yfo)lV_E1uj==Sh=$LkwNEasOf) zT5`b0yEWGfLaG^o+eYhw|&EXwMkEM>mX1|P;97mZ;zVY)Zsr#NQ z_wXNtrD+7xw4BGGkPG2sC178@xc9VW`wjIKq1&9CoxjJoJ{NDBp#buct7%`48WHE) zC$>LXBJREU2b$<4faQak(xe%J!T?_wMX2wIi)RGlMfr1i&r78EsVhp4-iqCvF&mHG z4kS$mO(x`l|FPc44H*0NiCw@p1ufF6T1qrfZx zWV5;6dMF$~gZGYJq({OgEp7LSuk~T2jza-BbAVZV3a>nup0jCE;N8am$F1!WO{#9F z%ZtF*))3`(x4OT{&;Ibpq5mgm{eg5pR8mNE`+AdK3E!M1R^k^_?eqFd6IT^(Ix_RdbaCSknTxXyUb|;m z&nNLmSwmlEZ7K+W|5x57X?vWEy@v0lp0n|tEjaXJUEYw9gaX7 z^uv?6E_PQbj8#SqOIQ0dtdeinTHL0b>j}|=KjZ()=~AFKB8@fg?{KMr7-*`eVN9v2 z5+(3xlWu4Te*okrAKMW0)Vu@Z-fg&P#851~z%5(K3%P>WkTRft_~S4dR%F~-z-#%4erE*iyIUDsI_aw!@R(+*>ZLLojl=EX;6?#;ZLvr}?BDkWfMk8f46 zly8wLw37nqASMlS?e0US<+1v!ZuJu)o=388_yaKFMZa(&D8r_&%q$fZ3;!1>^11Gy zH&1jY#kjMB{(5BY4VdEIM{#~yf1SA&y(8`ZDF$CA#^sPyKho>0h@rMeW|863S2=5b zZI*LJ9-puF-3MKE)x!UULqU`HK!EVidubDLM*;EsR7K7@Orc9%wX6s~WvK{qfnBqS zdPL)Yb>-qs`Os_K<6M_n3M(u4Uxf>>_qOZ-@3gObHKXsUN)R2Leg&}D3?__yiWf2{ z_V(gf^NLae+P38aZ?Jgbun=?<`Y)FtSr$1)N&!<)Ij|Hl_DA<$3TbL0u@oA_Pu=53 zPo9Vv!!I_vf6b{+B`MUR`4m&}!#^f5CPR^?F3DHuO97sVgG>x75ne&Bz@{VV{7gnk zz8pm<GC_er@IEsh z=7|sF0pe@QiuD95$$$3Lq|hqpBYVqOF`P2;GOKCPD)>t;&-s!xZ6Jz5f8M#F4bB9D zOoaNMO_xXyn1JGe19K1ta!J0G{E&HVTagC;yuR9vu(I*GVb9~LyzHxGW96Qzj^QDC zE5ak9qmHPu7iTq@REe+X$-7)cl>80e4z-=L?xp<4*t2f}Kg7z~cc!4y2C3ucni?(e z75ZH8?}@;V(BeweHxn$bx($aD63nujoxUaXE=Bh5z3nT-JrVJl8`doS#?v+%74Wa9szPtaGOjx8g5fJYN_27HkJicm~v@1-<} z=W)j=oqqC*zV(;aQ(H2V33Wf}k58JCua0sVA6TvIxx@}&yk;iI5dXaG(c#y2Ia9d* z#BG`lPxe*;<8k0(!0r7>CAY`SYLb6L48Ai6O&lTPYx&rh(3%eL+-H*_-hgW~78pr{ zot~+JNFcA#<@circTpjM-F_~Dv}@90IQpwjj_|L$2aqngFHQcV>5gVpD)#EfvCH8X zJ`uyzy7SDjemiuw<618slKkzNKqLfa2n!~@1*bm+(w)%w!*Q)P|2(#-(mL}HRv4Mg zQm8<>^G3{Aw#Z$6Xm2=s|066T!!JM%k?jWis-FoDxz7xDSlmL2rBBR`P|pqRTQo>8 zL?C~^Kw^%_`UjEioZ0#v1)6#A$I|JdN)OaT__=giTkbGnlfr;+LlYC8?ae5GTDFhc zdIc)R2o+ZybDfS7&D}Drw#-E>P%E+8Y4hqD`sI6)1gJ?#q4+3$>{87bS;qMtfBFBJ z>;4i@z9z!ze@nySP$v=-d%_-N(;>EmFErFAzEQPm{Mzwm|lFqUBuc9NI-DcEi1#S=7N~U6xl7j!oQ23A>GoOCz zu0p#A=$Xd8@q5I)xv<){ovZFNrVr)1zbKQgP9@^=CvwF8IWZ zNc?lp$>(V1gmqWooCCW!CtVxP=Ce86&vh}M{{0;zP9QWnasl7{W*~V=bYa*TaUQb? zo31v}b-tP!wp&WVNC_^Rxk&M7s4NtWosm9ztiOQqHqWNR^Z9yT#Kj8fZe6_*wqfro2X#-n{{aPZ-%v-r`uHAzt5cdI zc=SZ1D4J4B_7E{?n+3yKJT|Kl^({bi|l+Q!jcn7xl}x1MqMkULV?ct=_mz zelqcVi2J`-$wF?gN9x({!1C?NARW47f7xM!DYuxa+LGXSku;(Q((ad}-*XG=87a#* z_qLd-MV`|x3T44Il;|yPMop}pTE(n_UmtLWFy}q^h4?@l)1AXwfNl#25WC-`;+|m( znBiDcJEZwd5~TSWx1Ez7uAzS@*kHymO4-ZA(Uz@rRVjc2I3hMEt zfbZ1wmLFA-VzxpnW7{5f=A%wtsm^!hv@faA{FKODZwoqK>gEtF_xvmZ?~ZxiC^YVQ z|9?JtO31xW@F`AuqX9_s9~GDLIm(Nrc*<(;$M4O6D2;k@?+ZC}ShUd-z&I`^vbp+h znB`!{hwppFhV32vHTJvcPVZUS5}=Ue|B`&%XgifJL=I$2^<$s+pbq@-*kGp%@vem^ z@pBXV)z*$R-k|9#Xs7IF>IM+?NB&!Orq(|SWY7o_up1xdwF99sfv>K!6DwU&)>7Er zx?Gv_CR-FYp_MpWvuz-8kSV~(7BC?fm2HOV$WliWir*Z+#L}PnAGc5jbd$xzv|I|nA8yRK z5ZJiJ?7XFdoubkp&CJ55^plmn;;2l3yP4a5PG{XFQwp%L(|gmbA)GwDDJ1mERH(v^ zXsDeLyvf8MB?A&m{5e*NB^`~dRE-jj(vkxmZ5rKIpqwn10gsato-wTWfN!fW*Rn;b zp{(nR|4 zt+nh1hx~ijq4^wm)4oM5mVI1RPWVUFBE=B!>t|LN4Ldb$A$x8%ATgGU^w8lhurIzd zfy@ndCcapnr4I{ycx^b4^)lrpt(xC-rJ|Kjm#Q7``M<9iq>#j8;Po7+Q-}#ij@`-h z9rf7i_ve83GwHfM>rq`RUn2jp;%NWVJK~oIO#V|!pga~qfbeZxn^tswR-;JJfj+5si4i|3iE<2-3D8F^f<b zL{D5BKg+S}W6N8Ls2gGFnsRB5KZE&f_k@`KT+q4zUc7?#}&R{u6s_{6ZX_c3;&Z_Q?#CkO)G$u%5{DcU%B zvqJE}u-y7%w0^p;8u0Pm8s5)s8qHPErTcZ_&Qwp!C}+5=s5}RJMyi04LzC)eL6rCq z^M9&WkRmcqCEhy+csh5sgzdoGgNVC&2^mV!S$1~zJ`>+dJEWpqj3zX*cE1o`ldqJP ziDC`HxME3);a|7$ep<9`X4nuW5i`a44y(0?Cy|JAQWN{t>@sImEox4X8aMP-#$J(4 zGW*-R5KdkdH0QjC7&^z#2v~aQg@z@~pPy2!NOAbL;_-oAeIY@2`;A->U@cZ!r}Mz` zgSEUx9oCttaX(H&#$%t9a44HSVg9aJUzCxGuxMOL4u$fdYwy<7$i8`sZiP92L8<3b z(IoM`%bJ!`i&9Pmy0J5-9&G6iLQG#2qU#S4tywRc^Y<`wi1o%SK13^UN)g2k+J;4 zZ|&+AVX!!f5RmK+t|DPl~W-1C^UN3iax* z=qP`5R^~UkS*aSw=<_cDB|K{~4ZlyB;7?TM9s+7gnXpFod!U1o1|Cm(Jg{*Wm=?STJhVV&FP z&R^e|g2d|gZ9!rx@z%!rD6ZFK^yjN(`t++b0s(C_0^;wcugdn5j7HKOm)|~P_=_Y2 zy}{>(SvAs1Zz%k=K{2YjZ(vRQ^gf<#17!9UQ$ls`!@jG2to6Ik37<>ukirY|pNeuS zr&RRuf8$rPX-n6NUA3Qr*rKxb!9IWYS0f@CN2OiR$~c*#b3r(8k?Wz?NvjeE@rz8< zNb=taXf_Ne#}9ZDD9|A?@7ry*zfw2T1f!O@^kr{-1ZPjyhCi>B7`t$<88ND4rNH!a ze(Xn?Y|!@Xs`PZhFU7BG(>D29lc>ApLXZW81m%$IQXM;BTNRLdGZfpc))!X$S#@D; zUltUjVE`S7r7ZyTTB!CUS4icu^B=r7MwUZNKQJwTwEQLF&fuJOX#Y~bw7n1BgX5Cv ztF#mGT3Mp07rc=&*UtNxDVA$CxmNN^jdx+Oc`4jIMx>J)#Bb4>= z@&6(|0)PU%U+d3a6Grd`EwIVDXIp*B8tHo#)S*3p#b9vkL!78~E_+|Bt>|3r9<@=w zngkXv-w*Fa9>YNF8FXG9gCqtM#l?j;0d z#97D}K;WRP$zis!I+_8|-*9*qLKR{z%j+WlvGahZjJ%>+y zSf>u!zMdsH?>94Q>?13Q!Hh);he++PhbY%{$+M>!1aP-32oMbB+IZDIwO=8gKL7)* z`AfBY#p^-gym$51z4^IqE9-gdN4&c0@}Y>v_fW|P;s;4rr3^&u!3ZQ$Q4|ix^L{LSE;(JsBjeBRuvZmC7!jovh5X{^DSijU z2D6=qm2LhNjC&-}zL#`0k2@`lIN;mEoo)f~oCy9!4&8g-a9jmYs0WB_K&__ve%BuM ztKaZtCXIt*m!Wb_O}CT-JCw(!$X-H9!FmPPenpQhS|`yT`Coz(xfWEJ>|g*$yue~L zDxcU)K4OlDpw+zW4-sxHs5v;eyem-@FAlu71YX`pyl`fl)G*U~p3e>+K}*z-(Mh>Z zQ6uKvFXF!iYd171%kiKrHOcE2EE09s`*IXm*`%U7z)n{OpsP@5c4i_w@4+oT_ocl) z+F{GQcL}GlC*hx(0|TjD-?0`61y;fjeohOW3+J>Rs+l|Z%4u+HuO9#+tC9y9>Qwa4+X3JV~6|6 zPokd>F=p$TQM*L|Xw9rBDUdl&el_~{;LB*PgRZRG1-jB3`WD@PqE|# zzWFoi-V$+R#?QAm=Pw+|9zF{D9WvJBz+&bsS%vTktsOy4&m#<)=|c5#JH}QUA5_eT z+0IS*VBp3>UySh@UY4??vP5P>k^*$F4 z+OG!t>ZuOL4u;20=a->CB(#OB{0h;AXKN5P|>PLUl5&cbh z)dfMDHw=^Z5h4V@mYRlqIqp4n$4Qm7rb=gAs%*r%ImW5)k}A*=JYxq|q+|8AYSLHN z!fmm0+zz7{OMNzgk`o~(CpwynUI>w~OlkS9!U+0!2=O~F+Q%45^xl#UhX(APlMV}`a{w|Ah zSpoMHee2Ew5@EWE1d&xmv!Pj`4{mcXzjUj`^COp03-LT#ybpkNS3BY71MTpIqd+Kh;X5VWdJMqPE!u@-gG1X z{{HjAXQwQR-Pxjm`ofy-A47qxaIb^(Ks=SIPl(B@hf~+zCXcReee3s^D&^OcvG|Mp zJCG2wTPgmOzm$`x5OVP@FEQJ_r1-zT5_Hu8-pq1!|Uvrpmz z)slQ`wlgvV@oZm+I>}tzyYW{vgT(%baHT+=vur;7dhH?;}=^>aPu4U_w3*Z3rZNq&=M z31MVj{!ukp5ho!JF^Jw@vDIC4$ezh#?i6tv@c*Q+Q>pH#h5p83%wvWtc?^sES;>+= z|NLo9ku99OuhQuCj5zk-BmDy~z|=P%kNBGdf{Kx%<3M`Z2C0gDJ>&8kZ4;&3&BaWC zg>DJlbIB1MT7o4{l=+1<{yjG1EF9f*x9x+ zEwZs*GBGcAUUr$zAJzr!*i#+4b#01=>-*kO^uJASsl0U`lv>98V})rXfkR+x_!C+` z0;NCjea32@uAMO?c`tm82A=I6B)jARGzJ5{X1<*EEZ(kNUjt$x`zgEBsKxCImP`6{ zllLW-Ae$ke#p`JOm!wp_$))%pr}~!$%VmnU7d)X8VR1x`XbI;R5Z~+%Ie%$ES@r<; z4^1Yk=)IEw_}AuO`XB3e#2efb(WPUH~2*g$9{9=RnkFxE4y2m7!e&VgbiHy_V7 z6$QZN?a(8-ugkVVEz(Y0Rz-M0RgeqyhTPP^GV387HT;k{!s2K1LHcXBQ-pYmH&yRz zsL$c;EjoQ;$rd{40A6b4KjB-`O7R=VKX1YW0+5GO{4FPf zgp+9Wrh$^~_Si=CW<^#6ZA3D^^n49y$z$py9KL!e%28V6DF=}JsY}q zL5sSP_FT%5ACN|HR^d-~{6;BbR)D(a|G?g$3yL5ZxmZ@xdDa;*T^;UFFPn0WZE!Y` zZuE9g$3mRl1L`@M;Gt^qnfwD@7qyR+&P%FQgyh2;x72!Z?CqRe2Ta4y06|fF5 z=+{@snF46c5yaZ7$*skt!o%gKyfG)rL_%D_p&gp{I3AZStia%Wi)wV9Lw=hxTy@Lb zlaP&|Dm^17QMVa=K=c;pht$|eU3#G7V-9~3hGivM>TeqLdw`z9wEW1;xi5UR-(_AS zrx#x=r{fYo@hWHaaOXUCd&wj0isGD5%<^|j(V7YHz|f~54y*T-n zfNBSF_vgj{!RMIQzpgG%^A_yzRH5``a$S+p$@_8a2lnQ(ic*Et!_va$Sd2kCoQR`uXZI1N0L-86P2}qKuXJQ$OI4IrH>i>w zcj3DZ%Y`VW@mq;AEDzEmD*-A=HDik}c%_%=p=v}&6R_68b5AGouVo$l7d|+X?`|+F z;JwSW;<=oNiccagOP`5@@&DlBu4G`_;%RQ5D>82BoX80`yUFb2^q6)tY- zhuqf%Vr7LDK4I2dPUjp}LYoezkYc=2UE^YbYsB3zA9p^6WT-{s-0p0mV{6e`cX!;AP7Kb9Sr(ZA8g_c^S+_P8og#oCu@WWAWkfxA)dh&0uZbpHG`dD>WY@ zs{-y!U{tV^Ibt^ zBkVbQLBSy+sk#F)RX5($Xo{cfmA%JyUh$YuR$vWc?G{2%jQL6&;}tL-*0WypaS5xa z)jxoAeii>#ug`Tb6sLe1?zi^KR z3~x+EucSj1m5|!#5VP^klrJppC<^!ihskN^NgNh&hP|Q`>Tu!|{@D ze;-ypIawvtpin^+Q71T`)0A!Iu;m(K6&H%fCJp`8A&P>Br_x*iG&$UiI>p{PWEXcX zTnnq81Tc%TzR-mQfV~jEIE3y1HE2w7);A>PNhDyT-e@l}U^im}KU84=nAeJ%U@tpF z$8-MVtGL^1hQje-*-nlz42B8jHkrYx{ZMh(Co)GUji#7Bf}pSC?)rErvt#zzdRiVG zR}Q`qW>~<-@|Wgkfuagh9c@(CP}R3WTz>F?{5FT$_C%mt2#|j1K&B6yPMg}m|0Rqc z>~b%ar?Ds!M9{w1+8eV?wiO^ujg`2va|=x)_O552YVnGwJ6FH?5tWwh&~hjp`yEoi zyeu5*;te#lZHA`6zUfOHUG5jJpJ$6cW+ETn)3y2Nn;7}mi&OwESrrNMX23TA)!B2^ z2R0r&x^eu-b{u^u)M%5}O0Ws85NX2GVM^Frr92Do1~O;k z$aDcGLel|3rZ};iKlp-+I_>?`I~7Je>l%q>F=WCbl>#aXS|Ujv`P>DF-5V7PsExFW zI7et1-VePW?_$7TX>+3`tM2=Vhxqd|7djc$i{yb9!K(*8tRlfpHCQM$n>m1x$MQ2N z@T2(sl%+h#Mfz1zsqG7KVQy9^&MPv7-(q&q4!}dz3Oc5cVNCC|_2W&}lXzxMU8{^M zElP!-mbgz$=6L5`&agzc5FRaWLFpF7EIVHh62AZu2@S_~PI>y0i(T6EPp$i0)+z6X zH&&1h*B_6Q=kW$>#Qv#PT>*T}84T42{IaXOY?D|wHzLPa&8cf5Ik;IB?`GMfGqo`< zqF{}|aQztZYW1sjOGjO3G~!1k-(qVE6{W*0gUcGR8ZK_+)tXW=1$9nO64xN1lT&9F zvW@bqS+;zc1Q^=#G#qw!;p0Lqk%grwq7o{MYpQ2QBi*GZpWEV}rH>Jx0;FFS6$vGi z+kx7jInK6j;BgLtgdsXjuMqzF-LBO|4jTNB8Z9EuM$HGX<6W+$(B~0#P+Y&}7N#&n z)}Y8t)xdE=ccE#cLq#9|UJXMgGZfqFcwx%yc)x;4!aiEblNS@}c@PeOnjtVsrqr4| zQN#!o@yxu(-&UO24fwaH9HV!ZX@E8TQ;q~}5?ovm*W0-N)H7mp?sa2`p55@RElDy* zP~=Gb`t?20bSdKP#b^1Q)p*u(cZ0pTl-bUGd#Dkc3qn=x`RP64rS%_7;hpJ3lh!}DnAHJ4=u zCC=L6td2M!;`rhLI{x%0&}^nz1)oSBJ_QmooU?BW7C*#OT5b8>-aQx`oc>7jT$X-q z&&mu|-nZU6*J~1mBdIBStd!#I0w;?*G{+{?X{8&Di|D@#X!{f-8zSP`fR0B?YQIf{EiyAvE)ZP@hT=07jChp+NS0 z&9Ye-A))c@R$PP%-xw1(SWvpgq@4$cS#60=>_kdiFsv=FOl{p?zuBW%Tr6{RJT&Vn zg~_y*_a@Xtb41eHeV8Qf^_cN0KMA<^Qhv(u&7Rk6LLHhY{Ptx`e^G(0sL$(nIWnMD zh3!2nVBRRbEZO%!S1xWvK`z_dRf~!D(V)=NaC|vMB_kMOfbj%;5V^@l zBcVeXQ;kS<4iN^(a5C$CqL?JveAKU#&+HYAT0dXaU!mpMlaG#@8dZy>G^&w_s-ttl ze}y)#XTTg4%o=V}7P1YRs3wi;$MtdIRTc(G=)1OgS@Kd!h||6|9v^-IW=M?TEu;H$ z8(027qt@eb%)6Q3yGsdzOO(mJd5VfHv7-;l^6_rM1Yy3TI9}j=x{7z<7_OLtMzT!Oc zRdY*nd$dOl#qwQw-*f$x#>!W(zFYmY3wpA$+Gde=oA#-q8vZ$cGrC|( zdArb@5U*|go=uC~+=i!H?-XP9bKU)<4|~fmt9idT;sxvyR}a5j@0SydWIxc@yJ{E- zC5~`8iwDSE&XVmQvyZGp>xlG%+px#P?N$nh(A!Js-|E;122wVZOxj`y!XQ$|`!(z! zh}WLxJeITqU)xzL|ITDmC^&@mtvT&ovdr$goDh;IOMFLdSJ(rV3B9FOp{P?YC;W@7 zL4%pvc|sKjE0?MY(mHT7u8#C((WEzTkcM~o8&R(#6{T$Nsp4+61R;$-P#OjRolz>m zIbeY=!R;#g#-fjkn+?f+m64&^+KhR6b69L87QRT9pN@|prw}$~oyO?NNLB7{xAT6`3nK1g&`t&bh4kA_TM7D zPNX|U4Rmj11Ca?_Z-B(_cmaMU0t{UTb+Z_q@UWca*F1_S5v(cvz@OEhSY7`$D)DG- zC&LWFpG2_1swTnlt)zOAgb`NG^11(HUuJFfV2%4nfSr=$hhf@=*^5xlNiTm$lU8#D z7G}5eB&=+pxpep`3H&>5VyN`PmK46PE4z^A&lPzzJFQsbWcDj(N_$S%(|lSW$zFH1+xuPR&DKxs113IT z_-|7z+K0HipL|5Dic*0~yXicGvHzjP%cLvdbO!Maty}m=d|79tS&*ey9V7KD%W(%z zHnyoqz@@ITs_lWt|CSR7EC-XunFLr)7{uUC(HLTiquI#yydAajSH-Dor1d7^oeYR) zP?pj1Q0$ zFqxb=UQt!^I6C>Nl;MUl%MgP*Y~-7Zb=LX$8`t~cF#wZZ^{hTb8d?H^6ov(koOY3FmJ;F~M!Hl&;$yeZe^%_*T z&nzrf>$B!Vrxm*9rbeNwllFA|QO!X=UL4oh&89u{xGrab7xW&xm~%sYN+U8t&_k!V z@i2&>lz&E+@c{~tSl;(!fV^+N7t~TDTg&-KiNNi{b=Z*J@b~l2w+a?6oZlYuWk2C^ zX7Ok#U-yt2RkL~eIwX%>F*g6Y&O5tjuAuv!$D~EMl2iJgAexZ&14imantY3~DJYxv z_V8QbM`*jWjzQtP{zG3MbFZ!XN+Uy(0Us&KO7k1uO9p?Z&&@8)Sun{qpeMqu{GP$A zBNUkmZ>2~}n}d}bXQxT*e1rTlJmJrO68Zh8rBC2+VpK{5_SIL117)~B5}nb}Z4C9W5)ZD+M)ihZ8mNid{+_H*+AWae3IGv3sZ!m9FATHZFb@SLgZf z&0&x1Ymh6`g-d`+7@SZQ)i?x;o3pS;=2sNP_9k;O_)FBN>(byi6mbJDg;KZT6yz3# z8IP9$H6kWMw1Lcv>N#9{%0?T^mJsBV#GL!EW#4gw+9>dr349L84kZb)l(~-qxq;nd4RFS_9e!~UaqLJnDNN;S82Nt zy~9%Bo82DHpA34r>ueco^zSIh3++&Tj(H+{(b#`|9{m3Z!>sg2Y))|psRK_9X9!}J z*uuSM^U8xOWHZ_|=Xx`_E?Y|F-;d=p&rw_ow2P#HHXdSSdjNPglxo)LH%J+Tyfv6 zXW>XqV`oeTX8-wfUiiz;7;KAb_cgQ+?OD#T_*DXL*+@95b@s%jGD)31JB#RBm=?#( zvtSS5dIN`siIu{lMTv$Z1fEpQ@yp4MGZW#0;1;IX-|`N34$z$694267K*_`S0(zYh zv~loLNbaY9iEEzIv()$afmPur^nj`fP{^(RaKQ-cK83ga=l2wbRMrj*yXJcL;Y96* zbtp+V-rp-GhXtLM;>DHvp@EETJ_GS(pZ9@T%cMv<9Lq~W&;>;a7@(uZe;lq2I6UtO zj6x8Q+Kxt5=(gO_&PHNpH>)SnGoMjCk7`%LjkcbuT@z7rm^A>#fF|a)E6cEh`G@u$ zUg#|?q6=*?Pyt_ZnuwTEe+8wigkM;apMXyYEi%|^L5sV^Z`>hruvrM z`8;qd42MJlb4!t)h>Y5ZlYC|U$Hgvz)1nUgEDf)Q^mAG-tA2=llTKF`6kOTjOoc<1 zeyeygaR7+2{CLu<3_^kUk~x>9-=8f;vlZoCsfv?$gwZTacbroY59OE)E5(ZQbxe}a zp+2;mZHuwQhdAM+X4JG^?|UL%9%&6@)DA%EIa?9Oug2@Fn*BD$>zV)h8fFxk!Aj)2 z+P{G(ziD_KT!x+7o>9?%c~R!}VMac82K?p`-R)6uAGHYG@%G$Mt9N~w&fB^iF-*4( zD7V9kQ)8%Q>!hcT+I`o1k^h_TgwW$E+9S4S>9szO3MtY%w<&jjjBFTg?0)M znPVAdYb|U!?e+uCjnWO*9Tb3}20mDpr}};3cmz2KTQ{ieLcuU10ZM6~@a%Pg&A$z2 zhOzKZvozG(2Rc@-a~MpfbnrSm}fBhK>yi8FSy*>#*j zohK;Pj_}2deRhpMJ_JUpXY`BDMUId=xt+3!FSg8UiKhpYA;&${|BYT;aG2`q_erMQ zwXw9re8Cot*Dacp=e#Bkp9$ms{_~q(~E~W9fsu3F@6~HIhAG1fO1t z3}*EX<+ZkeZ-20Ryma_|%8WbqPJs4M29cr+h=UP7M67Jm8A~RgisfIhPY$}Wu+J!5mp~py zvQcQdpLV2To4(=Y^s!cV6iRKbz%jO&bSx9w9g)t*&rFh2qv%) zeaWmT1{7(?7Y#>KuckPN+;PX?b&yIp93a z&!MWZ;3E%$tm7-RJApjf^&CwhDxDP*+9G(wK9hB2Y#P~bkq>x_91~70%%x!%c>?m8 z>T8VFN!_B#@DO>BhJ6@PW&#%%8koMETzJvU3%Q43P(Pon^n6Uu@!Pd}MBSE60mN1E z!C%YB248gPtEG#OKtkUKZh4)>5j0H7jD{PRgfsgupLNC6n}?KPfm=E8fK#NY3d=u4 zDIWw>F@w5L(BM>$#USr20W0%lrfAkYm{`?TSIGWdYBT0vX;vZ(Ft!dx zR8yRUFk!p2A@woKby%dC@FQXolk9g}71GYm@b5OO;~M!GfDHI;tJbi3GUM?^m?vN* zL1zb+zmCm<0V|1N@KZ^H?4|BZUIt(-cr?7~RM;{|>q8q(^>AWfa>PB}8>;sDEHX;( zw2=QPb4h9Vfu_}>tLy5M2b$e^2EQ4mHvV#gNl!c91vCKBuC|o&Dy%5VLYB6z9RzMRFNgI-pRaB&N z0HHNCC?NbuaqXv8tQCdARxo0u&54((w|8jpXi2ONM@|Zq1jt9S4|n#~&7N9RZyrt* zJMvuDy1|Ma#XZpK!;oR{O*XKtekGj?(5>BQxdnFoz>3!;ZbB~%)mHnLJ&&d@MY7cc zJg4hxq8bTT`;k2mZ%v@f95Z=IGg=?2p$>%mqCmI%tLa1Fq+$&DRD@^M9pD6Iuz_b6v|Q zmv~^7t6lHb(JB4D+hc7*wUv*{z8sU6nncMW0l~!ijjEVxPeCXccDkm6NqebVA2nX@ zdY3)F)Gao)a(bSc|NiNdmDn;Bn@n&(cd)J3(pWeT_ z(Yq#}`x5M47B%=T$+uWHqJYzfVcEM3a$H>)CXz4|<;|HkZoo{>qqKG)RKPTZWkHKf zGcMo@K7)7IbqNyW1f)Y=)KZ-J!>NxybwKK~(C#V6`s~wCKS5nxGhtBI0o5TUFB`Kf z4^#z2_gZj&I8$_uS-sWV)fT`(XGv_wy2L55GWpZOM4m|>q8r)+{&odMJK4R?sx?9V z*KjYcjG-ppWZZ0;-LQmO3OQe(zx!Uo7GmHkDK&Y{Gu-W4m0NmV_-$~RR3e0u-l!*b7ibQWDH-!|7BoPF<^duGj=nRQyjtLL{v$6VXpMCO!Z8e&Dl#r9~4Is3d)DS01NQu6)*>1lFCgd7&2Bc%$C+zcl(b z$xi@G+DDUXM2BmD%H-h2`x5$@Au5~52JWt8id5A(R7}?#ddY^WUu1hTcwB6W-SXp4 zl5=|&>@N+>X|G7y)ZyAZ(VT!8^VT-x)HNR_hwy@oH?OEFG zS6%BUOqBd@Sy~*`>|s*rac~;&PDo`sgF+Ys|(46;9gb6C2S*Ja&o( zqF?ly2HM|6roPQgMw7?anzR~>bnLcZQKpU_DG>O4u&doa-8;0u4H?QRzshQ2*HFKR zXmo&oR6%_(!lsK5>_S*RR4q0f=+tZ%Sn) z#isMc53y8KcpmH0A9p7!25sUIeuv%Eu$vzwa7KfFho6UqtMlI3jLBrsDjY! zl)7Auq_MKRfa0ZKSFMEzTj$#9LviGKRsRorZc zXaGAzgbJF5|HIZ1)Ifp{waUh&!^K9WC5U=w#=38Pt2>E(DBPm6X=6nZ_S4qjm;To5 zab`rmzQEh<2Bd=4#S^E>2cX-9x$Nr{QdFN(?ujbT#tQuV_k}r6C^wGT`j(QVdX69B z&i_++@wddENFD8tcNwPtR%ny~iBd4Mz&a_q(tJ6+QJI9K*QZG?f1`ELUu)e_iLB2R zs3re4{U4;zoYJ8(UG3iUG_+5TXylL${&y9C;ZmTi2o|c8M~$U@`z}`O@C8-KA3e5< z;R&^>3jW$+Uc(tr^BD(*Zw93q7|YFtc^Sb|b=83jR~_W}l5Opg?q2Md2`2x0OjZCW zrOBkuy$1N+ft=;3fqdFZ)*ANr@A^AXVLx@986i1oM zgSMlCh33E`>NW}LZXpA8`A4r)``QSTkoB8Vv+uRN}>4#tEW|0qi; z@A-%OwxNVw$cJ_*0+vL<*aJ@~L*$;k<5~N{P z|0nY+urvWc2AzkA&hXBQ8amu>s7_=d*hURqGC@(EWcXz);W4b$wuM;dhyKg-;0fZnD@Z9GysG$06DTq zDMdxAJBI#VHOkk=!jIu~bErD;6u;M&3M zvyXoPD4U&#HvPo#!uaRHbc0=qZ6clvUR=WHc2BRdxeyOd4w{nvrz2@iA*>LSeXe&K*h(Wx2WmCsE3$ZaX;ld3u~|nME;o?I-b_fn(GSS=888Q1W zu`7|J%{!Y;zA=rGLVQ1Y}D3XjBI;Y02fcg!|19sOvBrC1dM+0UcB7JwajRAZc-)Bs(w2!ow8$L`g`H5 z?-bdCWEE4(xt$h%eCh1#KSBPZLB`&mtYWfU=mLTt9a67E<5gMUAGzCo^$YMngzd|l zrSUL^yF;gQ`AD!s{w=keKeQ*VVJd=v$$ns_vlJGNUk5M|Cd%5GVPl{8#~HHLYo6@` zhnG$V3i^76=9F*~DFTm#VXQT@?JotI3L>*q7ChhDm0#-?5q|F-AotpS8~)Zh;MGypLSqsU4$5oHlFgVpeU|gQ)P~-Yhg)$ zh^3MHyYbm+p?Pvd77hKw&eQ(x?Ozp{(y7$rgX8*XjM6_>^o|5kAQqq*_a@Y&hThlFXD_Mes?+N<~#8LLVdkMgo% zzwnz(+(L?T2aEqS5AH+|5`DLtg??oak}aOQ>WwnRKf7%4n_M-Vp*&c6E?o4#ISx|U z&XMigzQ|+?27fs`zs6nGka0O|P-a)~&1;?TN4CHg_aW4CYbZ9oO(;Qj$5u8f>PH(l zU0f!at1u3_uQaL)W*hQ5+DWD4$&co&23G|lB8SleyriAh)jU!7(QHMMunccqwg z(ET;31Jx>IZNvS)&@@>Ehd!*7CQpGp!>yxR z0+~*xTx66s@S_hCp#I~eE8pu^#Ga7;rCmG+DvLI_WZA92zl-<4QPuY}{ado+i4~VG zzYHyy11Iu~mbBLmUqi<}Q^d*UR>zw-&QOgFEfu<)?^yLW?qt2H+_K#{$&>%Y6^pwR zJnSB(^LIzyzQPnhS#F1}YJ?S&+s6P*QL8CxUL7ZgkGKJ4i5J|>=JRa<--Tnxe`uCT z%5Sa2tkaSE9|suc$6TTCtL)O9q^Wnk(AU>t83F+Y2*O7E``5?3E#ER$W)2McOK85p z(vHJcHDJ+io0v2zVXdBt?qnk_$Y-=-m|Dj~H{1A~!bMjCHe>YGpDse11y5mZ!OvlDO!^}qtKvO8AWbHifx^S#9iv0~ z&>#!rxp9$!n`?tD*$j5wDnH@(+K&fkxs_9KWE?zGIuIH@=!pBfO*x)JAFLbJrH`nY znq>}aA{USUcSekl*(lMG{$}g`fJc2}h*4B#|M1J`+Uz;Dzv#y~5BFKSB#P3?DWc=0 z^#&wnIZo8Aw^~}?lxz-<7RxP&2=n6E2NGSUtGh}8jDl6pn}&2vcjl|@vnG23)~0RU zhUP)iVTEyJz?0+vMF#bw|F|e#0{8ubOg>h*nT3M4Q=h$-b=f*ng&-v)NVZxkH9|lPR%8g1l4)l3X2hdDr~@^JpwyBcg9J?5hR2CvFAI^`WC z7x;)ZpgVWZS%vu{3Jrg%mU{u{3;m?s{4P|T@wm7;{ZzM1(EQ8N(x6gkhOrN{YLsjn zs9FJPjnM02ClEhYoEo*V?R+RGY7-`M-~Twn54}Fn&%9h&D>K64N!T#1z^ddE8`k3? zE4nv_HU&$ab=pS4aGqD#o*wJYy6n0pzv@K;q@z8RYwGz?a1{9M?aAp+|JIo9+<)>? zek2R%@=fqPAhL%7S(W~@kIdoHymp~-`{K^4vvY*;vPenk$)<*a)kuRh_BJhvvNHxl z)aH5vfxNH0Ay1B#bIncgg|qW?tU=FG+Qcj6wRG(!lj!EN(ZcuG;h0uq3DW1x72%H0 zdzO|sT_F8(N?7QC>;3<_gJXDpX+T{HU6U)E0!5ayjQjl7T&FksfGXe7z!T>eZI*LP z>-F{7Qj1z-^^UTszCh^xHHnmb7-wdOha05kr`Cl| zoRaK{QJAPZj`bvUQ26)A0z{lqaL&?1? zF{qTscxo>bNKk7R++`F}kSGVWq%^cG`IL~&t#Y_jK>#gz0rRk?Hz zN#kvXUkdnWihj!mKlB|+(=v!Te$e}|{KAg4>bxt=gS@tIakB~3gmH^``wRa#vin(< zEUGB)F0dh9A>Eal5%fg8{L;jFALpCY_pWrEuK_He97$tbKG9?9}8$Kb@`hh<~mU2jdee{?N>=J}NJ|70xzkKL*Ca`*V;j9-+}>Hir0 zo`Hb@LH-P`|4zFe`My7A0@PkwdU#02Z~qaepqY1+!QfFHYCwsR%3g$;ve+?3QwT?vS&IU%A?En2jV= ze;KgvAE3GsCA}C?B~^O#4356;iDYBCOh&`KN^uwNaDZMPE02ouWyHp6jbzC6m9w9P zV~nl_Kt6PuqHb^QUp0%R$c5TTsmc_gEd54Hdi^ESZ11MC_|N2X{^!vpRsAL*8{c8E zw#Sm$ffh=wSdp9m@c4UR!fB1EMwkOrUHs7y%(H13$tFL)V$gL`>n8Am1rAfu zrKp5w^~go~*yq_Gp_kyurR^&zM{m+*>hBFwc}Z=)eIwORDAcB-FR=9ee%!Y?!hkpM ze`vOakKXb2bbTx*Cr9l2CuGPgV+-Eyz)$f(W=PQS-rlX7ZlgU#@z%VeLR=~ZGQ0&+ zZDQc|ixx!u5-y~MX~QU=N6#XFe)HPj9Pjkk#{LSvh7j4pTAa#(V!bebxN7~Jc8473 zWK?&2Dlqh+#REl1%nDZqWrg*px)r9%g>gO9R)A8D`jN#sAZTg%4n=Fz+gXixU83()q%hmgX<7SvF2Tpe3RA2CoY9DKD$;)MxxZ4#--G{}7uPf@ z2Wud&$e6r;oZtT|O%v!I1tIXY_P{}it~j9)@Y!dr1IS9f&79N)L<3%!c3&oYLV4QZ z<~WFcH@SGD?B7ea5u@40u&+nl%f}vr8mrms6%^e}83l(R4~D-R$$Q zx)`uulwY~CeCFzS;JXAur_w^t`)F<1xwiAOy#k93Gt1%*rGamf0Tpe?q<+>YZw>Ix77%zKgt*;E>ewVK(@21ncMBoZ?nFuzAyc zd#S4X{w$++HW=+IZ#1%L$WH+jR;<={b%<*7-)lQ}1(NK$lZi||E%XPzd!penLs0Ew* zyXHd{6wpc7Hxm0dTZLE(1uMEwC58E{30r=;mZPv)EGk(WQ1FB*E5>uh!7VihzP zO`$*X%MN%OBQ$J^&kiIo6Cw)xyF2>Ub~9X3&b9kHgx7nEv>mM9DVAei_`1IXD8fV3 z?VK|LT8xB>3*$h`m%wf_(2}ADDvSBz9HTFEex8@QKr(z(cGalPB9?F`_3i|RqvLi1 zRCYaY4uSLuZf#5G8VGZ;XC}uIt|T4l6C{Ug(wlD9**tZ>FiH45$wF^G<;~ z%tix5Yu|9AQ-J13=q#=5Xu+u813xW5P%=@@Bt-+946>oM73#oezx?wBvs7(#tubbG zeEY^$-xeB|?hQEe!fP@!Mx@lXc?%Y(hhc+omP!mazu34UV#vn1C^mIg^6~7K5f-st zBwo5~^7?$4LI{@ISvLH9U`K26QdodjN4F(L7N>8&$j829>74MQxo*48Sp|49?1%0B zEih(zm*C!c|*@!PRCPQcPwXoZAQak}H%5u&t zdGo&&@uG)?#>LySJq)~ej(^4bZ*OlQQpHFUEHZ|J5}g-6V942pg*)Ojeh12mg8|&* zqyCjbB8g_I0DCcHOVHyL$@0YJVo&zm=vh%~MRuQXU=rSpz)XVO_o@XE9!a(_^CH*sH-|4dGeeAM6Br&VJ`4 zR!qsY)0)`2lIc&3q;=SVXND>cjS+G-zudlL4;=1Dn&MW~#@vMcWUa+!OtQUBKj#<8 z^mWznj_?1&ydX%B^tEtA4_AmgiFohYe@R)T);IUOGQM+e-QOJ7h~i&F21?PuaNw0W zjuIExaiN&Du4Rnxf`e>t=AJZN+Ej6^qBlbQAN2=AakaGVdRAKRc;XH|XYGlhn;pjw*!un56VA;9tKDQak*;frJ_Sh@ka7Th)? zs#;PCH#}afKh&+7m7VKD+ZIjo1NpGBr}BdJmf?~&0i<_PQMusMcu2MzJ%j1ZkfcC6 z8?XdwBG4X$8+_oRSR3;(J0Z6mdGt!zaDVISYfnBcr;kzbFoy0iTzX{waaF+Q4OwmK_=5Ikrcc;ZYE zTCUuusO~FLJfnjg5Hb%Y4m@GNOz8x^8Nl{86FX*%A0A*UGEVH5xrt~7zIWT@p*bL+ zpQc-q_;?8Rh5X_{aU%qHie&_;Th@`kE`o03gd3X#fvW_)6^dGmchzZNuLTqdmj2d& zQ@1Zkf48kNW&oeQy6ez?@$J_~^#hsrxSCm`=$d~FLSaMZYd9 za((3{C$j2sqc42qWb^L2;{<-S{8{rU{ir~P>%5YzIkW-4SjWBm|Ir=?tWDL z=&-APb@%Pmi5^6C7UEqpMpiTheLS6dB^ON9B;qoX)K%y4oX8)&=kWvA`arjKJzSbs zZ`3s(aU63SUM= zxEo`{c`$yKOz+0Rj2(qbV3+&rXNFmUl1PV~38Y1O z-cvI5AkFXz`@fiTFqsX3(AIH&h7(cAcLLK)cz$ChCB`66R>lqkB1h3opuYO($bs)D$-9fw6j{-hc`Pek+9!G^5OPXN zUu;bz_hm_fCsP^@L;T=MXdXCO-p6H!!@TfsDj4ILC^#uqDqRzk8$~T6!3I#od4<1Y zMWWDPN${5q_xNsi4>0<7yzE}lSB*)OytfmPRMH>MK_R7^-s7%w3ae0X_ATg{ymh`W zt)a(u;*CJm1zQ9>)td2H*=i@Jq0C(iMBR(^rZU5i$_;1En_tXe&hw^Tp^rPpPXO&> z{VXuyk}~qNah6Kbs&!6v16Xl;@URCb^F)O`DbLhah(4uksa|qfM)K(vH*OXSBq<$T z40fSA+`^NdE%$_j;nzz5kBKzQo<`Q`6i_~cW872aNEH@-TI;b&b9uu;L_jvwZa((V zH2?WQTq+u%Z=C2rx=}(aCw1_j;}!r{X&8 z*YNC2<9qyK13DIGGuViP)A@cal~flzJSW5+w%d_LDeCBIlGZN%3rZKavBJ&CdB%%n zhu5cfhLJOnw_I}rqKQHnIxN=hyZ53y_xIsFMB#pa-INW}Rih*)2-Dr?XyS zBtzo;P&2Q~xK>+tbZfsJ??p`;5hkDkJ`H-JMUlw8*)=u4d)j?{`$gw4vTa|7?j_bM zwiYgqf7I4GfaXP|U3RyOL8!If4yvY+vL{D^mAA9VLkHbD=RQ8BHvZQOtCeH(ug>{Z z_S}F-^o3OirX1m*kk~Eo-S#FcWEjr7)aZcpNbGmMVIY|B5=`o}!#M;dH>6Yiif8YU zS?&D(@pJ;it+a=GE}kb|(W?tC*Kr!g^j$Q8M91tpuT8Mt^M#;^b_S1Uccap21MY(Q zL5~md4t96*#ROR;hP5+YQ)U_yV~Qd<5a)XRv)#OKHxu~jXk}&rBQM^Ye^XR;Q`U6* z>_&md{U?#cO&BkQM7hmDIzr-Lv!0{e4fKr}!tncb`O0#AWs#6Yf!;b1IVviOzn{3c zkr^6lwINAX(iw%%WzHdU#d$#elLHwYh*osl{7Yy2Ld`xRXW^5hl~*gtBOiU6W^*zsVuy&S zuaH01^5#J@3x}kbk_RB1PoP(l$khOJoZ#-srQ)-x8hHw_HSWFq%(V~i5917*-a-&3 zw+YZR6Sb2tHMNtY+qNl>ziD4K-Zoc}R5jXV?lLOaXr!)Arn&GRF}FaPxSgaj_$}rd z>=vIr0oz_qK6~=a3_*%XP$^@MiWbZXs(kT@48wQDKcF=5^P9|w z<$|iGpf~e^vx+uHLKce+CTVZfS*dYxEjfW};!yomTQB`ATI6)bEZJM3+-nW@$mTQI zuyh6J5Jd=;BOIq0>~eJEA~pm^=W5h|ig;e`&EDPJQH4w+-+sFHB;={*y{LT1rdy|{ zr&^^m%wa2g+fHL zmm{nsV62SV)0dSq4%x_<;niUF>!X(2xW`SRJJD!@HeoGGL{e9D&6kD#Of~L4dor{G zn~KQgVI1j`;EW)`4+(UaSrlg_V=f<8(FkyhsQd#FjhAPxGGB*3&QR`qJ4nD?;O5ml zhVgoNau>*xIv3gIr{omv{n2Z95IAAnlyoV#u<8P@nF}T81%1yme+Ax z^D$4a9|YZ(mCYWhFDtyhtrULMtb4Py+#vds=)K+L0)fB{e<8l+v%n6h;D^UH-cEw9 z^aJ0_^N(sNioJhXk3-*GSPxYu6_`%KLL5FU2hQ$9GoDmiBs#cU*vkh==Kj0A|BU+R z!KjaV%;`|>e)Lg#oCefe5ij7i`IXPfnQ3qN-s9)aKDnT_SOVRQg-}5`o-2`op5#!y z-$u}u@LzYp_ z0LJ~*iW{muUf^nw6>ibMe`)3_J`q z?&D?8oFm|bo#r&Sp>XqDu;i*qwCF8Gn8Hah_N0x?p^d%1qpPV{pL$zYLJ_Y9D%e_Uox3It;I+E+lqtC z`iPman259v9u30jpV&luL;ho zu{kHD#pRLuyJHzpZLT(R>=fUqcVZ)F-$1p&P5OjS%3{AXyBVzo>BIZ54yE_+?P6Oq zu`3Z>$7AZIwffiKuTQNO-}n1g^+5O;vqX9s>)ZrleXS z;9uO)MrEV?dgwsP`=4V~aRF{s88QCrHYx*zfRb>msE?*!{jky2HH^$Mko&B?4+yyO zXQVQHKn%|3;lK+i)^07bhL%&WhDq-=zko=7-<5b?hzo-7p(bw2PW>Q7`s*u(KfLR_ z9+GBYvQo2WbN1%FA@kG6hYpVB1vSVX0gl0BY2-(>}1T>7*CXiYOiv?!1J>!>wd zvg|^TP+9Q=@{v~9$n!};qSl$e2PxNHKmm~b6QZ6OJ zqxi@qOVZ3xsGWaN`p$svhukY|H{})Ubmb5>_qa*|B8HvI2>Obw(c^nB z9c4vuDH)5pC=i+-4j@SBFMgz37RI5$>`*9IrlEvw-Rl$3THAVsi!!#-*wADAiz4^O(^qa}0P8NLGEDyldQ_VdyKvbb3e7ikAA;=q+wgLTs~v*(mumVG%{e}gH-u1MCk+o) z#?Bqi##51Pwx?&DfJmSRo>LOX2CWxJv_QmM(~I00!bj>}>+tS*P(b;03Sn+tWb(8Z zWPWp`C3P zMZF^`16hL8D8*FM7WpGY&RZZ0XQzw^wen5tir5KA$Oz~Wv^{3blUTD4>qvS>=71lz z*FG~{nfTieB9<#G`1xi?)=azd|nJS?6YNe_|J- z_#rCfw%s#-Sjt=Yb1MkuyzAKb3Z<$Yhu<#ZW+oiovhDjw(sAwESeg2D*01D6C(p7` zG2dcc6^tt^jIS?HMS_AnjEawz*rAS42|3>ebFhmwnRN{*8mx=G6q5u9-T#F;HXzK+ zNq4zsu(^Dd{AodK#DoT#;U?r}|18mm z?rzZviNOpt3wsPeSTwZ7r~bl|_ueH1eEof11Zsq)jbUU}`qxX!W@1P5RSgx5C{kJV zgseT!{?#IEQ4cOKA^w2VF}{7?7465<@9l`x=4+o`xMpobW>(8m-i}h>fM6U+-**QY zv%E3;=ir~n`)@e5!Es~<*YUVBI9FF!a2Q+Ta?MkjgTzk|Rx!s#rO2o{Km5VxOG z-Nuc!3_!KqLb^)J$@BV#bcW1OVv9>g!eDKR|#0#{Zr+BlsZ}FXwJXi(ZyElYISes!KO{6OlUJXs;31y!T+%A6>yn+;6Hg;`}VRrPOd)Cd)V217YwdgU|783 zO?MX!JO@=OC?R6aG?@%M8hq5lRKlf)ab6V!RR1 zaFg9k`2J$qw_n~JjsoCt*VV&Ze;eZOVS#f$mrvcuij~dBTehbAvqPYIC!O8wq{3VI z_F3srQ$@?3E+K=HTtonSiuL6eD+N2Yc1TZS>E@q z9*KM3|BX_FY|{r;^Rau>3^)-?|6j11_4k|A1!`26n;hu5nUdtsCTCF> zisFzW6#pGsYWjc-xR&S{%RZUqcaV+Y>WYs_!<^3=3xS(??oo$#%MoI0FiuEd;mss0 zQN_~NEAW40SL;K8z)(k?pQ*o1(Q;9|ZnDDP^mB7t5AB2UkQzI)`;|9bgK^i(RebVB z7nQI)9(*g)sw92TNa^|~bB>kfx=dR5^l5SegWmRKR*}s{$ z5|R~M#|@Fl4zi`Y740w^P(Ssh7-kOg^HU0g5b!L&o+h5(G}u2a+6Yo47##kSbAokX;PtNz(G8wdzJz5%+N9+x>?&z)eK^$XXR z4sOkoktYO|uIYPkCV_Dcjj6({u#N9>#0^(*EVcS$tWR zyDWNv(qQKeoLBn>Bj2HKpS!sx4s)weE+3mSj%)bb7m7lDY1@d+CClGy|G~*YVjo4X z`9hELX8hJSo}p2barB<$&7)VGV!Z&Kt1}gMelg3fyY+|bmUfaKT`Iq=n>qN7FClh9 z&G(rz(#*ij@cW)ve|3n&HvuUYm^}lkV2%S$puyoj*_Y{?#wEDLM+NPfh4|AYBOj{$^y_^1?5qJLv(Nv=P9G0`Z28{bEJ zQI&H4{!kwkMR^RgNRPg@H}_|*XhSxzI90ybGi4;B)Sy+gCS~%|&69nQ^NHFr4UOEW zna-mWS}?*E>O`DO+;g|ohY)kKN4AC$zQF!4(DVqs1sv%PaJw8w3IIKDb5QAY?Nen$W7}Ft-R_5$X zW>!v6M4u^6zvIa5bzX_eUEp6`-R+Cr5#!e}*GIGo$l&AspB4c0D7?J958u+q$A>xa z#lP%Cf~rYHV)nWl(t_9YKZqU8x;GUr4hdW`T*dlR0o9wXC9r}cPg|Gz}oNt1TLZ>gJcn(jG|SnSb{u%8QL+Md5(z7(vQ6 z*}CvK6AG&NJG16pJ$`iwalGK(tNiuL?WEZu^LD=54Xb@UmNrHA_6mqwy?h<$Q11DF zRbCkO1BUPyH*Cr5ApT&QH&Wq0(0={YLc@xZ>PFho8Y-*en_8ao*iJq3b;b#R<&(b< z4|pf`{sH)0Fs6O#P9EO+x&_*K|w^3ELP<2Ebmpoj;o>?cn4 z5X7GHF7D;w=xY}DAm_{`@4NKn4sFyA-YC@V&d41$HV+LTrFF7O<`s-N#0Gr0-1A(x zX(Qed&(6rU3&oCz*?ciNMQDPiMj?6?rQyTr~TPGlPx6LxECGG3)7xcCE-eXD8*8 zQas1M{F{M>wNK3Ri$p3YAwzoOw9keak@2%>b^;>f0F(@bk@yg#9cfDI$J=rLHH|~2Nvu2p4;#)XwZNIN5yV zMnZ6m@cBvXYFjIzu>FDSM@jf&)I*u<%&W`8Q5z@kVmQ_6@rW-pBW{(Ep*NYwumsxA z!4`#g@)$K7PtMk*Ex-5kaKD8yKbM9x{m!-SdS}~chKAO1@cMtHd>sx@R5*z1DhgkB z9v8$xGZ&*1T{C1Oe9cbIBAR6uXDAhQt~HH{sbPl|Ru$#^~xQp8gb4amCmY8rNb+Cn`71NVh1;Q zW2TobSTq`1)Ft1bT)c~0e^x3+`j=Ii(}K2JIS1g3 zcH+ryZd}=|zgqub*5hE5MTm3HPF1Fxz&nErePyI;AfVI&y3)|)>`AEEr^WWk02!X>@KKpZz8X;|1r4`}|gC0VoZWBr;6;MxzI@~6)Sn@)F&{gQrr~X1@{Jn09uj_J_ zq$=}Izs?!F&@xc+9YexCH(@AWJh(x(gXeRqmAL|;8%#2+L#I?~euR83&XpzEj_nH5 z>0dqE*+&f&8}Uw2EQwj=qcny`ZoM5r-%jg&hxHk!`t`SA$m>tun|={bxwsMZns?`3 z6Objdo>fH(sZY`Dw=*Nct&%fVo=@jrgOX~G6`l*7*HZu0j34)f>i_WpZ_eRPr#kTk z+VRVJ#rF!&X@YHh zoRwaCntEr9?LX{b`QZWP8`nl4_74rR)Z^x6&DRUA>e)-1GTn#h=glH#r^YjNW?P*o z@yPa%-GHW(+~jys9+%tZ{O!E*-_w)6?J1EroWU+GSUWpKH4S5i)kq+ z)>kiQc$s;SlGNF7Hx|CWRnBxfIhxk_WE=D@HkOP>=eM*b3y&;QcQ9=XcbL!CjxnCk zadrI9mX1(_&gd5FC(qf*@mPcZ!|)T$7-+_8`3>79@1}bX8Cf2QcD&yqENh30{*7i6yQnQ7&DG|3n@!rKp%AvfC z{(t@&puUeKCBfuU%%c~6Oc`_9Sc;1qJ7<5-rB=|B=>B%dsaNsL|L2Yr=kPsy@sfr4 zQWA~O>F&zUpFU|Rz41hL8Zeb*0JH6=hr&xr|2exHrb6_e4=UcVYo;H%#; zef@2Py)XZ6pF2B@eJShvZgy)X3Ld}m$zs8Zq(GX#ALHGkC1i5C>`K<_6k5IXDrb_Y*!J$iexkJb4ox z5=6gUWA^u#cH9P(VV(Z#JEuMUl&jpA!LnoDRCsk8m@%wX>hs+tQrBwirhhz%r#nh5 zPj3u`2TK{WYcfNXb83*R%+QptZG^)Hx(wK``nK$Al7Z{OiAp&TW2(uKxhRGc*}-u2 ziJ)VOlI^DFLH^b4QsZUo^JMdP%KT1nnca$&mEHG+a5wG#gKq)N=5Kwk3Zv5zPYyhV zlegZ>CvHiDKgiSdoLdDq@>X9#uf@v`zp-F&ZnZ2xG_FL+C2Q@ zG_BcL1+OM*jf4to(vHQ!kaeUI{W~%=yMBv2iam(P-bj+s(742j+jXO1{S}s_!!vCX ztGa1?AIKsCH1pnqVMyzRqy&LU(Of(XWdPBa6}*aYca_BU^g6f4eJ{qlIX6F&`^$mA z@RG2+(Lq_wu$e$m>~rF!sY9IliA?d^l&pa9n=D1qtJ~r!4`Pbw_@OYSp~$W0L9wyA zZW+F6FAE&Pucet11pnm+)*yfeQOK!LYNV65FBeh%H9y>}o?-lov*)ZWElsi~S^jXU zL=nq=4V0r+(!A(t887|Y_wehWkI8#x4YEeG~G9Yc3_4$?7nH%NEakl%Pe-+LVU5A1#Ib*(sKEj?;n zbek)hNB-u*Y2@1i?)D1O(r(ULFXP&qX0PPEBengGx6`ag(QUU#kebYn`mR_qTB zBd~4dnV!G>wY9cVF3`H`r@e?7IN2bm{<+|%R(KUj;Dt5v-t;UWekH7NLAYf-{Pa1p zQo;3Ia@B{RX#F$ok78vjQo40Bwr-i_l^$%zY=&PBZ{kVL$%NV&K6E3G>(dmdFj> z)TpeA+yOzTuHc~~v2_Jzp#5>*=#{R{oXwcmGnW z;u05^0>o>NS}gJ_9&&YP2I=0Tyi|sAkVdWNdwjgVyPYdg2iw0@Z2F0bd%I~Y9iDv< zc9fNsO;!$P1mvdpo^jpIh89jXc1OoV4M!u44Cyq0-?WVAJ23|3LELE5j~THZ+RFyB zem>U|@*f&;q*2@6htK1ROi_;Eh#gMiE$LzLNgP)h7iXOWRIW~d_>NX^XKtK@E@4m8 zUHG^bFKiDf#*-$RFPu58X6%YwZdjG}=N+PsDEh71-2L0I%sfDSpG5 z4IV+w!dp)iwvudlW|e+&HFzc+tVh=}&mm3jL~JW@o|p?y-YgMv_E+NhIJ494iE?u~ zW@Rw{Ookm_V3;@2&!7j4-~YaRHChzCJt6_pf}wgq)beV?{X>^E<$vks;$NJ=k2I~l zitPb-E;sJ3a$hT`DLYFf4!4Hp&nZc2tImBN0o)IjP?E{#&XS!KB8%d4QWz=oc6H&? z(s#X_A=as(d??Ge;^In)pzZK$r}$rvni6SM7<*X^u1%;nhq`IuK3V>UHE{>_q*h5I z>>PJxMPQxLG}n}&p^G?m+XrwKF-JP~D(|Dc^`6gmYF9lsECx=j4=dreF!_lX2+pW3 z$v5nhPW@I8vkM*z!)%mvIGPE6nW$}XfXZ3C;y(VKS{qHIY~dWx@&;#r+sz&4@p6m9 z7E`O_7c^U_2JmC%ExjK0xG(MdOgf#3{F}I*3X`HgQa3#QM@2A*=E)W^@d~u*_oX(9 zr>1YHBL{sghp|W6gC1jmt~Au3ZUkHZyj>e0U^vF?jq?QMGkYpZ`6Xe3dGzfoeLn^MDlbf}mAB^S)s_4NJt z0=PNC5WlS|0e-JY8fzPFQ~D4YB1fS4S#wpiwrOWDM~Ngse8;lJ%^&RSby7RoaP$XZpm9xGzJ^c_BC;KZP zD_Xb#7x9kxHEo{nJg!uzSq%#=<{>!bK74^&C0>AiLsd<2YZs!^UF#^gOo$rIYzC$? znDS_?KKzmo9o0h#VZ(eT*QY2>#Ne!cDBJZw3SY$4bGjfiN;4mTTl64OROmt3q=*eK2`L`@qCyZifShS6Wv zE?TheR-K99(*7IK`TRMA0XkkcYO_R_^g!rvQ>J(vTHWuv{#J@dM3A8Q%N+Mv`&D?u z1^?@T91zGj8a4^kyJsb8>t^~V%8C;pVyM#RB3CTmUXZ?^_%4`~SR%Y`*NTI^6V31yq_C#saqfn*F_qDAk1;cPl-;T^EwLAhT0vV-mYkE8s4}?D* zlD^GQbCy=jx3L3D@8YJ=uD@@8EVM$Ou+N^xX73hv8*^KY92~x!$a)9-q0R(hEod{N zp?fSolCpYDtH=Ras|f`}s0jPqRS^qy1VLxH+yMo6CBdv>I1D9t{sZ}O?yD)~K;cfd ztv#ol+RpIWRYltt%1!kZ0yL`Q3Gb-9V9q$eK)>e&B9_;{qw%MV*1NTk%%A@ymR5XN z&=4*>$nin9yX;z?eu_V9TCO#{)HhT$#8dP#y+p8m>C(!f z*{uNj90Pq8H*3Wxi?mL68k39Xzs%+wbe^=ezasRFbZLIOeJkESsX5?!?o`eTs;T?1&%T z5k_zDcUwged|jtc9FER*@_s6fjdyWr`92~^qB#a=29UnVnRjh?g?r>HSK44-3AwM0 zSSn{87YEPn+hhw=n%$@n?S7UuEFE6V5AyP7UAM3*9(7;%Y%?yuW<`QnwN>cY|4Gt? zL2Qk!>|w76^KOBqX3?wlY_*Y*fA4fH*;&&KZpa4rG&8I6*CiLdgw1q4CdeuOrurdb zzYNbfUz>aVNW+cVBkP+>lFWzRqNT~VbNeKQDqA>dt%G7Z|6^@jAGg!5~Rt3-XYq?Iw z9*5>(M?zc3=Uc=a^bCUNueJ5VUypGb@WRhrZTe7wn2q4oJlcr_!@$K1gK!|qGy_@>;btPXDjsGB9uTbhQh7{jZCtnB7hbGP02+JNy& zcE3hGJ%c#y8n06+io^s=0`j88E+ss2W0u{Xl$&gbP@h@;y|*Xqy{qaX7e1dM%rU@r zd0faiijMjv-w!@XdV9Y<+O!@NUX0XKu74%aQ3xOusjG6E<;bX@uV6%!)+8!SBl#n# zu^}e7xR+;Ng5W-olrZ3+vIFKl-|*dP*Kn zH(d6wHINX4VujOpC9#v2`6ylr#kO5@0rQMeRWeYtU$2CVmC>si$fof! z+=DM4Egl!k0R(R)o{6gx_GCR)rGf?+E!uwn>;5h2{*m%9z1aH+{U$ntBQMru6WFY3 z`@_#;1#`}CVZt8%hGEO(kNv_|jxYB0gXsn#Lk1F6B4llwxPqP0VPL$+cWS2kCMlK` zt>$_Crwd!x@+XP9fcWjQHD9=I*LrgIL;YP zs@{(dx$f~@>07FdU+b~2PBT8C8fYnO)nB^mn% z2l&uKO(*Tz{BF=cKvf8q%3tVyU)2uRMZJJv6frrhgiP@xj+m38#V=<>|Ja3~8Is4# z&tlQUt1MoBpLAWF=9KBeo%+!T_wd!~Q`x^i=^eXQYmU?iy_(L{s-=Ofx@r98PesXb ziJGYB4dMyT)ncDvn-h*vT0^}9!;{YeV)qSR-am(drvXv5p)NKKb0@OL78g^7)2d@i zBQJA!>WJ-;+P9pda>B0@pE_0z{SVmT?}HR~+?I%q0VSc*)WwuF)@DWN9FJHm~cJEUQH2!Y2=?P;zjO0Ha8rQ%34~}N$)JEv!B`;>5gYmDYGL4S0B{RWuXGcfJ zSqpSGov?M6Xw>(p4i4MREz^=JO54?1Mfg>1ciyTKR_hkmQR|%^H?{&)ffy|XQPWt9 zutlv^TqAjv(Z*G=PlroSq@%z}sc#3BUd$8mJ#IE;Vk4}E1a?Emeg^N*C%7JEDQ_Dl zB3Rt-@Wuy>3lb^q0A??|<>TvfVnwKh1{g8&9XfT@;58BxF^}ah(KWsmpuM$_mmQP2 z@Tp}4XkjHFcifZx1b=h-lSLOAVyZY(a|Ibze=m|E-PiLg!n16KMzNL^B0-?ors%Re zJ;-%)usFTOrvV4EeHyQ1#Rk(9#`S(Feikw6^yulUuK}HzVLme#CT*sdBJnan z9%UwoCd3m$^!|>a39uwnt4P>}a%5y#J?0kfQz&%>C0HP^om5yU#q@}u2_KYlv+-@G z<4d+fydVq&&40k^ZajRe-T|{u`YSzM2#)b?x5c{Ds6KNNJQR62o9dOt-ibdc$l0%x z%Ydy4Zo!Cs&VYc#clTs>c4afccWdr#`>2R?unI^e^iSI05#6+Px^BBlSngDSg+&Cw$q1`R*HEHUymT#Gdm_7wXwYEl`h>Bt`3q%++&UYx0whM+BZyQ zd~)86D268p9^?-v)=D2F;8O6*9BRgna zmRr^aApo{^T^u}f2cz)R6T+SRPV#KiBN$#5M06nrKfvMtx{hTI<$03Vij}#Hm?9hs zW=DGcaop|J_e8c3p zT?=`6T{|J69#~sh5hXx#60v@$7JO-i0Otq}B?}Y};U!_ULv&?TNwpJRVU_@gaIdqy zf`F$tYjPY@SVIZGkWS*K`wTb3zJV5D93Z3V*4~WtTyxw~dM|NoyVKO3XmeQ?>vFfv z@OG;0&ro2b@rkk4dXcJ?@MnI`nkJl@1^4YYoJ6_{m&}fS#n>(5{PsE5^KzN|QV2Au zzkeu)Nfo)*By`runhaXZd?w*o#mH~K9E{3$8*@DH*S^{w8Cl{mh>NE9 z*dn((iEMvJuTRJE9iO;YlXW)(n@vN@QVZ5nv#Z>|ZowDI+w@@1!It+JF%AnKzfDvv zGNciN4L>YpI~7XxdoV@tuSS%%eZw=_VaENWum!hJA4~<+g5L%BOD z#WrIC!p!P#d5UQO@nh}+Dk0t^!9S*2+BPc@Vqt3x;(HQ=etYvP;n-n=^!$Oph?|v- zI$h5Bdw~Eig3rr)%*qiH@L`m<)h<5)c?_4+j<+7V!izVm!4m3uF3eT^@*2#8(Agj4 z7l@a$5$61J>-IK>Psjm(LwMQ9qSysg4eD^;C3-D!GvIwv`2?40>>UfT2z9GqeTxpI zvA-(VMiCny|Ft_E@m993^z~zKe+FIKQ>weo5~nqOApcumT+wX$kmuyiryXxrHny9( z_F5Y?1I>g~&ZoO~@7|qpJM2&Nu@%;wn&#!@L6Sgs3pI`=6XZw}vRrr9Ce?8>AEt8= zL+oM9jz0 zF5c}{CdB<4jkBY`AEF1?%I!??Q|YH1?ZA8nDHTH?=LRXWnJ|B^%@;2plv+WxG<5Pg zuPYvHid5iCJ%L0%Fy2z8BmeeABYn@6vC<|gZ8&YT&>~`AEHR>(9wKe9PK}4X7E%9h zyJYCiZSK_e8`nZC#3V_!Vzje39b@94p-VRz+v$DO@S4(pcT2qkqf(^i$t+QeD@IVVRBI;HZT;k% z8#nq}-USB8EK_q68eE*|ouG%25i{IZ<^?25dB>E!bUwLNR=e`b(Rors8JjQuB^57* z5N6i*G+yeWbw5wODBW@t;$Jz`3mkJG9K}HT$w}S%Ut2#`X;WMfTuBV4VR&{#Q8f&F z|6HyN!86f}xevIH?2$9QqGg>}ESJT58t98iPVndHnH$N(&9xOi^+b<9f3&b4WX#zk zzmW__sACVBF|oKXa|gZmPR+UCKsJ2#MR7zRfmC9TFnWj+y^Fz@jJqX0@X}K8;&;{E zQFT?W_==x>&w+U!1NO#XetEJ4UIvNW4e@)QT6p^FVLyx_?fb7L^AmS%Zy!0hBza6WifAcgr$AOU@fjgm>Dt*P@t!$(67pSSJpev?R>p1Z3NttGml89 zfXoZawl&$5v1d@;)>+jPITmj{iH(sl2{iv`7!jlP8v8g~b?r)9v>s$F080G)&SAgv*bEX5Z7K z%2T};KRv)FQtAZh&JqiKt$;M;e*-G6ox9q}nYV=HzfuZO=3P;a^QW7V*0MidEuR}1 z)iTqOh!puq22EwpofTasHkIRp_%UC!tWgf(5zFj2c2Z(P_A+2Tt*rn)4z5ppCL#~o zjC}LSggjVsA2T|y#)=Dmh^c_imvs;wKGt|Y92D6I-@G{czGgMB`mPbCtQ!(Nx7oB` z^s`t<7`)s3SQRr+gY%>@hEh(FE8pqUQMZGPhdiSM&x~0teNA=Didii8@@2{c{Ffd6 z9}ff^$*OemiM`a|WDSML)m`(7yx(8=D? z5G*iTsq^V;E@h?YOz)!0vYUcU{REcyV8WU}p>;GzmyF*yZxoqV&pFm$8tDdJYld~W zN$Ih9vZYm9rATRojDyI>D;h+kYEV@O^e;i`O5tIfD&^Hd#i1Rf7SV%{BPTFL*L9-(S$(P zr3~}D5%I%H`Gbzzg}UehPjXLt-cBf>IfCdTjA=bSKGWGm(4D=ri26y^-u9G& zC-0{&uSLf_Y-_|#c)hBiXW%OtCkMWMGTniU1DpR)4sd=M+p$ly-%&VtQsg)x^i&Kc zwq>yNQ|E@Wk~@wj=5;$+Sy=&{@0SP8fOM_KqG4KX;QXh*{eAgSJ&<1~vEB21`AmE_PI3I;4E~htCAGyFEpY766JLK>*$?&_elER+03h`CnBx*ijXK2T{$Xk;MIAuqV?%&ipVyO8f`P#61I0l z^O3q;GLgK!J+zakt?ylWekk_9gUHl(>)ZG`*)cYTc&Vlm68Y)mYQEW!3`xd_^oL(w z%}ec+?d;hzRF08=qTwwhKNz^G^A3i)(-m^jBe|-B>iLSXv3 z4{HBvo+V3o7PdLeD2v=&(Vd~hxE}w-%k~>|ss;tm=f<)iE`uiZs&DhSrDtA?MKrb4 zj4o8S6~(ua<`$+D>lBSADlb~xzg}wI%xiN#ds%#bypx;7a<1#XY^BRi{ryKrGaT7> zxkf~m!Cq>yQStMM`}wExq>X=^I2^bKQbrj41%|XHP*;?mmm%h3h{IqB@vAbz^Pda# zS~=5^rC;sRFlJ!ac&FYwa9NXA4k6djte)usx*JeCEp)Ur`-6~wZ}{}=M~ORa-Y7mK{V5lRgxL-VUXoYl5zil7z)`A}Jm-CXB|TgzF%?ix{zCqc zWq==zd_m{~f^9Kx);SOQTG8Eb5@Pe+y*1iDt$gVwyDUH!uU}{lM+%-K>`a|?>g2kZ ztHyTH(|dx5cIG(D1~$~IEIbB~LL|RK(09`vt&cv@Wy_qaf%7Y*%Ux*2RG@4~0!z1! zI(|GRX3N{}TEgn%3w?bEG2JQdFMnC{d6$|WFq!;(ICt66Wt$@^+yu#qcZ7h4|M0y1 z>VBpTznZ#rL8^l}pczLo08k?KwzXtUhJbp`JmfaV_L`K&)~h`qT}CMb(Q$%Ed@v|&Tw!rpsua@C_W|jN%q$PZYrA~#7A@bDU}j<(+KdUVckS_EN%qo z{TDZ~X6rbmVCt&selMA7EA#wRXjnYa&WwfG!AE9$S_v>BzrqkI{j%y<|LNBFfOV_V z4!P>CjIDyqF8wq6gospe!>-rb%w;lUVcwsd<;$fZ5gwD^)kMQ2)mr}G?>b-XmBB&Y z(4c$4MvQy>6v|$(gE}i+&eZJ|mPV?`zY@*&Ea~-+eA;A~ zb!(txUEYNg&SoH1H&+mIjQyMIRx!L7r30v1BX`$;XIWo6zy~ zcKf}6EPN@JrvpUzrL+YWsk^E}(?Gza>v}&-1g|5Ok%TmC=YOR7bp)2H*;m4wHk)D( zU@fe*%Pv_@r9ieyfhNuvtcBI(GBvgM!pfRzlB=Uafr?}z0xx{4d?(9MYEaQATGU`e zu~apIN|b{k&|pfS5yTwD3RH=908v6?JS48&Ss}CV_Pzygqj?lz_DHH6Q5<7^Dc*JK zC9eCjOhq@Z5Hxj>c;T5ydbeXznYd)Z8=h2_Tu_iAB86@MUfEx+UK?z$-|~|x**EPt zU>Q7SWe?As*;QN2mK#(U&mYkn=}<)2h_p}i_q3>VrtoQ~3^THb$7&ko`a*-uk`gxu zo}rNVOK3t}B#G>;W$HE1tknA+36ZMzxjRqn8$G?A5+j{3bdaBczg>qDL&qMYxZB-1 zuy2x@s=S(x&XBjPTtt2>#axHdhYV{oY>6UK^)vw(kE^BNa6UA1%YYWH?>$Iek^FtS zVVD95tS8j+hbkG++}sWr+qoUe`NQ%nZMcP|2#^@n{=+MaG_Usy)zzdSG93sYdBa2_iOrU9p+{~4N6RYr^NsJ+Iwy#Dv@8E!GreXu4D-u*qk238HxG=t{lSel`s?1ysQvZ_>s&@88h8 z>YWXnKuP83o>fXD;Zg^TK+bOg44kB&%!k%j3__Tz1{32fEch$x01a;r%q`G0tIy4+ zFAf%-ckxVCe;B^9^@!YE`inT9+_oQ8*t4HOYr@>G7i-(Tw>2h%^h-dAY;9^rJn8Q= zm}qu$8eYSLyl5r1ao&UuiFeS*&-P0v5cD#tAJ)W1O^o*Lvk9B%Jd zqsAFkqKDA6zA0fLfj$b4VvX+V$aKRTni4sZrj;Rjxvh+vSm{j@L$iykvo~j9P6MIN z?A2oqR!D*8flQ}qwjF5Znfy&fuMU0ZeI_Mq?qLNr`3UA3%C3rVY*sov>ujYX&y-+m zTqHk@oY73KBRb=uhBr{;zu^-3j`~LXfh!%$>dzS59Ft=e+bt)>E__|z8x?Ai+&BsL zQ4#n=ZKK>~L&WMBH^2M(c6WmQLev0Ifk_?gti!83Jhc~c0KUh2D`1|X96pZmxVQa>~;1ESu8XqERMM%WdBvK!1OR?{JDU|KpC;F7@L3H_f*tqgQGA2xqZ* zRCRQHMDACo7FB@Oeql^+$7!}BA{Ari>#w7@O&#IWimP9nJ? z$MVOg4e&|C*%oDkW5Xu~0r>H61?yQ7Ab9yUCw?6S+|-qkWrqyMKSp=&f(*x=v<)P z$C!1^nzQ~-R)%Y2RX%^*(2J?s-P{f7Rx`;@a8fgc(tz$6S%=?hL0*~j?|_hjibepi zafu4wYh(Jdud2+JBnR=7x9cT6iKo(H*8zKseg^|5V7^D z5APUe6ybBCgH{luWd+@4MUsDSn7$&Z1;+&6-vp-JLXcUk33u)*n1)Q>Rs!W?mDFNYAZq}st( z3a#g{2NfJ6>O2V?WeD{*;WbyDnNP#XB+(6hs+jdYagwM3Ylm;~s)1BJuU<;i#2zOF*xKxe8hT&nj-!a^-t);&2qmh z9|!GTtPc6wm0C)UzNR4&)(*W-If^_tKK@YSNW|2vwCJxXpv!_Wp=w=IKTioJXkXeh zXOU`pX}=j7jharEh@OVP5SvBr)#9iIDP}G!OtF*sLDcJ8G!bk5>3X2IzkS?o*hct1 zzk8R>=EA{q0nrhM@3-S<5M8P=^h_{~KlJbg1uy*yZcE&1;Y~yi=g|Btds5x*d^?1(jf1XSVC}4yls_|q~-j5;Qdiwl_aCD#%tfRaJd;uk2Y#H zRJ;}A-)tW#Sz0LyKsnvL`74n*e6grkxgASLiDE-tO@l4;l6<-Upo|hv;e=|vmkg<) z?KQBXH1B-YNb zZ4Mt9kQ0y=R(6$=l-PY^W(C@T@$e;K{5y)~aZ8Vhm@U2HyzWTy%I+Z^t?Ij8i#~<3 zS4w%cR9VZ)mvs9*_`%(lCORqXpc``&daDP8OS|ro)c?~4l+0+w4d4$vWqdUqb&4RCC zh?9>1^~uRr#aDe$iNg_A!~XOva$iN;$2bj$WG?J}jrHK$TndR^j$$tb(#USI9u2m2 zWes*5`>>SNjYMk)Y=iEEU-jh|Z5B;L1{TnpjRdX0&b0 zvfu>IpBqBZ3K~^2yNeN;C3MaC{yz-SjivQ-!QR@IU*cG=F^JW>o`W}EUR%6l@QxBg zUw`6jmVPOd$8roYo;gV%D-!2l;U9^)l;ck+OlBQ?bB2=GY>nb25{=V#wC@6`Vh-Ld zBz_UTR5m{=qK|}Yk2NK9%2s&~W5RQlQsI34sDX0x*1 zNOj92z3loP5Q=?DlYDKeI6#x-qR;Pms9AVFkYsBU!U6?H1n~KJY71e0424;~ym>2u z?FO9~95$o`Vm=3scidSFbhHd8w>BfqF59%o}4>{>X4=E^@>y zF4E>hX@~e36Q2wCdqx>m#J#aFCfpvI-|GbElXtwITWKS%LC$md(_Ph^nEXGmgjoTK z#GWUwWoJGIs}D&-w#2QO8byR8F^8*rE`zH5c5S<;$(EnV+RuSNE#S>n3scDmM93U4@EmPGf$Cc#8_DDe)c~FD z*i7sb6*M|>VlPjch+nQY&6g|;(9~^jzm>6AB1oIXF4Z10EGAoWulFap~bR7Zdr`04na7yU$7UY`c=n4fO`-Nt+B zXWBU!G_Ycc8*u3MY!_Il*jb&i?zS?`vo1%l?!S}s2}T0wK>WsMJ<49bWiUrOk-iO+Ms(0SW?Q}6Q;7)7f=G?%mSvKMi&vwH2hGQv|opqFiR~i zoT5US&dH~#c{ox#36ig+HI54wQm->~*`SXWlX}ZU>sZ=}J+;YUAKp{Y|1ctui%o3& zGTI~PM%xVN1VnSXkCjR#_C*|SR?T$ndwt`S=Q6eoBcoVWA>mA~&lJZUcj{}RKcr%F zs{wX@#!bt}J{CPI@!J&td@9ilbb2F;yNuYNt&W>-1T9?p7?jD=F6alSo9)`#TNXT^ zj}dQ*U?1sGQk2=bMTqZX`FOeckb*4rK4!taoGm!^9`)_H2$g`Ii>}NGNpyg@Wc>Qf z69ZSp21pL+i=Aew)n`G)jR$;D9cWk9_C0iH7^SEmkZ3>YQiHCY0UC-P=uq5hI$7gQ zy?GCkb$+(e)L+*g-404F1K4yMK%f-8FexL5L*vpRpRrIvrF;iXQH}K2d z;X~Yhbfrn#i|nZ(kphRrNj$Fn(D;?#rN+!{t3INCJuyuzLIeg~eBhE}g$B5Js(Xfr zL-a}L>1K;&&V*97Gkci#HS%IeWKEFxG_hq`aC07?>~>_Po3>n}3AkS_-Z7QiRUR2D zZK7bdG$yDX5%HTo=H>(Av9?*wF*1o3E;Z zRAinm8uKl3> zO}QS9XFLqZYH^_*zKa+i8Ax`*w#VCY*_Z-*TDKA+dKY23A2}QnWa`Qj5$IGBk7N;P zj#Uvm>%fqQSFhv8>bC0tsL*8s*-40DE3mn#gX=P#g6S$L0nNd^xx`gNy+$t|1(ZB7 z)0#Qab5^lO;%|0nhRW28={ADfk(nF=%8&Y`7pzmQ?2$g2GptHP<2ZJw(u+tAai>w?G+y_ws%Q;M`D?{5aF ze}u#k&{rW-;1!sP8r8-@WHxrxW-1?OQ?jr@0u{YFDNTG5KC zlXd24MLA;&xTmG{4H?>5vI6;>+%UU=#6{~`bSidRwjO4i8(sd>DA2}Nk5A} zw)UZrDld@-?!{uSMFbCXO-=A00YNNINP89se3S~=Z8&|K1*zSg?e{~^c_!N4;|Z4H z!|-h>BVZ9L{PYWA2!{wFol<53gA1eSdp{ zTFFMUk|z=*+j)zpLp#AXjv9K@E=0A1!V`&+;2hvoc0I5O8FW@W3l@MNUn2`EP;TL8p93vMKk`2E5hZI&>{}D4{9Zb3v6un*U@S;xy zTBV<~O^i2ee^{g(6SXi$yi(!t43RlqD%)Dve{{&$5tT7!Xk{=4X5w%0cx9-z?5-^p^NBHO z=d7ciCO<5A2lScTte?(smUHjh&=sic{rcc*SVlkDnJ){}^a#)YoCFTs9g8;>Y4j>G zv=SVe)(IE-z^44f`n7K&!2i2ng(MM3kT&E}1?mB1IP4}Fw$w`UDKWUUXc8T>y5PEx zZ>D}De4X0$JwrluJoGy=VlyR}k@qv5k8JaNiU`hy)bVt5)S#n=3lxIhJLpU-$Vd}w zQDf=UCl_0fE+f0U2-Kp!BmiEoK=1Kfw=y9 zt!Y(_ZaZ#Ja+u^^+V)5HZIT=OskX?^B!9d#J(+~||53jy5Df!V303#s(fR?(-r7Fw z04=5%Fy!nnmw2qArc8yCXH|Rchu%s^CA2aH4&G|Zn|G6?_fFc>Ejv{Z?wbiLmo0{( zvMW>*?N)2ReADc#EfN0NFv?v~x%(R2u=|r*e}^YZ&NQT@wk|lcNx=9yV))}JOzDC@ ze!Nhwtk3SrgM4dxNA%cyr0XNobgqTW<0ay$NH8XRw8`u`n0zh={&~;Or7d#gWV9o zr~%9G7Qz-aWB2yY3bWbH;Oc}&JL>>3oz1mynCiEv@!4(`?ewj0(oX?UOy878tjEb< zrJh(DAu2UYqc~GZH3@NA!b3VWr0A}RwMuUy1A2yhQuwo~d0F{E;=wqb=sEWB@F-)k zMac*_<*|5>^qJaswEKEax zaa!H42~~B}*zJYBPQ7xjWv&_qG5GQCwu_|ksIk8ZaOFvII#?KCoy=BzgipT|I_%Kf zYQ^6A_6GlVD1X4>ru$TRyP>qbz)c*rUjcHK8A9%Y@CdA+KmRiTFC_g43HNcmWVefs zmVG0Q)PW2ii5IjD!s(}0@!(QtdNK@1jD8Q#b3aw5`Q0Tirz#Vg`fYGt7We*p0>-Q- zW;o{|Ao-|(=cCyr_o5JKYO!>iMZXraowae}lw#^P;XtH0s9X}`s0{db&+X7-9%Af3 zf2zPK`==weo$IHoaT`!Z#*FNZRH}g#C!`*S0xusf@^6Fol9@)|Hy8=aaCBODtf7G;~C4nIMZ0M#KJ9G^(*dx*r-}k(Xg6E zu(QDV##SZOLCEihdGa^S^mr}IwAI$^r_t+(p-?SiC@aR>*hjnml-EeGtR(ZFDg#kst#3G??FL{6DJRfxD8f z3m1)@j%^zq+qP|VY-`81JGRxaZQJVDHafZc{m#APj`I_$YRy%1KAN#Mc>C)iU{=(A z_10U9$E^U9{)FF?87Vc)?$b3?aaMVSjCzq%l|d)|kc{tO%0q+Qd7&a>eI}DvRpy*?ylVaF4GadkqLz z1Pi#aH`qbsAz~9BorMG%j?@M0Amh~08&0CZ3Zfw(J0>Z~()u&c-+9ZhUCF8mB|{=` z($~qs)NxhMyoiGeHs_ruUUkGLOLgB9<6HeP&Qn=#mJ6gK{dix84Wao0EC~Ip%99Qk zNKbKx9o(rIJ}iY-y?$+v)W&=v+n!aNni*9MZeJhI;q_3s^QC?Z%Tl0tUUyk@?Bn3+ zZ*OnENS{nraI)nVY=4-laOlSQ5WW<){hu*5nk@g$+P$_TDl^fy!fh4sOScPm5>s)o z@RExkl4XA~U9~rdae7wm*{7ma0t={lc`Cn@Wp-gNs(*M6%--Z4QyHj&v`6tzed8%@ zGB@-na>24d^FXKhN-n?h@D{X6q%7~nc4Z_G#QLar`FE#@V_Jbo_J0`ScUNNhn19VT znN%(kkBg3Q#^B@wK49qkoCtyj_JuV<7hZI}S&Hcu`xkVjn#c;Itvv;DI!I^1>QUVn z%TmnJCtmF(vA=n6tk~CEL{JRt1W{b)l@h(L{d~9DiSYohC;y%x)e%&X!B@oHz=H6y zt5tu;n`mpp4mJZRVrmr~0E?;ud0Fw_KRf!yPEFFVsYIgN(i}C_;>;&a)Ex?wNvOWM zJo#HRy<=SI$VUI;hvV500sk*Qyw#Q23DaY3m9;CZ+C8)bQxV#z#^No#WxFrbxenjB zRKCNv+G0RJ#ni5uQGJ*qOX5}|BAWWoEd0psHyBDLR0~&-;c~FcW%r#Kw`#j4YDM@F zqX($bA+AcDq3J~m&c2KFmKj3G@?^l#WZz|}jaZhY;%jY?74smo@)gqv=4 z0~5X2^F>Bq`v&d@!xXBtjDNFZ&5uW5#%}jMu7!L4+Ih*<&V7Yp7Upe7Sn1?J*<*Ur ziciolGLM}YiTgJj6;r&?3%80@YE##?+-@G}2`+F0XC%R+Vz7E_;nbP)&XI$4xRQ9*0*fjD6IBfZcAE&JNwz z99kKe%k!+T$l@s82M&Qul;ROK|b z{S|G16Su0~avvvhQSE`4rVJAnvolBa4xK!KuSmXD0cUFE3ZZi$S+Lc;`DlWftr-|g zNd*X7;j-1!$=*A>I44gTjzU_L@);8LHTEh=xj(UDmphitzs5 zy~r!b=Va`(I_$C`$;sHY=(t_@XnvRvmMtLGyKU0z zNCb3bHF1JXC%m?xl9Dz7r9#2B%bc55{;<=V8no{nlO|}mG2ZX5wD93_s-nr)w_xR9yicPDyZIAfGD1_=E|Mrd#L zr=lx}>D0|hg_7WfkDxaFdv9`V5`52s(~&yPC(U{gDW(LH8o8fD(kF60zEXCyy~wQo zNzeZcdS`RYU|1DRTO{{X1PfQuX|do!w(e=7_CuKFGqsnAlU$GXxjJ$6rD~${sA2&a zVIuSEjvZx8yk*4TYMg-`Sp#!t>F9`&8hOs=JQwa?cjs_D5Yw>RFJtS@N!oF)GdMTuAa3lyLjwOft3X=3lVy`d5KP`xm0l4Tp!lZHx2$){>l}gRyguUdE2f zX%;S#^WthDh|*$wWZ_w`kq$xN9tNBz{X>zY-sqE}aW8aL-2dXR=K5hyNepH7=_(wG zRva8Cecyu`(lf7^>zplLQxbg>|0-})+O*(i*CGuE)KRN2nZdF|1&mPSjCE%K* zH^HYFzjAkB8A%xx6w4ADc}21ukox#O+?xu!jSg-sl-)Wa*ST2 zsxnGqZRXj5P-1Mz=HFoHHa{*%VlTe(dN8PZv>m@2dEUP4dRK|-<4_~{1z9NinP2aW z(Z{Q!6@SyPGf3iDYK9+zhIR@pP<^6jql$^n;7>=#fYosLT>hM;ydyg@=EfvZH+&8O zvf#PS+w671^cm&Fnomr61=9_~5xtdxKv>bfpp3%c$9uQ#QajNp#o;s=R}VsVFcFEH zY0YVyYTt2GBvp2IXu zeC!a97UMd_V^=2G9!=kOWI7T61x+cZFI0E~q4ECc19ELhO?9FmyFKf1tQYZ$hl0%y zru0k7b=z~%Xd!$N*`ZTeP)ckxk%u3%>x-|797#esX6``JKkhJ#bCpUnB_y0!NYLb! zY~P}eXzhnDz8pcj1e+p;79xv4F#CX0QLohKPm_UT(0zG3Y}iJbM(-j-?7ic|bD5r@ zIV&(0`VN|73G^XTC(`E8X+RtELJX(kII(;IXuIRPTSj9<*RKE;Yp;@2YFI=B>Qc-K zk9ivi5$*cl&D(@la1eO>x8MpgJIr7au(&|5(76;yDL*YM!$1bUJ7kGgQjw&~2imistlOBhMsEyPZ-j+>bNVcQyV&Lh(O0_4L8)j@IZ_H3dfNTp4-y+&H5Vgmzwo|>jX zbN4;*93;B=6Mpb&NMd4ejNSsz#vb%_fUVqE0LE-^x9N#gw`Xm4r`Tf!A(tC+DqXQu z>07F3@)~ZViyPccig5;HgwJi2&a{e^3v(8cN0tAlFk@nX>1cQMRdpQ{qWJd;A#r5? zUrn5W0T><}W$cR9EUKtNsT4x#_V$N1-bM1KYYpL)xCPBH{h9jkEo%@Vjx_(#67xE8 zlGVbkC`F5O2gYRpfpKc*;QXc5(RQMb^9AA{cHALtz7)Hd#$BRA^zw|%VgejEOaX+i zEP-M3T8f|vxFCw1QoZ^eWWetdp9sA!0XqsKHf^hvql%dT$n@fh!PL#q4T0xC9!^o0 zewDlXNiJloiVzczN^`!FT{j%#E{U~)XVhv}8R>(Luj#KOKGNl6K*52qGt8A~ zS%uyQO9V~|o^hN0)Xs2a@;Ku+XU*(3G}v9Yx1}$BdMb8z{#Wn-TXo*Lp$1dyGA27i zYY>M9=IzBdPa_BvzOzMqHze!+?<|mlc|m~T9L6f9lO%iwA3K~JV4v9VAo1c)kauHD z;I%9rh-<5fLT7+xV=?}j5eO#8SfL&(UY~Q^K;&_W_XA!!2SNb=#?PyA@Td`y(-Zff z&hvt<@G2(|f9^NBN;~U%n#2Q$))Ft}Xd`411hGGja0k?3cxP(fE#i3D7?$v552MjV zEIpapJ2Q6Cj2Wl#?;m;2ZM9~Qzf`G~L80Yr172y!G*hYwIv4H%gI11|XZ7+cP&HJ|0 zA38W|Qu63+uq71IbaaI)D8rpH43%hMJgE@|uNiZaL`jUpSg`u+DW{F-M#GUhJ)V2%;bhKYk|)GBls; z7j9DYvaj$ZBwBZuFumZ=iL!nlR;8%ZRi?O&AFV2+ovf~`)H>+3IT|M?bZ1Ik`iP%n zfBGHZ?fzbM_dr@y*qF|i>(uXx2VM%KV9+EWI0z4|cX(0)Nx)S=$N5?#t2wLYs+oq% zWt#sYh3;Kc=SN#XB*$>*c3rZqb(!P65kqk#$@&{7K$Fp(LrQgKHRjPl#VRISMX^Z-WPC&tZf@`7RYu zeX4wFhhH}`K}9)wk}ssn1jLe3e848ad~@efp$8#(l!GbPHHUc$Wir)@mRoA;5n;~= zEQ)jbK@{6kONoT?L7Tdq?Ic=O*yLFIsOuB0Ra!tus%oVKXfPCGHceFDC2ZyC`k8Vq zjK_PMB~s%nnUysD+*wslacq$wwd8i+AI2`DBz>=#xW;LbP5y$A5Z3E~&BxQNFc4=etchoi z8)8_hK}ay043DCMuR$}ieq-cb*A^I~`x;J=#$u_#qx#wU_Tal4%m2}YC(+>tg>Mxu zM^@qSmMkb~Nt&)Emhuchg7%u7o!pBz*dcpZ;_h)5-RjKA z3PQqLH*0O~5mv=n=xf{$3{8gB2+i~jhR?en^>&=kI&Dt>)WqGefsKVzC}Qd2xa|3H zfuV7x9UBScpl==JJs-v%RBt6 zHTnqT5REkr?O5p_YK83F3wr6O9y6b{ZX<(^!Q{Vs`A+bNwHtV|Vw8I1XqXxGcCNL^)jZRAm{tD7z@ zTbap~URg5GCwp{4JXe!45u|pEArQ$3DINmtrbjp)i=#y~>!H?*P$CQ(dT zPnrk1Gc8Kkl53~ZCaUmwN$*Y+YYn6p5l?K`dc`T8HLQvP9d9d62Zz2w^9*!!-ruAy zq2nE5ev%@iaAAWQ6uvF5kpO+Hb&b+}NO30Besgw~y9!82@nS>;17iMSPyxOv_edZ^ z*u#tvMmtSagN{D%qWR!4gchb?wvAAUDlm|C`UeW=YZn+{GcDtB+ue|{d!e($w`iqH zfzpb4S=x(s7dj3|F+@njcI zSy7O~yJx2L1*7Cymr`k@7cs`#x(iqH5ZS0v$LogM82rF!h|(mn_*aS*?Zt{~#FJwP zj)zO)n+Qy5V@`?K!ClCiWYFayMt<-yNi5Ww`Qb?vGI^AekEI8QVGy}tHKKzpylCv$5Qtyv8#NIlEoy4wzU@$Nw+8Tqx(MI`9v}6E8tqcR&dfiPCTcXv- za461f6QahALJw^1Kq6z+2-;5ZvDr!lH-{Ok)Oj~;Pf~Kt0y-uS0-9Gd%X?RNm)5;R zn>u>(=Z6#AumiwWX#mybC5>tr2TEovpw`dV5=>}s9_+8#!)(TTf;F$~o6}oZz=3sn zM1ts42CfnlP6em0Z6;_gxfgU~0+Ezw+XxOg1OoC}0H|2j;}a_#O-K4ZYn$;7dg@jx zRzn5;UOa-MY%T@_8u_KyG`OJz)=p3|<{@FKI75`?^aT5va`ke!LQi3ohLh0lY~iLO=}Hp06IY ze32Si0C zBPzz(78}IMJU&}XLh=~9KB;uzKa4`8w9n{NJxT2DPwo}RvXxyWB#!1c!y317xm(9C z1`HEfK|tnLVZ!#RJ-rnA#)#)i23*b_q`Op@l(>$_k{7Vb$!XoFytJ*I=W%&D*}&?`cbS}CNXF(TQnk7g5nD5f{{9%p?TnxvOb z`i@rc6Qd_r-VokabB-1uNgCw`EUdJ-Q_@6eBO=E!AQi$YnuSe>A?u&?-!z>kdY#P% zl{u6^$}90*501OogNgo0{XWL`t_eE(+0r&0jfjh#+;ST- z(&qg8801IPtb@0R?^ zKyQ}x+9ld%9~aiMZfE}Pm(wDuH1%+jWC6XO3W;m+ZG=x}Tt(#mI-`nbT5C+e*5yT% zszV$iDjWp9nHcAI5s!Qz*s9S!snlo+^03lPS4TI z4||obKaKtMzZfY2W)S3&7~{emZJe|_f#K{!ltrsi^`O`V!_`Dobm%#W2%J(j!&5O^ zbU5jO*k7kWk2RRe#ey=HH*1s#R0#j}%aa|dx8LRA<}w=T$+1*?EkUAtGZ+%beHC_M zk7{z^ItM05V2h(nl5ozPz3Y5en80R`Cr5rhR|Js;!^dCQT>W3*_xM83P8k@pS5eX|aZrA1L4XxVqTlmr1KEw1VA zbiuabZx5gpUcyK&5|hY8=e(%pX0Z_4{UD1#!G80ApbjI#22_Gs(xqDG(cjrE|Ebu2 zC>>SMNYJem-eoU-BK0##{o}EEhat+YVhyp<94DkB-xA9d8r~u@S5T1P9YN=0;#y$l zx{&8`LT4(rTKs)n#tl-?iCN{=zs={fK^Z#%)8yGO+lxv@A%1dyG#P5By^$Y6wM^T& z@Dkb#BF1E@y(a=YNsSU3x)B{hN4SoQvs&^OMZkC?u*6vSQgZy&IS^+xN{6ek`}#G( zF_2wW?3(jzA;RP3T+E+W9^y{y~c%@LbotcnVF2i(nRsLk^$jbfa z)PVEVR%EAx?4q4lhP5hiq_bzQEc=E|Ei+uXbFK5b;ONc0RmSMmL@(-%=<_6-i<~=g zksBpJ95y=|N!fb73MnlB&R&qkSsxmW6Ayy`1A4r$ zy5_SWh>ox&HQ-*pMslkF0bBnwsm|~+2Fr*B07_$2%dZ!^G$o&|HFO(1Fx$N#ytcGu z7uTs7jCH)D-efSN7M*|;WOE|n7ctaO%wx844jr^(jdD*VgX7saFVl$n-E2((Ww=Y4 zIdvt0VJM*t#Da#>K|!^(Ka25QKeEoWWa}N_s2M=f{vM!J%43fAF7(5R?$e`EnL^;0 z*Z`IY*-Pi}tM9*3DLBgyZ{|gmjNlb3IsO!|Lg++NOH(y9wV#ultSf0$&oQVdo+o%q zaal+=-N`}0l=zVC+0O-Q9gcQM4d;NuI#Ac$7u{2XRK5bLc!$q4hN(c8bNMx2$LU^l z*>L5Q?kM!JGN=fp_!Bp?J?Kc*%-~db z6`3kPrF(y7x%efG$&R7OBX3oQJ)v8K*582Sj_h@39fKYFg`O=+RvJne24Mq*=`)K|i zjHt{Y+l}>0b6Gl=@mFE|MEj!w^1meVxIt2s!pp!Vu;jA{_-#JvF71`V=d;+pE(w9h zrbVa#qrUF$Cs@k7lr@QHSBGK)0rrjj0{Hg8$S!I7D}gn!!*&jHN0f`8R7i9z2|dDJ z*N00>aV4U)j%wL~Kj=W*52e@DgTOS34Gh43a!R*9EDp`?H_l@zTey&c%8K?j{9%E$ zJes|tniUO}=_*m&9s{9xO%@2etMaWPv9jW^6{Xal0^IRWW`s&M%42bi_V6XE%UZqF zCh1wLRmr+&H$1)`SX>{SM?n;>LkEhWe)vuBqEaW7SRHF%SRl6 zn6`Mnp~x=H>SJJZ#|=++_A}(Gt$mL-GJ?HaM*(k0KoUyZ}p5S=EQgeEgMRp4!$j;F!U<= zl*|8?@zO1<>XbB$2puqx*^gsX!s5bi!Q=pXeHn8zIZ-_1XkNwHzDIvdK)zB*+4Pjd zxwItS1#6yK#vIs{1boXXFG=26=Ox0R4HAc>|2M<>y38$B4w6=?r=O(^(8s?w!PjD( znb%3`4CbQ4-7epLYr@!?I3Z0^W%a`+eg`U(Z-w6;y^6X%v!K~E`iR{JIvomu_G#9% znX&CIWcrkx%XS+$Qh&3#qv@^>5XPS@!9*D=`(DB(H*<{}O}7(-MItf_P-I*AAyWL# zK58G+)Hf8WgPO21;~j)goh2Jn+Y%LBt{qLjCj(?y966(}n@nJdYcJ7y;f|z_xQ2?r ziYar&hutiX+6DbnrfI><; zBWqSTe5Av?Xksj3f##lgI)ON=)>7PSCRggxQ-ki&R=x2sP3j9V@ssx)Dod>zBqG0Z ztC%R9I{w{&lqYWKPDV*-mX@HdpHZrC*cgA@LrPvZ|W;VzP3WMNG!4F}4-Fvm&ifY3z2l90KaCNqkW$VR}_ zHX_6;9v_a?NS1nUNkQ>Id4OylTS|lYAv<`A@+2KX77A#!OYzP^5|U2Qa5c`6nGo^X zsc>|0=Or2rE#gprp+`qE_XQ@>28=ulV?}o@BHl#hJzK*2g_AJ~x9+64MJQ*{t(e>b zIk|4}R|+Z&f>2bcF+BHX0OX;5O13vM0}LmeFaSmpN_=6PqBn>9xuM0Ejy<02989N^ z5Sr$r%<3(d@g_xPxn#oq>G~M$7G5R&yJ=thCedQC>JT%prp}SNRKXT(1ZZp<>D~S!j}ESBI7ht^zB=%F{c*g zKrX-vkN~xJRP8PK)*l;5J%-E*iwS?;oqq>X0oiE9LiKC$FcKP-SIIDZOY}bR*a6Av z*3sa(%|6iVgjrt`GAUod*ISl|&X%QxcGB$}}@NvOq?|>CwZEzfAsw znaW4&*Ls_S=gDjXR2zmBz)T97vur(@s(9iZ&dDdFi4MeS!%K(t^vz!;spUbDy`Gq?Jg@oLGNj|-!sH%!VZ)%Ot|5U}@jIQ14>Ufmy5+ln zuMr|i{yCMnwD|Swa@sYd+;r|gjA;x8LPYS#!{FN`rkA}(^6j||)OFw?R_LuVC6wj! zWm0}!{Kepp_Mh=qkJH|oU*$GXjh;JwHkkoYNjWb=}K{yH(g!xNDt z&q<?eQt^qb0)7m^t;d}O@yUnnr)uQ zVx}Q^IjeDpgdHZ^G!%+z)^NfW+SQwCn^q(Kj5B&Tpvh~bicZl9(KjG4*3g5yAb+mC z%3#(5ND*1JAI+13xGDZkMMIQitN*hdG( z0UE<69T~O%Q({OILA zeYL{5Q~bswnnJlv3~NHyZMCN0Ae*|J?Of1t;H?wO&{gg&nH+3^Tu3A(Uj1r=3aCsGhpXFDq0cGN?q}Tnu7|=T1E!%f#sA7 zCtp^XTn$S;HVkIqx{?Rf8nHklCa&uWn2cMe z(atlHI(EUt@D|*J{n&jY_~G@p2DTl^`a{$w(tUCY`H}`6dSom&1VQStf@wF^H4g24 z6Zj!MvFg9xD=?uvxXL}$T~w0jq`*=KAnp3G9AA0mDU(|*Lun&*M18mm1kulAA@ z_LhK-k>bQ_BybEa46C2c6G)_B|#}Y=&7FxWE zS_);oN9+H^e2sBhKPG$xgzk-lfE#HAOx4gTdTljzeqrwl_^f z-o|I4&AmPUdYa?h?xf2PMlgO=M#Sx>xyI86gEFl}2K)ko2t(qhOtd@y!)9JbJ+Nsi z4z#a&a>Y{Ckf0y1ZN&14Ac!N%rA0BRa;TI1F<%ahJl6gY;FAlzd5JUi<%KRkCesuM)y^+5WT?Y@tct^2%BdBWB_+w0tJsZ{jIf zbU@|yM`~wIp8Q!foQo1j6QP2MlRoAIEL3Wag86^Y-Lh>r3kOoMrs+BMfD*$Eo_x7-vg{*8DuXm9LWvmJlE zv9%i(>CI-FI;vD%M*rPS5d&U8Z+!5{ztmzSF4le_-q&)}{@U#r$zd_B+b?JYrUAJ- z2%CEDvBG?Y{B#Qd>zp?=;0E>Agsf%kVy`1ptuG5|b29M?gE&NLiK8Ywg41e1*;pA% zPt+qFtM|^VW7}t-m0isYmQ{WEk6dDKfnedOJGD#W*G@p91X*M8U7OCEMJ*AFB8n31uP3R!Dg?xDn_#KOBSw7mR#!MVj6BX% zZ8*@@PLN=%AqMDQjKp3@cZvTIO9|Z`Ix3X*{02;zJ6OkP3vBxQdE2wBXV_tNJAv6XV}v&J5>WBi>z zYGKx}9v|UbgFP5X?J9isLSZdq*?y<2&D1yE)^4D0>34Nb)%2jFq59aUu1&g=lk8*A zhODEPBx~hwS^mxViAJZbdhFVR_m$5Dyjg6-4u>)TUzY5#xaeqj)?6!9knOC_5(mUt zwSRV5yj#S_f4uI68Ee#pRc_SpQnOjekp@Jb|qQ&FE>0|!T&3z7>8%)DUDn^eL}$HJ|hchkEpCGj1>0 zgx`uKcbZ>jbXSDgVu~DEAW1~G#I*o~h3RSS=M1YIG7%$6S2=QN)J^w9DkyX+IMghd z&jh-G96!-F#6%Xo{wiNPo^+A7Y%M4IA>ct@k?&9T3u;{%QlQkOi(Bo>=wyd^$p_ML zwIrZDZ%AOKp2*8>2!agE2YHQRZ&{N!;nNs3kUs+(ExK!>HBszIH)!MQx7nT4I?M(v z!l}?D_&8Cs*^5-@8kJ)whlGoL&w1i|wuGr$ZBSz;*pnPy*$y=OpWx@AtfU18g@Bn4 ztBOlOhSYy$L}E6Qv>yq+1i&>0(gF3%FgD9-PekM`arv|^O-5v&30}oD`|^kFR-^2o zZgG3iVMNIA|A#?o@g$r@jv?x>7jbt9>=zlggAuYIo3AZQNGJQpnM4O=TeU&w8=?9z zmsO*b$l`f`sy0+Uc#(Vcj2`|UfuefZGC}r37jg%(0Y9WK&D>Wy-_ifYSqOPVe9L(X5n zWI1J;FOL_dHe%D643?C1fw;{!@Q!BUd!+T0DD%%hKNUOJ`RE9WGh2NKyu5EJqq#>5$Xoiw!7OwH4u{o&#I-$0%*J1aMKW z40{wP&g?7Ke_>v4OT67q=R8ZCo&+mfiyZE&Yu=ItLN)r~{>h)ne46~aNze(p+apJZFm!gV;w#<+RPoRvb=+`tu-+(i zFiP0n;k>m}t;CP9poBqCtRN}ovqMkDi_jt6kKnsgn5;j*fgI)ug8&7xW2zsk{6jUD zS!l)E#h-^kG>i*jP5`MS=&?(E-}4PRK(`BC#mHoXZl;F6Xx8xVZzgtoJ^zEx8chRZ z=}k+ZR*g(a&EzKc8hoN|^;Pu#-h~Gs0_}1>I^at7tgIu5xs1k&g0hAcC=}F`+T=z+ z42mpN40yyX9adW5lMXoyMm(R zBe>GvyAetOn4a`igWFmv?Jh^er?y=xczse}*tq>wXg_#z{kfz$XaT8y()a02FnNT* ziFnKLuW4i#)*Z|uIWc)89>X%u2SV=|jdq7SZ*vX^{;r=0a-hI;vv#sxz(xnY8aSUw z?gA|Xb*C=b?76fYHdKt_Pd&;M(PI4?3&2)>R9!ec7XRyjcPFJk0h7aFAocFENN8;X**lt%v%w!rblS ze=~ozw;)H@&jX#Bhdw>>XH!-ApJXV3xyY93w@^t)psoi`{Nk!Gio)iCim1VCT&~%a z?fE_}i>lwTUT-O#FmCc5E$uBqw3XaSWYW(~_GMU5cb2Uje~LP;)pjpPyERL^4H-m4 zPwx|QGi8%oW%culXqlCkC6oMh$^A!d0$gEvkZoXy#kSiDqm|8M>Eqm1@qtOMH~;nq zVSaxO7AEYB-hvMxfidwx)+9h%O1F}9llFEY#(ri#ZuP#(>(p@{#WY1Y@n$lp*y2|9 zphiN^AiZ#|bM&C+>LwrJb+!oOVG%kYyS=u2*%JD%(Z*wcf`DBOA_^fV;z!Kkgf?_l zVjs#vs(hvN%=UWn(~S2{rZZsy%&me^)3ooE9a5A_W|J30xna({gj0*7OY(J*!;_3F0pboHQ|0AC*Q9--C&JLi}uMNln zqp2sx#j@el31VX8$b-yGdHo5}oaiJ>>m>jhCU9QlUee#kLa`$S6@$d%WrXlbq2aZK z`3*!Z3-E4$y+G~3lY)=Q@rIVh&Q@(%jgmM+|c;0kdbm+MuL->uv1;Wn16N6 zZDL8VCFh8hKk=kj>k>JR`qt9iK-|n1d>#%%YJmt{)Gkn$**EKCip;_80lO)_k%QZX z{9H@=?M%td`6xo+NjgPg{c5rccN`%A(fwqgj6Zhar&gNcpwaRHECHvdX`=wJq9`UZ zEVX;-3Cx|riSxYjAbWpS0vnp^&>CUbrtc&8JZo_T17=Gh9!4U}W&tx^+S?kH3SWll z^VP}N$M>AF8AE@H*viKN+DsH;X7(Y2y0~~4Ma&T&Cy2J^95EoUP8x&y(PJD7N(N>c z4g!%j+|I=ucqsY>N5AG0I{i=NepAy5Dam)t1SKX>;Jdkm3R_CRP5zB)TPciLDcQ2t z4ZAPsQ1#i0m2VTj@ts@RG|lU@$$yR?`@-begH!CW^?bbBj)3%^4R4&7CsQa_{|;eF zhrp;y=4V^vL=V-QhuAChUF}2h&a|?9lDDa?bta`PMp|49N%u>9w#VRbqMYRBK)w(H zlivFP(jST~%v6hck3A$hhvr|gEp58Aa!bJRV8P*BywHK4qw6PmSaQi&>-g{!L4x7s zU5(N;H>}HgeL6$KOF|6M5XzYbBevFDk)?f#bdPkD4AK|7oDn$m_0ExAt#!^jE7UH& zS^nEvd59kF1#Vxbfr3SCMZ#*!Le2$K@730oUY8j|W<;M93N?BC>YzOnNWzlO5kJqr zsJNRGz}7TiNI>RtwENlQixli1*&O3u=wm^HpxuHm&pW}1TQnBC;pM+U-%Ao2Q2?kw zmBlhUIIjWkA%s*;B9L%k$Eue6sewdazU7~o><-MWb{TNOh$hRFwJG6w~4 z!}wGu*3prK{ROZ+2WI||J`QyqteG88Jp`tJ_faHQI|?5zW|f=L0uGR^b)4OkZfNCj zI=pM=L2V{c)nO`#nC%*U=#N&6Yam=srCG7g>Rm+VK?)PL)Lpy-mC&^kpobnVeJS2w z0eGk+Ds1v}4GaS%L)w~@j@(iHTs=I{(NL^oSi*Jaxg8j^Zl4!}7=aI5!7}fFF3 zWsnZas=9_#-rzmJw4e~w^&vbV(A`=J+Z;%k4$)nv&L~2o9hI_Jx?f`nf_V;%0%$g9gFzc&&0`?cot9Ce^+1|llBw@@_lSQ?_zsC}=W4L>5 z)Bch?aj>*6$PU&DWQJiIX72Tb$nW@zNGOz`_Ry4TtZu%_N|HrUH(WjoUru(Fe zyTYY6LT63K*-#B=PE4zt(V$yBpA~R^Dq-V4_9Ghe0Cqyb{~b9&kL#`8n!@kOADH7= z)Q!MC6ZIpqa^m-TM4u3Het3gqCR1TZNGtV2vkxTg)P=oFkoavsl(QZL@I3*Q9i^7& z#zNr&9v@B7Lif=s;e(dpWkAq4<@j9iONj27c-v5-gNf!l3g$a%290hT3yZgk5N{OR zg>}5-$ou|1$*EbRpi_^;-K|NUer|e=Lxe^ae+Xmy>&ZaJL2oD0dLAzPCS%D!!1T3f z|HN?EzG*0cUEP<^PcSUVy9-e%`c#!4p$!5EB@5xU9&7%PTCSP+ADC=VHLiAnA%9z? z97NAhMG&!%HuQOJd;Vz`C4We4J_GG3J>E;pj*&g$G}Q_mXydb<0on z2y49c?SqFk&mVOMQC7#rNH*3Nlhh-^Bf}!b`@Fz|;jHTqR=-PI!Ep~@0=3ny2(go{PdJj9sb*RrbM zYZK(fp(0^yR~Aoi{Ce>d8$QLvNdgx(tkP<`^5jD25xI|Q)j}^#YZcG`!_-^GHTl2q z!<2%85(=n*q#!v21nH1YrF*0_6A(rZM5P-fCFFCdKzQyTv{r||Q&QaxIsYoaQavq7gYD;484HQ1VG;a{ARY#wv%tB|7uB=E&)(`7o5YR&9g}=4l58{%!B$p+ z#J-Ty8|LA_l>_SP1e19tGh{1#9<6aMdou=J9@3fwTzn{5Jn1bk zAvym2j>12zlLP-Iw(Q`|Pidu>nxpG8Uaq5yVJTw{!~^X z`eZ14a>6h-p{>~7kH7R2Xe4P!uYD_h$N61g+p8B4COoa+4p|Bxam;8dYQOY*Dc97= z^E9|sPIo&tL+iXizAL+X{_Eu3J$AE?)WD%6AxOFUcm{U1`KCsy0CYFJfzr=gzHsLq z$qc16dCyIaXo-Vvk!0~T93(!u|B#Qj8_!RLChi37bme#?0a(OMZeBNBt~hm8uk-DY zB4POu-28#dY(;xRo&v^#F~+cU!XvYupYFgaM!>WRuWLyoNGqkLZq zCbv{xqqt`Jmi+3s`1kx*CUIxEeA}61fU&H@43BCxqU+mw=ROTj9Y^jqRJgFI5s6ib z#VW?rwfGRf=pxRPUS(4)#{V>p?J=}j6}&N_{N_;e6I^H!O*lVQ?Ttxc?FFhIL=NSD zpV%s&*iO{T@YVETm3=}ULWB*LWyyTVy>%PzYNIlzUGAj6r)VRc&kxu&SP=1srEg$C zvj3IMNn?yee#x2omTNUt<({v!qeKYE4)1?XrkYe*7A-oQT;%#XK)Tyu-1&k;?)g}@ zYPta5YjDCgX~n(FgbJ~~mwOU!NXDDEBjzpOw0mLV^{hYxc94DG_#+<6uuvPFZ)1X{ zdJpAaSH1ZPiZfSWa35V9o;uu$hCu$^ z=$jo)@xqI|nDV(WS+a4Rqjy=k(scKQS(oSB{?@>UI&ps19eypZC;M9>8aOn-*&Y0H?pmp^6|T(?(1G4GmcaCSG2G-k)>fQ;&GCn3SsD`g z6)hs%u!rYVLe zLwrjoARZ)}(PMy;>|MtgyLx^;G(Wo%!Cg@( zQ8ElmiX_M61kdiun=Ez%^^mS_h6a-^%#2qQCsiPO;?a)p^w&ZEUf&22Elt(zP+X$! zZ9!D#?CIFMAc2zBba5X+15;B$icF0f)#w^K$56c%OYK(8@`W{2PH~>ytN88Q=IC#b zPkM8oSWcOkc&Ug8il4KXXG*N;Z(e4pZVpIe0dtWwNa+=%$Z}Lc1`3=$a;?FoGr#Zr zEX0K28k^%1n4SAzuK$_Lb(DcBbMoEMhW)dL5F@MG8GE%9(WOJsQPPXQ*YW%V>BF~m zwa-6$^)+dpUE$N!a`b<#OcP+AE{!Z>lI}|@Q{P>N4~XJxIe!%QN{Uz7;XWtx+&2{3 z?l#6I6o!;eQt@#I?^mJ+NHY@!CpA3``nf;Fb=uVISzyvhfnKk+h^f^6ZA2&$EpgQ> z@dY8l4B)`?6NNO5ZU(@(F-GjHpLt+^->|x=sra$h`}8o)>fZrrvRJWNcZPFcaO2}% z)`)AG&M7d*fO?PMscU+i)S38rG{+5Ylcxj^L742WsCmETi+>fb*!!Ahn^J9^IW#Nk z*KJdMu{UxulD~9`=GQw;+-1(3v;-dV>f2arW~WTtlyEvQTu+uP2R4h_BPmT?gLxGX z(Ts>z4W6*Sk{Gjr`)eYsb|yIjleMu<>?5OjcJIHfY-z{>A+J}$2PPw3$#>y-=gkdA zlpC7TOqIKiydBq!t|n@qJt=*Z=BYzLTqSAYZjlq~ge#bn;V6Cip?_A*g8UhK)vO94 zNM_$n#56;{`$w9KA`+i8ttu$*idU!fE!}jUVW~1D^c96mW=agBgidwU6B`K~-w;jW z=ofcUNKM@ruN2$aP>P6i{CkYOo>4?3__$b&fj1&4yS2~m^Km2?-Fr+S6_2MLO7JeQ6m8q zf~2Eo1^Xd92>1dM9tLB3C%^W_gWp^^J7|lyE^;+Zh{~_}-*^>_IPCR`S7)$08 zJ6U*d39xr1JB~x^;l;4z=2qhoqx+u1i}^anFZMD*sr}QgrswvGl`2YmKm_bSN1BIv z!9Wwj#w)Z$NfTr=^=4H3a_NTW5lj9?=r_JE3vYt>sFhMi zm65YY({Xi&xuda=Gq|Hhw?DSm40=x`jZBz&j1?KwNOEjdUKqtaJZd0%4spF|Q8mGSf ztKv=Sgr{GD0KuU|T(bwg3Qe7Q?OiDy6`?jTD$iOLxGtE7UQ&2M{)_;xg{9FxJaBXJ z6uew4oyYgwW%E@)K{e^~GkbLW$FI3td@+(14>my`N|stTBJ|~DAhpUbq-+;F&;e26 z$n~%(bRNx$kzA_3R;(%7ogC$}5S`K9%|N1w4%QfDX_#qII;;y$nIg^<%Y7Tv>@M7| zY-k@cc3f1szB7KXG2W9E25|XNJikcY+bqXgyhE8i2TxIK;`=DBlo~X`bV>0&s~!OJ z=aSlcNIv|B{-dWI-BNtTR!*L9_~6cZYXuCs^j-)%!kqG-1tBBnCHNr&zr@x50MDE` ztq~c~S3b3QO(fMSO!e&@y=jQVChasjM*B?PgtSo#Nw`* zVSS$lWc#sI^uYaqnB)bTp$=4OvnzBKMEH1)Ug@{J0|NrbemEBfh<-iAY3MCD(<9wy zIy>i;@5feGxV1)=cTVtNmYD=l7j)4a(psOWLOsMkV8P67f*P@bRo4Tb=NkRDA2@-5 z6h3VfUPw$))SXP99Nl;X8Lpz3&yt(jhea?2CZ#-$)PVFp^v~z5B2htZADaO}4WP(z z*L@P#_L%h~hHLCp|QjdY%o6l8yuQ` z+}TO96esD*TGIur(-l9@;iz!WuK4f4s*%+Tnp!_{)qTGSHFV8ivnLMX-w@(FTg;ga zvfBoG8G#t{WG%P+P42h_*qESKox#MybWzd^s6>5<7 zk@58=G2l0?3O42R&&?PkB8iv_7x0%Yz6*;&z7(N;)A4~U;LGS9{va(T-cX}}#~od; z-_C+UBu`L(ucQR>+jP=pzLRiAjoNv?d57cDNB!du{`P^2B!d#?oK4i`dqf+`UwaL# z-vjGn9#i^i#B#aZ#XzBr06z^;n8cc6!txy??;G`>Fw6qpaqjEv%rX@Gr_lnR`#|6u zyY_$0NXL$BXzG#HT#e7S29H@XJ^X36kL1OhvcI2};7H&FP2J9j9NZ|n`b#BG?-c3P zwp8{Xx32i1AK`xa+vGt_;WFzPaB2Hx%ZFEfMF}X*0HS8O`0R(0ma5 zmi#o4m9K>KI0u%8o9~NmN~H_Ze`@ec-`shzGf=zW2ce8Q3H-GO{oKaS!j2_j_KN@=d4N7YFe8ZPiDz<3+l7DZ{yAeUX_;|Q zcLp!RU}0j{*d?{P4tk*^ zZIOvyNf2Z&<%e90!0A*TaHDA3=d%(D84EeMpjROgJ|g-snm)6!n%q#e=K_!-y*?;P z&V5OR4-RtNNu>w`w&xz<=;D%`CauKVtLQw1Rp(X0sa{~6$C!g#@~2&MoedlHs@gr#i% z?jGnLvV0)(p`pGZQmk1RrWkQ4GQ*ixL#|EqNkEOD!^*>B<}ugu4c1jGWplqw!E@Oe zy6?J191Lq?y*lIZeTlJt_IZui(1wh$n9bahs$cx_N&QNVbU<6ILTZSV0s*4vxCGgI zb72?14c0pU4iDb>%^Wb!$HZ$+Bv2=q09x>i*>pRKCyt`TOJH=2OeV2)P|aJP&3A=p zP@H{C{_&7cG@g~s=GBMa?Q<&$dvWQLFOf*@zg)`=AKF???OLx;%gUkN;$^WOW*E4P zE9O+IPV%*N-3tN}?i{7nk8MdhF{_K~9|m*Ee;jYmPWGJUt!$E!a0|?^3_U8ut4`cKdsBL1d*@81tkXEDu|>Mv%$7K}vCfWdb7 zc2;Xb#;PW?c>B@P*5;ZUfmWl#!>`=haiXyEzW6nO!PyULh4qatuqw&<_aR7-|DOh> zBQT*5ci<1yi{f>gt!IZ=5_403`=UK5l-d_fsR_cz;yM;x~L@p=1N zVZQG7-ar2G!X-<_<$hkJajow`708S+DI8+B$t<2v@Ear`L6;|E(Em=h*jq!%Az!?i zp}-%MUqFrPRcOR?=^t(g^$!>QAlt{=l3yz4F3w~3zNN>}27Lx@yXrnOKO@J;W8>lf z1cVyq0_Eug>0=5ZMehMir@Yu|fzrE}k)7ea$-;QIoza%^xxd-LObac>8Samh6jABk zSI+E^XJq|_!jZED^`Hsg!g?6frIYQ6PSS%$5s0sRs$RwW^{PHVrXh8hC`3*S#l?R; z%z|dZ1n%~U;1=3?%VmXxyIdL~S|vk1{7NEy6T-^$L7RX9fu%)%3<@5#Y;YHRjpmNs zSaf*ti++tLSYrHztx~*~(jF-vQqTctveG|-?Mawl1C zwoW#OjO3KL!%f_E6KS_JR;jP4iPz?EwjoOeROo>VqLWUgGVS#GAItUF3xx~3*em$R$d}NdZlI;NQ``-7`wiC)w*3Z@;>F#_$Rm=KIX; zUJWVQ%?al9X*2ZVAN>#4o-6`Cu#@-r?1>J*4Y@!jN8#RW+=7F9>&9N6PB9vio@$uy zK?;vjgrlhcgK)D}^4+Ty$~QjB^S7_)Bn4LHkJCg$to4)A9U9hsY@mp(wbZ2dUsY@p zYaB^ezC3KFTO;Y77~V^wvx?u{6V?cIIX_QdkO<#4H{KK1jRDO+@5QBZwnB7niW3k{ z7n;vU3^wK3+f?mSr6P(cC%-{)pF>bGI6AXZXH6Np_yfVK`~Z3-Gwk8yFvZNS25tsd z?J^}GSLC@3X1;#O|=AX-~K-3i2Vii4JYsNG-1_rm_a4mY@MORcHs9fhwFX=^xS!g4lgDkS|$-a)p;j| zOW2WkwSL!INdRX$)}!5jd2?(4cn^0&iphv80txwpiJ&5Pu+01LVJFz=Zw8rgxH0dJFf|jI+6W2GTqY^al4~F^3@~XsdU#K&wb-+ScO+Ua?`juC66>x@>lSCt+jVC zv1r%#3c8M{RX+FfXdd25M@DY`KgR8dn_NA~Ircb)iAaxNg}__M&w3I~DQ<>vCA=Tk>pStnjxBsS-Z4_BBF zEpOb`(rhxng*e8*MWNS?=WnPkU({(6iO21?;_7MF1bHKzS9X(51$$lBMq)ukPALK<7TeX%P`;yv8+|NcB=QlDejFzvU8<-M;a@q-jTww==T|$pb1*7Q*A1P}1pAISr zl8qs1(%5=8T|B~1#=UaB@#)TaP{0Zd*4E%SjO4qYJMJ%~G35xv_sCBE{ay@FMJQg8*|I|+cnEsM?V?7f0Qf9FRFE$ zKA(5-1R&XVGJIT>`m`cycoIa zgdDW*xjO{nm*w}lrJ{sZ}t0LG3bZ;=d>o#~d?QM^wElapV3*Lfu*a~hd#gIN4(D_V8udf|#NA1>xIW|)@ypJE z+~*@rfP5&+OB=eSuXkq0BWj>#Cn4u7X-%ha5R(N?QUHqHdjvl`!(0pgrc787THBW# ztH%mt+T`_SAK&kOsYy2A_tCJCQ(eyU+64wVFXe>~}}>A$8M zw}Sj>LFt(}aq?G1XX$Y(%1uU1hv~8minohWM5-u5>S+g_S8HxMp&>;952>k0k?5Gmvb7H1r_n3qQ zHdS*erpj6MK0Yu=a3~!umNN9*OrSRs+NnSRr$hEb&d!pHeL z)AQYf8ao6e%`pwN2oO(SnTLVD{Nv*O+eLMv-Rbh!IeFKDN_GnaS4dli?`%Q)j@_^} z;x19bHr3Snu1fuZdMX`3wD|O!>q--b{Gyci_;hb-Ra#R5?PUs+l~xAGz&1&%Gv}qO z|Eu$7cEt)$y6_3E8acZ+0+?%UF3r+E1#*)^{eT~8Sc4X#lP}y_KRN|U?OnY;Oc^S{ z%^%}CGWC(1$N1 z5{6|4HR5pyN8gLpgfNsnz@i<23YDmA+|#qCgGc9;yt=G>sug}2>@UX;1@(V{N|`H6 zuG8pl!QaoRvhRcY-lnuj?J`Df9=?0Dr?S}hI4ir0_XbHuUd+nzJM!`P zgOcOy-}372@m?P@m~X2)Dv`1c9L7GSM{LK}W_MR}%jS#k4Z-wcHPsShLx*Y{I*Z#SeDV4FixIie}YxU}_vCOA_UJ5?JZH+MI+`X_09_J!$MdDS!zFjcyp zF%+XS&a9WvE4txaJ?gb?jM8QE)KL-^N^yreY_RMXh1&HQQCCHSv|U@Zlw)u6AG!?J zxwIi$MqV-&NpXCWLpTTO+$~;C`Q9qe{lU;xhr=}NfSL=ak1wJd*5>(Ud0!~w8P9*d zqAY<2^Qr_pe$3o)RQ(~3$`Mv*-3AqPjB5Sz4`QR5JLg#72~le%WT+R%A8#C4 z!^A@F{vA&x$)7ZtjUJaYP$unLbxkE<#qjEk^N#Tkl;{z*(|K*}LA_L=7*6)^ke-{u zLpb>%Rc#C+;d$rZKQ_QK??ggm{;(?%v7Y9qQGfrC>|_(VH8`67k4%!A0roSyAr;l=q=SqWxK`gs)$D zM1PCPIRfhhoDI-JMi(c99xL-V{~x$^tdV{0_J2l!=D8-DHD^3Ue%C=vt4LYjrDBKX zuq9%4o^qAI!GC!4Tc+*6lXQw!?@o5!<+GJam=Oh*lWT&Y$b@tDXx|8M-&2`Y4IZ91 z%#DBY8)}G;gOKFy4ca2te06@5Tx6JlbWu*(fGly|lBV-Bls(>PV zl$yP#x5tG_jFhZTHR7z!ooDqdgq{}o;kG$9Uf7SKqwu@XbaA8DkG?&5aeEwc-mQ8Kg5C{$hwU;B@4ouKOM{Z?2x;4%y8}G*F$5ff zyA)6%g?9`sI*8dGb%r-AZ!tZF`&LF+mS6p0vsY$7HoMkLLL0sU=3PCs>gj73J{Pw{{o^$X?OW=h!#3$yePr%8=j z;>;gRKg1$(AG{NW_nZ3|m^}B`G5PLt*HTXC*;nsgW*$oqer9%INw33@N~X^8!E(V@ zKFl%(evfh`w>~n!h2?^|ymy?Hs=hK+)K0W9TL z?#u;pehg68%uIg3xT90Sn&DpYjgBW4sSDd!XMUUY$c znSu44bY*p=%Z_bSm=r^K_eKck6kSb=-Pj+P%Kqtw-K7EK+ zYsfr#A=Q1xx{rx=v^%DRB=UapI?F8AOxP-NH7v@D;i~9}UcS1|jpXOw?BiJCS~j|4 zHk`l(y*pT*wtSiMU?-Magrb1Qj4U}`1DEwi{MXw+qL)4F6;b*Z|A8{E zD}lGytWm*?NA*sv=U}v=)7{3yiyR^~U~VHmyLpOZ(eW+Y{+FM5Khcl3cCrJzX_)Pp zRu$Ww@9~tLf!W{!*=^nR&p*x*cQys$^t&LhTI6|kAOE1?UCyhMm*DZ(Rm%M_n81eEx+w`-3 zgl=3l{Yvs9o4D4)wAatRiuKQdf9mMZu}QlL&9T7pJC7EB)=z^2$AYR`25-Eaf`Ef6Ikl-7=lCMfL>}R#ofpuZn zbISNol=BMH#Rdnhee!WY_a#^>{^_50m{OsIIh2W~G zqe_Ul9T&h}z~;9-(nss3hpMquvP!o1Le~i!L`0%i) zR)(v;^O@X9x>OSv^uA~Kp8-WIm%aQz#M^`r=ywm2*afV{R}@ zCYE*GA_MTI z!n*bL=OrafOs}Fh5biCjkwX8=a5<9g9^aD;fLA)&jD`$jLVns{evQC5sw;Ue-Xsgm zTP6BAV`0MG()dKXSwy6J(F?2XN&YxY1js(wg z_SGf!ZdJ-;Ro}fy2fQqh3PNxORH#_rIbfYMW~`G&dDodW8FDH|z)FrAzpWBSkC4mk z<|APmErMfHb04iCWFfupyyX~-py^Z4TO;}1>t8|~G)k9Yx-Bq~m)P5N{on1f_Vies zhC5U)7guOIL?V&t$|=tIc8Dgo`A$I3;Q>ni&Hae~B3@<%GkA!fC?2xDrZBJMZgxWc z%q1PFW(6r&9_>Gxv{J!qhG74zyA%$!wzBK{#)M}X5ukJ~KA@0Nx$}i1lDnhu`U?Jl zbRe4eM9rH2nSXZb;;fxt+*#S7*gE!+zCK*5^nm=rYrc2kf5|JI1Ct;d^M0+8bfn#$ zl^$w3PUBf0{hBLe>gaBC{_IAh{WD|R5{UMV@qf`JmTydoXQ=@{|E-t;fnp=@k1g_!0`OLBD z0CeLYw_=HIo}_X)T$#@E-*A|K!k#vl~rG$d4x8eN-4W1FnYTVu3>- z`u2OfmSTL1UEHnBvDd*3{-v5kR#67(4dq&Pq)*43%DI91(sMtk$n8#E~ ztjJM4>aYm@FGjDG^1mo@={?zq#5o@Z+pAx`nCK-}vmwCyvm;hM;j1-28_xK5IGO{U zzNlPFiKpWPMD9zf3}XG4T5a`e`L1#gKyjNhD_%}xz=~OEv8DzO)TIzLT&|4qK}8uX z&MKXsLNnEN?j{@kOkl5j1O8_%%E(@mRE_3x*xmX$Om7lS-(CNbFs7&45y`|JX`RR^ zgySo;Y$HeHL?c=R^K0b_r!>yW{UemvyIvXjQJ||J<#1RKk~n9Uh;G+M);_tUXm7Px|Oty zVocT%?&ystCjT93M;_A$&-UzSU~_f6Z{@>5U2pnHU2l-&$e^Z#v$FMF={fec32$v} zx@@x*EYssH6ZtjFts`ugW9FUc^R7t}q)>(9-=wp%>Va2D7XrGjq}D69>7%TXqLpmt zARkEFNTyPG7AH*yI*fPmyboE1qYgbQsHPZzgiM(Oqu`qrk>>r!W8Ok zGI0Yg=3Ckv*ckkvio|vusO*Z$g)F##_!BiTuTCT^8X|7AH!XYi$M40?_WLt~FVP4Y zqfp`#cMw3%%>bQwYdE3bR(vhKWpz6a-gV3W!TW>N@5E`~Z@6Sk!b{gd+xfw|yfaZ~ zPH=rQXM+oFo5|-3-x`DA_8ZjUzHa%7XYr2I;Y%z$9ENoNlU8P6`k+Wq>$3PI`H5X~ z5yc%}aNczxmdSx-sY-FRBf}cs-*FBiaC1WjzY+}%{pDZLrB_V90@N47qir-QqN~-t zW2DJY0l44la;~o^4W79S6`S`p&EURjFbxziqIet;>#K25D3>y7CLj5J>&G0xb}L5l z$i(OMMWv!ky~hw`)klr$bf@@*Xq{vms<`Bxc1d>0bLBW4!FW`@r1Bs&RIL;SeWj$4 zu2MZs(^8$v4d_ig1v6IPMYan!z#2_3lb6aHJ_03su&?Ogy-kifG^FJ4z@NhzIQt;o zmij+v4*T9QMUM8p+zV=`K;I?eCt@xSH!15UCdD}qMNi*Lbi`C9Za4hKp$UG5;l{#_ zbwxtjPuWZzMDE~i%<1t{aROJP%W;X|_IQ{-JfgA6qBS#@zCqz2im7CeHgv_1r1sas z?Ni0`$g$GD*z!yPe&7$P-btZigSm)ucwUsGI;*$~MAIJuu>0o9TKh4?bZ7G71Sv`BGk3%`4+#U~pGnpB>IC~jvMDo9a4eK*pcj{bR z+*n`lk9V1p{;vE(JSBk3E+!B9B<)KKs$*mWq%EK9rEe9@tmH5db#_7+x1C#k*Q$8e z^l{75aPqkzR%VHFfreJFF*oe-c^M=4qhId#7n%-_e3Jz-35BqUO1aqWTr69inF6KT zrZJ?0Pm#tSx!{pg@cBmGZLdrDW`5f>t{kR55l^bz)(d`Bt1KCZa&&5_&4>{C35ZsB z9!1|%A*?@Na(B>^zkrF9NBEhD(`~NSSE3`ZA85Mr^nEYky|APIi~l|l5HM98YlgE; zCS*+Sykij--qS%y7NC#GV?9-p%-&ah`XJpmw8+GbP3=0wtpk(7&h8aEL*IwWj|eer z;%5glJUq92n^)-+3Fl4pn|A$`O0R=3(s{oDQa*RbcE_&$*q6BUTDqJYv;*nM?_Pe2 z;y|{o>Bs^v1uZglux*d>@jUPLeD~JCERhGm353sG!*I5Zgr7Gmn?>ABn&8e+(|gEG zY2%1SY42uIX=7#xwUq05=f>0Sdgb&q88qXI&^nO}tAc#XyuQRb(!$P31 z@2v`^m%K~ve$-KvpIverq38J{#piaKBx&5+|2C3ysLfre(9xC=7Lqb_pciDx}fCYQOO@3WDhVB zlyA4x4=H?B`%6R()0}G^iV6zp1us!3y<4w1Zj*@)eQ|auMl^n+iS4qQ{nh-Sdtn^F z&KCoas60@PQ%cFK7P;*jWf^#B0kPhv9$PH3g507GmD^VOC6>VaqaYwszj+!g_Qvf0 z{IjPIu?jMT`ss1o=Ybd)wp&oQ=2%;DcO&ja_28`=zG_KfQNp%pe#L0u;H?vM@b&@u zL*04FWi6I_=h`eXuwr|LYiVnG@b)^^xmCQ(wPR$krQnvgBdiZxb$j_!K+;x^Yj>Dt zR>^i+uGO9~#;KAuvOMwUcc^{HT+$C!xWTkU>g2G zv63LSeJ9+uNKqy4JLb4C6*=H0)MckGkHrGmex<2-*L%GG$Kou8f3h_oV})G^2-Wg) zubJ?alL=^t_3qo;OuE|LvcWLF%JH9OMeh9HLkl7L?V>HvC9`@ve*xrhj>=r=uO`-< zzhgY*sh{*Qh=(XNgJUQB6x|}Bi#!c; z)kri$fVhnfcxQKG3w@9=pKb!j;}=&LJ@u11{(Et8fLtlG@kT8|VQ9?C^`E~=GA4&X z5*scek6 zy|+X1ZjVb+csHs7sbA1>#^F4Okt!t1`VAV3HMKWL8k>U5-UA=_XnN_Ni32w!@gBKo z1vRe;;m1xyZYhQi-TM4q2flWhCv{S@-F(O4q#~C%@*Y$#Jd+s33`cONhx4GH8-q$! zyj@Hsn17Gvm&{yzFS{Ppkb^YI-D~5U$?~inOHwJXX-JiXwky8pM$`d*>SI!0xvV~+ zSi~vhTk_L=OAqr62Ef&vCqNU1f~iEksvQ{rE(!hfpt4f??|Q^-b>4;j13P}%pgRId z_up5efOIM;(!B#yG5+;3>|_(l>s@OCh0wi&ZOE^y6avKn0>#xAcux_t48?a38z+iE z>)?ms&2V~3!XwmAdTR&-g-+2x&6nvgDWKM>LkR=+EZz+NMm-p?!sx!|?pFCijL4we(>u>3!lN zm#mrpWAwV9duRk~Iou2k4QxUW_4w~C{!)M#Hov@OInk}O)n017##-v+hR@7d%gh@)#^-+qI0ZjV_#i3!Oir06XLTYXDF3Z5 zYx2Q|IiWvnI6P=T7ESX_i;|^ak)-g*nX>qWU1Wx`OzTl!fNJw81}zk~^sN_dHr*6*sB9y9vcjn-uLtGtl}gwot7Kg@ zjfcGAfV%*{eJ7B4qW{;TQdAp!<4M`MvVVx2oZed&-6@CuxVIuN)yhbOytKG1Bm0wc zzOzi~|Kb7&Vr7WQpr-|4OkLJ~fXbH-!*4A(M1eO4YJq$zsrSduD+-n~ecw4BcL@jV z9Sq)ZedhnS9EQLJimcz2+@mQ+kHClSog2u9;dy7Uu4Um7DAUpfcjI28Sm@@eQW z0a81867Zn=)~aDz*wfT8M<*N@SnFJXHL<675d5+Hy1ifFMBLADm+<$!tat@t+C0|d z975u&oSufC!HTwD0nWZ?@=$uu`_4#dKhQ;)CpGX%d^<-qxzM49WP}$&@fY5KpD#>H zA0pRUdK?Pgq6_`g`4Wb1ylZ#fXh(yk+vG%>uV@abq(FQ&rsCph8Vr8RUE$HF`^UB@ zkvCANp?7=p_q_vWoN!P)){@{n;F1sM^nb&r*4SRTh`QIDKa@1lTXv3@gu&hYYspJ# zp=q`8aKX4OV95XRM+Er&(kfq7n{u&^?svcO%Y`1dy3b(c@hU3(lWQI{#|7irbc#k2 zM*aHf=d??vEDMyk+n)Glc;9S!j>YAL()tnPbyXzV7wl!(gOT#0nwSiIh*l!$ ze`<`Fr8Guxwoy4*Avv8@?r{|`Uxn-Pg!w+|oK>3frM!;fdDb8wq|Nj0sQncX^zAox zqqODCs;)14+I}fBZLpES)uDOfLk#=KuCv>EN$M5DCY|QDcz>uRLg$Mjgt2?@9_A>>_H&{zS=!N}>oQ zmh0UM>_EQVK1Z8_O`b$zI1KR+8tXhmJTEY|2!_|m&e^WW3Sdrr+|x=X#&A=Q_NMVJRg}b-0gx>go{(T;MLg7{ zcYU)se`$M!s(ER(@nBa3Ug_7NUgC@kX@1a~i@S^M(+N1Fur#nLCfBjX^N}~R3SDHglG%A()6y!t65f* z<<)~J9z9jM2KdL)xQ~MuBK;5Vviu}{lWI~~H3c~-ZOcsj3d!6JG z*w0C#;&=Ht64tuQvVmuJ8{1W#8)6pxIqLdpFjckU28GHK{@BdZ70}nMzP!z!!@B!* z^`NG`am+r~sD#w0gi7gyyCHX?SK{I7D5@ag!mF-uj^p{c|xV8C#TRO zTiRf}H@{1@r07PAjkNCxNrDAUGLiIkE7$GgZeKva^aTB~dHbb|bO?l3Ua>ycHVUBQ zB_=OX{E=Vm&Vlb+O?$dDs4{NUH=o6Gu`|c7+aeE!I+BWxUnMF*Smrw*S(|8_Gv@N~ z9l}mCoZuqtHeaII>VlWpP3`RLGRD{|EtMS0ofKpXRMBOm?)H!}P=GYJ(~B&(Xq1)C z6v3KF9jj>x2o68qBAwssQlo+ah?hEXN6EQD`Ef=)%5#tT#Mh$BWs(HuDVvAEVlDfI zL8TT~x?qRNrJe@Bwd8-6%z_UEH{YDh%HHfMf3H<@eq-A=|72ZGj=X|r4_i1&suP=! z4Xl5L09PT*y~;wlH#VFRsrhxew4Fe+IbYsX!4rlJOh)A+B<%Rj+Wqv)}DK^}`9;tQxyVYI%wndKHvhP2H8jHU4wc zaoek^VnNxLDa7vM7=NTc=|fZH=n?+IT>7Tk*WY`U(3;?~t+-SZgXp=pJDnKOH9E*+ z)bOn`n(n9b164+vRlO+&huO>`GrUi}!lih0NqxckeS0rztmOW#go;S;@>(u;}+8BYI77GtSh^C;8*ZQcnb!B5+MIN8$9 zn$Unv#TLuxa?kR^N9R;eX3Vcy1dJlMo9|~oWXKNZ`d~D#oskuHvqrnY+JQo-35vDZ zuVxuA3;oSjv%Nv&acDt0?NBEZE2U9~?{(W#j6W3x+%{UA3|Zh$NhX|8bQL5DOA;ih z$FZez1`RL-r{{Q57(P!u_CxtSP6l+7ROi^IM_GaY(X4m#xe*aw)b?Miy4x8?w#}Ie=2?uc` zu^*VR#@Kh4G$~YOauLU`Ec!h8dPg=cb8$I$kN%VKA7bN6j+m5_*yR%oW#Sn{dl=7P zY@m(6JRQfGrt&$8KDj$)Z#oo`8o|Wv_%_J1X1b5x$$>cS?3w6pYxD)^OXTNbjE;t= zMj=L|t;*+?W0}wTkLSiEiwkwTQy&Cu!tnP#;x|Lv)5hr~7~SP4uv8wS17j?Ac@RmUdLE6Kh9-e!ffpxtXu7XCwcCf9XJr-#jx{ z(t+a*8)911k|k9oq5LI^*x#hGgGAvD%~m+k3=M~*gB$T^XHN$?*35g0L-7JgH!pOh}(yP=p>t0@K}ZM3uIQJl?<<2?CE8vCkD|U zzEs;}`*m@?ZY1{tjzbiURk^=@!spPI`fKBTf9hUY9I+d*RlKxVRdwUYk%htJ+nomC z-#arDw3W}KQuX$SUTcZ^Gr4UMKrRqpxd*Al&rF}%ES`o86KUeV29!*Xn-NNt;hzcw6q4glC>>>(*hmhgUecuy;B~)Eswh2pDC*!Gj3t%ao}VI8qRn-kF{g$r?84;>73?tR|McWt2P~`I|Lr_lUqFjUkB`; zP&w1|`8hQ!==g@8c+G2-`}VHBubs^FROYU(TUYIj`I7FKb9MgqvFv1zjzuHWO-}dc zS4@7^ODxw!nr%R3;TFax@4o)y{*=_NRUlyXum;Itq@1v_^kJ8+PWzrpE{JDvptkNk zPbm4)uEOAh=YE2gP?U*v7_6L|?u)KoD{M8b>%P&37-R*QVrL z-vOEi-Z{Op;09FW>wdr&NemV?WI|sMwOjWHf?|^T#&f9@S)asdh6DhLZ+{4a3$8fdCP0oZOY`2 z3+e0f{cu`;$IYbFS3zyn0hNwV&exisjaH_@xi^t)G^Pk*V;$Pc9&s6*W^?tcDAuSZ(Mu*`)9HFYq@D_-pP=2OjEfV^v?oqL(AhO zT>JaAq!fBxPZ41tk}*rF_lqmO;6P~7R7&2vv|#z6yQB}C1h4DtI9|l+T(}t9_Kmj= z!zu#0CXtB?>dy`w8~I>*z#bR{xRn^p0Mv5|6_x;u)I!2lqE7Vz(KfSo2C2wFiDleIDE2eyXM85YyoKYK~m$q&nFp}`1RT5{>oe8pR8ZU z8Qg!REWXdPUsO=LV9)FLwr@B4+PdNV&iis`a~)c)jE8;Wd6nzqFUMv_2DtN<8JUs} z>w$-qO(p&D5D6_10P~J>D)|dip(b=~(;z?dCXk0g4*ZEcxhvB)Zac9{{TuMl;bM2H z-kgH*_LqZvjue6=joddbcT}E&vwz%EQD{8*aqrAyp!99$!UJ=%vkabKQW{fh-ylEG0dr_5K!G7s0m@YWXLX>C`D(|K5u(6JGzMi}(t$P#kgtSiKwqVG`} z&{hK#Rm?Vx8M`&0g54wfx@^C`cAEacHTBgztT2s+*G2#QDYi~LB48e;Ba?hWDy_Lg zQKdY0qAAbYk9~f>#B8g4te&xt+T_Wh3iN=^d@lrj%Q|O%AXNS`%<^dp-G(uox#_l)sZa9F-h_87G&2i|-wW%0ISv%YMX z1MzCJx8pGD^|JxA9=1sg&R1{93<`>wZe1U%5Iz!|)n?axa(-x60P1h}V)s3+rjPTa z?}sP-A8*Y6q$}TYDOI&i+mST5mubfq{uy31CDCGw*abl3=;w# zM-vY#B~kUCzds+rRRL|r0>2YB<`xmP6nZpNX&EWy&d;j-iii>qr$;l@IGQID>vMl& zg<2ZR`>O*jCQj@ZST{|e@MmzxS(ED{>!&}N;LKjQ`6qsyK%S8ZM+O^^|6q5 z{kY>mbB>UkZ7P3Y^&I}|WB)d3%B3)04KdW&9e%=HX5M==IyuLHc|fYSfA9WY_#f|0 zpnpc1ToKYa>tM&4a`_?9t*14N=I6$lC%H39D;^w8LiSG}aX@|ITE5$TH$3x=aPU{Q z`q8Gy!*zwCv0vj=mXX3ugYxG&Na??}-0E=QC>*Z(dVB2D>$Q8ccRzLPE8bDx zS1jElk~#nfw7whLb;w!JTXgkrdR{K9W_mERF*7z4Lm{d5^CX_z;wTXEE}&MJ>tA9p z@r~OScr9n`Gb;Ld`JC;^Q*OQ`6UY+y;^PO10YD|yyr_%kf#ho@^?{fbKgsUj9dXpp z;?Aiqc&2`F(T#zY3Fj=-CU3+~3=N^!B2us&E;To^oV&T`fo}DAaa!=#&DPZX5@$HT%u%>7PTF0E$oLto3a6k~)O|wB$YXyf_B%WqsGdLm|sTxx-V% z7F?o5J+ITw_CvS)5Ted)T{TlvUs5puT9$i6IDp1{?%YHy6jkA~F8OH(t|95HKwC+$ zIf}~7?(c~1I+Bxxy9-}cZ8x*s77rgL%CZdyzK!`fDN@^L;v zbw%!Alp3gQYuTlj{~Yu%IB1s|&2~z;sCqVRbwmZ}7N^-;KM^2})*68PX*<%sd|)C* z+$%QV>Sj}8YMf`+hT>I{4iI>fnhV@i!2WqskNAFA`_|__vr%lI^R9+D}K zNB!X9s+?`-Oc&GG6Win}+qNX)urFa^dGcxNAD2YY%lFf<7v`(5kLO>c?0)KYl7?G6 z^8Bm1bdLeo9wzL%dol?GMNb_|-M6%kXBZw4d4B8($1`;N5vHZE@tEorO}4YCIOI5Y z0*r+KpmeyE1U^=hFF2IpiEVJRPtfZ`buN2YKnrE!rAyLJcSvcGs>3yLM!o%aH#&BaGZ@H#OKj*E z^Y1DfS;|WTvXD#f5v;YAu9a5uwt!zYHu+u5-~tf&kD!DQ6dH)@g8t!`?JV%zudj92 zaayIr7jZWG5xYgjy(xEElEB>MFb5@e%;HboPudMJ^+}ctSHI?6;dmF{+ zgb91R-dKZgNmNK6?c#EUP@L%}E)(J3$|_%Q#kpIx8jqIM-Cc#c#i=Kd;|ZPEmPu&{ zUuM8D;!$3P>UQ-xVMg;$IbjDGW1 zXIR2Zalr$o@g*ULej2=%nnv^2GB{gg)(o$9GUE83ZF$)=qo1_Qy`{Yf1Ay{Z5k5{y zBt9hLON5%J%NnaGZB8lOFPQRM=Pgz*EiMvE{~GQK3~>R-K$?&*&==Zr^cA{P5;xQ& z=8Rr1z7|gFU|-qE%eAD-&!@MLH@_UP8&Y(}*Ven4DHFC|f&HnH^(B*P-SXsmwH@>u zXA``K8-vQYY%yXouB$QQWPM@Zgm^oL_uyH{S-AOS%YC=OSLvCF?&}kfolv-8ZSuY4oUtRz zby5e6HkMh_Z?p5xuNnVxFpLiDygYx+L*)YVCpuzO@vp*x zu7{fnDo?&E!L_{8_aQLZ^{MMsuKg~weZD_#yWtQyjB7jSP#);kgf0(is;hRRpAPpv z+s8sy`eiI;SqEpKAn_~?mA|;GcTh%G>8)alS3~jt&F5a!AEUHP@5%!m%WJ#n_t_kj`yOAoH^03XV+^h2bo*L17aLRNncp-;+z)(z8yuGK9@FQ%U|Mnk z;Ll3~)XJGDV~utAZcsh8?W?-tOA8%SSD00$P8dbD?w>%dV2&pfm4RVh%W{q?l5$L; zR!mVNm0$!O+CMO)^4>XmdU*fE1Cy~S!tk!iUT(G&you+|w`t}kCDP=gV~~mkcS4NQ znC`59jZj~?Z4a%>7Hx0;Xavi+$X}0)qMr~+14?1GF+)8J!zD>rDu7I!_N9s&&OOVh z>=6e}CPI>6$U{>x8cCg=1-BSsF6p4PD?-J%D2soH-OUWAXy+ECw>W#(1wk(wR>7E1(QtU{Vzc<`B7< zDDR{A)gVtk!eLu!63H9b>5wSy>Rtt^eLhwlrpZL&fQ4rRMd4Y-LSRWJT*nVQ+(7q2 zy7SHL)mJ?d%uyLDS%M?m;n2{4QfiZ3EAF`=&f=p~IZy?7Q_LoY5H{%EZ?EAt?% zPa0Wk{dRACy?Uh`7-x;Hfrjxdl);sbYSal)@C0t#Su96S1v;M$D4%e!QjYMK z&4{a$UX&cQYMxrwWCrDEjW@Rc$>Zmf!6sC_MR7BHzDNm_as8PY!(-MgCI{-u&d=Qy zx{rxWAQ3cx`20FB*$SP{JfJqpih`W|ge4gRJ7jVQ1R5)(+A3((7j>oJIG@#h^RSZigbN9; z^dtp&LY&|Kw7|Xo5Co#clRJZ!-z-X&cdiF%jCt|*CA)vhuIu;XR>d@tp8$(ixITN&te-Y8G6^ki-d-1VUN-rpRv zo%q!J<#-eNHM)4{NZbD3H@|fbC^|CgZnA6()Ks7f6fSMz1(Y1yw}$u}`LPgoz~ITX zSV2bG0fv?=TSq9>uCwOIyl~pnR@0m~?Uu~|!z|f#pLZkZF*9)<5}|X;Yn3oL+4{%1 z?}dPa)jfO8`z3WQ|HXJ&|4GnEG~1Bs(x%c4F3|DIm28rE=4jy}Z2M9iwW7^&?4l^G zV=}eCwF{!2A6wo~#CVc){A=%@qWw~zw2 z`j@yG@PsG~^7=)FLcCLCffN|)UM$7C@wlwhpFq*<33EhBaW~O!zq)(DEdDP5+3SOJ zvF~aXgl&O>%5_=)t^0;yy4qj;Ey8_(W#2_}2D)~mb?BM!ndUSy5&(QIqOJv`sY>jE z9i-N!FKkWde`>Zux1>Oe#kK&J_)?9IHKjFmlpbyBIf&uR;398WwUF40W$kESnzL=OeZ^*zCLvvV%->p`vP{*wsfu} z#{Nm^%>1WXS_jf4s$Z*3n;#9gLxFXiq~0jLuPpaU>2*2N$XelfP$i^M{zpOfL8e&( zv8_;};s(MkMD=wd9pi^BTB|n9l^ds6@Hn*@1bs454p>8L2<5f5V5dq5rCxknIg83Qh8@?(3#>q4{l^s5sA7fGtjBeR9HXff)75|k{Pp_$U25E!pjI@q1|(pjSoCf# zFR*7w@OeNHOV--p#%nKsUeCTjA9J$?g1NZlh>u~wO`pufwWv5nqdV&xCh7<=V zro1t%UXg#M%*CKtFDK*YHxLMy3E%QcA+bH=4dnixVy+IKJvehiUdjpsDj`><;Ps-x z$N;adCpvlI2|s!wEb!WsNJK5bF)_tqgnoEc2=IuBfE4#kOsea3f-NiX<>x z9pt<=SVCvFw)vI%_Gw&V*&Dn}m#n{Y?Y37%X%SAyrmc&2;6Vna(&Qf2=sW!OI}j^Z!3Zyo&%Ql zO*SW&MegZ3M4&g8>OX203d&|+)5^X7TobI z<_&P62+7=BSo8+6vo`!U*4k~qWPEf2XBDmOKyoYj|aLxKV?J!P@=T?O6ZgsHO5Dxp9KJe@^3fwoOYUzZ#aUXBpF&>_<-EQyGw%?)6XP4FsT8Xf}{WT>8V<0az-ZlGE z&jAc219(FruR1;pur^7uJG|_~PG`RRzBxlyTFsKf+6OL(?>Pe*`K$nf>ptEm$uKtU zk~C#kYtw61g6U$64`gJmG5_&{{pxe7?JH;gV#1~8VBBf5GGVZf9KzX>gcB8K!)kdh zfr3`f`S9CQ$Z=={5;RbqXV!r^r4>Hj*<)^5RYBeTj7Am+n*&5-IHvlSQBi`-bl&ba z$rTm42>YhLgp50}K+!a)EiI3!{9^IL*+cg>fUG^_+vg92$q>xhq*WzruV4=Clu(A<1cUl{Qqr=2|m& zy(~|qc{6KvOO^b8M%JRg>fKPKgFyXm9UTg*e=E(Eo~|5wVwLaeSYzpeRHUOT*kCu* z3YXdDPOgE2z_KpgC1u4`($qmpS;Lcu{&J1YZu@0VYUdg0F5jIm9AsYpGf6Pd&+>r2 z;8oFQxdAXHumm+%&`A>Fl0eU5WP!uxeS9TZ8hgM0-Ffw)6KM9d_W$Nx+h`mc`@c=| zF)&S~)d-JTV4C{sRv^Lkj5!t&UbUAr!k&j!9fHuA5{=qY#C4ly`6zl|m@ftl-}_^; zcq*X!^R>1%$23ldiKn7Fk>~(dqYZQVm-AsGjD^5${**vGPk}ieSDH8rLXX-eNB~KG zQe1Dpi=kGeqKlG~^qM5DjInc8P9QOtk?7CY8pmc|Z63^iF5@+l_+sEtbP5vL;$#>P3h?2)k@EZ-+I$V25xj)Dr&pv_-)IOn zP#!c=;+eB~+gkV8tQ&nzB{R=-X0*+9^b}M#YW#YRr*0_$%^LwF*gYaaKI= z-D7lm(EgS1RN`Nd3r-RQrtcme!+nm7dcnn)MuB*D-t3WRoe2Mi&(&s7u0Wg(-U&-^ z8>DW)h!miI6pl__-wBPL#$SG-=UDuX>0klq)^Zeg|E=3f9ZZ$cX7UDk?vEs>60UgE z2e(#&Y|CHJYml>wBL0x_K0X<+0RMZ@bB->uzME?wto?_)>y#e$hduea<;9=<>FD2c zd7)MXj0h{-yh48D7ls3ifkV_Y6K?A9huf-=|65e|m$UFRIE)ePqTHT)|IKx!H8bgvayg9lxinH7nDqPv2unEV(QF z9k6j(887D_B$)kBO;-d1P9kW_E6EJgUs*+PP!bm#zRY{{__O~^I~xXKSmn1I8|~j) z=tg}GdCjO#g=t+WsA`=zxZB`T@phHOWcbo;Wl3CPD!D5dmr`&g)( zQxVGhI?Wb9j2lmWUHEr2m%!1ynd~(AJuZwsMld2hF*%NLZWc73HPR&(djCk$1HXFw zCQDqRgR^(WYQ5~w<4~DBSBR60AX~6&N&QO@$ng-IjK|xN-@43aDN3)wtZ(ha%-Q_! zTtUtLK6l=PiUfmpY{1CHKzyTUK#1)lCvd6LZN@Wi5b_B-&uxx<>V`l3UwMsAb|5uJ zEkyy;V?_4%wAGYYbzmJ5yZooON+;GyfRaL)SA{h75@iPwjwymH39r|ZgfIoeZu(OopF)z_jntdSv0!H;=EAv`-=0$-*fn_sL zIow|?tlG|$Rw`Vi``%A%mFb&5?xfFC@(@y_`&X(1Yu^?CtCm8JNRfvE$#2BL?pr}^ zi?`p6qE*HB{JCO}6z}gDnU;;_4FBBnVj~>nNVMTX$LRi(f5{5)5i-Z5kV*S((>Fyf zX3EtB1oNU+c%OFT3gi>IzkrUaCHNy0;vYbrA!k3*x7MEjHj;^bGJP;4v*{$zS3^o& z?x){zK4l%ps|CC#JguDU&c9y*AjRS354fyPUO>i8HNhYG+*Ms3#0mc;B&NhfPm~Q0 zY+7t(g!!M5Py-_o4C*}hhY)j+DKPh*hNz0;I^VOvg)18{27l03w5#SS@$X-B$;E&V zjm@3EA0(M)36ewXJ+M@r^OcD(gfJu%%M)Wr)#OEqs<%1)8J7&S>43N-@bY=b{hlnv z>4hTz#hT;QyIxXC=lU*{m~)%}v-7cV3`qFr8#Lsq$b`CW@^2gNWq1%XnAD{{A=s{( z6h48>O7D7rF0E`*JYslA^R6V#Agbiw+x<`e6$COqG7JCi>-!CWT_z5Rv5fyl4;Hrk z%YZ%{BtyR=%PR11G%-$E`*%ktw9bRs_-DKfpDDa8Zw65J{Jv*-Wq dMholi;b+%;xa{z=N(%6GUF+u6VhyX1{{!?kDDwaS literal 0 HcmV?d00001 diff --git a/src/assets/404_images/404_cloud.png b/src/assets/404_images/404_cloud.png new file mode 100644 index 0000000000000000000000000000000000000000..c6281d09013e0a2c5f8e699a0a6038d9480291e5 GIT binary patch literal 4766 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 literal 0 HcmV?d00001 diff --git a/src/assets/layout/animation-image.gif b/src/assets/layout/animation-image.gif new file mode 100644 index 0000000000000000000000000000000000000000..fdbd32c675f85af4ed57021ac0638a21a3c6cad3 GIT binary patch literal 6334 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 literal 0 HcmV?d00001 diff --git a/src/assets/layout/login-bg.svg b/src/assets/layout/login-bg.svg new file mode 100644 index 0000000..ab3dab9 --- /dev/null +++ b/src/assets/layout/login-bg.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/layout/login-front.svg b/src/assets/layout/login-front.svg new file mode 100644 index 0000000..b96a536 --- /dev/null +++ b/src/assets/layout/login-front.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/layout/login-top.svg b/src/assets/layout/login-top.svg new file mode 100644 index 0000000..ca5cac8 --- /dev/null +++ b/src/assets/layout/login-top.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/layout/login.svg b/src/assets/layout/login.svg new file mode 100644 index 0000000..9ac16cb --- /dev/null +++ b/src/assets/layout/login.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/layout/logo.png b/src/assets/layout/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9838306b47f1bc31966393bd51a71864f2c6776b GIT binary patch literal 10543 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 literal 0 HcmV?d00001 diff --git a/src/components/ElSvgIcon.vue b/src/components/ElSvgIcon.vue new file mode 100644 index 0000000..c7c60cd --- /dev/null +++ b/src/components/ElSvgIcon.vue @@ -0,0 +1,36 @@ + + + + + diff --git a/src/components/TestUnit.vue b/src/components/TestUnit.vue new file mode 100644 index 0000000..499707a --- /dev/null +++ b/src/components/TestUnit.vue @@ -0,0 +1,15 @@ + + + + + diff --git a/src/components/__tests__/el-svgIcon.test.jsx b/src/components/__tests__/el-svgIcon.test.jsx new file mode 100644 index 0000000..238a998 --- /dev/null +++ b/src/components/__tests__/el-svgIcon.test.jsx @@ -0,0 +1,236 @@ +import { markRaw, nextTick, ref } from 'vue' +import { mount } from '@vue/test-utils' +import { describe, expect, it, test } from 'vitest' +import { Loading, Search } from '@element-plus/icons-vue' + +import ElSvgIcon from '../ElSvgIcon.vue' + +// const AXIOM = 'Rem is the best girl' + +describe('ElSvgIcon.vue', () => { + it('create', () => { + const wrapper = mount(() => ) + // console.log(111111, wrapper.classes()) + // expect(wrapper.classes()).toContain('el-icon') + }) + + // it('icon', () => { + // const wrapper = mount(() => ) + // expect(wrapper.findAll('Search11222')).toBeTruthy() + // }) + // + // it('size', () => { + // const wrapper = mount(() => ) + // expect(wrapper.findAll('20px')).toBeTruthy() + // }) + // + // it('color', () => { + // const wrapper = mount(() => ) + // expect(wrapper.findAll('red')).toBeTruthy() + // }) + // + // it('nativeType', () => { + // const wrapper = mount(() => ) + // + // expect(wrapper.attributes('type')).toBe('submit') + // }) + // + // it('loading', () => { + // const wrapper = mount(() => ) + // + // expect(wrapper.classes()).toContain('is-loading') + // expect(wrapper.findComponent(Loading).exists()).toBeTruthy() + // }) + // + // it('size', () => { + // const wrapper = mount(() => ) + // + // expect(wrapper.classes()).toContain('el-button--large') + // }) + // + // it('plain', () => { + // const wrapper = mount(() => ) + // + // expect(wrapper.classes()).toContain('is-plain') + // }) + // + // it('round', () => { + // const wrapper = mount(() => ) + // expect(wrapper.classes()).toContain('is-round') + // }) + // + // it('circle', () => { + // const wrapper = mount(() => ) + // + // expect(wrapper.classes()).toContain('is-circle') + // }) + + // it('text', async () => { + // const bg = ref(false) + // + // const wrapper = mount(() => ) + // + // expect(wrapper.classes()).toContain('is-text') + // + // bg.value = true + // + // await nextTick() + // + // expect(wrapper.classes()).toContain('is-has-bg') + // }) + + // it('link', async () => { + // const wrapper = mount(() => ) + // + // expect(wrapper.classes()).toContain('is-link') + // }) + + // test('render text', () => { + // const wrapper = mount(() => ( + // AXIOM + // }} + // /> + // )) + // + // expect(wrapper.text()).toEqual(AXIOM) + // }) + // + // test('handle click', async () => { + // const wrapper = mount(() => ( + // AXIOM + // }} + // /> + // )) + // + // await wrapper.trigger('click') + // expect(wrapper.emitted()).toBeDefined() + // }) + // + // test('handle click inside', async () => { + // const wrapper = mount(() => ( + // + // }} + // /> + // )) + // + // wrapper.find('.inner-slot').trigger('click') + // expect(wrapper.emitted()).toBeDefined() + // }) + // + // test('loading implies disabled', async () => { + // const wrapper = mount(() => ( + // AXIOM + // }} + // loading + // /> + // )) + // + // await wrapper.trigger('click') + // expect(wrapper.emitted('click')).toBeUndefined() + // }) + // + // it('disabled', async () => { + // const wrapper = mount(() => ) + // + // expect(wrapper.classes()).toContain('is-disabled') + // await wrapper.trigger('click') + // expect(wrapper.emitted('click')).toBeUndefined() + // }) + // + // it('loading icon', () => { + // const wrapper = mount(() => ) + // + // expect(wrapper.findComponent(Search).exists()).toBeTruthy() + // }) + // + // it('loading slot', () => { + // const wrapper = mount({ + // setup: () => () => ( + // 111 }} loading={true}> + // Loading + // + // ) + // }) + // + // expect(wrapper.find('.custom-loading').exists()).toBeTruthy() + // }) +}) +// describe('ElSvgIcon Group', () => { +// it('create', () => { +// const wrapper = mount({ +// setup: () => () => +// ( +// +// Prev +// Next +// +// ) +// }) +// expect(wrapper.classes()).toContain('el-button-group') +// expect(wrapper.findAll('button').length).toBe(2) +// }) +// +// it('button group reactive size', async () => { +// const size = ref('small') +// const wrapper = mount({ +// setup: () => () => +// ( +// +// Prev +// Next +// +// ) +// }) +// expect(wrapper.classes()).toContain('el-button-group') +// expect(wrapper.findAll('.el-button-group button.el-button--small').length).toBe(2) +// +// size.value = 'large' +// await nextTick() +// +// expect(wrapper.findAll('.el-button-group button.el-button--large').length).toBe(2) +// }) +// +// it('button group type', async () => { +// const wrapper = mount({ +// setup: () => () => +// ( +// +// Prev +// Next +// +// ) +// }) +// expect(wrapper.classes()).toContain('el-button-group') +// expect(wrapper.findAll('.el-button-group button.el-button--primary').length).toBe(1) +// expect(wrapper.findAll('.el-button-group button.el-button--warning').length).toBe(1) +// }) +// +// it('add space in two Chinese characters', async () => { +// const wrapper = mount(() => ( +// '中文' +// }} +// autoInsertSpace +// /> +// )) +// +// expect(wrapper.find('.el-button span').text()).toBe('中文') +// expect(wrapper.find('.el-button span').classes()).toContain('el-button__text--expand') +// }) +// +// it('add space between two Chinese characters even if there is whitespace at both ends', async () => { +// const wrapper = mount(() =>  中文 ) +// +// expect(wrapper.find('.el-button span').text()).toBe('中文') +// expect(wrapper.find('.el-button span').classes()).toContain('el-button__text--expand') +// }) +// }) diff --git a/src/directives/button-codes.ts b/src/directives/button-codes.ts new file mode 100644 index 0000000..8a7db9b --- /dev/null +++ b/src/directives/button-codes.ts @@ -0,0 +1,21 @@ +import { useBasicStore } from '@/store/basic' + +function checkPermission(el, { value }) { + if (value && Array.isArray(value)) { + if (value.length) { + const permissionRoles = value + const hasPermission = useBasicStore().buttonCodes?.some((code) => permissionRoles.includes(code)) + if (!hasPermission) el.parentNode && el.parentNode.removeChild(el) + } + } else { + throw new Error(`need roles! Like v-permission="['admin','editor']"`) + } +} +export default { + mounted(el, binding) { + checkPermission(el, binding) + }, + componentUpdated(el, binding) { + checkPermission(el, binding) + } +} diff --git a/src/directives/codes-permission.ts b/src/directives/codes-permission.ts new file mode 100644 index 0000000..1d0bf24 --- /dev/null +++ b/src/directives/codes-permission.ts @@ -0,0 +1,20 @@ +import { useBasicStore } from '@/store/basic' +function checkPermission(el, { value }) { + if (value && Array.isArray(value)) { + if (value.length > 0) { + const permissionRoles = value + const hasPermission = useBasicStore().codes?.some((role) => permissionRoles.includes(role)) + if (!hasPermission) el.parentNode && el.parentNode.removeChild(el) + } + } else { + throw new Error(`need codes! Like v-codes-permission="['admin','editor']"`) + } +} +export default { + mounted(el, binding) { + checkPermission(el, binding) + }, + componentUpdated(el, binding) { + checkPermission(el, binding) + } +} diff --git a/src/directives/example/clickoutside.js b/src/directives/example/clickoutside.js new file mode 100644 index 0000000..f05ef9b --- /dev/null +++ b/src/directives/example/clickoutside.js @@ -0,0 +1,21 @@ + +export default { + mounted(el, binding) { + if (typeof binding.value !== 'function') { + throw 'callback must be a function'; + } + el.__handleClick__ = function (e) { + if (el.contains(e.target)) { + binding.value(false); + } + else { + binding.value(true); + } + }; + document.addEventListener('click', el.__handleClick__); + }, + beforeUnmount(el) { + document.removeEventListener('click', el.__handleClick__); + } + +} diff --git a/src/directives/example/copy.js b/src/directives/example/copy.js new file mode 100644 index 0000000..9316355 --- /dev/null +++ b/src/directives/example/copy.js @@ -0,0 +1,31 @@ +/** + * v-copy + * 复制某个值至剪贴板 + * 接收参数:string类型/Ref类型/Reactive类型 + */ +import { ElMessage } from 'element-plus'; +function handleClick(ev) { + const input = document.createElement('input'); + input.value = this.copyData.toLocaleString(); + document.body.appendChild(input); + input.select(); + document.execCommand('Copy'); + document.body.removeChild(input); + ElMessage({ + type: 'success', + message: '复制成功' + }); +} +export default { + mounted(el, binding) { + el.copyData = binding.value; + el.addEventListener('click', handleClick); + }, + updated(el, binding) { + el.copyData = binding.value; + }, + beforeUnmount(el) { + el.removeEventListener('click', el.__handleClick__); + } +}; + diff --git a/src/directives/example/debounce.js b/src/directives/example/debounce.js new file mode 100644 index 0000000..001021e --- /dev/null +++ b/src/directives/example/debounce.js @@ -0,0 +1,26 @@ +/** + * v-debounce + * 按钮防抖指令,可自行扩展至input + * 接收参数:function类型 + */ +export default { + mounted(el, binding) { + if (typeof binding.value !== 'function') { + console.error('callback must be a function'); + return; + } + let timer = null; + el.__handleClick__ = function (e) { + if (timer) { + clearInterval(timer); + } + timer = setTimeout(() => { + binding.value(); + }, 200); + }; + el.addEventListener('click', el.__handleClick__); + }, + beforeUnmount(el) { + el.removeEventListener('click', el.__handleClick__); + } +}; diff --git a/src/directives/example/longpress.js b/src/directives/example/longpress.js new file mode 100644 index 0000000..c76f977 --- /dev/null +++ b/src/directives/example/longpress.js @@ -0,0 +1,45 @@ +/** + * v-longpress + * 长按指令,长按时触发事件 + */ +export default { + mounted(el, binding) { + if (typeof binding.value !== 'function') { + throw 'callback must be a function'; + } + // 定义变量 + let pressTimer = null; + // 创建计时器( 2秒后执行函数 ) + const start = (e) => { + if (e.button) { + if (e.type === 'click' && e.button !== 0) { + return; + } + } + if (pressTimer === null) { + pressTimer = setTimeout(() => { + handler(e); + }, 1000); + } + }; + // 取消计时器 + const cancel = (e) => { + if (pressTimer !== null) { + clearTimeout(pressTimer); + pressTimer = null; + } + }; + // 运行函数 + const handler = (e) => { + binding.value(e); + }; + // 添加事件监听器 + el.addEventListener('mousedown', start); + el.addEventListener('touchstart', start); + // 取消计时器 + el.addEventListener('click', cancel); + el.addEventListener('mouseout', cancel); + el.addEventListener('touchend', cancel); + el.addEventListener('touchcancel', cancel); + }, +}; diff --git a/src/directives/example/watermark.js b/src/directives/example/watermark.js new file mode 100644 index 0000000..49cbf03 --- /dev/null +++ b/src/directives/example/watermark.js @@ -0,0 +1,28 @@ +/** + * v-watermark可接收参数,均为非必填 + * { text: 'vue-admin-box', font: '16px Microsoft JhengHei', textColor: '#000' } + */ +function addWaterMark(str, parentNode, font, textColor) { + // 水印文字,父元素,字体,文字颜色 + const can = document.createElement('canvas'); + parentNode.appendChild(can); + can.width = 200; + can.height = 150; + can.style.display = 'none'; + const cans = can.getContext('2d'); + cans.rotate((-20 * Math.PI) / 180); + cans.font = font || '16px Microsoft JhengHei'; + cans.fillStyle = textColor || 'rgba(180, 180, 180, 0.3)'; + cans.textAlign = 'left'; + cans.textBaseline = 'middle'; + cans.fillText(str || 'vue3-admin-plus', can.width / 10, can.height / 2); + parentNode.style.backgroundImage = `url(${ can.toDataURL('image/png') })`; +} +export default { + mounted(el, binding) { + binding.value ? binding.value : binding.value = {}; + addWaterMark(binding.value.text, el, binding.value.font, binding.value.textColor); + } +} + + diff --git a/src/directives/example/waves.css b/src/directives/example/waves.css new file mode 100644 index 0000000..af7a7ef --- /dev/null +++ b/src/directives/example/waves.css @@ -0,0 +1,26 @@ +.waves-ripple { + position: absolute; + border-radius: 100%; + background-color: rgba(0, 0, 0, 0.15); + background-clip: padding-box; + pointer-events: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-transform: scale(0); + -ms-transform: scale(0); + transform: scale(0); + opacity: 1; +} + +.waves-ripple.z-active { + opacity: 0; + -webkit-transform: scale(2); + -ms-transform: scale(2); + transform: scale(2); + -webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out; + transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out; + transition: opacity 1.2s ease-out, transform 0.6s ease-out; + transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out; +} \ No newline at end of file diff --git a/src/directives/example/waves.js b/src/directives/example/waves.js new file mode 100644 index 0000000..7fa67e6 --- /dev/null +++ b/src/directives/example/waves.js @@ -0,0 +1,72 @@ +import './waves.css' + +const context = '@@wavesContext' + +function handleClick(el, binding) { + function handle(e) { + const customOpts = Object.assign({}, binding.value) + const opts = Object.assign({ + ele: el, // 波纹作用元素 + type: 'hit', // hit 点击位置扩散 center中心点扩展 + color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色 + }, + customOpts + ) + const target = opts.ele + if (target) { + target.style.position = 'relative' + target.style.overflow = 'hidden' + const rect = target.getBoundingClientRect() + let ripple = target.querySelector('.waves-ripple') + if (!ripple) { + ripple = document.createElement('span') + ripple.className = 'waves-ripple' + ripple.style.height = ripple.style.width = `${Math.max(rect.width, rect.height) }px` + target.appendChild(ripple) + } else { + ripple.className = 'waves-ripple' + } + switch (opts.type) { + case 'center': + ripple.style.top = `${rect.height / 2 - ripple.offsetHeight / 2 }px` + ripple.style.left = `${rect.width / 2 - ripple.offsetWidth / 2 }px` + break + default: + ripple.style.top = + `${e.pageY - rect.top - ripple.offsetHeight / 2 - document.documentElement.scrollTop || + document.body.scrollTop }px` + ripple.style.left = + `${e.pageX - rect.left - ripple.offsetWidth / 2 - document.documentElement.scrollLeft || + document.body.scrollLeft }px` + } + ripple.style.backgroundColor = opts.color + ripple.className = 'waves-ripple z-active' + return false + } + } + + if (!el[context]) { + el[context] = { + removeHandle: handle + } + } else { + el[context].removeHandle = handle + } + + return handle +} + +export default { + mounted(el, binding) { + el.addEventListener('click', handleClick(el, binding), false) + }, + updated(el, binding) { + el.removeEventListener('click', el[context].removeHandle, false) + el.addEventListener('click', handleClick(el, binding), false) + }, + beforeUnmount(el) { + el.removeEventListener('click', el[context].removeHandle, false) + el[context] = null + delete el[context] + } +} diff --git a/src/directives/index.ts b/src/directives/index.ts new file mode 100644 index 0000000..45ab0fb --- /dev/null +++ b/src/directives/index.ts @@ -0,0 +1,26 @@ +import buttonCodes from './button-codes' +import codesPermission from './codes-permission' +import rolesPermission from './roles-permission' +import lang from './lang' + +import copy from './example/copy' +import longpress from './example/longpress' +import debounce from './example/debounce' +import watermark from './example/watermark' +import waves from './example/waves.js' +import clickoutside from './example/clickoutside' + +export default function (app) { + app.directive('ButtonCodes', buttonCodes) + app.directive('CodesPermission', codesPermission) + app.directive('RolesPermission', rolesPermission) + app.directive('lang', lang) + + //example + app.directive('copy', copy) + app.directive('longpress', longpress) + app.directive('debounce', debounce) + app.directive('watermark', watermark) + app.directive('waves', waves) + app.directive('clickoutside', clickoutside) +} diff --git a/src/directives/lang.ts b/src/directives/lang.ts new file mode 100644 index 0000000..d66c76c --- /dev/null +++ b/src/directives/lang.ts @@ -0,0 +1,44 @@ +import { watch } from 'vue' +import { storeToRefs } from 'pinia/dist/pinia' +import { langTitle } from '@/hooks/use-common' +import { useConfigStore } from '@/store/config' +//element-plus +const componentToProps = { + ElInput: 'placeholder', + ElTableColumn: 'label' +} + +function checkPermission(el, { value }) { + let saveOriginTitle = '' + const { language } = storeToRefs(useConfigStore()) + //save the original title + const name = el.__vueParentComponent?.type?.name + const nameTitle = el.__vueParentComponent?.props[componentToProps[name]] + saveOriginTitle = nameTitle || el.innerText + watch( + () => language.value, + () => { + //element tag or component + if (name?.startsWith('EL')) { + //self cunstrom + if (Object.keys(componentToProps).includes(name)) { + const props = el.__vueParentComponent.props + props[componentToProps[name]] = langTitle(saveOriginTitle) + } else { + el.innerText = langTitle(saveOriginTitle) + } + } else { + //common tag such as div span output so on; + if (el.__vnode?.type) { + el.innerText = langTitle(saveOriginTitle) + } + } + }, + { immediate: true } + ) +} +export default { + mounted(el, binding) { + checkPermission(el, binding) + } +} diff --git a/src/directives/roles-permission.ts b/src/directives/roles-permission.ts new file mode 100644 index 0000000..1b80598 --- /dev/null +++ b/src/directives/roles-permission.ts @@ -0,0 +1,20 @@ +import { useBasicStore } from '@/store/basic' +function checkPermission(el, { value }) { + if (value && Array.isArray(value)) { + if (value.length > 0) { + const permissionRoles = value + const hasPermission = useBasicStore().roles?.some((role) => permissionRoles.includes(role)) + if (!hasPermission) el.parentNode && el.parentNode.removeChild(el) + } + } else { + throw new Error(`need roles! Like v-roles-permission="['admin','editor']"`) + } +} +export default { + mounted(el, binding) { + checkPermission(el, binding) + }, + componentUpdated(el, binding) { + checkPermission(el, binding) + } +} diff --git a/src/hooks/use-common.ts b/src/hooks/use-common.ts new file mode 100644 index 0000000..5ed49ac --- /dev/null +++ b/src/hooks/use-common.ts @@ -0,0 +1,47 @@ +//复制文本 +import useClipboard from 'vue-clipboard3' +import { ElMessage } from 'element-plus' + +// i18n language match title +import { i18n } from '@/lang' +// the keys using zh file +import langEn from '@/lang/zh' +import settings from '@/settings' + +export const sleepTimeout = (time: number) => { + return new Promise((resolve) => { + const timer = setTimeout(() => { + clearTimeout(timer) + resolve(null) + }, time) + }) +} + +//深拷贝 +export function cloneDeep(value) { + return JSON.parse(JSON.stringify(value)) +} + +//copyValueToClipboard +const { toClipboard } = useClipboard() +export const copyValueToClipboard = (value: any) => { + toClipboard(JSON.stringify(value)) + ElMessage.success('复制成功') +} +const { t, te } = i18n.global +export const langTitle = (title) => { + if (!title) { + return settings.title + } + for (const key of Object.keys(langEn)) { + if (te(`${key}.${title}`) && t(`${key}.${title}`)) { + return t(`${key}.${title}`) + } + } + return title +} + +//get i18n instance +export const getLangInstance = () => { + return i18n.global as ObjKeys +} diff --git a/src/hooks/use-element.ts b/src/hooks/use-element.ts new file mode 100644 index 0000000..3079482 --- /dev/null +++ b/src/hooks/use-element.ts @@ -0,0 +1,214 @@ +import { reactive, ref, toRefs } from 'vue' +import { ElLoading, ElMessage, ElMessageBox, ElNotification } from 'element-plus' +import type { EpPropMergeType } from 'element-plus/es/utils' +export const useElement = () => { + // 正整数 + const upZeroInt = (rule, value, callback, msg) => { + if (!value) { + callback(new Error(`${msg}不能为空`)) + } + if (/^\+?[1-9]\d*$/.test(value)) { + callback() + } else { + callback(new Error(`${msg}输入有误`)) + } + } + + // 正整数(包括0) + const zeroInt = (rule, value, callback, msg) => { + if (!value) { + callback(new Error(`${msg}不能为空`)) + } + if (/^\+?[0-9]\d*$/.test(value)) { + callback() + } else { + callback(new Error(`${msg}输入有误`)) + } + } + + // 金额 + const money = (rule, value, callback, msg) => { + if (!value) { + callback(new Error(`${msg}不能为空`)) + } + if (/((^[1-9]\d*)|^0)(\.\d{0,2}){0,1}$/.test(value)) { + callback() + } else { + callback(new Error(`${msg}输入有误`)) + } + } + + // 手机号 + const phone = (rule, value, callback, msg) => { + if (!value) { + callback(new Error(`${msg}不能为空`)) + } + if (/^0?1[0-9]{10}$/.test(value)) { + callback() + } else { + callback(new Error(`${msg}输入有误`)) + } + } + + // 邮箱 + const email = (rule, value, callback, msg) => { + if (!value) { + callback(new Error(`${msg}不能为空`)) + } + if (/(^([a-zA-Z]|[0-9])(\w|-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4}))$/.test(value)) { + callback() + } else { + callback(new Error(`${msg}`)) + } + } + const state = reactive({ + /* table*/ + tableData: [], + rowDeleteIdArr: [], + loadingId: null, + /* 表单*/ + formModel: {}, + subForm: {}, + searchForm: {}, + /* 表单校验*/ + formRules: { + //非空 + isNull: (msg: string) => [{ required: false, message: `${msg}`, trigger: 'blur' }], + isNotNull: (msg: string) => [{ required: true, message: `${msg}`, trigger: 'blur' }], + // 正整数 + upZeroInt: (msg: string) => [ + { required: true, validator: (rule, value, callback) => upZeroInt(rule, value, callback, msg), trigger: 'blur' } + ], + // 正整数(包括0) + zeroInt: (msg: string) => [ + { required: true, validator: (rule, value, callback) => zeroInt(rule, value, callback, msg), trigger: 'blur' } + ], + // 金额 + money: (msg: string) => [ + { required: true, validator: (rule, value, callback) => money(rule, value, callback, msg), trigger: 'blur' } + ], + // 手机号 + phone: (msg: string) => [ + { required: true, validator: (rule, value, callback) => phone(rule, value, callback, msg), trigger: 'blur' } + ], + // 邮箱 + email: (msg: string) => [ + { required: true, validator: (rule, value, callback) => email(rule, value, callback, msg), trigger: 'blur' } + ] + }, + /* 时间packing相关*/ + datePickerOptions: { + //选择今天以后的日期,包括今天 + disabledDate: (time: any) => { + return time.getTime() < Date.now() - 86400000 + } + }, + startEndArr: [], + /* dialog相关*/ + dialogTitle: '添加', + detailDialog: false, + isDialogEdit: false, + dialogVisible: false, + tableLoading: false, + /* 树相关*/ + treeData: [], + defaultProps: { + children: 'children', + label: 'label' + } + }) + return { + ...toRefs(state) + } +} + +/* + * 通知弹框 + * message:通知的内容 + * type:通知类型 + * duration:通知显示时长(ms) + * */ +export const elMessage = (message: string, type?) => { + ElMessage({ + showClose: true, + message: message || '成功', + type: type || ('success' as string), + center: false + }) +} +/* + * loading加载框 + * 调用后通过 loadingId.close() 进行关闭 + * */ +let loadingId: any = null +export const elLoading = (msg?: string) => { + loadingId = ElLoading.service({ + lock: true, + text: msg || '数据载入中', + // spinner: 'el-icon-loading', + background: 'rgba(0, 0, 0, 0.1)' + }) +} +export const closeElLoading = () => { + loadingId.close() +} +/* + * 提示 + * message: 提示内容 + * type:提示类型 + * title:提示标题 + * duration:提示时长(ms) + * */ +export const elNotify = ( + message: string, + type: EpPropMergeType | undefined, + title: string, + duration: number +) => { + ElNotification({ + title: title || '提示', + type: type || 'success', + message: message || '请传入提示消息', + position: 'top-right', + duration: duration || 2500, + offset: 40 + }) +} +/* + 确认弹框(没有取消按钮) +* title:提示的标题 +* message:提示的内容 +* return Promise +* */ +export const elConfirmNoCancelBtn = (title: string, message: string) => { + return ElMessageBox({ + message: message || '你确定要删除吗', + title: title || '确认框', + confirmButtonText: '确定', + cancelButtonText: '取消', + showCancelButton: false, + type: 'warning' + }) +} +/* + * 确认弹框 + * title:提示的标题 + * message:提示的内容 + * return Promise + * */ +export const elConfirm = (title: string, message: string) => { + return ElMessageBox({ + message: message || '你确定要删除吗', + title: title || '确认框', + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }) +} + +/* 级联*/ +const cascaderKey = ref() +export const casHandleChange = () => { + // 解决目前级联选择器搜索输入报错问题 + cascaderKey.value += cascaderKey.value +} diff --git a/src/hooks/use-error-log.ts b/src/hooks/use-error-log.ts new file mode 100644 index 0000000..a59d854 --- /dev/null +++ b/src/hooks/use-error-log.ts @@ -0,0 +1,32 @@ +/*js 错误日志收集*/ +import { jsErrorCollection } from 'js-error-collection' +import pack from '../../package.json' +import settings from '@/settings' +import bus from '@/utils/bus' +import axiosReq from '@/utils/axios-req' +const reqUrl = '/integration-front/errorCollection/insert' +const errorLogReq = (errLog: string) => { + axiosReq({ + url: reqUrl, + data: { + pageUrl: window.location.href, + errorLog: errLog, + browserType: navigator.userAgent, + version: pack.version + }, + method: 'post' + }).then(() => { + //通知错误列表页面更新数据 + bus.emit('reloadErrorPage', {}) + }) +} + +export const useErrorLog = () => { + //判断该环境是否需要收集错误日志,由settings配置决定 + if (settings.errorLog?.includes(import.meta.env.VITE_APP_ENV)) { + jsErrorCollection({ runtimeError: true, rejectError: true, consoleError: true }, (errLog) => { + //判断是否是reqUrl错误,避免死循环 + if (!errLog.includes(reqUrl)) errorLogReq(errLog) + }) + } +} diff --git a/src/hooks/use-layout.ts b/src/hooks/use-layout.ts new file mode 100644 index 0000000..5b4eab2 --- /dev/null +++ b/src/hooks/use-layout.ts @@ -0,0 +1,44 @@ +/** + * 判断是否是外链 + * @param {string} path + * @returns {Boolean} + */ +import { onBeforeMount, onBeforeUnmount, onMounted } from 'vue' +import { useBasicStore } from '@/store/basic' +export function isExternal(path) { + return /^(https?:|mailto:|tel:)/.test(path) +} + +/*判断窗口变化控制侧边栏收起或展开*/ +export function resizeHandler() { + const { body } = document + const WIDTH = 992 + const basicStore = useBasicStore() + const isMobile = () => { + const rect = body.getBoundingClientRect() + return rect.width - 1 < WIDTH + } + const resizeHandler = () => { + if (!document.hidden) { + if (isMobile()) { + /*此处只做根据window尺寸关闭sideBar功能*/ + basicStore.setSidebarOpen(false) + } else { + basicStore.setSidebarOpen(true) + } + } + } + onBeforeMount(() => { + window.addEventListener('resize', resizeHandler) + }) + onMounted(() => { + if (isMobile()) { + basicStore.setSidebarOpen(false) + } else { + basicStore.setSidebarOpen(true) + } + }) + onBeforeUnmount(() => { + window.removeEventListener('resize', resizeHandler) + }) +} diff --git a/src/hooks/use-permission.ts b/src/hooks/use-permission.ts new file mode 100644 index 0000000..2c78780 --- /dev/null +++ b/src/hooks/use-permission.ts @@ -0,0 +1,184 @@ +import NProgress from 'nprogress' +import type { RouteRawConfig, RouterTypes, rawConfig } from '~/basic' +import type { RouteRecordName } from 'vue-router' +/** + * 根据请求,过滤异步路由 + * @param:menuList 异步路由数组 + * return 过滤后的异步路由 + */ +// @ts-ignore +import Layout from '@/layout/index.vue' +/* + * 路由操作 + * */ +import router, { asyncRoutes, constantRoutes, roleCodeRoutes } from '@/router' +//进度条 +import 'nprogress/nprogress.css' +import { useBasicStore } from '@/store/basic' + +const buttonCodes: Array = [] //按钮权限 +interface menuRow { + category: number + code: number + children: RouterTypes +} +export const filterAsyncRoutesByMenuList = (menuList) => { + const filterRouter: RouterTypes = [] + menuList.forEach((route: menuRow) => { + //button permission + if (route.category === 3) { + buttonCodes.push(route.code) + } else { + //generator every router item by menuList + const itemFromReqRouter = getRouteItemFromReqRouter(route) + if (route.children?.length) { + //judge the type is router or button + itemFromReqRouter.children = filterAsyncRoutesByMenuList(route.children) + } + filterRouter.push(itemFromReqRouter) + } + }) + return filterRouter +} +const getRouteItemFromReqRouter = (route): RouteRawConfig => { + const tmp: rawConfig = { meta: { title: '' } } + const routeKeyArr = ['path', 'component', 'redirect', 'alwaysShow', 'name', 'hidden'] + const metaKeyArr = ['title', 'activeMenu', 'elSvgIcon', 'icon'] + // @ts-ignore + const modules = import.meta.glob('../views/**/**.vue') + //generator routeKey + routeKeyArr.forEach((fItem) => { + if (fItem === 'component') { + if (route[fItem] === 'Layout') { + tmp[fItem] = Layout + } else { + //has error , i will fix it through plugins + //tmp[fItem] = () => import(`@/views/permission-center/test/TestTableQuery.vue`) + tmp[fItem] = modules[`../views/${route[fItem]}`] + } + } else if (fItem === 'path' && route.parentId === 0) { + tmp[fItem] = `/${route[fItem]}` + } else if (['hidden', 'alwaysShow'].includes(fItem)) { + tmp[fItem] = !!route[fItem] + } else if (['name'].includes(fItem)) { + tmp[fItem] = route['code'] + } else if (route[fItem]) { + tmp[fItem] = route[fItem] + } + }) + //generator metaKey + metaKeyArr.forEach((fItem) => { + if (route[fItem] && tmp.meta) tmp.meta[fItem] = route[fItem] + }) + //route extra insert + if (route.extra) { + Object.entries(route.extra.parse(route.extra)).forEach(([key, value]) => { + if (key === 'meta' && tmp.meta) { + tmp.meta[key] = value + } else { + tmp[key] = value + } + }) + } + return tmp as RouteRawConfig +} + +/** + * 根据角色数组过滤异步路由 + * @param routes asyncRoutes 未过滤的异步路由 + * @param roles 角色数组 + * return 过滤后的异步路由 + */ +export function filterAsyncRoutesByRoles(routes, roles) { + const res: RouterTypes = [] + routes.forEach((route) => { + const tmp: RouteRawConfig = { ...route } + if (hasPermission(roles, tmp)) { + if (tmp.children) { + tmp.children = filterAsyncRoutesByRoles(tmp.children, roles) + } + res.push(tmp) + } + }) + return res +} +function hasPermission(roles, route) { + if (route?.meta?.roles) { + return roles?.some((role) => route.meta.roles.includes(role)) + } else { + return true + } +} + +/** + * 根据code数组,过滤异步路由 + * @param codes code数组 + * @param codesRoutes 未过滤的异步路由 + * return 过滤后的异步路由 + */ +export function filterAsyncRouterByCodes(codesRoutes, codes) { + const filterRouter: RouterTypes = [] + codesRoutes.forEach((routeItem: RouteRawConfig) => { + if (hasCodePermission(codes, routeItem)) { + if (routeItem.children) routeItem.children = filterAsyncRouterByCodes(routeItem.children, codes) + filterRouter.push(routeItem) + } + }) + return filterRouter +} +function hasCodePermission(codes, routeItem) { + if (routeItem.meta?.code) { + return codes.includes(routeItem.meta.code) || routeItem.hidden + } else { + return true + } +} +//过滤异步路由 +export function filterAsyncRouter({ menuList, roles, codes }) { + const basicStore = useBasicStore() + let accessRoutes: RouterTypes = [] + const permissionMode = basicStore.settings?.permissionMode + if (permissionMode === 'rbac') { + accessRoutes = filterAsyncRoutesByMenuList(menuList) //by menuList + } else if (permissionMode === 'roles') { + accessRoutes = filterAsyncRoutesByRoles(roleCodeRoutes, roles) //by roles + } else { + accessRoutes = filterAsyncRouterByCodes(roleCodeRoutes, codes) //by codes + } + accessRoutes.forEach((route) => router.addRoute(route)) + asyncRoutes.forEach((item) => router.addRoute(item)) + basicStore.setFilterAsyncRoutes(accessRoutes) +} +//重置路由 +export function resetRouter() { + //移除之前存在的路由 + const routeNameSet: Set = new Set() + router.getRoutes().forEach((fItem) => { + if (fItem.name) routeNameSet.add(fItem.name) + }) + routeNameSet.forEach((setItem) => router.removeRoute(setItem)) + //新增constantRoutes + constantRoutes.forEach((feItem) => router.addRoute(feItem)) +} +//重置登录状态 +export function resetState() { + resetRouter() + useBasicStore().resetState() +} + +//刷新路由 +export function freshRouter(data) { + resetRouter() + filterAsyncRouter(data) + // location.reload() +} + +NProgress.configure({ showSpinner: false }) +//开始进度条 +export const progressStart = () => { + NProgress.start() +} +//关闭进度条 +export const progressClose = () => { + NProgress.done() +} diff --git a/src/hooks/use-self-router.ts b/src/hooks/use-self-router.ts new file mode 100644 index 0000000..b307e6d --- /dev/null +++ b/src/hooks/use-self-router.ts @@ -0,0 +1,43 @@ +import router from '@/router' +export const getQueryParam = () => { + const route: any = router.currentRoute + if (route.value?.query.params) { + return JSON.parse(route.value.query.params) + } +} +// vue router +export const routerPush = (name, params) => { + let data = {} + if (params) { + data = { + params: JSON.stringify(params) + } + } else { + data = {} + } + router.push({ + name, + query: data + }) +} +export const routerReplace = (name, params) => { + let data = {} + if (params) { + data = { + params: JSON.stringify(params) + } + } else { + data = {} + } + router.replace({ + name, + query: data + }) +} + +export const routeInfo = () => { + return router.currentRoute +} +export const routerBack = () => { + router.go(-1) +} diff --git a/src/hooks/use-table.ts b/src/hooks/use-table.ts new file mode 100644 index 0000000..3d817b3 --- /dev/null +++ b/src/hooks/use-table.ts @@ -0,0 +1,122 @@ +import { ref } from 'vue' +import momentMini from 'moment-mini' +import { elConfirm, elMessage } from './use-element' +export const useTable = (searchForm, selectPageReq) => { + /*define ref*/ + const tableListData = ref([]) + const totalPage = ref(0) + const pageNum = ref(1) + const pageSize = ref(20) + + //列表请求 + const tableListReq = (config) => { + const data = Object.assign( + { + pageNum: pageNum.value, + pageSize: pageSize.value + }, + JSON.parse(JSON.stringify(searchForm)) + ) + Object.keys(data).forEach((fItem) => { + if (['', null, undefined, Number.NaN].includes(data[fItem])) delete data[fItem] + if (config.method === 'get') { + if (Array.isArray(data[fItem])) delete data[fItem] + if (data[fItem] instanceof Object) delete data[fItem] + } + }) + const reqConfig = { + data, + ...config + } + return axiosReq(reqConfig) + } + + /** + * 日期范围选择处理 + * @param timeArr choose the time + * @author 熊猫哥 + * @date 2022/9/25 14:02 + */ + const dateRangePacking = (timeArr) => { + if (timeArr && timeArr.length === 2) { + searchForm.startTime = timeArr[0] + //取今天23点 + if (searchForm.endTime) { + searchForm.endTime = momentMini(timeArr[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss') + } + } else { + searchForm.startTime = '' + searchForm.endTime = '' + } + } + //当前页 + const handleCurrentChange = (val) => { + pageNum.value = val + selectPageReq() + } + const handleSizeChange = (val) => { + pageSize.value = val + selectPageReq() + } + const resetPageReq = () => { + pageNum.value = 1 + selectPageReq() + } + + /*多选*/ + const multipleSelection = ref>([]) + const handleSelectionChange = (val) => { + multipleSelection.value = val + } + /*批量删除*/ + const multiDelBtnDill = (reqConfig) => { + let rowDeleteIdArr: Array = [] + let deleteNameTitle = '' + rowDeleteIdArr = multipleSelection.value.map((mItem) => { + deleteNameTitle = `${deleteNameTitle + mItem.id},` + return mItem.id + }) + if (rowDeleteIdArr.length === 0) { + elMessage('表格选项不能为空', 'warning') + return + } + const stringLength = deleteNameTitle.length - 1 + elConfirm('删除', `您确定要删除【${deleteNameTitle.slice(0, stringLength)}】吗`).then(() => { + const data = rowDeleteIdArr + axiosReq({ + data, + method: 'DELETE', + bfLoading: true, + ...reqConfig + }).then(() => { + elMessage('删除成功') + resetPageReq() + }) + }) + } + //单个删除 + const tableDelDill = (row, reqConfig) => { + elConfirm('确定', `您确定要删除【${row.id}】吗?`).then(() => { + axiosReq(reqConfig).then(() => { + resetPageReq() + elMessage(`【${row.id}】删除成功`) + }) + }) + } + + return { + pageNum, + pageSize, + totalPage, + tableListData, + tableListReq, + dateRangePacking, + multipleSelection, + handleSelectionChange, + handleCurrentChange, + handleSizeChange, + resetPageReq, + multiDelBtnDill, + tableDelDill + } +} diff --git a/src/icons/SvgIcon.vue b/src/icons/SvgIcon.vue new file mode 100644 index 0000000..208ac15 --- /dev/null +++ b/src/icons/SvgIcon.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/src/icons/common/404.svg b/src/icons/common/404.svg new file mode 100644 index 0000000..e69de29 diff --git a/src/icons/common/bug.svg b/src/icons/common/bug.svg new file mode 100644 index 0000000..05a150d --- /dev/null +++ b/src/icons/common/bug.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/chart.svg b/src/icons/common/chart.svg new file mode 100644 index 0000000..27728fb --- /dev/null +++ b/src/icons/common/chart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/clipboard.svg b/src/icons/common/clipboard.svg new file mode 100644 index 0000000..90923ff --- /dev/null +++ b/src/icons/common/clipboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/component.svg b/src/icons/common/component.svg new file mode 100644 index 0000000..207ada3 --- /dev/null +++ b/src/icons/common/component.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/dashboard.svg b/src/icons/common/dashboard.svg new file mode 100644 index 0000000..5317d37 --- /dev/null +++ b/src/icons/common/dashboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/demo.svg b/src/icons/common/demo.svg new file mode 100644 index 0000000..05a150d --- /dev/null +++ b/src/icons/common/demo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/documentation.svg b/src/icons/common/documentation.svg new file mode 100644 index 0000000..7043122 --- /dev/null +++ b/src/icons/common/documentation.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/drag.svg b/src/icons/common/drag.svg new file mode 100644 index 0000000..4185d3c --- /dev/null +++ b/src/icons/common/drag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/edit.svg b/src/icons/common/edit.svg new file mode 100644 index 0000000..d26101f --- /dev/null +++ b/src/icons/common/edit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/education.svg b/src/icons/common/education.svg new file mode 100644 index 0000000..7bfb01d --- /dev/null +++ b/src/icons/common/education.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/email.svg b/src/icons/common/email.svg new file mode 100644 index 0000000..74d25e2 --- /dev/null +++ b/src/icons/common/email.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/example.svg b/src/icons/common/example.svg new file mode 100644 index 0000000..46f42b5 --- /dev/null +++ b/src/icons/common/example.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/excel.svg b/src/icons/common/excel.svg new file mode 100644 index 0000000..74d97b8 --- /dev/null +++ b/src/icons/common/excel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/exit-fullscreen.svg b/src/icons/common/exit-fullscreen.svg new file mode 100644 index 0000000..485c128 --- /dev/null +++ b/src/icons/common/exit-fullscreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/eye-open.svg b/src/icons/common/eye-open.svg new file mode 100644 index 0000000..88dcc98 --- /dev/null +++ b/src/icons/common/eye-open.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/eye.svg b/src/icons/common/eye.svg new file mode 100644 index 0000000..16ed2d8 --- /dev/null +++ b/src/icons/common/eye.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/form.svg b/src/icons/common/form.svg new file mode 100644 index 0000000..dcbaa18 --- /dev/null +++ b/src/icons/common/form.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/fullscreen.svg b/src/icons/common/fullscreen.svg new file mode 100644 index 0000000..0e86b6f --- /dev/null +++ b/src/icons/common/fullscreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/guide.svg b/src/icons/common/guide.svg new file mode 100644 index 0000000..b271001 --- /dev/null +++ b/src/icons/common/guide.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/hamburger.svg b/src/icons/common/hamburger.svg new file mode 100644 index 0000000..9766c95 --- /dev/null +++ b/src/icons/common/hamburger.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/src/icons/common/icon.svg b/src/icons/common/icon.svg new file mode 100644 index 0000000..82be8ee --- /dev/null +++ b/src/icons/common/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/international.svg b/src/icons/common/international.svg new file mode 100644 index 0000000..e9b56ee --- /dev/null +++ b/src/icons/common/international.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/language.svg b/src/icons/common/language.svg new file mode 100644 index 0000000..0082b57 --- /dev/null +++ b/src/icons/common/language.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/link.svg b/src/icons/common/link.svg new file mode 100644 index 0000000..48197ba --- /dev/null +++ b/src/icons/common/link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/list.svg b/src/icons/common/list.svg new file mode 100644 index 0000000..20259ed --- /dev/null +++ b/src/icons/common/list.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/lock.svg b/src/icons/common/lock.svg new file mode 100644 index 0000000..74fee54 --- /dev/null +++ b/src/icons/common/lock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/message.svg b/src/icons/common/message.svg new file mode 100644 index 0000000..14ca817 --- /dev/null +++ b/src/icons/common/message.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/money.svg b/src/icons/common/money.svg new file mode 100644 index 0000000..c1580de --- /dev/null +++ b/src/icons/common/money.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/nested.svg b/src/icons/common/nested.svg new file mode 100644 index 0000000..06713a8 --- /dev/null +++ b/src/icons/common/nested.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/password.svg b/src/icons/common/password.svg new file mode 100644 index 0000000..e291d85 --- /dev/null +++ b/src/icons/common/password.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/pdf.svg b/src/icons/common/pdf.svg new file mode 100644 index 0000000..957aa0c --- /dev/null +++ b/src/icons/common/pdf.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/people.svg b/src/icons/common/people.svg new file mode 100644 index 0000000..2bd54ae --- /dev/null +++ b/src/icons/common/people.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/peoples.svg b/src/icons/common/peoples.svg new file mode 100644 index 0000000..aab852e --- /dev/null +++ b/src/icons/common/peoples.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/qq.svg b/src/icons/common/qq.svg new file mode 100644 index 0000000..ee13d4e --- /dev/null +++ b/src/icons/common/qq.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/search.svg b/src/icons/common/search.svg new file mode 100644 index 0000000..84233dd --- /dev/null +++ b/src/icons/common/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/shopping.svg b/src/icons/common/shopping.svg new file mode 100644 index 0000000..87513e7 --- /dev/null +++ b/src/icons/common/shopping.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/sidebar-logo.svg b/src/icons/common/sidebar-logo.svg new file mode 100644 index 0000000..1825fb3 --- /dev/null +++ b/src/icons/common/sidebar-logo.svg @@ -0,0 +1,2 @@ + diff --git a/src/icons/common/size.svg b/src/icons/common/size.svg new file mode 100644 index 0000000..ddb25b8 --- /dev/null +++ b/src/icons/common/size.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/skill.svg b/src/icons/common/skill.svg new file mode 100644 index 0000000..a3b7312 --- /dev/null +++ b/src/icons/common/skill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/star.svg b/src/icons/common/star.svg new file mode 100644 index 0000000..6cf86e6 --- /dev/null +++ b/src/icons/common/star.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/tab.svg b/src/icons/common/tab.svg new file mode 100644 index 0000000..b4b48e4 --- /dev/null +++ b/src/icons/common/tab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/table.svg b/src/icons/common/table.svg new file mode 100644 index 0000000..0e3dc9d --- /dev/null +++ b/src/icons/common/table.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/theme.svg b/src/icons/common/theme.svg new file mode 100644 index 0000000..5982a2f --- /dev/null +++ b/src/icons/common/theme.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/tree-table.svg b/src/icons/common/tree-table.svg new file mode 100644 index 0000000..8aafdb8 --- /dev/null +++ b/src/icons/common/tree-table.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/tree.svg b/src/icons/common/tree.svg new file mode 100644 index 0000000..dd4b7dd --- /dev/null +++ b/src/icons/common/tree.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/user.svg b/src/icons/common/user.svg new file mode 100644 index 0000000..0ba0716 --- /dev/null +++ b/src/icons/common/user.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/wechat.svg b/src/icons/common/wechat.svg new file mode 100644 index 0000000..c586e55 --- /dev/null +++ b/src/icons/common/wechat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/common/zip.svg b/src/icons/common/zip.svg new file mode 100644 index 0000000..e69de29 diff --git a/src/icons/nav-bar/dashboard.svg b/src/icons/nav-bar/dashboard.svg new file mode 100644 index 0000000..5317d37 --- /dev/null +++ b/src/icons/nav-bar/dashboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/nav-bar/example.svg b/src/icons/nav-bar/example.svg new file mode 100644 index 0000000..46f42b5 --- /dev/null +++ b/src/icons/nav-bar/example.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/nav-bar/eye-open.svg b/src/icons/nav-bar/eye-open.svg new file mode 100644 index 0000000..88dcc98 --- /dev/null +++ b/src/icons/nav-bar/eye-open.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/nav-bar/eye.svg b/src/icons/nav-bar/eye.svg new file mode 100644 index 0000000..16ed2d8 --- /dev/null +++ b/src/icons/nav-bar/eye.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/nav-bar/form.svg b/src/icons/nav-bar/form.svg new file mode 100644 index 0000000..dcbaa18 --- /dev/null +++ b/src/icons/nav-bar/form.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/nav-bar/language.svg b/src/icons/nav-bar/language.svg new file mode 100644 index 0000000..4b8ed72 --- /dev/null +++ b/src/icons/nav-bar/language.svg @@ -0,0 +1 @@ + diff --git a/src/icons/nav-bar/link.svg b/src/icons/nav-bar/link.svg new file mode 100644 index 0000000..48197ba --- /dev/null +++ b/src/icons/nav-bar/link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/nav-bar/nested.svg b/src/icons/nav-bar/nested.svg new file mode 100644 index 0000000..06713a8 --- /dev/null +++ b/src/icons/nav-bar/nested.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/nav-bar/password.svg b/src/icons/nav-bar/password.svg new file mode 100644 index 0000000..e291d85 --- /dev/null +++ b/src/icons/nav-bar/password.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/nav-bar/table.svg b/src/icons/nav-bar/table.svg new file mode 100644 index 0000000..0e3dc9d --- /dev/null +++ b/src/icons/nav-bar/table.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/nav-bar/theme-icon.svg b/src/icons/nav-bar/theme-icon.svg new file mode 100644 index 0000000..49a3613 --- /dev/null +++ b/src/icons/nav-bar/theme-icon.svg @@ -0,0 +1,2 @@ + diff --git a/src/icons/nav-bar/tree.svg b/src/icons/nav-bar/tree.svg new file mode 100644 index 0000000..dd4b7dd --- /dev/null +++ b/src/icons/nav-bar/tree.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/nav-bar/user.svg b/src/icons/nav-bar/user.svg new file mode 100644 index 0000000..0ba0716 --- /dev/null +++ b/src/icons/nav-bar/user.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/lang/en.ts b/src/lang/en.ts new file mode 100644 index 0000000..5d08966 --- /dev/null +++ b/src/lang/en.ts @@ -0,0 +1,123 @@ +export default { + router: { + Dashboard: '', + 'Setting Switch': '', + 'Error Log': '', + 'Error Index': '', + 'Error Generator': '', + + Nested: '', + Menu1: '', + 'Menu1-1': '', + 'Menu1-2': '', + 'Menu1-2-1': '', + 'Menu1-2-2': '', + 'Menu1-3': '', + menu2: '', + + 'External Link': '', + + 'Basic Demo': '', + Hook: '', + Pinia: '', + Mock: '', + 'Svg Icon': '', + 'Parent Children': '', + 'Second KeepAlive': '', + 'Tab KeepAlive': '', + 'Third KeepAlive': '', + SecondChild: '', + ThirdChild: '', + + Worker: '', + + Permission: '', + + 'Permission Switch': '', + 'Role Index': '', + 'Code Index': '', + 'Button Permission': '' + }, + navbar: { + Home: '', + Github: '', + Docs: '', + 'login out': '' + }, + + //page + dashboard: { + 'switch theme': '', + 'switch size': '', + 'switch language': '', + en: 'English', + zh: '中文', + 'Button Group': '', + 'unocss using': '', + 'global var': '' + }, + 'error-log': { + log: '', + pageUrl: '', + startDate: '', + endDate: '', + github: '', + search: '', + reset: '', + multiDel: '' + }, + permission: { + addRole: '', + editPermission: '', + roles: '', + switchRoles: '', + tips: + '在某些情况下,不适合使用 v-permission。例如:Element-UI 的 el-tab 或 el-table-column 以及其它动态渲染 dom 的场景。你只能通过手动设置 v-if 来实现。', + delete: '删除', + confirm: '确定', + cancel: '取消' + }, + guide: { + description: '引导页对于一些第一次进入项目的人很有用,你可以简单介绍下项目的功能。本 Demo 是基于', + button: '打开引导' + }, + components: { + documentation: '文档', + tinymceTips: + '富文本是管理后台一个核心的功能,但同时又是一个有很多坑的地方。在选择富文本的过程中我也走了不少的弯路,市面上常见的富文本都基本用过了,最终权衡了一下选择了Tinymce。更详细的富文本比较和介绍见', + dropzoneTips: + '由于我司业务有特殊需求,而且要传七牛 所以没用第三方,选择了自己封装。代码非常的简单,具体代码你可以在这里看到 @/components/Dropzone', + stickyTips: '当页面滚动到预设的位置会吸附在顶部', + backToTopTips1: '页面滚动到指定位置会在右下角出现返回顶部按钮', + backToTopTips2: + '可自定义按钮的样式、show/hide、出现的高度、返回的位置 如需文字提示,可在外部使用Element的el-tooltip元素', + imageUploadTips: + '由于我在使用时它只有vue@1版本,而且和mockjs不兼容,所以自己改造了一下,如果大家要使用的话,优先还是使用官方版本。' + }, + table: { + dynamicTips1: '固定表头, 按照表头顺序排序', + dynamicTips2: '不固定表头, 按照点击顺序排序', + dragTips1: '默认顺序', + dragTips2: '拖拽后顺序', + title: '标题', + importance: '重要性', + type: '类型', + remark: '点评', + search: '搜索', + add: '添加', + export: '导出', + reviewer: '审核人', + id: '序号', + date: '时间', + author: '作者', + readings: '阅读数', + status: '状态', + actions: '操作', + edit: '编辑', + publish: '发布', + draft: '草稿', + delete: '删除', + cancel: '取 消', + confirm: '确 定' + } +} diff --git a/src/lang/index.ts b/src/lang/index.ts new file mode 100644 index 0000000..d052994 --- /dev/null +++ b/src/lang/index.ts @@ -0,0 +1,19 @@ +import { createI18n } from 'vue-i18n' +import en from './en' +import zh from './zh' +import settings from '@/settings' +const messages = { en, zh } + +const localeData = { + globalInjection: true, //如果设置true, $t() 函数将注册到全局 + legacy: false, //如果想在composition api中使用需要设置为false + locale: settings.defaultLanguage, + messages // set locale messages +} + +export const i18n = createI18n(localeData) +export const setupI18n = { + install(app) { + app.use(i18n) + } +} diff --git a/src/lang/zh.ts b/src/lang/zh.ts new file mode 100644 index 0000000..fb18a4f --- /dev/null +++ b/src/lang/zh.ts @@ -0,0 +1,177 @@ +export default { + router: { + Dashboard: '首页', + LowCodePlatFrom: '低代码平台', + RBAC: '用户权限角色', + Guide: '指引', + 'Setting Switch': '配置文件', + 'Error Log': '错误日志', + 'Error Index': '错误日志列表', + 'Error Generator': '错误日志生成', + + Nested: '路由嵌套', + Menu1: '菜单1', + 'Menu1-1': '菜单 1-1', + 'Menu1-2': '菜单 1-2', + 'Menu1-2-1': '菜单 1-2-1', + 'Menu1-2-2': '菜单 1-2-2', + 'Menu1-3': '菜单 1-3', + menu2: '菜单 2', + + 'External Link': '外链', + + 'Basic Demo': '基础例子', + Hook: 'hook', + Pinia: 'pinia', + Mock: 'mock', + 'Svg Icon': 'svg使用', + 'Parent Children': '父子组件通信', + 'Second KeepAlive': '二级路由缓存', + 'Tab KeepAlive': 'tab缓存', + 'Third KeepAlive': '三级路由缓存', + SecondChild: '三级路由示例1', + ThirdChild: '三级路由示例2', + Worker: '多线程', + Permission: '权限路由', + 'Permission Switch': '权限切换', + 'Role Index': '角色权限', + 'Code Index': 'Code权限', + 'Button Permission': '按钮权限', + + Charts: '图表', + Directive: '指令', + Excel: 'Excel', + 'Rich Text': '富文本', + Table: '表格', + Guid: '使用引导', + Other: '其他' + }, + + tagsView: { + Refresh: '刷新', + Close: '关闭当前', + 'Close Others': '关闭其他', + 'Close All': '关闭所有' + }, + navbar: { + Home: '首页', + Github: '项目git地址', + Docs: '官方文档', + 'login out': '退出登录' + }, + //page + dashboard: { + 'switch theme': '切换主题色', + 'switch size': '切换尺寸', + 'switch language': '切换语言', + en: 'English', + zh: '中文', + 'Button Group': '按钮组', + 'unocss using': 'unocss使用', + 'global var': '全局静态变量' + }, + 'error-log': { + log: '错误日志', + pageUrl: '页面路径', + startDate: '开始日期', + endDate: '结束日期', + github: 'Github 地址', + search: '查询', + reset: '重置', + multiDel: '批量删除' + } + // permission: { + // addRole: '新增角色', + // editPermission: '编辑权限', + // roles: '你的权限', + // switchRoles: '切换权限', + // tips: + // '在某些情况下,不适合使用 v-permission。例如:Element-UI 的 el-tab 或 el-table-column 以及其它动态渲染 dom 的场景。你只能通过手动设置 v-if 来实现。', + // delete: '删除', + // confirm: '确定', + // cancel: '取消' + // }, + // guide: { + // description: '引导页对于一些第一次进入项目的人很有用,你可以简单介绍下项目的功能。本 Demo 是基于', + // button: '打开引导' + // }, + // components: { + // documentation: '文档', + // tinymceTips: + // '富文本是管理后台一个核心的功能,但同时又是一个有很多坑的地方。在选择富文本的过程中我也走了不少的弯路,市面上常见的富文本都基本用过了,最终权衡了一下选择了Tinymce。更详细的富文本比较和介绍见', + // dropzoneTips: + // '由于我司业务有特殊需求,而且要传七牛 所以没用第三方,选择了自己封装。代码非常的简单,具体代码你可以在这里看到 @/components/Dropzone', + // stickyTips: '当页面滚动到预设的位置会吸附在顶部', + // backToTopTips1: '页面滚动到指定位置会在右下角出现返回顶部按钮', + // backToTopTips2: + // '可自定义按钮的样式、show/hide、出现的高度、返回的位置 如需文字提示,可在外部使用Element的el-tooltip元素', + // imageUploadTips: + // '由于我在使用时它只有vue@1版本,而且和mockjs不兼容,所以自己改造了一下,如果大家要使用的话,优先还是使用官方版本。' + // }, + // table: { + // dynamicTips1: '固定表头, 按照表头顺序排序', + // dynamicTips2: '不固定表头, 按照点击顺序排序', + // dragTips1: '默认顺序', + // dragTips2: '拖拽后顺序', + // title: '标题', + // importance: '重要性', + // type: '类型', + // remark: '点评', + // search: '搜索', + // add: '添加', + // export: '导出', + // reviewer: '审核人', + // id: '序号', + // date: '时间', + // author: '作者', + // readings: '阅读数', + // status: '状态', + // actions: '操作', + // edit: '编辑', + // publish: '发布', + // draft: '草稿', + // delete: '删除', + // cancel: '取 消', + // confirm: '确 定' + // }, + // example: { + // warning: + // '创建和编辑页面是不能被 keep-alive 缓存的,因为keep-alive 的 include 目前不支持根据路由来缓存,所以目前都是基于 component name 来进行缓存的。如果你想类似的实现缓存效果,可以使用 localStorage 等浏览器缓存方案。或者不要使用 keep-alive 的 include,直接缓存所有页面。详情见' + // }, + // errorLog: { + // tips: '请点击右上角bug小图标', + // description: + // '现在的管理后台基本都是spa的形式了,它增强了用户体验,但同时也会增加页面出问题的可能性,可能一个小小的疏忽就导致整个页面的死锁。好在 Vue 官网提供了一个方法来捕获处理异常,你可以在其中进行错误处理或者异常上报。', + // documentation: '文档介绍' + // }, + // excel: { + // export: '导出', + // selectedExport: '导出已选择项', + // placeholder: '请输入文件名(默认excel-list)' + // }, + // zip: { + // export: '导出', + // placeholder: '请输入文件名(默认file)' + // }, + // pdf: { + // tips: '这里使用 window.print() 来实现下载pdf的功能' + // }, + // theme: { + // change: '换肤', + // documentation: '换肤文档', + // tips: 'Tips: 它区别于 navbar 上的 theme-pick, 是两种不同的换肤方法,各自有不同的应用场景,具体请参考文档。' + // }, + // tagsView: { + // refresh: '刷新', + // close: '关闭', + // closeOthers: '关闭其它', + // closeAll: '关闭所有' + // }, + // settings: { + // title: '系统布局配置', + // theme: '主题色', + // tagsView: '开启 Tags-View', + // fixedHeader: '固定 Header', + // sidebarLogo: '侧边栏 Logo' + // } +} diff --git a/src/layout/app-main/Breadcrumb.vue b/src/layout/app-main/Breadcrumb.vue new file mode 100644 index 0000000..8dae76c --- /dev/null +++ b/src/layout/app-main/Breadcrumb.vue @@ -0,0 +1,86 @@ + + + + + diff --git a/src/layout/app-main/Hamburger.vue b/src/layout/app-main/Hamburger.vue new file mode 100644 index 0000000..aa6b6ca --- /dev/null +++ b/src/layout/app-main/Hamburger.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/src/layout/app-main/Navbar.vue b/src/layout/app-main/Navbar.vue new file mode 100644 index 0000000..aa1aa51 --- /dev/null +++ b/src/layout/app-main/Navbar.vue @@ -0,0 +1,129 @@ + + + + + diff --git a/src/layout/app-main/TagsView.vue b/src/layout/app-main/TagsView.vue new file mode 100644 index 0000000..b6ddfe3 --- /dev/null +++ b/src/layout/app-main/TagsView.vue @@ -0,0 +1,305 @@ + + + + + + + diff --git a/src/layout/app-main/component/LangSelect.vue b/src/layout/app-main/component/LangSelect.vue new file mode 100644 index 0000000..de9b18e --- /dev/null +++ b/src/layout/app-main/component/LangSelect.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/src/layout/app-main/component/ScreenFull.vue b/src/layout/app-main/component/ScreenFull.vue new file mode 100644 index 0000000..f984fa5 --- /dev/null +++ b/src/layout/app-main/component/ScreenFull.vue @@ -0,0 +1,57 @@ + + + + + diff --git a/src/layout/app-main/component/ScreenLock.vue b/src/layout/app-main/component/ScreenLock.vue new file mode 100644 index 0000000..6c420a4 --- /dev/null +++ b/src/layout/app-main/component/ScreenLock.vue @@ -0,0 +1,225 @@ + + + + diff --git a/src/layout/app-main/component/SizeSelect.vue b/src/layout/app-main/component/SizeSelect.vue new file mode 100644 index 0000000..b2feaaf --- /dev/null +++ b/src/layout/app-main/component/SizeSelect.vue @@ -0,0 +1,39 @@ + + + + + diff --git a/src/layout/app-main/component/ThemeSelect.vue b/src/layout/app-main/component/ThemeSelect.vue new file mode 100644 index 0000000..7affc64 --- /dev/null +++ b/src/layout/app-main/component/ThemeSelect.vue @@ -0,0 +1,52 @@ + + + + + diff --git a/src/layout/app-main/index.vue b/src/layout/app-main/index.vue new file mode 100644 index 0000000..c6916ba --- /dev/null +++ b/src/layout/app-main/index.vue @@ -0,0 +1,120 @@ + + + + + diff --git a/src/layout/index.vue b/src/layout/index.vue new file mode 100644 index 0000000..295abbf --- /dev/null +++ b/src/layout/index.vue @@ -0,0 +1,68 @@ + + + + diff --git a/src/layout/sidebar/Link.vue b/src/layout/sidebar/Link.vue new file mode 100644 index 0000000..1875bee --- /dev/null +++ b/src/layout/sidebar/Link.vue @@ -0,0 +1,31 @@ + + + diff --git a/src/layout/sidebar/Logo.vue b/src/layout/sidebar/Logo.vue new file mode 100644 index 0000000..2729cbc --- /dev/null +++ b/src/layout/sidebar/Logo.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/src/layout/sidebar/MenuIcon.vue b/src/layout/sidebar/MenuIcon.vue new file mode 100644 index 0000000..fd78e1d --- /dev/null +++ b/src/layout/sidebar/MenuIcon.vue @@ -0,0 +1,25 @@ + + + + + diff --git a/src/layout/sidebar/SidebarItem.vue b/src/layout/sidebar/SidebarItem.vue new file mode 100644 index 0000000..1cc500c --- /dev/null +++ b/src/layout/sidebar/SidebarItem.vue @@ -0,0 +1,82 @@ + + + diff --git a/src/layout/sidebar/index.vue b/src/layout/sidebar/index.vue new file mode 100644 index 0000000..edae7cc --- /dev/null +++ b/src/layout/sidebar/index.vue @@ -0,0 +1,42 @@ + + + + diff --git a/src/lib/element-plus.ts b/src/lib/element-plus.ts new file mode 100644 index 0000000..a4c34bb --- /dev/null +++ b/src/lib/element-plus.ts @@ -0,0 +1,8 @@ +import * as AllComponent from 'element-plus' +//element-plus中按需引入会引起首次加载过慢 +const elementPlusComponentNameArr = ['ElButton'] +export default function (app) { + elementPlusComponentNameArr.forEach((component) => { + app.component(component, AllComponent[component]) + }) +} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..dc02059 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,52 @@ +import { createApp } from 'vue' +import { createPinia } from 'pinia' +import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' +import ElementPlus from 'element-plus' +import App from './App.vue' +import router from './router' + +//import theme +import './theme/index.scss' + +//import unocss +import 'uno.css' + +//i18n +import { setupI18n } from '@/lang' + +import '@/styles/index.scss' // global css + +//svg-icon +import 'virtual:svg-icons-register' +import svgIcon from '@/icons/SvgIcon.vue' +import directive from '@/directives' + +//import router intercept +import './permission' + +//import element-plus +import 'element-plus/dist/index.css' +const app = createApp(App) + +//router +app.use(router) + +//pinia +const pinia = createPinia() +pinia.use(piniaPluginPersistedstate) +app.use(pinia) + +//i18n +app.use(setupI18n) +app.component('SvgIcon', svgIcon) +directive(app) + +//element-plus +app.use(ElementPlus) + +//import vxe-table +import VXETable from 'vxe-table' +import 'vxe-table/lib/style.css' +app.use(VXETable) + +app.mount('#app') diff --git a/src/permission.ts b/src/permission.ts new file mode 100644 index 0000000..a2f7bb3 --- /dev/null +++ b/src/permission.ts @@ -0,0 +1,50 @@ +import router from '@/router' +import { filterAsyncRouter, progressClose, progressStart } from '@/hooks/use-permission' +import { useBasicStore } from '@/store/basic' +import { userInfoReq } from '@/api/user' +import { langTitle } from '@/hooks/use-common' + +//路由进入前拦截 +//to:将要进入的页面 vue-router4.0 不推荐使用next() +const whiteList = ['/login', '/404', '/401'] // no redirect whitelist +router.beforeEach(async (to) => { + progressStart() + document.title = langTitle(to.meta?.title) // i18 page title + const basicStore = useBasicStore() + //1.判断token + if (basicStore.token) { + if (to.path === '/login') { + return '/' + } else { + //2.判断是否获取用户信息 + if (!basicStore.getUserInfo) { + try { + const userData = await userInfoReq() + //3.动态路由权限筛选 + filterAsyncRouter(userData) + //4.保存用户信息到store + basicStore.setUserInfo(userData) + //5.再次执行路由跳转 + return { ...to, replace: true } + } catch (e) { + console.error(`route permission error${e}`) + basicStore.resetState() + progressClose() + return `/login?redirect=${to.path}` + } + } else { + return true + } + } + } else { + if (!whiteList.includes(to.path)) { + return `/login?redirect=${to.path}` + } else { + return true + } + } +}) +//路由进入后拦截 +router.afterEach(() => { + progressClose() +}) diff --git a/src/plugins/vite-plugin-setup-extend/index.ts b/src/plugins/vite-plugin-setup-extend/index.ts new file mode 100644 index 0000000..20e200d --- /dev/null +++ b/src/plugins/vite-plugin-setup-extend/index.ts @@ -0,0 +1,38 @@ +import { parse } from '@vue/compiler-sfc' +import { render } from 'ejs' +import type { Plugin } from 'vite' +export default ({ inject }): Plugin => { + // let viteConfig + return { + name: 'vite-plugin-setup-extend', + enforce: 'pre', + // configResolved(resolvedConfig) { + // viteConfig = resolvedConfig + // }, + async transformIndexHtml(html) { + const result = await render(html, { ...inject }) + return result + }, + transform(code, id) { + if (/\.vue$/.test(id)) { + const { descriptor } = parse(code) + if (!descriptor?.scriptSetup?.setup) { + return null + } + const { lang, name } = descriptor.scriptSetup?.attrs || {} + const dillStr = headString(lang, name) + code += dillStr + return code + } + } + } +} + +const headString = (lang, name) => { + return `\n` +} diff --git a/src/router/index.ts b/src/router/index.ts new file mode 100644 index 0000000..3d10321 --- /dev/null +++ b/src/router/index.ts @@ -0,0 +1,222 @@ +import { createRouter, createWebHashHistory } from 'vue-router' +import basicDemo from './modules/basic-demo' +import charts from './modules/charts' +import richText from './modules/rich-text' +import table from './modules/table' +import excel from './modules/excel' +import directive from './modules/directive' +import other from './modules/other' +import guid from './modules/guid' +import type { RouterTypes } from '~/basic' +import Layout from '@/layout/index.vue' + +export const constantRoutes: RouterTypes = [ + { + path: '/redirect', + component: Layout, + hidden: true, + children: [ + { + path: '/redirect/:path(.*)', + component: () => import('@/views/redirect') + } + ] + }, + + { + path: '/login', + component: () => import('@/views/login/index.vue'), + hidden: true + }, + { + path: '/404', + component: () => import('@/views/error-page/404.vue'), + hidden: true + }, + { + path: '/401', + component: () => import('@/views/error-page/401.vue'), + hidden: true + }, + { + path: '/', + component: Layout, + redirect: '/dashboard', + children: [ + { + path: 'dashboard', + name: 'Dashboard', + component: () => import('@/views/dashboard/index.vue'), + //using el svg icon, the elSvgIcon first when at the same time using elSvgIcon and icon + meta: { title: 'Dashboard', elSvgIcon: 'Fold', affix: true } + } + ] + }, + guid, + + { + path: '/RBAC', + component: Layout, + children: [ + { + path: 'https://github.jzfai.top/low-code-platform/#/permission-center/user-table-query', + meta: { title: 'RBAC', icon: 'skill' } + } + ] + }, + basicDemo, + richText, + charts, + table, + directive, + excel, + other, + { + path: '/setting-switch', + component: Layout, + children: [ + { + path: 'index', + component: () => import('@/views/setting-switch/index.vue'), + name: 'SettingSwitch', + meta: { title: 'Setting Switch', icon: 'example' } + } + ] + }, + { + path: '/error-log', + component: Layout, + meta: { title: 'Error Log', icon: 'eye' }, + alwaysShow: true, + children: [ + { + path: 'error-log', + component: () => import('@/views/error-log/index.vue'), + name: 'ErrorLog', + meta: { title: 'Error Index' } + }, + { + path: 'error-generator', + component: () => import('@/views/error-log/error-generator.vue'), + name: 'ErrorGenerator', + meta: { title: 'Error Generator' } + } + ] + }, + { + path: '/nested', + component: Layout, + redirect: '/nested/menu1', + name: 'Nested', + meta: { + title: 'Nested', + icon: 'nested' + }, + children: [ + { + path: 'menu1', + component: () => import('@/views/nested/menu1/index.vue'), // Parent router-view + name: 'Menu1', + meta: { title: 'Menu1' }, + children: [ + { + path: 'menu1-1', + component: () => import('@/views/nested/menu1/menu1-1/index.vue'), + name: 'Menu1-1', + meta: { title: 'Menu1-1' } + }, + { + path: 'menu1-2', + component: () => import('@/views/nested/menu1/menu1-2/index.vue'), + name: 'Menu1-2', + meta: { title: 'Menu1-2' }, + children: [ + { + path: 'menu1-2-1', + component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1/index.vue'), + name: 'Menu1-2-1', + meta: { title: 'Menu1-2-1' } + }, + { + path: 'menu1-2-2', + component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2/index.vue'), + name: 'Menu1-2-2', + meta: { title: 'Menu1-2-2' } + } + ] + }, + { + path: 'menu1-3', + component: () => import('@/views/nested/menu1/menu1-3/index.vue'), + name: 'Menu1-3', + meta: { title: 'Menu1-3' } + } + ] + }, + { + path: 'menu2', + component: () => import('@/views/nested/menu2/index.vue'), + name: 'Menu2', + meta: { title: 'menu2' } + } + ] + } +] + +//角色和code数组动态路由 +export const roleCodeRoutes: RouterTypes = [ + { + path: '/roles-codes', + component: Layout, + redirect: '/roles-codes/page', + alwaysShow: true, // will always show the root menu + name: 'Permission', + meta: { + title: 'Permission', + icon: 'lock', + roles: ['admin', 'editor'] // you can set roles in root nav + }, + children: [ + { + path: 'index', + component: () => import('@/views/roles-codes/index.vue'), + name: 'RolesCodes', + meta: { title: 'Permission Switch' } + }, + { + path: 'roleIndex', + component: () => import('@/views/roles-codes/role-index.vue'), + name: 'RoleIndex', + meta: { title: 'Role Index', roles: ['admin'] } + }, + { + path: 'code-index', + component: () => import('@/views/roles-codes/code-index.vue'), + name: 'CodeIndex', + meta: { title: 'Code Index', code: 16 } + }, + { + path: 'button-permission', + component: () => import('@/views/roles-codes/button-permission.vue'), + name: 'ButtonPermission', + meta: { title: 'Button Permission' } + } + ] + } +] +/** + * asyncRoutes + * the routes that need to be dynamically loaded based on user roles + */ +export const asyncRoutes: RouterTypes = [ + // 404 page must be placed at the end !!! + { path: '/:catchAll(.*)', name: 'CatchAll', redirect: '/404', hidden: true } +] + +const router = createRouter({ + history: createWebHashHistory(), + scrollBehavior: () => ({ top: 0 }), + routes: constantRoutes +}) + +export default router diff --git a/src/router/modules/basic-demo.ts b/src/router/modules/basic-demo.ts new file mode 100644 index 0000000..e93584b --- /dev/null +++ b/src/router/modules/basic-demo.ts @@ -0,0 +1,100 @@ +import Layout from '@/layout/index.vue' +const BasicDemo = { + path: '/basic-demo', + component: Layout, + meta: { title: 'Basic Demo', icon: 'eye-open' }, + alwaysShow: true, + children: [ + { + path: 'hook', + component: () => import('@/views/basic-demo/hook/index.vue'), + name: 'Hook', + meta: { title: 'Hook' } + }, + { + path: 'pinia', + component: () => import('@/views/basic-demo/pinia/index.vue'), + name: 'Pinia', + meta: { title: 'Pinia' } + }, + { + path: 'mock', + component: () => import('@/views/basic-demo/mock/index.vue'), + name: 'Mock', + meta: { title: 'Mock' } + }, + { + path: 'svg-icon', + component: () => import('@/views/basic-demo/svg-icon/index.vue'), + name: 'SvgIcon', + meta: { title: 'Svg Icon' } + }, + { + path: 'parent-children', + component: () => import('@/views/basic-demo/parent-children/index.vue'), + name: 'Parent', + meta: { title: 'Parent Children' } + }, + { + path: 'second-keep-alive', + component: () => import('@/views/basic-demo/keep-alive/index.vue'), + name: 'SecondKeepAlive', + //cachePage: cachePage when page enter, default false + //leaveRmCachePage: remove cachePage when page leave, default false + meta: { title: 'Second KeepAlive', cachePage: true, leaveRmCachePage: false } + }, + { + path: 'second-child', + name: 'SecondChild', + hidden: true, + component: () => import('@/views/basic-demo/keep-alive/second-child.vue'), + meta: { title: 'SecondChild', cachePage: true, activeMenu: '/basic-demo/second-keep-alive' } + }, + { + path: 'third-child', + name: 'ThirdChild', + hidden: true, + component: () => import('@/views/basic-demo/keep-alive/third-child.vue'), + meta: { title: 'ThirdChild', cachePage: true, activeMenu: '/basic-demo/second-keep-alive' } + }, + //tab-keep-alive + { + path: 'tab-keep-alive', + component: () => import('@/views/basic-demo/keep-alive/tab-keep-alive.vue'), + name: 'TabKeepAlive', + //closeTabRmCache: remove cachePage when tabs close, default false + meta: { title: 'Tab KeepAlive', cachePage: true, closeTabRmCache: true } + }, + //third-keep-alive + { + path: 'third-keep-alive', + name: 'ThirdKeepAlive', + component: () => import('@/views/basic-demo/keep-alive/third-keep-alive.vue'), + //注:移除父容器页面缓存会把子页面一起移除了 + meta: { title: 'Third KeepAlive', cachePage: true, leaveRmCachePage: false }, + alwaysShow: true, + children: [ + { + path: 'second-children', + name: 'SecondChildren', + component: () => import('@/views/basic-demo/keep-alive/third-children/SecondChildren.vue'), + meta: { title: 'SecondChild', cachePage: true, leaveRmCachePage: true } + }, + { + path: 'third-children', + name: 'ThirdChildren', + component: () => import('@/views/basic-demo/keep-alive/third-children/ThirdChildren.vue'), + meta: { title: 'ThirdChild', cachePage: true, leaveRmCachePage: false } + } + ] + }, + { + path: 'worker', + component: () => import('@/views/basic-demo/worker/index.vue'), + name: 'Worker', + meta: { title: 'Worker' } + } + ] +} + +export default BasicDemo diff --git a/src/router/modules/charts.ts b/src/router/modules/charts.ts new file mode 100644 index 0000000..c8841eb --- /dev/null +++ b/src/router/modules/charts.ts @@ -0,0 +1,42 @@ +/** When your routing table is too long, you can split it into small modules**/ + +import Layout from '@/layout/index.vue' + +const chartsRouter = { + path: '/charts', + component: Layout, + redirect: 'noRedirect', + name: 'Charts', + meta: { + title: 'Charts', + icon: 'chart' + }, + children: [ + { + path: 'keyboard', + component: () => import('@/views/charts/keyboard.vue'), + name: 'KeyboardChart', + meta: { title: 'Keyboard Chart', noCache: true } + }, + { + path: 'line', + component: () => import('@/views/charts/line.vue'), + name: 'LineChart', + meta: { title: 'Line Chart', noCache: true } + }, + { + path: 'mix-chart', + component: () => import('@/views/charts/mix-chart.vue'), + name: 'MixChart', + meta: { title: 'Mix Chart', noCache: true } + }, + { + path: 'echarts-demo', + component: () => import('@/views/charts/echarts-demo.vue'), + name: 'EchartsDemo', + meta: { title: 'Echarts Demo', noCache: true } + } + ] +} + +export default chartsRouter diff --git a/src/router/modules/directive.ts b/src/router/modules/directive.ts new file mode 100644 index 0000000..ce26e09 --- /dev/null +++ b/src/router/modules/directive.ts @@ -0,0 +1,48 @@ +import Layout from '@/layout/index.vue' + +const directive = { + path: '/directive', + component: Layout, + meta: { title: 'Directive', icon: 'education' }, + alwaysShow: true, + children: [ + { + path: 'copy', + component: () => import('@/views/directive/copy.vue'), + name: 'copy', + meta: { title: 'v-copy' } + }, + { + path: 'debounce', + component: () => import('@/views/directive/debounce.vue'), + name: 'debounce', + meta: { title: 'v-debounce' } + }, + { + path: 'longpress', + component: () => import('@/views/directive/longpress.vue'), + name: 'longpress', + meta: { title: 'v-longpress' } + }, + { + path: 'watermark', + component: () => import('@/views/directive/watermark.vue'), + name: 'watermark', + meta: { title: 'v-watermark' } + }, + { + path: 'waves', + component: () => import('@/views/directive/waves.vue'), + name: 'waves', + meta: { title: 'v-waves' } + }, + { + path: 'clickoutside', + component: () => import('@/views/directive/clickoutside.vue'), + name: 'clickoutside', + meta: { title: 'v-clickoutside' } + } + ] +} + +export default directive diff --git a/src/router/modules/excel.ts b/src/router/modules/excel.ts new file mode 100644 index 0000000..d722541 --- /dev/null +++ b/src/router/modules/excel.ts @@ -0,0 +1,23 @@ +import Layout from '@/layout/index.vue' +const excel = { + path: '/excel', + component: Layout, + meta: { title: 'EXCEL', icon: 'excel' }, + alwaysShow: true, + children: [ + { + path: 'exportExcel', + component: () => import('@/views/excel/exportExcel.vue'), + name: 'exportExcel', + meta: { title: 'exportExcel' } + }, + { + path: 'importExcel', + component: () => import('@/views/excel/importExcel.vue'), + name: 'importExcel', + meta: { title: 'importExcel' } + } + ] +} + +export default excel diff --git a/src/router/modules/guid.ts b/src/router/modules/guid.ts new file mode 100644 index 0000000..885f0e2 --- /dev/null +++ b/src/router/modules/guid.ts @@ -0,0 +1,14 @@ +import Layout from '@/layout/index.vue' +const guid = { + path: '/guide', + component: Layout, + children: [ + { + path: 'index', + component: () => import('@/views/guide/index.vue'), + name: 'Guide', + meta: { title: 'Guide', icon: 'guide' } + } + ] +} +export default guid diff --git a/src/router/modules/other.ts b/src/router/modules/other.ts new file mode 100644 index 0000000..31c708c --- /dev/null +++ b/src/router/modules/other.ts @@ -0,0 +1,35 @@ +import Layout from '@/layout/index.vue' +const other = { + path: '/other', + component: Layout, + meta: { title: 'Other', icon: 'eye-open' }, + alwaysShow: true, + children: [ + { + path: 'count-to', + component: () => import('@/views/other/count-to.vue'), + name: 'CountTo', + meta: { title: 'CountTo' } + }, + { + path: 'd3', + component: () => import('@/views/other/d3/index.vue'), + name: 'd3', + meta: { title: 'd3' } + }, + { + path: 'drag-pane', + component: () => import('@/views/other/drag-pane.vue'), + name: 'DragPane', + meta: { title: 'DragPane' } + }, + { + path: 'signboard', + component: () => import('@/views/other/signboard/index.vue'), + name: 'signboard', + meta: { title: 'signboard' } + } + ] +} + +export default other diff --git a/src/router/modules/rich-text.ts b/src/router/modules/rich-text.ts new file mode 100644 index 0000000..252e42f --- /dev/null +++ b/src/router/modules/rich-text.ts @@ -0,0 +1,17 @@ +import Layout from '@/layout/index.vue' +const richText = { + path: '/rich-text', + component: Layout, + meta: { title: 'Rich Text', icon: 'clipboard' }, + alwaysShow: true, + children: [ + { + path: 'tinymce', + name: 'Tinymce', + component: () => import('@/views/rich-text/TinymceExample.vue'), + meta: { title: 'Tinymce', icon: 'nested' } + } + ] +} + +export default richText diff --git a/src/router/modules/table.ts b/src/router/modules/table.ts new file mode 100644 index 0000000..64b8f8e --- /dev/null +++ b/src/router/modules/table.ts @@ -0,0 +1,23 @@ +import Layout from '@/layout/index.vue' +const table = { + path: '/table', + component: Layout, + meta: { title: 'Table', icon: 'table' }, + alwaysShow: true, + children: [ + { + path: 'dynamic-table', + name: 'DynamicTable', + component: () => import('@/views/table/dynamic-table.vue'), + meta: { title: 'Dynamic Table', icon: 'nested' } + }, + { + path: 'vxe-table', + name: 'VxeTable', + component: () => import('@/views/table/vxe-table.vue'), + meta: { title: 'Vxe Table', icon: 'nested' } + } + ] +} + +export default table diff --git a/src/settings.ts b/src/settings.ts new file mode 100644 index 0000000..f468d95 --- /dev/null +++ b/src/settings.ts @@ -0,0 +1,115 @@ +import packageJson from '../package.json' +import type { SettingsConfig } from '~/basic' +export const settings: SettingsConfig = { + title: packageJson.name, + /** + * @type {boolean} true | false + * @description Whether show the logo in sidebar + */ + sidebarLogo: true, + /** + * @type {boolean} true | false + * @description Whether show the title in Navbar + */ + showNavbarTitle: false, + /** + * @type {boolean} true | false + * @description Whether show the drop-down + */ + ShowDropDown: true, + /** + * @type {boolean} true | false + * @description Whether show Hamburger + */ + showHamburger: true, + /** + * @type {boolean} true | false + * @description Whether show the settings right-panel + */ + showLeftMenu: true, + /** + * @type {boolean} true | false + * @description Whether show TagsView + */ + showTagsView: true, + /** + * @description TagsView show number + */ + tagsViewNum: 6, + /** + * @type {boolean} true | false + * @description Whether show the top Navbar + */ + showTopNavbar: true, + /* page animation related*/ + /** + * @type {boolean} true | false + * @description Whether need animation of main area + */ + mainNeedAnimation: false, + /** + * @type {boolean} true | false + * @description Whether need nprogress + */ + isNeedNprogress: true, + + /*page login or other*/ + /** + * @type {boolean} true | false + * @description Whether need login + */ + isNeedLogin: true, + /** + * @type {string} 'rbac'| 'roles' | 'code' + */ + permissionMode: 'roles', + /** + * @type {boolean} true | false + * @description Whether open prod mock + */ + openProdMock: true, + /** + * @type {string | array} 'dev' | ['prod','test','dev'] according to the .env file props of VITE_APP_ENV + * @description Need show err logs component. + * The default is only used in the production env + * If you want to also use it in dev, you can pass ['dev', 'test'] + */ + errorLog: ['prod'], + /* + * table height(100vh-delWindowHeight) + * */ + delWindowHeight: '210px', + /* + * setting dev token when isNeedLogin is setting false + * */ + tmpToken: 'tmp_token', + + /* + * vite.config.js base config + * */ + viteBasePath: './', + + /* + * i18n setting default language + * en/zh + * */ + defaultLanguage: 'en', + /* + * default theme + * base-theme/lighting-theme/dark-theme + * */ + defaultTheme: 'base-theme', + /* + * setting default defaultSize + * large / default /small + * */ + defaultSize: 'small', + /* + * vite.config.js base config + * such as + * */ + //平台id 2->vue3-admin-plus + plateFormId: 2 +} + +export default settings diff --git a/src/store/basic.ts b/src/store/basic.ts new file mode 100644 index 0000000..d673308 --- /dev/null +++ b/src/store/basic.ts @@ -0,0 +1,112 @@ +import { nextTick } from 'vue' +import { defineStore } from 'pinia' +import type { RouterTypes } from '~/basic' +import defaultSettings from '@/settings' +import router, { constantRoutes } from '@/router' +export const useBasicStore = defineStore('basic', { + state: () => { + return { + token: '', + getUserInfo: false, + userInfo: { username: '', avatar: '' }, //user info + //router + allRoutes: [] as RouterTypes, + buttonCodes: [], + filterAsyncRoutes: [], + roles: [] as Array, + codes: [] as Array, + //keep-alive + cachedViews: [] as Array, + cachedViewsDeep: [] as Array, + //other + sidebar: { opened: true }, + //axios req collection + axiosPromiseArr: [] as Array, + settings: defaultSettings + } + }, + persist: { + storage: localStorage, + paths: ['token'] + }, + actions: { + setToken(data) { + this.token = data + }, + setFilterAsyncRoutes(routes) { + this.$patch((state) => { + state.filterAsyncRoutes = routes + state.allRoutes = constantRoutes.concat(routes) + }) + }, + setUserInfo({ userInfo, roles, codes }) { + const { username, avatar } = userInfo + this.$patch((state) => { + state.roles = roles + state.codes = codes + state.getUserInfo = true + state.userInfo.username = username + state.userInfo.avatar = avatar + }) + }, + resetState() { + this.$patch((state) => { + state.token = '' //reset token + state.roles = [] + state.codes = [] + //reset router + state.allRoutes = [] + state.buttonCodes = [] + state.filterAsyncRoutes = [] + //reset userInfo + state.userInfo.username = '' + state.userInfo.avatar = '' + }) + this.getUserInfo = false + }, + resetStateAndToLogin() { + this.resetState() + nextTick(() => { + router.push({ path: '/login' }) + }) + }, + setSidebarOpen(data) { + this.$patch((state) => { + state.sidebar.opened = data + }) + }, + setToggleSideBar() { + this.$patch((state) => { + state.sidebar.opened = !state.sidebar.opened + }) + }, + + /*keepAlive缓存*/ + addCachedView(view) { + this.$patch((state) => { + if (state.cachedViews.includes(view)) return + state.cachedViews.push(view) + }) + }, + + delCachedView(view) { + this.$patch((state) => { + const index = state.cachedViews.indexOf(view) + index > -1 && state.cachedViews.splice(index, 1) + }) + }, + /*third keepAlive*/ + addCachedViewDeep(view) { + this.$patch((state) => { + if (state.cachedViewsDeep.includes(view)) return + state.cachedViewsDeep.push(view) + }) + }, + setCacheViewDeep(view) { + this.$patch((state) => { + const index = state.cachedViewsDeep.indexOf(view) + index > -1 && state.cachedViewsDeep.splice(index, 1) + }) + } + } +}) diff --git a/src/store/config.ts b/src/store/config.ts new file mode 100644 index 0000000..f4053f1 --- /dev/null +++ b/src/store/config.ts @@ -0,0 +1,33 @@ +import { defineStore } from 'pinia' +import { langTitle } from '@/hooks/use-common' +import settings from '@/settings' +import { toggleHtmlClass } from '@/theme/utils' +import { i18n } from '@/lang' +export const useConfigStore = defineStore('config', { + state: () => { + return { + language: settings.defaultLanguage, + theme: settings.defaultTheme, + size: settings.defaultSize + } + }, + persist: { + storage: localStorage, + paths: ['language', 'theme', 'size'] + }, + actions: { + setTheme(data: string) { + this.theme = data + toggleHtmlClass(data) + }, + setSize(data: string) { + this.size = data + }, + setLanguage(lang: string, title) { + const { locale }: any = i18n.global + this.language = lang + locale.value = lang + document.title = langTitle(title) // i18 page title + } + } +}) diff --git a/src/store/tags-view.ts b/src/store/tags-view.ts new file mode 100644 index 0000000..26137cc --- /dev/null +++ b/src/store/tags-view.ts @@ -0,0 +1,65 @@ +import { defineStore } from 'pinia' +import setting from '@/settings' +export const useTagsViewStore = defineStore('tagsView', { + state: () => { + return { + visitedViews: [] //tag标签数组 + } + }, + actions: { + addVisitedView(view) { + this.$patch((state: any) => { + //判断添加的标签存在直接返回 + if (state.visitedViews.some((v) => v.path === view.path)) return + //添加的数量如果大于 setting.tagsViewNum,则替换最后一个元素,否则在visitedViews数组后插入一个元素 + if (state.visitedViews.length >= setting.tagsViewNum) { + state.visitedViews.pop() + state.visitedViews.push( + Object.assign({}, view, { + title: view.meta.title || 'no-name' + }) + ) + } else { + state.visitedViews.push( + Object.assign({}, view, { + title: view.meta.title || 'no-name' + }) + ) + } + }) + }, + delVisitedView(view) { + return new Promise((resolve) => { + this.$patch((state: any) => { + //匹配view.path元素将其删除 + for (const [i, v] of state.visitedViews.entries()) { + if (v.path === view.path) { + state.visitedViews.splice(i, 1) + break + } + } + resolve([...state.visitedViews]) + }) + }) + }, + delOthersVisitedViews(view) { + return new Promise((resolve) => { + this.$patch((state) => { + state.visitedViews = state.visitedViews.filter((v: ObjKeys) => { + return v.meta.affix || v.path === view.path + }) + resolve([...state.visitedViews]) + }) + }) + }, + delAllVisitedViews() { + return new Promise((resolve) => { + this.$patch((state) => { + // keep affix tags + state.visitedViews = state.visitedViews.filter((tag: ObjKeys) => tag.meta?.affix) + resolve([...state.visitedViews]) + }) + }) + } + } +}) diff --git a/src/styles/index.scss b/src/styles/index.scss new file mode 100644 index 0000000..ddebc39 --- /dev/null +++ b/src/styles/index.scss @@ -0,0 +1,69 @@ +//scss 语法糖包含常用的布局方式 flex column +@import './scss-suger.scss'; +//重置 element-plus 样式 +@import './reset-elemenet-plus-style.scss'; +//动画文件 +@import './transition.scss'; + +//reset style +body { + height: 100%; + margin: 0; + padding: 0; + font-size: 14px; +} +* { + box-sizing: border-box; +} +*::before, +*::after { + box-sizing: border-box; +} +a:focus, +a:active { + outline: none; +} +a, +a:focus, +a:hover { + cursor: pointer; + color: inherit; + text-decoration: none; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + line-height: 1; + font-weight: 400; + margin: 0; + padding: 0; +} +span, +output { + display: inline-block; + line-height: 1; +} + +//scroll +@mixin main-show-wh() { + /* css 声明 */ + //height: calc(100vh - #{$navBarHeight} - #{$tagViewHeight} - #{$appMainPadding * 2}); + height: calc(100vh - #{var(--nav-bar-height)} - #{var(--tag-view-height)} - #{calc(var(--app-main-padding) * 2)}); + width: 100%; +} +.scroll-y { + @include main-show-wh(); + overflow-y: auto; +} +.scroll-x { + @include main-show-wh(); + overflow-x: auto; +} +.scroll-xy { + @include main-show-wh(); + overflow: auto; +} diff --git a/src/styles/reset-elemenet-plus-style.scss b/src/styles/reset-elemenet-plus-style.scss new file mode 100644 index 0000000..c7a101f --- /dev/null +++ b/src/styles/reset-elemenet-plus-style.scss @@ -0,0 +1,4 @@ +//leave the padding of el-scroll sidebar +.el-scrollbar__view { + padding-bottom: 80px; +} diff --git a/src/styles/scss-suger.scss b/src/styles/scss-suger.scss new file mode 100644 index 0000000..677ad18 --- /dev/null +++ b/src/styles/scss-suger.scss @@ -0,0 +1,274 @@ +/*脱落文档流定位*/ +.center-50 { + //居中定位 + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 10; +} +.center-top60 { + position: absolute; + top: 60%; + left: 50%; + transform: translate(-50%, -60%); + z-index: 10; +} +.center-top70 { + position: absolute; + top: 70%; + left: 50%; + transform: translate(-50%, -70%); + z-index: 10; +} +.center-top80 { + position: absolute; + top: 80%; + left: 50%; + transform: translate(-50%, -80%); + z-index: 10; +} +.center-top90 { + position: absolute; + top: 80%; + left: 50%; + transform: translate(-50%, -90%); + z-index: 10; +} +/*fixed*/ +.fixed-center-50 { + //居中定位 + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 10; +} +.fixed-center-top60 { + position: fixed; + top: 60%; + left: 50%; + transform: translate(-50%, -60%); + z-index: 10; +} +.fixed-center-top70 { + position: fixed; + top: 70%; + left: 50%; + transform: translate(-50%, -70%); + z-index: 10; +} +.fixed-center-top80 { + position: fixed; + top: 80%; + left: 50%; + transform: translate(-50%, -80%); + z-index: 10; +} +.fixed-center-top90 { + position: fixed; + top: 90%; + left: 50%; + transform: translate(-50%, -90%); + z-index: 10; +} +.fixed-center-top95 { + position: fixed; + top: 95%; + left: 50%; + transform: translate(-50%, -95%); + z-index: 10; +} + +/* +flex布局 第一个字母为主轴 +*/ +//start +.rowSS { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: flex-start; +} +.rowSC { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: center; +} +.rowSE { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: flex-end; +} +//space-between +.rowBS { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; +} +.rowBC { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; +} +.rowBE { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-end; +} +//space-around +.rowAS { + display: flex; + flex-direction: row; + justify-content: space-around; + align-items: flex-start; +} +.rowAC { + display: flex; + flex-direction: row; + justify-content: space-around; + align-items: center; +} +.rowAE { + display: flex; + flex-direction: row; + justify-content: space-around; + align-items: flex-end; +} +//center +.rowCS { + display: flex; + flex-direction: row; + justify-content: center; + align-items: flex-start; +} +.rowCC { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; +} + +.rowCE { + display: flex; + flex-direction: row; + justify-content: center; + align-items: flex-end; +} + +/*col*/ +//start +.columnSS { + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; +} +.columnSC { + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: center; +} +.columnSE { + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-end; +} +//space-between +.columnBS { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: flex-start; +} +.columnBC { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; +} +.columnBE { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: flex-end; +} +//space-around +.columnAS { + display: flex; + flex-direction: column; + justify-content: space-around; + align-items: flex-start; +} +.columnAC { + display: flex; + flex-direction: column; + justify-content: space-around; + align-items: center; +} +.columnAE { + display: flex; + flex-direction: column; + justify-content: space-around; + align-items: flex-end; +} +//center +.columnCS { + display: flex; + flex-direction: column; + justify-content: center; + align-items: flex-start; +} +.columnCC { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} +.columnCE { + display: flex; + flex-direction: column; + justify-content: center; + align-items: flex-end; +} + +//*图标 +.star-icon { + color: #f56c6c; + font-size: 14px; + margin-right: 4px; +} + +.fix-btn-to-bottom { + position: fixed; + bottom: 0; + left: 50%; + transform: translate(-50%, 0); + z-index: 10; + height: 60px; + background: #fff; + width: 100vw; +} + +//table操作栏 +.table-operation-btn { + span { + //点击样式 + cursor: pointer; + color: #477ef5; + } +} + +//table操作栏 +.btn-click-style { + //点击样式 + cursor: pointer; + color: #477ef5; +} diff --git a/src/styles/transition.scss b/src/styles/transition.scss new file mode 100644 index 0000000..1c6400c --- /dev/null +++ b/src/styles/transition.scss @@ -0,0 +1,44 @@ +// vue global transition css define +/* sidebar-logo-fade */ +.sidebar-logo-fade-enter-active { + transition: opacity var(--logo-switch-duration); +} +.sidebar-logo-fade-enter-from, +.sidebar-logo-fade-leave-to { + opacity: 0; +} + +/* fade-transform AppMain*/ +.fade-transform-leave-active, +.fade-transform-enter-active { + transition: all var(--page-transform-duration); +} + +.fade-transform-enter-from { + opacity: 0; + transform: translateX(-10px); +} + +.fade-transform-leave-to { + opacity: 0; + transform: translateX(10px); +} +.fade-transform-active { + position: absolute; +} + +/* breadcrumb transition */ +.breadcrumb-enter-active, +.breadcrumb-leave-active { + transition: all var(--breadcrumb-change-duration); +} + +.breadcrumb-enter-from, +.breadcrumb-leave-active { + opacity: 0; + transform: translateX(10px); +} + +.breadcrumb-leave-active { + position: absolute; +} diff --git a/src/theme/base/custom/ct-css-vars.scss b/src/theme/base/custom/ct-css-vars.scss new file mode 100644 index 0000000..c97b647 --- /dev/null +++ b/src/theme/base/custom/ct-css-vars.scss @@ -0,0 +1,67 @@ +html.base-theme { + /*element-plus section */ + --el-menu-active-color: #409eff; + --el-menu-text-color: #bfcbd9; + --el-menu-hover-text-color: var(--el-color-primary); + --el-menu-bg-color: #304156; + --el-menu-hover-bg-color: #263445; + --el-menu-item-height: 56px; + --el-menu-border-color: none; + /*layout section*/ + //layout + --layout-border-left-color: #ddd; + //Breadcrumb + --breadcrumb-no-redirect: #97a8be; + //Hamburger + --hamburger-color: #2b2f3a; + --hamburger-width: 20px; + --hamburger-height: 20px; + //Sidebar + --sidebar-el-icon-size: 20px; + --sidebar-logo-background: #2b2f3a; + --sidebar-logo-color: #ff9901; + --sidebar-logo-width: 32px; + --sidebar-logo-height: 32px; + --sidebar-logo-title-color: #fff; + --side-bar-width: 210px; + --side-bar-border-right-color: '#ddd'; + //TagsView + --tags-view-background: #fff; + --tags-view-border-bottom-color: #d8dce5; + --tags-view-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04); + --tags-view-item-background: #fff; + --tags-view-item-border-color: #d8dce5; + --tags-view-item-color: #495060; + --tag-view-height: 32px; + --tags-view-item-active-background: #42b983; + --tags-view-item-active-color: #fff; + --tags-view-item-active-border-color: #42b983; + --tags-view-contextmenu-background: #fff; + --tags-view-contextmenu-color: #333; + --tags-view-contextmenu-box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3); + --tags-view-contextmenu-hover-background: #eee; + //close-icon + --tags-view-close-icon-hover-background: #b4bccc; + --tags-view-close-icon-hover-color: #fff; + //AppMain.vue + --app-main-padding: 10px; + --app-main-background: #fff; + //Navbar.vue + --nav-bar-height: 50px; + --nav-bar-background: #fff; + --nav-bar-box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); + --nav-bar-right-menu-background: #fff; + + //transition 动画 + //侧边栏切换动画时长 + --sideBar-switch-duration: 0.2s; + //logo切换动画时长 + --logo-switch-duration: 1s; + //页面动画时长 + --page-transform-duration: 0.2s; + //面包屑导航动画时长 + --breadcrumb-change-duration: 0.2s; + + //进度条颜色 + --pregress-bar-color: #409eff; +} diff --git a/src/theme/base/element-plus/button.scss b/src/theme/base/element-plus/button.scss new file mode 100644 index 0000000..af0da39 --- /dev/null +++ b/src/theme/base/element-plus/button.scss @@ -0,0 +1,122 @@ +html.base-theme { + .at-button-low { + --el-button-text-color: #262626; + --el-button-bg-color: #ffffff; + --el-button-border-color: #d9d9d9; + --el-button-outline-color: #d9d9d9; + + --el-button-hover-text-color: #c72210; + --el-button-hover-link-text-color: #c72210; + --el-button-hover-bg-color: #ffece6; + --el-button-hover-border-color: transparent; + + --el-button-active-color: #a8150a; + --el-button-active-bg-color: #a8150a; + --el-button-active-border-color: transparent; + + --el-button-disabled-text-color: #a6a6a6; + --el-button-disabled-bg-color: #ffece6; + --el-button-disabled-border-color: #c72210; + //loading + --el-button-loading-text-color: #c72210; + --el-button-loading-bg-color: #ffece6; + --el-button-loading-border-color: #c72210; + } + + .at-button-middle { + --el-button-text-color: #c72210; + --el-button-bg-color: #ffece6; + --el-button-border-color: #c72210; + --el-button-outline-color: #c72210; + + --el-button-hover-text-color: #ffffff; + --el-button-hover-link-text-color: #ffffff; + --el-button-hover-bg-color: #c72210; + --el-button-hover-border-color: #c72210; + + --el-button-active-color: #ffffff; + --el-button-active-bg-color: #a8150a; + --el-button-active-border-color: #a8150a; + + --el-button-disabled-text-color: #a6a6a6; + --el-button-disabled-bg-color: #ffffff; + --el-button-disabled-border-color: #d9d9d9; + + //loading + --el-button-loading-text-color: #c72210; + --el-button-loading-bg-color: #ffece6; + --el-button-loading-border-color: #c72210; + } + + .at-button-height { + --el-button-text-color: #ffffff; + --el-button-bg-color: #c72210; + --el-button-border-color: transparent; + --el-button-outline-color: transparent; + + --el-button-hover-text-color: #ffffff; + --el-button-hover-link-text-color: #ffffff; + --el-button-hover-bg-color: #dd715b; + --el-button-hover-border-color: #c72210; + + --el-button-active-color: #ffffff; + --el-button-active-bg-color: #a8150a; + --el-button-active-border-color: transparent; + + --el-button-disabled-text-color: #a6a6a6; + --el-button-disabled-bg-color: #f5f5f5; + --el-button-disabled-border-color: transparent; + + //loading + --el-button-loading-text-color: #ffffff; + --el-button-loading-bg-color: #c72210; + --el-button-loading-border-color: transparent; + } + + .at-button-text { + --el-button-text-color: #477ef5; + --el-fill-color-light: transparent; + --el-fill-color: transparent; + + --el-button-hover-text-color: #86b2f9; + + --el-button-active-color: #2c59cb; + + --el-button-disabled-text-color: #a6a6a6; + + //loading + --el-button-loading-text-color: #477ef5; + } + + .el-button { + //default + --el-button-size: 36px; + height: var(--el-button-size); + padding: 8px 30px; + font-size: 14px; + //loading + .is-loading { + color: var(--el-button-loading-text-color); + background-color: var(--el-button-loading-bg-color); + border-color: var(--el-button-loading-border-color); + } + } + + .el-button--small { + --el-button-size: 27px; + height: var(--el-button-size); + padding: 5px 24px; + font-size: 12px; + } + + .el-button--large { + --el-button-size: 40px; + height: var(--el-button-size); + padding: 10px 30px; + font-size: 14px; + } + + .el-button + .el-button { + margin-left: 12px; + } +} diff --git a/src/theme/base/element-plus/checkbox.scss b/src/theme/base/element-plus/checkbox.scss new file mode 100644 index 0000000..f47ff6c --- /dev/null +++ b/src/theme/base/element-plus/checkbox.scss @@ -0,0 +1,27 @@ +html.china-red { + .el-checkbox { + --el-checkbox-font-size: 14px; + --el-checkbox-font-weight: var(--el-font-weight-primary); + --el-checkbox-text-color: #262626; + --el-checkbox-input-height: 14px; + --el-checkbox-input-width: 14px; + --el-checkbox-border-radius: var(--el-border-radius-small); + --el-checkbox-bg-color: var(--el-fill-color-blank); + --el-checkbox-input-border: var(--el-border); + + //disabled + --el-checkbox-disabled-border-color: var(--el-border-color); + --el-checkbox-disabled-input-fill: var(--el-fill-color-light); + --el-checkbox-disabled-icon-color: var(--el-text-color-placeholder); + --el-checkbox-disabled-checked-input-fill: var(--el-border-color-extra-light); + --el-checkbox-disabled-checked-input-border-color: var(--el-border-color); + --el-checkbox-disabled-checked-icon-color: var(--el-text-color-placeholder); + + //check + --el-checkbox-checked-text-color: #262626; + --el-checkbox-checked-input-border-color: transparent; + --el-checkbox-checked-bg-color: #c72210; + --el-checkbox-checked-icon-color: #ffffff; + --el-checkbox-input-border-color-hover: #c72210; + } +} diff --git a/src/theme/base/element-plus/css-vars.scss b/src/theme/base/element-plus/css-vars.scss new file mode 100644 index 0000000..ed97652 --- /dev/null +++ b/src/theme/base/element-plus/css-vars.scss @@ -0,0 +1,17 @@ +@use 'sass:map'; + +@use './var' as *; +@use '../../mixins/var' as *; +@use '../../mixins/mixins' as *; + +html.china-red { + color-scheme: china-red; + @each $type in (primary, success, warning, danger, error, info) { + @include set-css-color-rgb($colors, $type); + } + + @each $type in (primary, success, warning, danger, error, info) { + @include set-css-color-type($colors, $type); + } + //--el-color-primary: #c72210; +} diff --git a/src/theme/base/element-plus/form.scss b/src/theme/base/element-plus/form.scss new file mode 100644 index 0000000..663d0bb --- /dev/null +++ b/src/theme/base/element-plus/form.scss @@ -0,0 +1,20 @@ +html.china-red { + //date + .el-date-range-picker { + --el-datepicker-text-color: var(--el-text-color-regular); + --el-datepicker-off-text-color: var(--el-text-color-placeholder); + --el-datepicker-header-text-color: var(--el-text-color-regular); + --el-datepicker-icon-color: var(--el-text-color-primary); + --el-datepicker-border-color: var(--el-disabled-border-color); + --el-datepicker-inner-border-color: var(--el-border-color-light); + --el-datepicker-inrange-bg-color: #ffece6; + --el-datepicker-inrange-hover-bg-color: var(--el-border-color-extra-light); + --el-datepicker-active-color: var(--el-color-primary); + --el-datepicker-hover-text-color: var(--el-color-primary); + } + + .el-select-dropdown__item.hover, + .el-select-dropdown__item:hover { + background-color: #ffece6; + } +} diff --git a/src/theme/base/element-plus/pagination.scss b/src/theme/base/element-plus/pagination.scss new file mode 100644 index 0000000..c0fb7a2 --- /dev/null +++ b/src/theme/base/element-plus/pagination.scss @@ -0,0 +1,30 @@ +html.china-red { + .el-pagination { + --el-text-color-regular: #8c8c8c; + --el-pagination-font-size: 14px; + --el-pagination-bg-color: var(--el-fill-color-blank); + --el-pagination-text-color: var(--el-text-color-primary); + --el-pagination-border-radius: 3px; + --el-pagination-button-color: var(--el-text-color-primary); + --el-pagination-button-width: 32px; + --el-pagination-button-height: 32px; + --el-pagination-button-disabled-color: var(--el-text-color-placeholder); + --el-pagination-button-disabled-bg-color: var(--el-fill-color-blank); + --el-pagination-button-bg-color: var(--el-fill-color); + --el-pagination-hover-color: var(--el-color-primary); + --el-pagination-height-extra-small: 24px; + --el-pagination-line-height-extra-small: var(--el-pagination-height-extra-small); + white-space: nowrap; + padding: 2px 5px; + color: var(--el-pagination-text-color); + font-weight: 400; + display: flex; + align-items: center; + } + + .el-pagination__total { + margin-right: 16px; + font-weight: 400; + color: var(--el-text-color-regular); + } +} diff --git a/src/theme/base/element-plus/redio.scss b/src/theme/base/element-plus/redio.scss new file mode 100644 index 0000000..8cf25fa --- /dev/null +++ b/src/theme/base/element-plus/redio.scss @@ -0,0 +1,18 @@ +html.china-red { + .el-radio { + --el-radio-font-size: var(--el-font-size-base); + --el-radio-text-color: #262626; + --el-radio-font-weight: var(--el-font-weight-primary); + --el-radio-input-height: 14px; + --el-radio-input-width: 14px; + --el-radio-input-border-radius: var(--el-border-radius-circle); + --el-radio-input-bg-color: var(--el-fill-color-blank); + --el-radio-input-border: var(--el-border); + --el-radio-input-border-color: transparent; + //--el-radio-input-border-color-hover: transparent; + } + + .el-radio__input.is-checked + .el-radio__label { + color: #262626; + } +} diff --git a/src/theme/base/element-plus/table.scss b/src/theme/base/element-plus/table.scss new file mode 100644 index 0000000..e94a1e4 --- /dev/null +++ b/src/theme/base/element-plus/table.scss @@ -0,0 +1,17 @@ +html.china-red { + .el-table { + --el-table-border-color: #f0f0f0; + --el-table-border: 1px solid #f0f0f0; + --el-table-text-color: var(--el-text-color-regular); + --el-table-header-text-color: var(--el-text-color-secondary); + --el-table-row-hover-bg-color: #ffece6; + --el-table-current-row-bg-color: var(--el-color-primary-light-9); + --el-table-header-bg-color: #fafafa; + --el-table-fixed-box-shadow: var(--el-box-shadow-light); + --el-table-bg-color: var(--el-fill-color-blank); + --el-table-tr-bg-color: var(--el-fill-color-blank); + --el-table-expanded-cell-bg-color: var(--el-fill-color-blank); + --el-table-fixed-left-column: inset 10px 0 10px -10px rgba(0, 0, 0, 0.15); + --el-table-fixed-right-column: inset -10px 0 10px -10px rgba(0, 0, 0, 0.15); + } +} diff --git a/src/theme/base/element-plus/var.scss b/src/theme/base/element-plus/var.scss new file mode 100644 index 0000000..3cd7b37 --- /dev/null +++ b/src/theme/base/element-plus/var.scss @@ -0,0 +1,63 @@ +/* Element Chalk Variables */ +@use 'sass:math'; +@use 'sass:map'; +@use '../../mixins/function.scss' as *; + +// types +$types: primary, success, warning, danger, error, info; + +// change color +$colors: () !default; +$colors: map.deep-merge( + ( + 'white': #ffffff, + 'black': #000000, + 'primary': ( + 'base': #c72210//#409eff + ), + 'success': ( + 'base': #45b207 + ), + 'warning': ( + 'base': #ec8828 + ), + 'danger': ( + 'base': #f56c6c + ), + 'error': ( + 'base': #d24934 + ), + 'info': ( + 'base': #909399 + ) + ), + $colors +); + +$color-white: map.get($colors, 'white') !default; +$color-black: map.get($colors, 'black') !default; +$color-primary: map.get($colors, 'primary', 'base') !default; +$color-success: map.get($colors, 'success', 'base') !default; +$color-warning: map.get($colors, 'warning', 'base') !default; +$color-danger: map.get($colors, 'danger', 'base') !default; +$color-error: map.get($colors, 'error', 'base') !default; +$color-info: map.get($colors, 'info', 'base') !default; + +//$colors添加 --el-color-primary-light-7 +@mixin set-color-mix-level($type, $number, $mode: 'light', $mix-color: $color-white) { + $colors: map.deep-merge( + ( + $type: ( + '#{$mode}-#{$number}': mix($mix-color, map.get($colors, $type, 'base'), math.percentage(math.div($number, 10))) + ) + ), + $colors + ) !global; +} + +// $colors.primary.light-i +@each $type in $types { + @for $i from 1 through 9 { + @include set-color-mix-level($type, $i, 'light', $color-white); + } +} diff --git a/src/theme/base/index.scss b/src/theme/base/index.scss new file mode 100644 index 0000000..56c3150 --- /dev/null +++ b/src/theme/base/index.scss @@ -0,0 +1,13 @@ +/*china-red*/ +//element-plus +@use "./element-plus/css-vars"; +@use "./element-plus/var"; +@use "./element-plus/button"; +@use "./element-plus/checkbox"; +@use "./element-plus/redio"; +@use "./element-plus/pagination"; +@use "./element-plus/form"; +@use "./element-plus/table"; + +//custom +@use "./custom/ct-css-vars"; diff --git a/src/theme/china-red/custom/ct-css-vars.scss b/src/theme/china-red/custom/ct-css-vars.scss new file mode 100644 index 0000000..17f6c47 --- /dev/null +++ b/src/theme/china-red/custom/ct-css-vars.scss @@ -0,0 +1,90 @@ +html.china-red { + --el-menu-active-color: var(--el-color-primary); + --el-menu-text-color: var(--el-text-color-primary); + --el-menu-hover-text-color: var(--el-menu-active-color); + --el-menu-bg-color: var(--el-fill-color-blank); + --el-menu-hover-bg-color: var(--el-color-primary-light-9); + --el-menu-item-height: 56px; + --el-menu-sub-item-height: calc(var(--el-menu-item-height) - 6px); + --el-menu-horizontal-sub-item-height: 36px; + --el-menu-item-font-size: var(--el-font-size-base); + --el-menu-item-hover-fill: var(--el-color-primary-light-9); + --el-menu-border-color: none; + --el-menu-base-level-padding: 20px; + --el-menu-level-padding: 20px; + --el-menu-icon-width: 24px; + + .el-menu-item.is-active { + color: var(--el-menu-active-color); + background-color: #ffece6; + } + + .el-menu-item:hover { + background-color: var(--el-menu-hover-bg-color); + color: var(--el-menu-active-color); + } + /*element-plus section */ + //--el-menu-active-color: #409eff; + //--el-menu-text-color: #bfcbd9; + //--el-menu-hover-text-color: var(--el-color-primary); + //--el-menu-bg-color: #304156; + //--el-menu-hover-bg-color: #263445; + //--el-menu-item-height: 56px; + + /*layout section*/ + //layout + --layout-border-left-color: #ddd; + //Breadcrumb + --breadcrumb-no-redirect: #97a8be; + //Hamburger + --hamburger-width: 20px; + --hamburger-height: 20px; + //Sidebar + --sidebar-el-icon-size: 20px; + --sidebar-logo-background: #fff; + --sidebar-logo-color: #ff9901; + --sidebar-logo-width: 32px; + --sidebar-logo-height: 32px; + --sidebar-logo-title-color: #2b2f3a; + --side-bar-width: 210px; + --side-bar-border-right-color: '#ddd'; + //TagsView + --tags-view-background: #fff; + --tags-view-border-bottom-color: #d8dce5; + --tags-view-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04); + --tags-view-item-background: #fff; + --tags-view-item-border-color: #d8dce5; + --tags-view-item-color: #495060; + --tag-view-height: 32px; + --tags-view-item-active-background: #42b983; + --tags-view-item-active-color: #fff; + --tags-view-item-active-border-color: #42b983; + --tags-view-contextmenu-background: #fff; + --tags-view-contextmenu-color: #333; + --tags-view-contextmenu-box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3); + --tags-view-contextmenu-hover-background: #eee; + //close-icon + --tags-view-close-icon-hover-background: #b4bccc; + --tags-view-close-icon-hover-color: #fff; + //AppMain.vue + --app-main-padding: 10px; + --app-main-background: #fff; + //Navbar.vue + --nav-bar-height: 50px; + --nav-bar-background: #fff; + --nav-bar-box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); + --nav-bar-right-menu-background: #fff; + + //transition 动画 + //侧边栏切换动画时长 + --sideBar-switch-duration: 0.2s; + //logo切换动画时长 + --logo-switch-duration: 1.5s; + //页面动画时长 + --page-transform-duration: 0.2s; + //面包屑导航动画时长 + --breadcrumb-change-duration: 0.2s; + + //进度条颜色 + --pregress-bar-color: #409eff; +} diff --git a/src/theme/china-red/element-plus/button.scss b/src/theme/china-red/element-plus/button.scss new file mode 100644 index 0000000..93c473b --- /dev/null +++ b/src/theme/china-red/element-plus/button.scss @@ -0,0 +1,123 @@ +html.china-red { + color-scheme: china-red; + .at-button-low { + --el-button-text-color: #262626; + --el-button-bg-color: #ffffff; + --el-button-border-color: #d9d9d9; + --el-button-outline-color: #d9d9d9; + + --el-button-hover-text-color: #c72210; + --el-button-hover-link-text-color: #c72210; + --el-button-hover-bg-color: #ffece6; + --el-button-hover-border-color: transparent; + + --el-button-active-color: #a8150a; + --el-button-active-bg-color: #a8150a; + --el-button-active-border-color: transparent; + + --el-button-disabled-text-color: #a6a6a6; + --el-button-disabled-bg-color: #ffece6; + --el-button-disabled-border-color: #c72210; + //loading + --el-button-loading-text-color: #c72210; + --el-button-loading-bg-color: #ffece6; + --el-button-loading-border-color: #c72210; + } + + .at-button-middle { + --el-button-text-color: #c72210; + --el-button-bg-color: #ffece6; + --el-button-border-color: #c72210; + --el-button-outline-color: #c72210; + + --el-button-hover-text-color: #ffffff; + --el-button-hover-link-text-color: #ffffff; + --el-button-hover-bg-color: #c72210; + --el-button-hover-border-color: #c72210; + + --el-button-active-color: #ffffff; + --el-button-active-bg-color: #a8150a; + --el-button-active-border-color: #a8150a; + + --el-button-disabled-text-color: #a6a6a6; + --el-button-disabled-bg-color: #ffffff; + --el-button-disabled-border-color: #d9d9d9; + + //loading + --el-button-loading-text-color: #c72210; + --el-button-loading-bg-color: #ffece6; + --el-button-loading-border-color: #c72210; + } + + .at-button-height { + --el-button-text-color: #ffffff; + --el-button-bg-color: #c72210; + --el-button-border-color: transparent; + --el-button-outline-color: transparent; + + --el-button-hover-text-color: #ffffff; + --el-button-hover-link-text-color: #ffffff; + --el-button-hover-bg-color: #dd715b; + --el-button-hover-border-color: #c72210; + + --el-button-active-color: #ffffff; + --el-button-active-bg-color: #a8150a; + --el-button-active-border-color: transparent; + + --el-button-disabled-text-color: #a6a6a6; + --el-button-disabled-bg-color: #f5f5f5; + --el-button-disabled-border-color: transparent; + + //loading + --el-button-loading-text-color: #ffffff; + --el-button-loading-bg-color: #c72210; + --el-button-loading-border-color: transparent; + } + + .at-button-text { + --el-button-text-color: #477ef5; + --el-fill-color-light: transparent; + --el-fill-color: transparent; + + --el-button-hover-text-color: #86b2f9; + + --el-button-active-color: #2c59cb; + + --el-button-disabled-text-color: #a6a6a6; + + //loading + --el-button-loading-text-color: #477ef5; + } + + .el-button { + //default + --el-button-size: 36px; + height: var(--el-button-size); + padding: 8px 30px; + font-size: 14px; + //loading + .is-loading { + color: var(--el-button-loading-text-color); + background-color: var(--el-button-loading-bg-color); + border-color: var(--el-button-loading-border-color); + } + } + + .el-button--small { + --el-button-size: 27px; + height: var(--el-button-size); + padding: 5px 24px; + font-size: 12px; + } + + .el-button--large { + --el-button-size: 40px; + height: var(--el-button-size); + padding: 10px 30px; + font-size: 14px; + } + + .el-button + .el-button { + margin-left: 12px; + } +} diff --git a/src/theme/china-red/element-plus/checkbox.scss b/src/theme/china-red/element-plus/checkbox.scss new file mode 100644 index 0000000..f47ff6c --- /dev/null +++ b/src/theme/china-red/element-plus/checkbox.scss @@ -0,0 +1,27 @@ +html.china-red { + .el-checkbox { + --el-checkbox-font-size: 14px; + --el-checkbox-font-weight: var(--el-font-weight-primary); + --el-checkbox-text-color: #262626; + --el-checkbox-input-height: 14px; + --el-checkbox-input-width: 14px; + --el-checkbox-border-radius: var(--el-border-radius-small); + --el-checkbox-bg-color: var(--el-fill-color-blank); + --el-checkbox-input-border: var(--el-border); + + //disabled + --el-checkbox-disabled-border-color: var(--el-border-color); + --el-checkbox-disabled-input-fill: var(--el-fill-color-light); + --el-checkbox-disabled-icon-color: var(--el-text-color-placeholder); + --el-checkbox-disabled-checked-input-fill: var(--el-border-color-extra-light); + --el-checkbox-disabled-checked-input-border-color: var(--el-border-color); + --el-checkbox-disabled-checked-icon-color: var(--el-text-color-placeholder); + + //check + --el-checkbox-checked-text-color: #262626; + --el-checkbox-checked-input-border-color: transparent; + --el-checkbox-checked-bg-color: #c72210; + --el-checkbox-checked-icon-color: #ffffff; + --el-checkbox-input-border-color-hover: #c72210; + } +} diff --git a/src/theme/china-red/element-plus/css-vars.scss b/src/theme/china-red/element-plus/css-vars.scss new file mode 100644 index 0000000..ed97652 --- /dev/null +++ b/src/theme/china-red/element-plus/css-vars.scss @@ -0,0 +1,17 @@ +@use 'sass:map'; + +@use './var' as *; +@use '../../mixins/var' as *; +@use '../../mixins/mixins' as *; + +html.china-red { + color-scheme: china-red; + @each $type in (primary, success, warning, danger, error, info) { + @include set-css-color-rgb($colors, $type); + } + + @each $type in (primary, success, warning, danger, error, info) { + @include set-css-color-type($colors, $type); + } + //--el-color-primary: #c72210; +} diff --git a/src/theme/china-red/element-plus/form.scss b/src/theme/china-red/element-plus/form.scss new file mode 100644 index 0000000..663d0bb --- /dev/null +++ b/src/theme/china-red/element-plus/form.scss @@ -0,0 +1,20 @@ +html.china-red { + //date + .el-date-range-picker { + --el-datepicker-text-color: var(--el-text-color-regular); + --el-datepicker-off-text-color: var(--el-text-color-placeholder); + --el-datepicker-header-text-color: var(--el-text-color-regular); + --el-datepicker-icon-color: var(--el-text-color-primary); + --el-datepicker-border-color: var(--el-disabled-border-color); + --el-datepicker-inner-border-color: var(--el-border-color-light); + --el-datepicker-inrange-bg-color: #ffece6; + --el-datepicker-inrange-hover-bg-color: var(--el-border-color-extra-light); + --el-datepicker-active-color: var(--el-color-primary); + --el-datepicker-hover-text-color: var(--el-color-primary); + } + + .el-select-dropdown__item.hover, + .el-select-dropdown__item:hover { + background-color: #ffece6; + } +} diff --git a/src/theme/china-red/element-plus/pagination.scss b/src/theme/china-red/element-plus/pagination.scss new file mode 100644 index 0000000..c0fb7a2 --- /dev/null +++ b/src/theme/china-red/element-plus/pagination.scss @@ -0,0 +1,30 @@ +html.china-red { + .el-pagination { + --el-text-color-regular: #8c8c8c; + --el-pagination-font-size: 14px; + --el-pagination-bg-color: var(--el-fill-color-blank); + --el-pagination-text-color: var(--el-text-color-primary); + --el-pagination-border-radius: 3px; + --el-pagination-button-color: var(--el-text-color-primary); + --el-pagination-button-width: 32px; + --el-pagination-button-height: 32px; + --el-pagination-button-disabled-color: var(--el-text-color-placeholder); + --el-pagination-button-disabled-bg-color: var(--el-fill-color-blank); + --el-pagination-button-bg-color: var(--el-fill-color); + --el-pagination-hover-color: var(--el-color-primary); + --el-pagination-height-extra-small: 24px; + --el-pagination-line-height-extra-small: var(--el-pagination-height-extra-small); + white-space: nowrap; + padding: 2px 5px; + color: var(--el-pagination-text-color); + font-weight: 400; + display: flex; + align-items: center; + } + + .el-pagination__total { + margin-right: 16px; + font-weight: 400; + color: var(--el-text-color-regular); + } +} diff --git a/src/theme/china-red/element-plus/redio.scss b/src/theme/china-red/element-plus/redio.scss new file mode 100644 index 0000000..8cf25fa --- /dev/null +++ b/src/theme/china-red/element-plus/redio.scss @@ -0,0 +1,18 @@ +html.china-red { + .el-radio { + --el-radio-font-size: var(--el-font-size-base); + --el-radio-text-color: #262626; + --el-radio-font-weight: var(--el-font-weight-primary); + --el-radio-input-height: 14px; + --el-radio-input-width: 14px; + --el-radio-input-border-radius: var(--el-border-radius-circle); + --el-radio-input-bg-color: var(--el-fill-color-blank); + --el-radio-input-border: var(--el-border); + --el-radio-input-border-color: transparent; + //--el-radio-input-border-color-hover: transparent; + } + + .el-radio__input.is-checked + .el-radio__label { + color: #262626; + } +} diff --git a/src/theme/china-red/element-plus/table.scss b/src/theme/china-red/element-plus/table.scss new file mode 100644 index 0000000..e94a1e4 --- /dev/null +++ b/src/theme/china-red/element-plus/table.scss @@ -0,0 +1,17 @@ +html.china-red { + .el-table { + --el-table-border-color: #f0f0f0; + --el-table-border: 1px solid #f0f0f0; + --el-table-text-color: var(--el-text-color-regular); + --el-table-header-text-color: var(--el-text-color-secondary); + --el-table-row-hover-bg-color: #ffece6; + --el-table-current-row-bg-color: var(--el-color-primary-light-9); + --el-table-header-bg-color: #fafafa; + --el-table-fixed-box-shadow: var(--el-box-shadow-light); + --el-table-bg-color: var(--el-fill-color-blank); + --el-table-tr-bg-color: var(--el-fill-color-blank); + --el-table-expanded-cell-bg-color: var(--el-fill-color-blank); + --el-table-fixed-left-column: inset 10px 0 10px -10px rgba(0, 0, 0, 0.15); + --el-table-fixed-right-column: inset -10px 0 10px -10px rgba(0, 0, 0, 0.15); + } +} diff --git a/src/theme/china-red/element-plus/var.scss b/src/theme/china-red/element-plus/var.scss new file mode 100644 index 0000000..3cd7b37 --- /dev/null +++ b/src/theme/china-red/element-plus/var.scss @@ -0,0 +1,63 @@ +/* Element Chalk Variables */ +@use 'sass:math'; +@use 'sass:map'; +@use '../../mixins/function.scss' as *; + +// types +$types: primary, success, warning, danger, error, info; + +// change color +$colors: () !default; +$colors: map.deep-merge( + ( + 'white': #ffffff, + 'black': #000000, + 'primary': ( + 'base': #c72210//#409eff + ), + 'success': ( + 'base': #45b207 + ), + 'warning': ( + 'base': #ec8828 + ), + 'danger': ( + 'base': #f56c6c + ), + 'error': ( + 'base': #d24934 + ), + 'info': ( + 'base': #909399 + ) + ), + $colors +); + +$color-white: map.get($colors, 'white') !default; +$color-black: map.get($colors, 'black') !default; +$color-primary: map.get($colors, 'primary', 'base') !default; +$color-success: map.get($colors, 'success', 'base') !default; +$color-warning: map.get($colors, 'warning', 'base') !default; +$color-danger: map.get($colors, 'danger', 'base') !default; +$color-error: map.get($colors, 'error', 'base') !default; +$color-info: map.get($colors, 'info', 'base') !default; + +//$colors添加 --el-color-primary-light-7 +@mixin set-color-mix-level($type, $number, $mode: 'light', $mix-color: $color-white) { + $colors: map.deep-merge( + ( + $type: ( + '#{$mode}-#{$number}': mix($mix-color, map.get($colors, $type, 'base'), math.percentage(math.div($number, 10))) + ) + ), + $colors + ) !global; +} + +// $colors.primary.light-i +@each $type in $types { + @for $i from 1 through 9 { + @include set-color-mix-level($type, $i, 'light', $color-white); + } +} diff --git a/src/theme/china-red/index.scss b/src/theme/china-red/index.scss new file mode 100644 index 0000000..56c3150 --- /dev/null +++ b/src/theme/china-red/index.scss @@ -0,0 +1,13 @@ +/*china-red*/ +//element-plus +@use "./element-plus/css-vars"; +@use "./element-plus/var"; +@use "./element-plus/button"; +@use "./element-plus/checkbox"; +@use "./element-plus/redio"; +@use "./element-plus/pagination"; +@use "./element-plus/form"; +@use "./element-plus/table"; + +//custom +@use "./custom/ct-css-vars"; diff --git a/src/theme/dark/custom/ct-css-vars.scss b/src/theme/dark/custom/ct-css-vars.scss new file mode 100644 index 0000000..772b972 --- /dev/null +++ b/src/theme/dark/custom/ct-css-vars.scss @@ -0,0 +1,68 @@ +html.dark { + /*element-plus section */ + --el-menu-active-color: #409eff; + --el-menu-text-color: #bfcbd9; + --el-menu-hover-text-color: var(--el-color-primary); + --el-menu-bg-color: #304156; + --el-menu-hover-bg-color: #263445; + --el-menu-item-height: 56px; + --el-menu-border-color: none; + /*layout section*/ + //layout + --layout-border-left-color: #ddd; + //Breadcrumb + --breadcrumb-no-redirect: #97a8be; + //Hamburger + --hamburger-color: #fff; + --hamburger-width: 20px; + --hamburger-height: 20px; + --el-text-color-primary: #fff; + //Sidebar + --sidebar-el-icon-size: 20px; + --sidebar-logo-background: #2b2f3a; + --sidebar-logo-color: #ff9901; + --sidebar-logo-width: 32px; + --sidebar-logo-height: 32px; + --sidebar-logo-title-color: #fff; + --side-bar-width: 210px; + --side-bar-border-right-color: #2b2f3a; + //TagsView + --tags-view-background: #304156; + --tags-view-border-bottom-color: #2b2f3a; + --tags-view-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04); + --tags-view-item-background: #fff; + --tags-view-item-border-color: #d8dce5; + --tags-view-item-color: #495060; + --tag-view-height: 32px; + --tags-view-item-active-background: #42b983; + --tags-view-item-active-color: #fff; + --tags-view-item-active-border-color: #42b983; + --tags-view-contextmenu-background: #fff; + --tags-view-contextmenu-color: #333; + --tags-view-contextmenu-box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3); + --tags-view-contextmenu-hover-background: #eee; + //close-icon + --tags-view-close-icon-hover-background: #b4bccc; + --tags-view-close-icon-hover-color: #fff; + //AppMain.vue + --app-main-padding: 10px; + --app-main-background: #304156; + //Navbar.vue + --nav-bar-height: 50px; + --nav-bar-background: #2b2f3a; + --nav-bar-box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); + --nav-bar-right-menu-background: #2b2f3a; + + //transition 动画 + //侧边栏切换动画时长 + --sideBar-switch-duration: 0.2s; + //logo切换动画时长 + --logo-switch-duration: 1s; + //页面动画时长 + --page-transform-duration: 0.2s; + //面包屑导航动画时长 + --breadcrumb-change-duration: 0.2s; + + //进度条颜色 + --pregress-bar-color: #409eff; +} diff --git a/src/theme/dark/element-plus/button.scss b/src/theme/dark/element-plus/button.scss new file mode 100644 index 0000000..93c473b --- /dev/null +++ b/src/theme/dark/element-plus/button.scss @@ -0,0 +1,123 @@ +html.china-red { + color-scheme: china-red; + .at-button-low { + --el-button-text-color: #262626; + --el-button-bg-color: #ffffff; + --el-button-border-color: #d9d9d9; + --el-button-outline-color: #d9d9d9; + + --el-button-hover-text-color: #c72210; + --el-button-hover-link-text-color: #c72210; + --el-button-hover-bg-color: #ffece6; + --el-button-hover-border-color: transparent; + + --el-button-active-color: #a8150a; + --el-button-active-bg-color: #a8150a; + --el-button-active-border-color: transparent; + + --el-button-disabled-text-color: #a6a6a6; + --el-button-disabled-bg-color: #ffece6; + --el-button-disabled-border-color: #c72210; + //loading + --el-button-loading-text-color: #c72210; + --el-button-loading-bg-color: #ffece6; + --el-button-loading-border-color: #c72210; + } + + .at-button-middle { + --el-button-text-color: #c72210; + --el-button-bg-color: #ffece6; + --el-button-border-color: #c72210; + --el-button-outline-color: #c72210; + + --el-button-hover-text-color: #ffffff; + --el-button-hover-link-text-color: #ffffff; + --el-button-hover-bg-color: #c72210; + --el-button-hover-border-color: #c72210; + + --el-button-active-color: #ffffff; + --el-button-active-bg-color: #a8150a; + --el-button-active-border-color: #a8150a; + + --el-button-disabled-text-color: #a6a6a6; + --el-button-disabled-bg-color: #ffffff; + --el-button-disabled-border-color: #d9d9d9; + + //loading + --el-button-loading-text-color: #c72210; + --el-button-loading-bg-color: #ffece6; + --el-button-loading-border-color: #c72210; + } + + .at-button-height { + --el-button-text-color: #ffffff; + --el-button-bg-color: #c72210; + --el-button-border-color: transparent; + --el-button-outline-color: transparent; + + --el-button-hover-text-color: #ffffff; + --el-button-hover-link-text-color: #ffffff; + --el-button-hover-bg-color: #dd715b; + --el-button-hover-border-color: #c72210; + + --el-button-active-color: #ffffff; + --el-button-active-bg-color: #a8150a; + --el-button-active-border-color: transparent; + + --el-button-disabled-text-color: #a6a6a6; + --el-button-disabled-bg-color: #f5f5f5; + --el-button-disabled-border-color: transparent; + + //loading + --el-button-loading-text-color: #ffffff; + --el-button-loading-bg-color: #c72210; + --el-button-loading-border-color: transparent; + } + + .at-button-text { + --el-button-text-color: #477ef5; + --el-fill-color-light: transparent; + --el-fill-color: transparent; + + --el-button-hover-text-color: #86b2f9; + + --el-button-active-color: #2c59cb; + + --el-button-disabled-text-color: #a6a6a6; + + //loading + --el-button-loading-text-color: #477ef5; + } + + .el-button { + //default + --el-button-size: 36px; + height: var(--el-button-size); + padding: 8px 30px; + font-size: 14px; + //loading + .is-loading { + color: var(--el-button-loading-text-color); + background-color: var(--el-button-loading-bg-color); + border-color: var(--el-button-loading-border-color); + } + } + + .el-button--small { + --el-button-size: 27px; + height: var(--el-button-size); + padding: 5px 24px; + font-size: 12px; + } + + .el-button--large { + --el-button-size: 40px; + height: var(--el-button-size); + padding: 10px 30px; + font-size: 14px; + } + + .el-button + .el-button { + margin-left: 12px; + } +} diff --git a/src/theme/dark/element-plus/checkbox.scss b/src/theme/dark/element-plus/checkbox.scss new file mode 100644 index 0000000..f47ff6c --- /dev/null +++ b/src/theme/dark/element-plus/checkbox.scss @@ -0,0 +1,27 @@ +html.china-red { + .el-checkbox { + --el-checkbox-font-size: 14px; + --el-checkbox-font-weight: var(--el-font-weight-primary); + --el-checkbox-text-color: #262626; + --el-checkbox-input-height: 14px; + --el-checkbox-input-width: 14px; + --el-checkbox-border-radius: var(--el-border-radius-small); + --el-checkbox-bg-color: var(--el-fill-color-blank); + --el-checkbox-input-border: var(--el-border); + + //disabled + --el-checkbox-disabled-border-color: var(--el-border-color); + --el-checkbox-disabled-input-fill: var(--el-fill-color-light); + --el-checkbox-disabled-icon-color: var(--el-text-color-placeholder); + --el-checkbox-disabled-checked-input-fill: var(--el-border-color-extra-light); + --el-checkbox-disabled-checked-input-border-color: var(--el-border-color); + --el-checkbox-disabled-checked-icon-color: var(--el-text-color-placeholder); + + //check + --el-checkbox-checked-text-color: #262626; + --el-checkbox-checked-input-border-color: transparent; + --el-checkbox-checked-bg-color: #c72210; + --el-checkbox-checked-icon-color: #ffffff; + --el-checkbox-input-border-color-hover: #c72210; + } +} diff --git a/src/theme/dark/element-plus/css-vars.css b/src/theme/dark/element-plus/css-vars.css new file mode 100644 index 0000000..e69de29 diff --git a/src/theme/dark/element-plus/css-vars.css.map b/src/theme/dark/element-plus/css-vars.css.map new file mode 100644 index 0000000..47b7af7 --- /dev/null +++ b/src/theme/dark/element-plus/css-vars.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["var.scss","css-vars.scss","../../mixins/_var.scss"],"names":[],"mappings":"AAAA;ACMA;EACE;ECKA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA","file":"css-vars.css"} \ No newline at end of file diff --git a/src/theme/dark/element-plus/css-vars.scss b/src/theme/dark/element-plus/css-vars.scss new file mode 100644 index 0000000..ed97652 --- /dev/null +++ b/src/theme/dark/element-plus/css-vars.scss @@ -0,0 +1,17 @@ +@use 'sass:map'; + +@use './var' as *; +@use '../../mixins/var' as *; +@use '../../mixins/mixins' as *; + +html.china-red { + color-scheme: china-red; + @each $type in (primary, success, warning, danger, error, info) { + @include set-css-color-rgb($colors, $type); + } + + @each $type in (primary, success, warning, danger, error, info) { + @include set-css-color-type($colors, $type); + } + //--el-color-primary: #c72210; +} diff --git a/src/theme/dark/element-plus/form.scss b/src/theme/dark/element-plus/form.scss new file mode 100644 index 0000000..663d0bb --- /dev/null +++ b/src/theme/dark/element-plus/form.scss @@ -0,0 +1,20 @@ +html.china-red { + //date + .el-date-range-picker { + --el-datepicker-text-color: var(--el-text-color-regular); + --el-datepicker-off-text-color: var(--el-text-color-placeholder); + --el-datepicker-header-text-color: var(--el-text-color-regular); + --el-datepicker-icon-color: var(--el-text-color-primary); + --el-datepicker-border-color: var(--el-disabled-border-color); + --el-datepicker-inner-border-color: var(--el-border-color-light); + --el-datepicker-inrange-bg-color: #ffece6; + --el-datepicker-inrange-hover-bg-color: var(--el-border-color-extra-light); + --el-datepicker-active-color: var(--el-color-primary); + --el-datepicker-hover-text-color: var(--el-color-primary); + } + + .el-select-dropdown__item.hover, + .el-select-dropdown__item:hover { + background-color: #ffece6; + } +} diff --git a/src/theme/dark/element-plus/pagination.scss b/src/theme/dark/element-plus/pagination.scss new file mode 100644 index 0000000..c0fb7a2 --- /dev/null +++ b/src/theme/dark/element-plus/pagination.scss @@ -0,0 +1,30 @@ +html.china-red { + .el-pagination { + --el-text-color-regular: #8c8c8c; + --el-pagination-font-size: 14px; + --el-pagination-bg-color: var(--el-fill-color-blank); + --el-pagination-text-color: var(--el-text-color-primary); + --el-pagination-border-radius: 3px; + --el-pagination-button-color: var(--el-text-color-primary); + --el-pagination-button-width: 32px; + --el-pagination-button-height: 32px; + --el-pagination-button-disabled-color: var(--el-text-color-placeholder); + --el-pagination-button-disabled-bg-color: var(--el-fill-color-blank); + --el-pagination-button-bg-color: var(--el-fill-color); + --el-pagination-hover-color: var(--el-color-primary); + --el-pagination-height-extra-small: 24px; + --el-pagination-line-height-extra-small: var(--el-pagination-height-extra-small); + white-space: nowrap; + padding: 2px 5px; + color: var(--el-pagination-text-color); + font-weight: 400; + display: flex; + align-items: center; + } + + .el-pagination__total { + margin-right: 16px; + font-weight: 400; + color: var(--el-text-color-regular); + } +} diff --git a/src/theme/dark/element-plus/redio.scss b/src/theme/dark/element-plus/redio.scss new file mode 100644 index 0000000..8cf25fa --- /dev/null +++ b/src/theme/dark/element-plus/redio.scss @@ -0,0 +1,18 @@ +html.china-red { + .el-radio { + --el-radio-font-size: var(--el-font-size-base); + --el-radio-text-color: #262626; + --el-radio-font-weight: var(--el-font-weight-primary); + --el-radio-input-height: 14px; + --el-radio-input-width: 14px; + --el-radio-input-border-radius: var(--el-border-radius-circle); + --el-radio-input-bg-color: var(--el-fill-color-blank); + --el-radio-input-border: var(--el-border); + --el-radio-input-border-color: transparent; + //--el-radio-input-border-color-hover: transparent; + } + + .el-radio__input.is-checked + .el-radio__label { + color: #262626; + } +} diff --git a/src/theme/dark/element-plus/table.scss b/src/theme/dark/element-plus/table.scss new file mode 100644 index 0000000..e94a1e4 --- /dev/null +++ b/src/theme/dark/element-plus/table.scss @@ -0,0 +1,17 @@ +html.china-red { + .el-table { + --el-table-border-color: #f0f0f0; + --el-table-border: 1px solid #f0f0f0; + --el-table-text-color: var(--el-text-color-regular); + --el-table-header-text-color: var(--el-text-color-secondary); + --el-table-row-hover-bg-color: #ffece6; + --el-table-current-row-bg-color: var(--el-color-primary-light-9); + --el-table-header-bg-color: #fafafa; + --el-table-fixed-box-shadow: var(--el-box-shadow-light); + --el-table-bg-color: var(--el-fill-color-blank); + --el-table-tr-bg-color: var(--el-fill-color-blank); + --el-table-expanded-cell-bg-color: var(--el-fill-color-blank); + --el-table-fixed-left-column: inset 10px 0 10px -10px rgba(0, 0, 0, 0.15); + --el-table-fixed-right-column: inset -10px 0 10px -10px rgba(0, 0, 0, 0.15); + } +} diff --git a/src/theme/dark/element-plus/var.scss b/src/theme/dark/element-plus/var.scss new file mode 100644 index 0000000..3cd7b37 --- /dev/null +++ b/src/theme/dark/element-plus/var.scss @@ -0,0 +1,63 @@ +/* Element Chalk Variables */ +@use 'sass:math'; +@use 'sass:map'; +@use '../../mixins/function.scss' as *; + +// types +$types: primary, success, warning, danger, error, info; + +// change color +$colors: () !default; +$colors: map.deep-merge( + ( + 'white': #ffffff, + 'black': #000000, + 'primary': ( + 'base': #c72210//#409eff + ), + 'success': ( + 'base': #45b207 + ), + 'warning': ( + 'base': #ec8828 + ), + 'danger': ( + 'base': #f56c6c + ), + 'error': ( + 'base': #d24934 + ), + 'info': ( + 'base': #909399 + ) + ), + $colors +); + +$color-white: map.get($colors, 'white') !default; +$color-black: map.get($colors, 'black') !default; +$color-primary: map.get($colors, 'primary', 'base') !default; +$color-success: map.get($colors, 'success', 'base') !default; +$color-warning: map.get($colors, 'warning', 'base') !default; +$color-danger: map.get($colors, 'danger', 'base') !default; +$color-error: map.get($colors, 'error', 'base') !default; +$color-info: map.get($colors, 'info', 'base') !default; + +//$colors添加 --el-color-primary-light-7 +@mixin set-color-mix-level($type, $number, $mode: 'light', $mix-color: $color-white) { + $colors: map.deep-merge( + ( + $type: ( + '#{$mode}-#{$number}': mix($mix-color, map.get($colors, $type, 'base'), math.percentage(math.div($number, 10))) + ) + ), + $colors + ) !global; +} + +// $colors.primary.light-i +@each $type in $types { + @for $i from 1 through 9 { + @include set-color-mix-level($type, $i, 'light', $color-white); + } +} diff --git a/src/theme/dark/index.scss b/src/theme/dark/index.scss new file mode 100644 index 0000000..a2b73a3 --- /dev/null +++ b/src/theme/dark/index.scss @@ -0,0 +1,13 @@ +/*china-red*/ +//element-plus +//@use "./element-plus/css-vars"; +//@use "./element-plus/var"; +//@use "./element-plus/button"; +//@use "./element-plus/checkbox"; +//@use "./element-plus/redio"; +//@use "./element-plus/pagination"; +//@use "./element-plus/form"; +//@use "./element-plus/table"; + +//custom +@use "./custom/ct-css-vars"; diff --git a/src/theme/index.css b/src/theme/index.css new file mode 100644 index 0000000..e69de29 diff --git a/src/theme/index.css.map b/src/theme/index.css.map new file mode 100644 index 0000000..9f709d1 --- /dev/null +++ b/src/theme/index.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["base/element-plus/var.scss","base/element-plus/css-vars.scss","mixins/_var.scss","base/element-plus/button.scss","base/element-plus/checkbox.scss","base/element-plus/redio.scss","base/element-plus/pagination.scss","base/element-plus/form.scss","base/element-plus/table.scss","base/custom/ct-css-vars.scss","base/index.scss","dark/custom/ct-css-vars.scss","dark/index.scss","lighting/custom/ct-css-vars.scss","lighting/index.scss","china-red/element-plus/css-vars.scss","china-red/element-plus/button.scss","china-red/element-plus/checkbox.scss","china-red/element-plus/redio.scss","china-red/element-plus/pagination.scss","china-red/element-plus/form.scss","china-red/element-plus/table.scss","china-red/custom/ct-css-vars.scss","china-red/index.scss"],"names":[],"mappings":"AAAA;ACMA;EACE;ECKA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;;;ACZF;EACE;;AACA;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EAEA;EACA;EACA;EAEA;EACA;EACA;EAEA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EAEA;EACA;EACA;EAEA;EACA;EACA;EAGA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EAEA;EACA;EACA;EAEA;EACA;EACA;EAGA;EACA;EACA;;AAGF;EACE;EACA;EACA;EAEA;EAEA;EAEA;EAGA;;AAGF;EAEE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAIJ;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAGF;EACE;;;ACvHF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;;;ACvBF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAIF;EACE;;;ACdF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;;;ACzBF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;AAAA;EAEE;;;AChBF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;ACdJ;AACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AACA;EAEA;EAEA;EAEA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EAIA;EAEA;EAEA;EAEA;EAGA;;;ACjEF;ACAA;AACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AACA;EAEA;EAEA;EAEA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EAIA;EAEA;EAEA;EAEA;EAGA;;;AClEF;ACAA;AACE;AAQA;EAEA;EAEA;EAEA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EAIA;EAEA;EAEA;EAEA;EAGA;;;ACjEF;ACMA;EACE;EbKA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;;;AcZF;EACE;;AACA;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EAEA;EACA;EACA;EAEA;EACA;EACA;EAEA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EAEA;EACA;EACA;EAEA;EACA;EACA;EAGA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EAEA;EACA;EACA;EAEA;EACA;EACA;EAGA;EACA;EACA;;AAGF;EACE;EACA;EACA;EAEA;EAEA;EAEA;EAGA;;AAGF;EAEE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAIJ;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAGF;EACE;;;ACvHF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;;;ACvBF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAIF;EACE;;;ACdF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;;;ACzBF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;AAAA;EAEE;;;AChBF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;ACdJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAWA;AAQA;EAEA;EAEA;EAEA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EAIA;EAEA;EAEA;EAEA;EAGA;;AAxEA;EACE;EACA;;AAGF;EACE;EACA;;;ACvBJ","file":"index.css"} \ No newline at end of file diff --git a/src/theme/index.scss b/src/theme/index.scss new file mode 100644 index 0000000..fa47ed9 --- /dev/null +++ b/src/theme/index.scss @@ -0,0 +1,11 @@ +// we can add this to custom namespace, default is 'el' +//@forward "element-plus/theme-chalk/src/mixins/config.scss" with ( +// $namespace: "el" +//); + +//base-theme +@use "./base"; +//theme style such as dark-theme lighting +@use "./dark"; +@use "./lighting"; +@use "./china-red"; diff --git a/src/theme/lighting/custom/ct-css-vars.scss b/src/theme/lighting/custom/ct-css-vars.scss new file mode 100644 index 0000000..7aad9d4 --- /dev/null +++ b/src/theme/lighting/custom/ct-css-vars.scss @@ -0,0 +1,67 @@ +html.lighting-theme { + /*element-plus section */ + //--el-menu-active-color: #409eff; + //--el-menu-text-color: #bfcbd9; + //--el-menu-hover-text-color: var(--el-color-primary); + //--el-menu-bg-color: #304156; + //--el-menu-hover-bg-color: #263445; + //--el-menu-item-height: 56px; + //--el-menu-border-color: none; + /*layout section*/ + //layout + --layout-border-left-color: #ddd; + //Breadcrumb + --breadcrumb-no-redirect: #97a8be; + //Hamburger + --hamburger-color: #2b2f3a; + --hamburger-width: 20px; + --hamburger-height: 20px; + //Sidebar + --sidebar-el-icon-size: 20px; + --sidebar-logo-background: #fff; + --sidebar-logo-color: #ff9901; + --sidebar-logo-width: 32px; + --sidebar-logo-height: 32px; + --sidebar-logo-title-color: #2b2f3a; + --side-bar-width: 210px; + --side-bar-border-right-color: '#ddd'; + //TagsView + --tags-view-background: #fff; + --tags-view-border-bottom-color: #d8dce5; + --tags-view-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04); + --tags-view-item-background: #fff; + --tags-view-item-border-color: #d8dce5; + --tags-view-item-color: #495060; + --tag-view-height: 32px; + --tags-view-item-active-background: #42b983; + --tags-view-item-active-color: #fff; + --tags-view-item-active-border-color: #42b983; + --tags-view-contextmenu-background: #fff; + --tags-view-contextmenu-color: #333; + --tags-view-contextmenu-box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3); + --tags-view-contextmenu-hover-background: #eee; + //close-icon + --tags-view-close-icon-hover-background: #b4bccc; + --tags-view-close-icon-hover-color: #fff; + //AppMain.vue + --app-main-padding: 10px; + --app-main-background: #fff; + //Navbar.vue + --nav-bar-height: 50px; + --nav-bar-background: #fff; + --nav-bar-box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); + --nav-bar-right-menu-background: #fff; + + //transition 动画 + //侧边栏切换动画时长 + --sideBar-switch-duration: 0.2s; + //logo切换动画时长 + --logo-switch-duration: 0.5s; + //页面动画时长 + --page-transform-duration: 0.2s; + //面包屑导航动画时长 + --breadcrumb-change-duration: 0.2s; + + //进度条颜色 + --pregress-bar-color: #409eff; +} diff --git a/src/theme/lighting/element-plus/button.scss b/src/theme/lighting/element-plus/button.scss new file mode 100644 index 0000000..93c473b --- /dev/null +++ b/src/theme/lighting/element-plus/button.scss @@ -0,0 +1,123 @@ +html.china-red { + color-scheme: china-red; + .at-button-low { + --el-button-text-color: #262626; + --el-button-bg-color: #ffffff; + --el-button-border-color: #d9d9d9; + --el-button-outline-color: #d9d9d9; + + --el-button-hover-text-color: #c72210; + --el-button-hover-link-text-color: #c72210; + --el-button-hover-bg-color: #ffece6; + --el-button-hover-border-color: transparent; + + --el-button-active-color: #a8150a; + --el-button-active-bg-color: #a8150a; + --el-button-active-border-color: transparent; + + --el-button-disabled-text-color: #a6a6a6; + --el-button-disabled-bg-color: #ffece6; + --el-button-disabled-border-color: #c72210; + //loading + --el-button-loading-text-color: #c72210; + --el-button-loading-bg-color: #ffece6; + --el-button-loading-border-color: #c72210; + } + + .at-button-middle { + --el-button-text-color: #c72210; + --el-button-bg-color: #ffece6; + --el-button-border-color: #c72210; + --el-button-outline-color: #c72210; + + --el-button-hover-text-color: #ffffff; + --el-button-hover-link-text-color: #ffffff; + --el-button-hover-bg-color: #c72210; + --el-button-hover-border-color: #c72210; + + --el-button-active-color: #ffffff; + --el-button-active-bg-color: #a8150a; + --el-button-active-border-color: #a8150a; + + --el-button-disabled-text-color: #a6a6a6; + --el-button-disabled-bg-color: #ffffff; + --el-button-disabled-border-color: #d9d9d9; + + //loading + --el-button-loading-text-color: #c72210; + --el-button-loading-bg-color: #ffece6; + --el-button-loading-border-color: #c72210; + } + + .at-button-height { + --el-button-text-color: #ffffff; + --el-button-bg-color: #c72210; + --el-button-border-color: transparent; + --el-button-outline-color: transparent; + + --el-button-hover-text-color: #ffffff; + --el-button-hover-link-text-color: #ffffff; + --el-button-hover-bg-color: #dd715b; + --el-button-hover-border-color: #c72210; + + --el-button-active-color: #ffffff; + --el-button-active-bg-color: #a8150a; + --el-button-active-border-color: transparent; + + --el-button-disabled-text-color: #a6a6a6; + --el-button-disabled-bg-color: #f5f5f5; + --el-button-disabled-border-color: transparent; + + //loading + --el-button-loading-text-color: #ffffff; + --el-button-loading-bg-color: #c72210; + --el-button-loading-border-color: transparent; + } + + .at-button-text { + --el-button-text-color: #477ef5; + --el-fill-color-light: transparent; + --el-fill-color: transparent; + + --el-button-hover-text-color: #86b2f9; + + --el-button-active-color: #2c59cb; + + --el-button-disabled-text-color: #a6a6a6; + + //loading + --el-button-loading-text-color: #477ef5; + } + + .el-button { + //default + --el-button-size: 36px; + height: var(--el-button-size); + padding: 8px 30px; + font-size: 14px; + //loading + .is-loading { + color: var(--el-button-loading-text-color); + background-color: var(--el-button-loading-bg-color); + border-color: var(--el-button-loading-border-color); + } + } + + .el-button--small { + --el-button-size: 27px; + height: var(--el-button-size); + padding: 5px 24px; + font-size: 12px; + } + + .el-button--large { + --el-button-size: 40px; + height: var(--el-button-size); + padding: 10px 30px; + font-size: 14px; + } + + .el-button + .el-button { + margin-left: 12px; + } +} diff --git a/src/theme/lighting/element-plus/checkbox.scss b/src/theme/lighting/element-plus/checkbox.scss new file mode 100644 index 0000000..f47ff6c --- /dev/null +++ b/src/theme/lighting/element-plus/checkbox.scss @@ -0,0 +1,27 @@ +html.china-red { + .el-checkbox { + --el-checkbox-font-size: 14px; + --el-checkbox-font-weight: var(--el-font-weight-primary); + --el-checkbox-text-color: #262626; + --el-checkbox-input-height: 14px; + --el-checkbox-input-width: 14px; + --el-checkbox-border-radius: var(--el-border-radius-small); + --el-checkbox-bg-color: var(--el-fill-color-blank); + --el-checkbox-input-border: var(--el-border); + + //disabled + --el-checkbox-disabled-border-color: var(--el-border-color); + --el-checkbox-disabled-input-fill: var(--el-fill-color-light); + --el-checkbox-disabled-icon-color: var(--el-text-color-placeholder); + --el-checkbox-disabled-checked-input-fill: var(--el-border-color-extra-light); + --el-checkbox-disabled-checked-input-border-color: var(--el-border-color); + --el-checkbox-disabled-checked-icon-color: var(--el-text-color-placeholder); + + //check + --el-checkbox-checked-text-color: #262626; + --el-checkbox-checked-input-border-color: transparent; + --el-checkbox-checked-bg-color: #c72210; + --el-checkbox-checked-icon-color: #ffffff; + --el-checkbox-input-border-color-hover: #c72210; + } +} diff --git a/src/theme/lighting/element-plus/css-vars.css b/src/theme/lighting/element-plus/css-vars.css new file mode 100644 index 0000000..e69de29 diff --git a/src/theme/lighting/element-plus/css-vars.css.map b/src/theme/lighting/element-plus/css-vars.css.map new file mode 100644 index 0000000..47b7af7 --- /dev/null +++ b/src/theme/lighting/element-plus/css-vars.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["var.scss","css-vars.scss","../../mixins/_var.scss"],"names":[],"mappings":"AAAA;ACMA;EACE;ECKA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA","file":"css-vars.css"} \ No newline at end of file diff --git a/src/theme/lighting/element-plus/css-vars.scss b/src/theme/lighting/element-plus/css-vars.scss new file mode 100644 index 0000000..2214616 --- /dev/null +++ b/src/theme/lighting/element-plus/css-vars.scss @@ -0,0 +1,17 @@ +@use 'sass:map'; + +@use './var' as *; +@use '../../mixins/var' as *; +@use '../../mixins/mixins' as *; + +html.china-red { + color-scheme: china-red; + @each $type in (primary, success, warning, danger, error, info) { + @include set-css-color-rgb($colors,$type); + } + + @each $type in (primary, success, warning, danger, error, info) { + @include set-css-color-type($colors, $type); + } + //--el-color-primary: #c72210; +} diff --git a/src/theme/lighting/element-plus/form.scss b/src/theme/lighting/element-plus/form.scss new file mode 100644 index 0000000..663d0bb --- /dev/null +++ b/src/theme/lighting/element-plus/form.scss @@ -0,0 +1,20 @@ +html.china-red { + //date + .el-date-range-picker { + --el-datepicker-text-color: var(--el-text-color-regular); + --el-datepicker-off-text-color: var(--el-text-color-placeholder); + --el-datepicker-header-text-color: var(--el-text-color-regular); + --el-datepicker-icon-color: var(--el-text-color-primary); + --el-datepicker-border-color: var(--el-disabled-border-color); + --el-datepicker-inner-border-color: var(--el-border-color-light); + --el-datepicker-inrange-bg-color: #ffece6; + --el-datepicker-inrange-hover-bg-color: var(--el-border-color-extra-light); + --el-datepicker-active-color: var(--el-color-primary); + --el-datepicker-hover-text-color: var(--el-color-primary); + } + + .el-select-dropdown__item.hover, + .el-select-dropdown__item:hover { + background-color: #ffece6; + } +} diff --git a/src/theme/lighting/element-plus/pagination.scss b/src/theme/lighting/element-plus/pagination.scss new file mode 100644 index 0000000..c0fb7a2 --- /dev/null +++ b/src/theme/lighting/element-plus/pagination.scss @@ -0,0 +1,30 @@ +html.china-red { + .el-pagination { + --el-text-color-regular: #8c8c8c; + --el-pagination-font-size: 14px; + --el-pagination-bg-color: var(--el-fill-color-blank); + --el-pagination-text-color: var(--el-text-color-primary); + --el-pagination-border-radius: 3px; + --el-pagination-button-color: var(--el-text-color-primary); + --el-pagination-button-width: 32px; + --el-pagination-button-height: 32px; + --el-pagination-button-disabled-color: var(--el-text-color-placeholder); + --el-pagination-button-disabled-bg-color: var(--el-fill-color-blank); + --el-pagination-button-bg-color: var(--el-fill-color); + --el-pagination-hover-color: var(--el-color-primary); + --el-pagination-height-extra-small: 24px; + --el-pagination-line-height-extra-small: var(--el-pagination-height-extra-small); + white-space: nowrap; + padding: 2px 5px; + color: var(--el-pagination-text-color); + font-weight: 400; + display: flex; + align-items: center; + } + + .el-pagination__total { + margin-right: 16px; + font-weight: 400; + color: var(--el-text-color-regular); + } +} diff --git a/src/theme/lighting/element-plus/redio.scss b/src/theme/lighting/element-plus/redio.scss new file mode 100644 index 0000000..8cf25fa --- /dev/null +++ b/src/theme/lighting/element-plus/redio.scss @@ -0,0 +1,18 @@ +html.china-red { + .el-radio { + --el-radio-font-size: var(--el-font-size-base); + --el-radio-text-color: #262626; + --el-radio-font-weight: var(--el-font-weight-primary); + --el-radio-input-height: 14px; + --el-radio-input-width: 14px; + --el-radio-input-border-radius: var(--el-border-radius-circle); + --el-radio-input-bg-color: var(--el-fill-color-blank); + --el-radio-input-border: var(--el-border); + --el-radio-input-border-color: transparent; + //--el-radio-input-border-color-hover: transparent; + } + + .el-radio__input.is-checked + .el-radio__label { + color: #262626; + } +} diff --git a/src/theme/lighting/element-plus/table.scss b/src/theme/lighting/element-plus/table.scss new file mode 100644 index 0000000..e94a1e4 --- /dev/null +++ b/src/theme/lighting/element-plus/table.scss @@ -0,0 +1,17 @@ +html.china-red { + .el-table { + --el-table-border-color: #f0f0f0; + --el-table-border: 1px solid #f0f0f0; + --el-table-text-color: var(--el-text-color-regular); + --el-table-header-text-color: var(--el-text-color-secondary); + --el-table-row-hover-bg-color: #ffece6; + --el-table-current-row-bg-color: var(--el-color-primary-light-9); + --el-table-header-bg-color: #fafafa; + --el-table-fixed-box-shadow: var(--el-box-shadow-light); + --el-table-bg-color: var(--el-fill-color-blank); + --el-table-tr-bg-color: var(--el-fill-color-blank); + --el-table-expanded-cell-bg-color: var(--el-fill-color-blank); + --el-table-fixed-left-column: inset 10px 0 10px -10px rgba(0, 0, 0, 0.15); + --el-table-fixed-right-column: inset -10px 0 10px -10px rgba(0, 0, 0, 0.15); + } +} diff --git a/src/theme/lighting/element-plus/var.scss b/src/theme/lighting/element-plus/var.scss new file mode 100644 index 0000000..3cd7b37 --- /dev/null +++ b/src/theme/lighting/element-plus/var.scss @@ -0,0 +1,63 @@ +/* Element Chalk Variables */ +@use 'sass:math'; +@use 'sass:map'; +@use '../../mixins/function.scss' as *; + +// types +$types: primary, success, warning, danger, error, info; + +// change color +$colors: () !default; +$colors: map.deep-merge( + ( + 'white': #ffffff, + 'black': #000000, + 'primary': ( + 'base': #c72210//#409eff + ), + 'success': ( + 'base': #45b207 + ), + 'warning': ( + 'base': #ec8828 + ), + 'danger': ( + 'base': #f56c6c + ), + 'error': ( + 'base': #d24934 + ), + 'info': ( + 'base': #909399 + ) + ), + $colors +); + +$color-white: map.get($colors, 'white') !default; +$color-black: map.get($colors, 'black') !default; +$color-primary: map.get($colors, 'primary', 'base') !default; +$color-success: map.get($colors, 'success', 'base') !default; +$color-warning: map.get($colors, 'warning', 'base') !default; +$color-danger: map.get($colors, 'danger', 'base') !default; +$color-error: map.get($colors, 'error', 'base') !default; +$color-info: map.get($colors, 'info', 'base') !default; + +//$colors添加 --el-color-primary-light-7 +@mixin set-color-mix-level($type, $number, $mode: 'light', $mix-color: $color-white) { + $colors: map.deep-merge( + ( + $type: ( + '#{$mode}-#{$number}': mix($mix-color, map.get($colors, $type, 'base'), math.percentage(math.div($number, 10))) + ) + ), + $colors + ) !global; +} + +// $colors.primary.light-i +@each $type in $types { + @for $i from 1 through 9 { + @include set-color-mix-level($type, $i, 'light', $color-white); + } +} diff --git a/src/theme/lighting/index.scss b/src/theme/lighting/index.scss new file mode 100644 index 0000000..a2b73a3 --- /dev/null +++ b/src/theme/lighting/index.scss @@ -0,0 +1,13 @@ +/*china-red*/ +//element-plus +//@use "./element-plus/css-vars"; +//@use "./element-plus/var"; +//@use "./element-plus/button"; +//@use "./element-plus/checkbox"; +//@use "./element-plus/redio"; +//@use "./element-plus/pagination"; +//@use "./element-plus/form"; +//@use "./element-plus/table"; + +//custom +@use "./custom/ct-css-vars"; diff --git a/src/theme/mixins/_var.scss b/src/theme/mixins/_var.scss new file mode 100644 index 0000000..1a5e4e5 --- /dev/null +++ b/src/theme/mixins/_var.scss @@ -0,0 +1,55 @@ +/*var mixin*/ +@use 'sass:map'; + +@use 'config'; +@use 'function' as *; + +// set css var value, because we need translate value to string +// for example: +// @include set-css-var-value(('color', 'primary'), red); +// --el-color: red; +// --el-$name-: $value; +@mixin set-css-var-value($name, $value) { + #{joinVarName($name)}: #{$value}; +} + +@mixin set-css-color-type($colors, $type) { + @include set-css-var-value(('color', $type), map.get($colors, $type, 'base')); + @each $i in (3, 5, 7, 8, 9) { + // --el-color-primary-light-7: #c6e2ff; + @include set-css-var-value(('color', $type, 'light', $i), map.get($colors, $type, 'light-#{$i}')); + } + + //@include set-css-var-value( + // ('color', $type, 'dark-2'), + // map.get($colors, $type, 'dark-2') + //); +} + +//el-$name-$attribute-$value +@mixin set-component-css-var($name, $variables) { + @each $attribute, $value in $variables { + @if $attribute == 'default' { + #{getCssVarName($name)}: #{$value}; + } @else { + #{getCssVarName($name, $attribute)}: #{$value}; + } + } +} + +// --el-color-error-rgb: 245, 108, 108; +// --el-color-$type-rgb: 245, 108, 108; +@mixin set-css-color-rgb($colors, $type) { + $color: map.get($colors, $type, 'base'); + @include set-css-var-value(('color', $type, 'rgb'), #{red($color), green($color), blue($color)}); +} + +// generate css var from existing css var +// for example: +// @include css-var-from-global(('button', 'text-color'), ('color', $type)) +// --el-button-text-color: var(--el-color-#{$type}); +@mixin css-var-from-global($var, $gVar) { + $varName: joinVarName($var); + $gVarName: joinVarName($gVar); + #{$varName}: var(#{$gVarName}); +} diff --git a/src/theme/mixins/config.scss b/src/theme/mixins/config.scss new file mode 100644 index 0000000..954f652 --- /dev/null +++ b/src/theme/mixins/config.scss @@ -0,0 +1,5 @@ +$namespace: 'el' !default; +$common-separator: '-' !default; +$element-separator: '__' !default; +$modifier-separator: '--' !default; +$state-prefix: 'is-' !default; diff --git a/src/theme/mixins/function.scss b/src/theme/mixins/function.scss new file mode 100644 index 0000000..14883fc --- /dev/null +++ b/src/theme/mixins/function.scss @@ -0,0 +1,60 @@ +@use 'config'; + +// getCssVarName('button', 'text-color') => '--el-button-text-color' +@function getCssVarName($args...) { + @return joinVarName($args); +} + +// getCssVar('button', 'text-color') => var(--el-button-text-color) +@function getCssVar($args...) { + @return var(#{joinVarName($args)}); +} + +@function selectorToString($selector) { + $selector: inspect($selector); + $selector: str-slice($selector, 2, -2); + @return $selector; +} + +@function containsModifier($selector) { + $selector: selectorToString($selector); + + @if str-index($selector, config.$modifier-separator) { + @return true; + } @else { + @return false; + } +} +@function hitAllSpecialNestRule($selector) { + @return containsModifier($selector) or containWhenFlag($selector) or containPseudoClass($selector); +} +@function containWhenFlag($selector) { + $selector: selectorToString($selector); + + @if str-index($selector, '.' + config.$state-prefix) { + @return true; + } @else { + @return false; + } +} +@function containPseudoClass($selector) { + $selector: selectorToString($selector); + + @if str-index($selector, ':') { + @return true; + } @else { + @return false; + } +} + +// join var name +// joinVarName(('button', 'text-color')) => '--el-button-text-color' +@function joinVarName($list) { + $name: '--' + config.$namespace; + @each $item in $list { + @if $item != '' { + $name: $name + '-' + $item; + } + } + @return $name; +} diff --git a/src/theme/mixins/mixins.scss b/src/theme/mixins/mixins.scss new file mode 100644 index 0000000..5e2f1f9 --- /dev/null +++ b/src/theme/mixins/mixins.scss @@ -0,0 +1,61 @@ +//input function +@use 'function' as *; +@forward 'function'; + +@forward 'config'; +@use 'config' as *; +// el-button{} +@mixin b($block) { + $B: $namespace + '-' + $block !global; + + .#{$B} { + @content; + } +} +@mixin e($element) { + $E: $element !global; + $selector: &; + $currentSelector: ''; + @each $unit in $element { + //el-button__text + $currentSelector: #{$currentSelector + '.' + $B + $element-separator + $unit + ','}; + } + + @if hitAllSpecialNestRule($selector) { + @at-root { + #{$selector} { + #{$currentSelector} { + @content; + } + } + } + } @else { + @at-root { + #{$currentSelector} { + @content; + } + } + } +} + +@mixin m($modifier) { + $selector: &; + $currentSelector: ''; + @each $unit in $modifier { + $currentSelector: #{$currentSelector + $selector + $modifier-separator + $unit + ','}; + } + + @at-root { + #{$currentSelector} { + @content; + } + } +} + +@mixin when($state) { + @at-root { + &.#{$state-prefix + $state} { + @content; + } + } +} diff --git a/src/theme/utils/change-theme.ts b/src/theme/utils/change-theme.ts new file mode 100644 index 0000000..aaac845 --- /dev/null +++ b/src/theme/utils/change-theme.ts @@ -0,0 +1,3 @@ +export const toggleHtmlClass = (className) => { + document.querySelectorAll('html')[0].className = className +} diff --git a/src/theme/utils/index.ts b/src/theme/utils/index.ts new file mode 100644 index 0000000..b4fbcde --- /dev/null +++ b/src/theme/utils/index.ts @@ -0,0 +1 @@ +export * from './change-theme' diff --git a/src/utils/axios-req.ts b/src/utils/axios-req.ts new file mode 100644 index 0000000..5fc3baf --- /dev/null +++ b/src/utils/axios-req.ts @@ -0,0 +1,67 @@ +import axios from 'axios' +import { ElMessage, ElMessageBox } from 'element-plus' +import { useBasicStore } from '@/store/basic' + +//使用axios.create()创建一个axios请求实例 +const service = axios.create() + +//请求前拦截 +service.interceptors.request.use( + (req) => { + const { token, axiosPromiseArr } = useBasicStore() + //axiosPromiseArr收集请求地址,用于取消请求 + req.cancelToken = new axios.CancelToken((cancel) => { + axiosPromiseArr.push({ + url: req.url, + cancel + }) + }) + //设置token到header + req.headers['AUTHORIZE_TOKEN'] = token + //如果req.method给get 请求参数设置为 ?name=xxx + if ('get'.includes(req.method?.toLowerCase() as string)) req.params = req.data + return req + }, + (err) => { + //发送请求失败 + Promise.reject(err) + } +) +//请求后拦截 +service.interceptors.response.use( + (res) => { + const { code } = res.data + const successCode = '0,200,20000' + const noAuthCode = '401,403' + if (successCode.includes(code)) { + return res.data + } else { + if (noAuthCode.includes(code) && !location.href.includes('/login')) { + ElMessageBox.confirm('请重新登录', { + confirmButtonText: '重新登录', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + useBasicStore().resetStateAndToLogin() + }) + } + return Promise.reject(res.data) + } + }, + //响应报错 + (err) => { + ElMessage.error({ + message: err, + duration: 2 * 1000 + }) + return Promise.reject(err) + } +) +//导出service实例给页面调用 , config->页面的配置 +export default function axiosReq(config) { + return service({ + baseURL: import.meta.env.VITE_APP_BASE_URL, + timeout: 8000, + ...config + }) +} diff --git a/src/utils/bus.ts b/src/utils/bus.ts new file mode 100644 index 0000000..1ca26c1 --- /dev/null +++ b/src/utils/bus.ts @@ -0,0 +1,3 @@ +//bus even +import mitt from 'mitt' +export default mitt() diff --git a/src/utils/common-util.ts b/src/utils/common-util.ts new file mode 100644 index 0000000..5be0bb6 --- /dev/null +++ b/src/utils/common-util.ts @@ -0,0 +1,126 @@ +export default { + getWeek() { + return `星期${'日一二三四五六'.charAt(new Date().getDay())}` + // this.showDate=this.$momentMini(new Date()).format('YYYY年MM月DD日,')+str + }, + /* 表单验证*/ + // 匹配手机 + mobilePhone(str) { + const reg = /^0?1[0-9]{10}$/ + return reg.test(str) + }, + /* + * 传入一串num四个 一个空格 + * */ + toSplitNumFor(num, numToSpace) { + return num.replace(/(.{4})/g, '$1 ') + }, + // 匹配银行卡号 + bankCardNo(str) { + const reg = /^\d{15,20}$/ + return reg.test(str) + }, + // 邮箱 + regEmail(str) { + const reg = /^([a-zA-Z]|[0-9])(\w|-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/ + return reg.test(str) + }, + // 省份证 + idCardNumber(str) { + const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/ + return reg.test(str) + }, + /* 常用数组操作*/ + /* + * 删除数组中的指定元素 + * arrItem 数组的index下标 + * return 删除后的数组 + * */ + deleteArrItem(arr, arrItem) { + arr.splice(arr.indexOf(arrItem), 1) + }, + /* + * 数组去重 + * arr:要去重的数组 + * return 去重后的数组 + * */ + arrToRepeat(arr) { + return arr.filter((ele, index, thisArr) => { + // 因为indexOf返回元素出现的第一个index位置,如果有重复的话那么他的位置永远是第一次出现的index,这就与他本身的index不相符,则删掉. + return thisArr.indexOf(ele) === index + }) + }, + /* + * 数组去重 + * seriesArr: 数组 + * return 去重后的数组 + * */ + deRepeatArr(seriesArr) { + return [...new Set(seriesArr)] + }, + /* + * 根据arrObj 删除arrObj2 根据arrObj objKey查找删除 + * arrObj: 数组对象 + * arrObj2: 要被删除的对象 + * objKey: arrObj中对象的某一个key名称 + * return: arrObj2删除过后的数组 + * */ + byArrObjDeleteArrObj2(arrObj, arrObj2, objKey) { + arrObj + .map((value) => { + return value[objKey] + }) + .forEach((value2) => { + arrObj2.splice( + arrObj2.findIndex((item) => item[objKey] === value2), + 1 + ) + }) + return arrObj2 + }, + /* + * 删除arrObj某一项 根据objKey中的key的值等于value的值 + * arrObj: 数组对象 + * objKey:arrObj中对象的某一个key名称 + * return: arrObj删除过后的数组 + * */ + deleteArrObjByKey(arrObj, objKey, value) { + //foreach splice + //for substring slice 不改变原数组 + arrObj.splice( + arrObj.findIndex((item) => item[objKey] === value), + 1 + ) + return arrObj + }, + /* + * 查找arrObj某一项 根据objKey中的值 + * arrObj: 数组对象 + * objKey:arrObj中对象的某一个key名称 + * return: arrObj查找 过后的数组 + * */ + findArrObjByKey(arrObj, objKey, value) { + return arrObj[arrObj.findIndex((item) => item[objKey] == value)] + }, + /* + * 根据arrObj 筛选arrObj2 根据arrObj objKey值查找 + * arrObj: 数组对象 + * arrObj2: 要被删除的对象 + * objKey: arrObj中对象的某一个key名称 + * return: arrObj2删除过后的数组 + * */ + byArrObjFindArrObj2(arrObj, arrObj2, objKey) { + const arrObj3: Array = [] + arrObj + .map((value) => { + return value[objKey] + }) + .forEach((value2) => { + const arrIndex = arrObj2.findIndex((item) => item[objKey] === value2) + if (arrIndex !== -1) { + arrObj3.push(arrObj2[arrIndex]) + } + }) + return arrObj3 + } +} diff --git a/src/utils/mock-axios-req.ts b/src/utils/mock-axios-req.ts new file mode 100644 index 0000000..e6f0a40 --- /dev/null +++ b/src/utils/mock-axios-req.ts @@ -0,0 +1,59 @@ +import axios from 'axios' +import { ElMessage } from 'element-plus' + +// create an axios instance +const service = axios.create({ + baseURL: '', // url = base url + request url + // withCredentials: true, // send cookies when cross-domain requests + timeout: 8000 // request timeout +}) + +// request interceptor +service.interceptors.request.use( + (config) => { + return config + }, + (error) => { + return Promise.reject(error) + } +) + +// response interceptor +service.interceptors.response.use( + /** + * If you want to get http information such as headers or status + * Please return response => response + */ + + /** + * Determine the request status by custom code + * Here is just an example + * You can also judge the status by HTTP Status Code + */ + (response) => { + const res = response.data + + // if the custom code is not 20000, it is judged as an error. + if (res.code !== 20000) { + ElMessage({ + message: res.ElMessage || 'Error', + type: 'error', + duration: 5 * 1000 + }) + return Promise.reject(new Error(res.ElMessage || 'Error')) + } else { + return res + } + }, + (error) => { + console.log(`err${error}`) // for debug + ElMessage({ + message: error.ElMessage, + type: 'error', + duration: 5 * 1000 + }) + return Promise.reject(error) + } +) + +export default service diff --git a/src/views/basic-demo/hook/index.vue b/src/views/basic-demo/hook/index.vue new file mode 100644 index 0000000..3d13e05 --- /dev/null +++ b/src/views/basic-demo/hook/index.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/views/basic-demo/keep-alive/index.vue b/src/views/basic-demo/keep-alive/index.vue new file mode 100644 index 0000000..377ec10 --- /dev/null +++ b/src/views/basic-demo/keep-alive/index.vue @@ -0,0 +1,58 @@ + + diff --git a/src/views/basic-demo/keep-alive/second-child.vue b/src/views/basic-demo/keep-alive/second-child.vue new file mode 100644 index 0000000..6025f54 --- /dev/null +++ b/src/views/basic-demo/keep-alive/second-child.vue @@ -0,0 +1,33 @@ + + + + diff --git a/src/views/basic-demo/keep-alive/tab-keep-alive.vue b/src/views/basic-demo/keep-alive/tab-keep-alive.vue new file mode 100644 index 0000000..d9df1ef --- /dev/null +++ b/src/views/basic-demo/keep-alive/tab-keep-alive.vue @@ -0,0 +1,19 @@ + + diff --git a/src/views/basic-demo/keep-alive/third-child.vue b/src/views/basic-demo/keep-alive/third-child.vue new file mode 100644 index 0000000..3b5409e --- /dev/null +++ b/src/views/basic-demo/keep-alive/third-child.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/views/basic-demo/keep-alive/third-children/SecondChildren.vue b/src/views/basic-demo/keep-alive/third-children/SecondChildren.vue new file mode 100644 index 0000000..7629df2 --- /dev/null +++ b/src/views/basic-demo/keep-alive/third-children/SecondChildren.vue @@ -0,0 +1,10 @@ + + + + + diff --git a/src/views/basic-demo/keep-alive/third-children/ThirdChildren.vue b/src/views/basic-demo/keep-alive/third-children/ThirdChildren.vue new file mode 100644 index 0000000..236516f --- /dev/null +++ b/src/views/basic-demo/keep-alive/third-children/ThirdChildren.vue @@ -0,0 +1,10 @@ + + + + + diff --git a/src/views/basic-demo/keep-alive/third-keep-alive.vue b/src/views/basic-demo/keep-alive/third-keep-alive.vue new file mode 100644 index 0000000..7314cb7 --- /dev/null +++ b/src/views/basic-demo/keep-alive/third-keep-alive.vue @@ -0,0 +1,19 @@ + + + + + diff --git a/src/views/basic-demo/mock/index.vue b/src/views/basic-demo/mock/index.vue new file mode 100644 index 0000000..cb12b67 --- /dev/null +++ b/src/views/basic-demo/mock/index.vue @@ -0,0 +1,17 @@ + + + + + diff --git a/src/views/basic-demo/parent-children/Children.vue b/src/views/basic-demo/parent-children/Children.vue new file mode 100644 index 0000000..95427d6 --- /dev/null +++ b/src/views/basic-demo/parent-children/Children.vue @@ -0,0 +1,76 @@ + + + diff --git a/src/views/basic-demo/parent-children/SubChildren.vue b/src/views/basic-demo/parent-children/SubChildren.vue new file mode 100644 index 0000000..f8ff07a --- /dev/null +++ b/src/views/basic-demo/parent-children/SubChildren.vue @@ -0,0 +1,34 @@ + + + diff --git a/src/views/basic-demo/parent-children/index.vue b/src/views/basic-demo/parent-children/index.vue new file mode 100644 index 0000000..a768d39 --- /dev/null +++ b/src/views/basic-demo/parent-children/index.vue @@ -0,0 +1,54 @@ + + + diff --git a/src/views/basic-demo/pinia/index.vue b/src/views/basic-demo/pinia/index.vue new file mode 100644 index 0000000..79a3129 --- /dev/null +++ b/src/views/basic-demo/pinia/index.vue @@ -0,0 +1,14 @@ + + + + + diff --git a/src/views/basic-demo/svg-icon/index.vue b/src/views/basic-demo/svg-icon/index.vue new file mode 100644 index 0000000..06ae739 --- /dev/null +++ b/src/views/basic-demo/svg-icon/index.vue @@ -0,0 +1,18 @@ + + + + + diff --git a/src/views/basic-demo/vue3-template/Vue3Template.vue b/src/views/basic-demo/vue3-template/Vue3Template.vue new file mode 100644 index 0000000..03bedc5 --- /dev/null +++ b/src/views/basic-demo/vue3-template/Vue3Template.vue @@ -0,0 +1,39 @@ + + + + + diff --git a/src/views/basic-demo/worker/index.vue b/src/views/basic-demo/worker/index.vue new file mode 100644 index 0000000..9e96667 --- /dev/null +++ b/src/views/basic-demo/worker/index.vue @@ -0,0 +1,45 @@ + + diff --git a/src/views/charts/components/Keyboard.vue b/src/views/charts/components/Keyboard.vue new file mode 100644 index 0000000..dc0d297 --- /dev/null +++ b/src/views/charts/components/Keyboard.vue @@ -0,0 +1,158 @@ + + + + + diff --git a/src/views/charts/components/LineMarker.vue b/src/views/charts/components/LineMarker.vue new file mode 100644 index 0000000..3868df2 --- /dev/null +++ b/src/views/charts/components/LineMarker.vue @@ -0,0 +1,278 @@ + + + + + diff --git a/src/views/charts/components/MixChart.vue b/src/views/charts/components/MixChart.vue new file mode 100644 index 0000000..08b4039 --- /dev/null +++ b/src/views/charts/components/MixChart.vue @@ -0,0 +1,232 @@ + + + diff --git a/src/views/charts/components/mixins/resize.js b/src/views/charts/components/mixins/resize.js new file mode 100644 index 0000000..7d3eb97 --- /dev/null +++ b/src/views/charts/components/mixins/resize.js @@ -0,0 +1,56 @@ +import { debounce } from '@/utils' + +export default { + data() { + return { + $_sidebarElm: null, + $_resizeHandler: null + } + }, + mounted() { + this.initListener() + }, + activated() { + if (!this.$_resizeHandler) { + // avoid duplication init + this.initListener() + } + + // when keep-alive chart activated, auto resize + this.resize() + }, + beforeDestroy() { + this.destroyListener() + }, + deactivated() { + this.destroyListener() + }, + methods: { + // use $_ for mixins properties + // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential + $_sidebarResizeHandler(e) { + if (e.propertyName === 'width') { + this.$_resizeHandler() + } + }, + initListener() { + this.$_resizeHandler = debounce(() => { + this.resize() + }, 100) + window.addEventListener('resize', this.$_resizeHandler) + + this.$_sidebarElm = document.querySelectorAll('.sidebar-container')[0] + this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler) + }, + destroyListener() { + window.removeEventListener('resize', this.$_resizeHandler) + this.$_resizeHandler = null + + this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler) + }, + resize() { + const { chart } = this + chart && chart.resize() + } + } +} diff --git a/src/views/charts/echarts-demo.vue b/src/views/charts/echarts-demo.vue new file mode 100644 index 0000000..79d05b8 --- /dev/null +++ b/src/views/charts/echarts-demo.vue @@ -0,0 +1,356 @@ + + + + diff --git a/src/views/charts/keyboard.vue b/src/views/charts/keyboard.vue new file mode 100644 index 0000000..82f752f --- /dev/null +++ b/src/views/charts/keyboard.vue @@ -0,0 +1,17 @@ + + + + + diff --git a/src/views/charts/line.vue b/src/views/charts/line.vue new file mode 100644 index 0000000..f4e4dc4 --- /dev/null +++ b/src/views/charts/line.vue @@ -0,0 +1,17 @@ + + + + + diff --git a/src/views/charts/mix-chart.vue b/src/views/charts/mix-chart.vue new file mode 100644 index 0000000..f4c8e64 --- /dev/null +++ b/src/views/charts/mix-chart.vue @@ -0,0 +1,17 @@ + + + + + diff --git a/src/views/dashboard/index.vue b/src/views/dashboard/index.vue new file mode 100644 index 0000000..af50a2d --- /dev/null +++ b/src/views/dashboard/index.vue @@ -0,0 +1,51 @@ + + diff --git a/src/views/directive/clickoutside.vue b/src/views/directive/clickoutside.vue new file mode 100644 index 0000000..476b635 --- /dev/null +++ b/src/views/directive/clickoutside.vue @@ -0,0 +1,35 @@ + + + + + diff --git a/src/views/directive/copy.vue b/src/views/directive/copy.vue new file mode 100644 index 0000000..ad1460b --- /dev/null +++ b/src/views/directive/copy.vue @@ -0,0 +1,19 @@ + + + + + diff --git a/src/views/directive/debounce.vue b/src/views/directive/debounce.vue new file mode 100644 index 0000000..f33d809 --- /dev/null +++ b/src/views/directive/debounce.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/views/directive/longpress.vue b/src/views/directive/longpress.vue new file mode 100644 index 0000000..a43d52f --- /dev/null +++ b/src/views/directive/longpress.vue @@ -0,0 +1,15 @@ + + + + + diff --git a/src/views/directive/watermark.vue b/src/views/directive/watermark.vue new file mode 100644 index 0000000..95d2e4b --- /dev/null +++ b/src/views/directive/watermark.vue @@ -0,0 +1,12 @@ + + + + + diff --git a/src/views/directive/waves.vue b/src/views/directive/waves.vue new file mode 100644 index 0000000..0d52b02 --- /dev/null +++ b/src/views/directive/waves.vue @@ -0,0 +1,17 @@ + + + + + diff --git a/src/views/error-log/error-generator.vue b/src/views/error-log/error-generator.vue new file mode 100644 index 0000000..a9a7f07 --- /dev/null +++ b/src/views/error-log/error-generator.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/src/views/error-log/index.vue b/src/views/error-log/index.vue new file mode 100644 index 0000000..95b783a --- /dev/null +++ b/src/views/error-log/index.vue @@ -0,0 +1,148 @@ + + + + diff --git a/src/views/error-page/401.vue b/src/views/error-page/401.vue new file mode 100644 index 0000000..3ca5835 --- /dev/null +++ b/src/views/error-page/401.vue @@ -0,0 +1,93 @@ + + + + + diff --git a/src/views/error-page/404.vue b/src/views/error-page/404.vue new file mode 100644 index 0000000..0a3f517 --- /dev/null +++ b/src/views/error-page/404.vue @@ -0,0 +1,225 @@ + + + + + diff --git a/src/views/excel/excel.js b/src/views/excel/excel.js new file mode 100644 index 0000000..ca0c83d --- /dev/null +++ b/src/views/excel/excel.js @@ -0,0 +1,57 @@ +import * as xlsx from 'xlsx' +const { utils, writeFile, read } = xlsx +const DEF_FILE_NAME = 'new-excel.xlsx' + +function getHeaderRow(sheet) { + const headers = [] + const range = utils.decode_range(sheet['!ref']) + let C + const R = range.s.r + /* start in the first row */ + for (C = range.s.c; C <= range.e.c; ++C) { + /* walk every column in the range */ + const cell = sheet[utils.encode_cell({ c: C, r: R })] + /* find the cell in the first row */ + let hdr = `UNKNOWN ${C}` // <-- replace with your desired default + if (cell && cell.t) hdr = utils.format_cell(cell) + headers.push(hdr) + } + return headers +} +export function importsExcel(file) { + return new Promise((resolve, reject) => { + const reader = new FileReader() + + reader.onload = (e) => { + const data = new Uint8Array(e.target.result) + const workbook = read(data, { type: 'array' }) + // console.log("workbook: ", workbook); + + //将Excel 第一个sheet内容转为json格式 + const worksheet = workbook.Sheets[workbook.SheetNames[0]] + const json = utils.sheet_to_json(worksheet) + // console.log("jsonExcel:", jsonExcel); + const headers = getHeaderRow(worksheet) + resolve({ tableData: json, headers }) + } + + reader.readAsArrayBuffer(file.raw) + }) +} +export function aoaToSheetXlsx({ data, header, filename = DEF_FILE_NAME, write2excelOpts = { bookType: 'xlsx' } }) { + const arrData = [...data] + if (header) { + arrData.unshift(header) + } + const worksheet = utils.aoa_to_sheet(arrData) + /* add worksheet to workbook */ + const workbook = { + SheetNames: [filename], + Sheets: { + [filename]: worksheet + } + } + /* output format determined by filename */ + writeFile(workbook, filename, write2excelOpts) + /* at this point, out.xlsb will have been downloaded */ +} diff --git a/src/views/excel/exportExcel.vue b/src/views/excel/exportExcel.vue new file mode 100644 index 0000000..5c52fdb --- /dev/null +++ b/src/views/excel/exportExcel.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/src/views/excel/importExcel.vue b/src/views/excel/importExcel.vue new file mode 100644 index 0000000..408f8ae --- /dev/null +++ b/src/views/excel/importExcel.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/src/views/guide/index.vue b/src/views/guide/index.vue new file mode 100644 index 0000000..6dacf2f --- /dev/null +++ b/src/views/guide/index.vue @@ -0,0 +1,33 @@ + + + diff --git a/src/views/guide/steps.ts b/src/views/guide/steps.ts new file mode 100644 index 0000000..c285e91 --- /dev/null +++ b/src/views/guide/steps.ts @@ -0,0 +1,45 @@ +const steps = [ + { + element: '#hamburger-container', + popover: { + title: 'Hamburger', + description: 'Open && Close sidebar', + position: 'bottom' + } + }, + { + element: '#breadcrumb-container', + popover: { + title: 'Breadcrumb', + description: 'Indicate the current page location', + position: 'bottom' + } + }, + { + element: '#screenfull', + popover: { + title: 'Screenfull', + description: 'Set the page into fullscreen', + position: 'left' + } + }, + { + element: '#size-select', + popover: { + title: 'Switch Size', + description: 'Switch the system size', + position: 'left' + } + }, + { + element: '#tags-view-container', + popover: { + title: 'Tags view', + description: 'The history of the page you visited', + position: 'bottom' + }, + padding: 0 + } +] + +export default steps diff --git a/src/views/login/index.vue b/src/views/login/index.vue new file mode 100644 index 0000000..93683fa --- /dev/null +++ b/src/views/login/index.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/src/views/login/login-alt.vue b/src/views/login/login-alt.vue new file mode 100644 index 0000000..c266eb7 --- /dev/null +++ b/src/views/login/login-alt.vue @@ -0,0 +1,270 @@ + + + + diff --git a/src/views/login/login-basic.vue b/src/views/login/login-basic.vue new file mode 100644 index 0000000..898d77a --- /dev/null +++ b/src/views/login/login-basic.vue @@ -0,0 +1,253 @@ + + + + + + diff --git a/src/views/login/login-lighting.vue b/src/views/login/login-lighting.vue new file mode 100644 index 0000000..adfadd0 --- /dev/null +++ b/src/views/login/login-lighting.vue @@ -0,0 +1,252 @@ + + + + + + diff --git a/src/views/nested/menu1/index.vue b/src/views/nested/menu1/index.vue new file mode 100644 index 0000000..a05f6e3 --- /dev/null +++ b/src/views/nested/menu1/index.vue @@ -0,0 +1,9 @@ + diff --git a/src/views/nested/menu1/menu1-1/index.vue b/src/views/nested/menu1/menu1-1/index.vue new file mode 100644 index 0000000..ca8ef65 --- /dev/null +++ b/src/views/nested/menu1/menu1-1/index.vue @@ -0,0 +1,11 @@ + diff --git a/src/views/nested/menu1/menu1-2/index.vue b/src/views/nested/menu1/menu1-2/index.vue new file mode 100644 index 0000000..1d0476c --- /dev/null +++ b/src/views/nested/menu1/menu1-2/index.vue @@ -0,0 +1,9 @@ + diff --git a/src/views/nested/menu1/menu1-2/menu1-2-1/index.vue b/src/views/nested/menu1/menu1-2/menu1-2-1/index.vue new file mode 100644 index 0000000..9608e0e --- /dev/null +++ b/src/views/nested/menu1/menu1-2/menu1-2-1/index.vue @@ -0,0 +1,5 @@ + diff --git a/src/views/nested/menu1/menu1-2/menu1-2-2/index.vue b/src/views/nested/menu1/menu1-2/menu1-2-2/index.vue new file mode 100644 index 0000000..fc1f837 --- /dev/null +++ b/src/views/nested/menu1/menu1-2/menu1-2-2/index.vue @@ -0,0 +1,5 @@ + diff --git a/src/views/nested/menu1/menu1-3/index.vue b/src/views/nested/menu1/menu1-3/index.vue new file mode 100644 index 0000000..1364e04 --- /dev/null +++ b/src/views/nested/menu1/menu1-3/index.vue @@ -0,0 +1,5 @@ + diff --git a/src/views/nested/menu2/index.vue b/src/views/nested/menu2/index.vue new file mode 100644 index 0000000..44c557f --- /dev/null +++ b/src/views/nested/menu2/index.vue @@ -0,0 +1,6 @@ + + diff --git a/src/views/other/count-to.vue b/src/views/other/count-to.vue new file mode 100644 index 0000000..9a8a61b --- /dev/null +++ b/src/views/other/count-to.vue @@ -0,0 +1,24 @@ + + diff --git a/src/views/other/d3/component/NodeDetail.vue b/src/views/other/d3/component/NodeDetail.vue new file mode 100644 index 0000000..cba58ee --- /dev/null +++ b/src/views/other/d3/component/NodeDetail.vue @@ -0,0 +1,61 @@ + + + + + diff --git a/src/views/other/d3/data.json b/src/views/other/d3/data.json new file mode 100644 index 0000000..85b391d --- /dev/null +++ b/src/views/other/d3/data.json @@ -0,0 +1,269 @@ +{ + "nodes": [ + { + "id": "父", + "color": "#dc5712", + "type": "gkNode", + "data": { + "id": "X202201010903", + "bh": "bh12224", + "sj": "2022-01-05 10:00:12", + "dl": "10A", + "img": "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.autohome.com.cn%2Falbum%2F2009%2F2%2F19%2Fe53e9b0b-f0bd-4a0d-b7fd-7d38924a6f69.jpg&refer=http%3A%2F%2Fimg.autohome.com.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1643968757&t=658b4aa47e7355dc55a5beb0e8f76639", + "video": "https://github.jzfai.top/file/video/test-video.mp4" + } + }, + { + "id": "子", + "color": "#e58308", + "type": "DLNode", + "data": { + "id": "X202201010903", + "lb": "bh12224-01" + } + }, + { + "id": "孙", + "color": "#f4d000", + "type": "CLNode", + "data": { + "id": "X2022010109030101", + "mc": "bh12224-01-01" + } + }, + { + "id": "Microsoft", + "name": "张三", + "age": 18, + "color": "#8a977b" + }, + { + "id": "Amazon", + "color": "#b6c29a" + }, + { + "id": "HTC", + "color": "#407434" + }, + { + "id": "Samsung", + "color": "#407434" + }, + { + "id": "Apple", + "color": "#65934a" + }, + { + "id": "Motorola", + "color": "#a0bf7c" + }, + { + "id": "Nokia", + "color": "#407434" + }, + { + "id": "Kodak", + "color": "#123555" + }, + { + "id": "Barnes & Noble", + "color": "#d1484f" + }, + { + "id": "Foxconn", + "color": "#e69b02" + }, + { + "id": "Oracle", + "color": "#dcd0a8" + }, + { + "id": "Google", + "color": "#e1eed2" + }, + { + "id": "Inventec", + "color": "#e3aa25" + }, + { + "id": "LG", + "color": "#a11715" + }, + { + "id": "RIM", + "color": "#e5bb81" + }, + { + "id": "Sony", + "color": "#a12f2f" + }, + { + "id": "Qualcomm", + "color": "#e6b33d" + }, + { + "id": "Huawei", + "color": "#e6b33d" + }, + { + "id": "ZTE", + "color": "#a12f2f" + }, + { + "id": "Ericsson", + "color": "#a12f2f" + } + ], + "links": [ + { + "source": "父", + "target": "子", + "type": "licensing" + }, + { + "source": "子", + "target": "孙", + "type": "licensing" + }, + { + "source": "Microsoft", + "target": "Amazon", + "type": "licensing" + }, + { + "source": "Microsoft", + "target": "HTC", + "type": "licensing" + }, + { + "source": "Samsung", + "target": "Apple", + "type": "suit" + }, + { + "source": "Motorola", + "target": "Apple", + "type": "suit" + }, + { + "source": "Nokia", + "target": "Apple", + "type": "resolved" + }, + { + "source": "HTC", + "target": "Apple", + "type": "suit" + }, + { + "source": "Kodak", + "target": "Apple", + "type": "suit" + }, + { + "source": "Microsoft", + "target": "Barnes & Noble", + "type": "suit" + }, + { + "source": "Microsoft", + "target": "Foxconn", + "type": "suit" + }, + { + "source": "Oracle", + "target": "Google", + "type": "suit" + }, + { + "source": "Apple", + "target": "HTC", + "type": "suit" + }, + { + "source": "Microsoft", + "target": "Inventec", + "type": "suit" + }, + { + "source": "Samsung", + "target": "Kodak", + "type": "resolved" + }, + { + "source": "LG", + "target": "Kodak", + "type": "resolved" + }, + { + "source": "RIM", + "target": "Kodak", + "type": "suit" + }, + { + "source": "Sony", + "target": "LG", + "type": "suit" + }, + { + "source": "Kodak", + "target": "LG", + "type": "resolved" + }, + { + "source": "Apple", + "target": "Nokia", + "type": "resolved" + }, + { + "source": "Qualcomm", + "target": "Nokia", + "type": "resolved" + }, + { + "source": "Apple", + "target": "Motorola", + "type": "suit" + }, + { + "source": "Microsoft", + "target": "Motorola", + "type": "suit" + }, + { + "source": "Motorola", + "target": "Microsoft", + "type": "suit" + }, + { + "source": "Huawei", + "target": "ZTE", + "type": "suit" + }, + { + "source": "Ericsson", + "target": "ZTE", + "type": "suit" + }, + { + "source": "Kodak", + "target": "Samsung", + "type": "resolved" + }, + { + "source": "Apple", + "target": "Samsung", + "type": "suit" + }, + { + "source": "Kodak", + "target": "RIM", + "type": "suit" + }, + { + "source": "Nokia", + "target": "Qualcomm", + "type": "suit" + } + ] +} diff --git a/src/views/other/d3/index.vue b/src/views/other/d3/index.vue new file mode 100644 index 0000000..0fd43d4 --- /dev/null +++ b/src/views/other/d3/index.vue @@ -0,0 +1,170 @@ + + + + + + diff --git a/src/views/other/d3/useD3.js b/src/views/other/d3/useD3.js new file mode 100644 index 0000000..b97cb7c --- /dev/null +++ b/src/views/other/d3/useD3.js @@ -0,0 +1,183 @@ +import * as d3 from 'd3' + +export default function() { + const linkArc = (d) => { + const r = Math.hypot(d.target.x - d.source.x, d.target.y - d.source.y) + return ` + M${d.source.x},${d.source.y} + A${r},${r} 1 0,1 ${d.target.x},${d.target.y} + ` + } + + // 节点拖拽方法 + const drag = (simulation) => { + function dragstarted(event, d) { + if (!event.active) simulation.alphaTarget(0.3).restart() + d.fx = d.x + d.fy = d.y + } + + function dragged(event, d) { + d.fx = event.x + d.fy = event.y + } + + function dragended(event, d) { + if (!event.active) simulation.alphaTarget(0) + d.fx = null + d.fy = null + } + + return d3.drag().on('start', dragstarted).on('drag', dragged).on('end', dragended) + } + + const chart = (el, opt = {}) => { + + const { links, nodes } = opt.data + const types = Array.from(new Set(links.map((d) => d.type))) + // let data = { nodes: Array.from(new Set(links.flatMap((l) => [l.source, l.target])), (id) => ({ id })), links } + const color = d3.scaleOrdinal(types, d3.schemeCategory10) // 根据类型生成内置颜色 + const height = opt.height || 600 // svg宽 + const width = opt.width || 600 // svg高 + // const nodeColor = 'rgb(19,19,19)' // 节点颜色 + const lineColor = 'rgb(148,148,148)' // 边线颜色 + const hoverColor = 'rgb(110,165,255)' // hover颜色 + const showTextLength = 5 // 超出5个字后截取 + + + // 生成力向图配置 + const simulation = d3 + .forceSimulation() + .nodes(nodes) + .force('link', d3.forceLink(links).id((d) => d.id).distance(50)) + .force('charge', d3.forceManyBody().strength(-400)) + .force("center",d3.forceCenter(width/2, height/2)) + .force('x', d3.forceX()) + .force('y', d3.forceY()) + + + // 在盒子里添加svg + const svg = d3.select(el).append('svg') + + // svg样式 + svg.attr('width', width) + .attr('height', height) + // .attr('viewBox', [-width/2, -height/2, width, height]) + .style('font', '12px sans-serif') + + const group = svg.append('g') + + // svg追加箭头 + const marker = group + .append('g') + .selectAll('marker') + .data(types) + .join('marker') + .attr('id', (d) => `arrow-${d}`) + .attr('viewBox', '0 -5 10 10') + .attr('refX', 21) + .attr('refY',-1.5) + .attr('markerWidth', 8) + .attr('markerHeight', 8) + .attr('orient', 'auto') + .append('path') + // .attr('fill', color) + .attr('fill', lineColor) + .attr('d', 'M0,-5L10,0L0,5') + + // svg追加边线 + const link = group + .append('g') + .attr('fill', 'none') + .attr('stroke-width', 1) + .selectAll('path') + .data(links) + .join('path') + // .attr('stroke', (d) => color(d.type)) + .attr('stroke', lineColor) + .attr('marker-end', (d) => `url(${new URL(`#arrow-${d.type}`, location)})`) + .on('click', (e) => { + // var rect = d3.select(this) + // console.log(22, e) + }) + + // svg.append("g") + // .selectAll("text") + // // .selectAll("text") + // .data(links) + // .enter() + // .append("text") + // .attr('x', (d) => (d.source.x+d.target.x)/2) + // .attr('y', (d) => (d.source.y+d.target.y)/2) + // .text((d) => '22222') + + // svg追加节点 + const node = group + .append('g') + // .attr('fill', 'black') + .attr('stroke-linecap', 'round') + .attr('stroke-linejoin', 'round') + .selectAll('g') + .data(nodes) + .join('g') + .attr('fill', (d,i) => { + return nodes[i].color || 'black' + }) + .call(drag(simulation)) + .on('click', opt.nodeClick) + .on('mouseover', opt.nodeMouseOver) + .on('mouseout', opt.nodMouseOut) + + // 节点追加圆形 + node + .append('circle') + .attr('stroke', 'white') + .attr('stroke-width', 0.5) + .attr('r', 10) + .on('mouseover', function(){ + d3.select(this).style('fill',hoverColor) + }) + .on('mouseout', function(){ + d3.select(this).style('fill',(d,i) => { + return d.color || 'black' + }) + }) + + // 节点追加圆形旁边文字 + node + .append('text') + .attr('x', 14) + .attr('y', '0.31em') + .text((d) => d.id.slice(0,Math.max(0, showTextLength))) + .clone(true) + .lower() + .attr('fill', 'none') + .attr('stroke', 'white') + .attr('stroke-width', 3) + + + function zoomed(e) { + group.attr('transform', e.transform) + } + + // 缩放平移配置 + const zoom = d3.zoom() + .scaleExtent([0.1, 40]) + .on('zoom', zoomed) + + svg.call(zoom) + + simulation.on('tick', () => { + link.attr('d', linkArc) + node.attr('transform', (d) => `translate(${d.x},${d.y})`) + }) + + + // invalidation.then(() => simulation.stop()) + // return svg.node() + return { simulation, svg } + } + return { + chart + } +} diff --git a/src/views/other/d3/useDatas.js b/src/views/other/d3/useDatas.js new file mode 100644 index 0000000..3a52e0b --- /dev/null +++ b/src/views/other/d3/useDatas.js @@ -0,0 +1,109 @@ +import { reactive, ref, watch } from 'vue' + +export default function useUserRepositories(state) { + const gkNode = reactive([{ + title: '工况ID', + field: 'id' + }, { + title: '车辆编号', + field: 'bh' + }, { + title: '数据时间', + field: 'sj' + }, { + title: '臂架电流', + field: 'dl' + }, { + title: '图片', + field: 'img' + }, { + title: '视频', + field: 'video' + },{ + title: '节点颜色', + field: 'ys' + }]) + + const gzNode = reactive([{ + title: '故障Id', + field: 'id' + }, { + title: '问题类别', + field: 'lb' + }, { + title: '故障现象', + field: 'xx' + }, { + title: '故障处理方法', + field: 'ff' + }, { + title: '失效形式', + field: 'xs' + }, { + title: 'Url', + field: 'url' + }, { + title: '颜色', + field: 'ys' + }]) + + const BOMNode = reactive([{ + title: 'BOM ID', + field: 'id' + }, { + title: '级别', + field: 'lb' + }, { + title: '编码', + field: 'xx' + }, { + title: '部件名称', + field: 'ff' + }, { + title: 'url地址', + field: 'xs' + }, { + title: '节点颜色', + field: 'url' + }]) + + const DLNode = reactive([{ + title: '电流评价ID', + field: 'id' + }, { + title: '电流评价', + field: 'lb' + }, { + title: '节点颜色', + field: 'ys' + }]) + + const CLNode = reactive([{ + title: '车辆编码', + field: 'id' + }, { + title: '车辆名称', + field: 'mc' + }, { + title: '节点颜色', + field: 'ys' + }]) + + const node = { + gkNode, + gzNode, + BOMNode, + DLNode, + CLNode + } + + + const nodeType = ref([]) + watch(() => state.types, (newValue) => { + nodeType.value = node[newValue] + }, {immediate: true}) + + return { + nodeType + } +} diff --git a/src/views/other/drag-pane.vue b/src/views/other/drag-pane.vue new file mode 100644 index 0000000..265d7a0 --- /dev/null +++ b/src/views/other/drag-pane.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/src/views/other/signboard/component/index.vue b/src/views/other/signboard/component/index.vue new file mode 100644 index 0000000..b8bfcad --- /dev/null +++ b/src/views/other/signboard/component/index.vue @@ -0,0 +1,89 @@ + + + + diff --git a/src/views/other/signboard/index.vue b/src/views/other/signboard/index.vue new file mode 100644 index 0000000..68a91b4 --- /dev/null +++ b/src/views/other/signboard/index.vue @@ -0,0 +1,58 @@ + + + + + diff --git a/src/views/rbac-test/TestAddEdit.vue b/src/views/rbac-test/TestAddEdit.vue new file mode 100644 index 0000000..6901919 --- /dev/null +++ b/src/views/rbac-test/TestAddEdit.vue @@ -0,0 +1,5 @@ + + + diff --git a/src/views/rbac-test/TestButton.vue b/src/views/rbac-test/TestButton.vue new file mode 100644 index 0000000..cc86c33 --- /dev/null +++ b/src/views/rbac-test/TestButton.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/views/rbac-test/TestDetail.vue b/src/views/rbac-test/TestDetail.vue new file mode 100644 index 0000000..6901919 --- /dev/null +++ b/src/views/rbac-test/TestDetail.vue @@ -0,0 +1,5 @@ + + + diff --git a/src/views/rbac-test/TestMenu.vue b/src/views/rbac-test/TestMenu.vue new file mode 100644 index 0000000..fefd172 --- /dev/null +++ b/src/views/rbac-test/TestMenu.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/src/views/redirect/index.tsx b/src/views/redirect/index.tsx new file mode 100644 index 0000000..08e5b88 --- /dev/null +++ b/src/views/redirect/index.tsx @@ -0,0 +1,13 @@ +import { defineComponent } from 'vue' +export default defineComponent({ + setup() { + const route = useRoute() + const router = useRouter() + onBeforeMount(() => { + const { params, query } = route + const { path } = params + router.replace({ path: `/${path}`, query }) + }) + return () =>
+ } +}) diff --git a/src/views/rich-text/TinymceExample-bak.vue b/src/views/rich-text/TinymceExample-bak.vue new file mode 100644 index 0000000..9c8b168 --- /dev/null +++ b/src/views/rich-text/TinymceExample-bak.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/src/views/rich-text/TinymceExample.vue b/src/views/rich-text/TinymceExample.vue new file mode 100644 index 0000000..707aa3e --- /dev/null +++ b/src/views/rich-text/TinymceExample.vue @@ -0,0 +1,7 @@ + + + + + diff --git a/src/views/rich-text/tinymce/index.vue b/src/views/rich-text/tinymce/index.vue new file mode 100644 index 0000000..0ec18ff --- /dev/null +++ b/src/views/rich-text/tinymce/index.vue @@ -0,0 +1,119 @@ + + + + + diff --git a/src/views/roles-codes/button-permission.vue b/src/views/roles-codes/button-permission.vue new file mode 100644 index 0000000..5d1f95d --- /dev/null +++ b/src/views/roles-codes/button-permission.vue @@ -0,0 +1,7 @@ + diff --git a/src/views/roles-codes/code-index.vue b/src/views/roles-codes/code-index.vue new file mode 100644 index 0000000..70d8d5d --- /dev/null +++ b/src/views/roles-codes/code-index.vue @@ -0,0 +1,4 @@ + + diff --git a/src/views/roles-codes/index.vue b/src/views/roles-codes/index.vue new file mode 100644 index 0000000..8aa90c8 --- /dev/null +++ b/src/views/roles-codes/index.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/src/views/roles-codes/role-index.vue b/src/views/roles-codes/role-index.vue new file mode 100644 index 0000000..8554d60 --- /dev/null +++ b/src/views/roles-codes/role-index.vue @@ -0,0 +1,3 @@ + + + diff --git a/src/views/setting-switch/SettingSwitch.vue b/src/views/setting-switch/SettingSwitch.vue new file mode 100644 index 0000000..18c7ee4 --- /dev/null +++ b/src/views/setting-switch/SettingSwitch.vue @@ -0,0 +1,50 @@ + + + diff --git a/src/views/setting-switch/index.vue b/src/views/setting-switch/index.vue new file mode 100644 index 0000000..18c7ee4 --- /dev/null +++ b/src/views/setting-switch/index.vue @@ -0,0 +1,50 @@ + + + diff --git a/src/views/table/dynamic-table.vue b/src/views/table/dynamic-table.vue new file mode 100644 index 0000000..93fc6f6 --- /dev/null +++ b/src/views/table/dynamic-table.vue @@ -0,0 +1,90 @@ + + + diff --git a/src/views/table/vxe-table.vue b/src/views/table/vxe-table.vue new file mode 100644 index 0000000..7bde329 --- /dev/null +++ b/src/views/table/vxe-table.vue @@ -0,0 +1,368 @@ + + + diff --git a/ts-out-dir/package.json b/ts-out-dir/package.json new file mode 100644 index 0000000..28540d9 --- /dev/null +++ b/ts-out-dir/package.json @@ -0,0 +1,124 @@ +{ + "name": "vue3-admin-ts", + "version": "2.0.0-rc2", + "license": "MIT", + "author": "kuanghua", + "packageManager": "pnpm@7.9.0", + "scripts": { + "dev": "vite --mode serve-dev", + "test": "vite --mode serve-test", + "build:test": "vite build --mode build-test", + "build": "vite build --mode build", + "preview:build": "npm run build && vite preview ", + "preview": "vite preview ", + "lint": "eslint --ext .js,.jsx,.vue,.ts,.tsx src --fix", + "prepare": "husky install", + "test:unit": "vue-cli-service test:unit", + "test:watchAll": "vue-cli-service test:unit --watchAll", + "test:cov": "vue-cli-service test:unit --coverage", + "test:majestic": "majestic", + "vitest": "vitest --ui", + "tsc-check": "tsc", + "coverage": "vitest run --coverage" + }, + "dependencies": { + "@element-plus/icons-vue": "^2.0.4", + "axios": "0.21.3", + "echarts": "5.3.2", + "element-plus": "^2.2.9", + "js-error-collection": "^1.0.7", + "mitt": "3.0.0", + "moment-mini": "2.22.1", + "nprogress": "0.2.0", + "path-browserify": "^1.0.1", + "path-to-regexp": "^6.2.1", + "pinia": "^2.0.16", + "pinia-plugin-persistedstate": "2.3.0", + "vue": "^3.2.37", + "vue-clipboard3": "^2.0.0", + "vue-router": "^4.1.5" + }, + "devDependencies": { + "@babel/eslint-parser": "7.16.3", + "@types/echarts": "4.9.7", + "@types/mockjs": "1.0.6", + "@types/node": "^17.0.35", + "@types/path-browserify": "^1.0.0", + "@typescript-eslint/eslint-plugin": "5.30.0", + "@typescript-eslint/parser": "5.30.0", + "@vitejs/plugin-legacy": "^2.2.0", + "@vitejs/plugin-vue": "^2.3.3", + "@vitejs/plugin-vue-jsx": "^2.0.1", + "@vitest/coverage-c8": "^0.22.1", + "@vitest/ui": "^0.22.1", + "@vue/cli-plugin-unit-jest": "4.5.17", + "@vue/cli-service": "4.5.17", + "@vue/test-utils": "^2.0.2", + "@vueuse/core": "^8.7.5", + "eslint": "8.18.0", + "eslint-config-prettier": "8.5.0", + "eslint-define-config": "1.5.1", + "eslint-plugin-eslint-comments": "3.2.0", + "eslint-plugin-import": "2.26.0", + "eslint-plugin-jsonc": "^2.3.0", + "eslint-plugin-markdown": "^3.0.0", + "eslint-plugin-prettier": "4.1.0", + "eslint-plugin-unicorn": "^43.0.2", + "eslint-plugin-vue": "9.1.1", + "husky": "7.0.2", + "jsdom": "16.4.0", + "jsonc-eslint-parser": "^2.1.0", + "majestic": "1.8.1", + "mockjs": "1.1.0", + "prettier": "2.2.1", + "resize-observer-polyfill": "^1.5.1", + "rollup-plugin-visualizer": "^5.8.3", + "sass": "^1.52.1", + "svg-sprite-loader": "6.0.11", + "typescript": "^4.7.2", + "unocss": "^0.33.5", + "unplugin-auto-import": "^0.11.2", + "unplugin-vue-components": "^0.22.8", + "unplugin-vue-define-options": "^0.12.2", + "vite": "^3.1.8", + "vite-plugin-html": "^3.2.0", + "vite-plugin-mkcert": "^1.7.2", + "vite-plugin-mock": "^2.9.6", + "vite-plugin-svg-icons": "^2.0.1", + "vitest": "^0.22.1", + "vue-tsc": "^0.34.16" + }, + "pnpm": { + "peerDependencyRules": { + "ignoreMissing": [ + "html-webpack-plugin", + "vite-plugin-mock", + "unplugin-auto-import", + "unplugin-vue-components", + "vue-template-compiler", + "unocss", + "unplugin", + "vite-plugin-mock", + "@vitejs/plugin-legacy", + "@vitejs/plugin-vue", + "@vitejs/*", + "@babel/*", + "vite", + "vue", + "@unocss/vite", + "rollup", + "vue-jest", + "@babel/*" + ] + } + }, + "browserslist": [ + "> 1%", + "not ie 11", + "not op_mini all" + ], + "engines": { + "node": ">= 16 <18", + "pnpm": ">= 6 <8" + } +} diff --git a/ts-out-dir/src/api/user.d.ts b/ts-out-dir/src/api/user.d.ts new file mode 100644 index 0000000..9018183 --- /dev/null +++ b/ts-out-dir/src/api/user.d.ts @@ -0,0 +1,3 @@ +export declare const userInfoReq: () => Promise; +export declare const loginReq: (subForm: any) => import("axios").AxiosPromise; +export declare const loginOutReq: () => import("axios").AxiosPromise; diff --git a/ts-out-dir/src/api/user.js b/ts-out-dir/src/api/user.js new file mode 100644 index 0000000..e259b7f --- /dev/null +++ b/ts-out-dir/src/api/user.js @@ -0,0 +1,26 @@ +import axiosReq from '@/utils/axios-req'; +export const userInfoReq = () => { + return new Promise((resolve) => { + const reqConfig = { + url: '/basis-func/user/getUserInfo', + params: { plateFormId: 2 }, + method: 'post' + }; + axiosReq(reqConfig).then(({ data }) => { + resolve(data); + }); + }); +}; +export const loginReq = (subForm) => { + return axiosReq({ + url: '/basis-func/user/loginValid', + params: subForm, + method: 'post' + }); +}; +export const loginOutReq = () => { + return axiosReq({ + url: '/basis-func/user/loginValid', + method: 'post' + }); +}; diff --git a/ts-out-dir/src/directives/button-codes.d.ts b/ts-out-dir/src/directives/button-codes.d.ts new file mode 100644 index 0000000..c29f87b --- /dev/null +++ b/ts-out-dir/src/directives/button-codes.d.ts @@ -0,0 +1,5 @@ +declare const _default: { + mounted(el: any, binding: any): void; + componentUpdated(el: any, binding: any): void; +}; +export default _default; diff --git a/ts-out-dir/src/directives/button-codes.js b/ts-out-dir/src/directives/button-codes.js new file mode 100644 index 0000000..ce70b9e --- /dev/null +++ b/ts-out-dir/src/directives/button-codes.js @@ -0,0 +1,22 @@ +import { useBasicStore } from '@/store/basic'; +function checkPermission(el, { value }) { + if (value && Array.isArray(value)) { + if (value.length) { + const permissionRoles = value; + const hasPermission = useBasicStore().buttonCodes?.some((code) => permissionRoles.includes(code)); + if (!hasPermission) + el.parentNode && el.parentNode.removeChild(el); + } + } + else { + throw new Error(`need roles! Like v-permission="['admin','editor']"`); + } +} +export default { + mounted(el, binding) { + checkPermission(el, binding); + }, + componentUpdated(el, binding) { + checkPermission(el, binding); + } +}; diff --git a/ts-out-dir/src/directives/codes-permission.d.ts b/ts-out-dir/src/directives/codes-permission.d.ts new file mode 100644 index 0000000..c29f87b --- /dev/null +++ b/ts-out-dir/src/directives/codes-permission.d.ts @@ -0,0 +1,5 @@ +declare const _default: { + mounted(el: any, binding: any): void; + componentUpdated(el: any, binding: any): void; +}; +export default _default; diff --git a/ts-out-dir/src/directives/codes-permission.js b/ts-out-dir/src/directives/codes-permission.js new file mode 100644 index 0000000..4c4ea18 --- /dev/null +++ b/ts-out-dir/src/directives/codes-permission.js @@ -0,0 +1,22 @@ +import { useBasicStore } from '@/store/basic'; +function checkPermission(el, { value }) { + if (value && Array.isArray(value)) { + if (value.length > 0) { + const permissionRoles = value; + const hasPermission = useBasicStore().codes?.some((role) => permissionRoles.includes(role)); + if (!hasPermission) + el.parentNode && el.parentNode.removeChild(el); + } + } + else { + throw new Error(`need codes! Like v-codes-permission="['admin','editor']"`); + } +} +export default { + mounted(el, binding) { + checkPermission(el, binding); + }, + componentUpdated(el, binding) { + checkPermission(el, binding); + } +}; diff --git a/ts-out-dir/src/directives/index.d.ts b/ts-out-dir/src/directives/index.d.ts new file mode 100644 index 0000000..74987fc --- /dev/null +++ b/ts-out-dir/src/directives/index.d.ts @@ -0,0 +1 @@ +export default function (app: any): void; diff --git a/ts-out-dir/src/directives/index.js b/ts-out-dir/src/directives/index.js new file mode 100644 index 0000000..8f032e2 --- /dev/null +++ b/ts-out-dir/src/directives/index.js @@ -0,0 +1,8 @@ +import buttonCodes from './button-codes'; +import codesPermission from './codes-permission'; +import rolesPermission from './roles-permission'; +export default function (app) { + app.directive('ButtonCodes', buttonCodes); + app.directive('CodesPermission', codesPermission); + app.directive('RolesPermission', rolesPermission); +} diff --git a/ts-out-dir/src/directives/roles-permission.d.ts b/ts-out-dir/src/directives/roles-permission.d.ts new file mode 100644 index 0000000..c29f87b --- /dev/null +++ b/ts-out-dir/src/directives/roles-permission.d.ts @@ -0,0 +1,5 @@ +declare const _default: { + mounted(el: any, binding: any): void; + componentUpdated(el: any, binding: any): void; +}; +export default _default; diff --git a/ts-out-dir/src/directives/roles-permission.js b/ts-out-dir/src/directives/roles-permission.js new file mode 100644 index 0000000..4735d77 --- /dev/null +++ b/ts-out-dir/src/directives/roles-permission.js @@ -0,0 +1,22 @@ +import { useBasicStore } from '@/store/basic'; +function checkPermission(el, { value }) { + if (value && Array.isArray(value)) { + if (value.length > 0) { + const permissionRoles = value; + const hasPermission = useBasicStore().roles?.some((role) => permissionRoles.includes(role)); + if (!hasPermission) + el.parentNode && el.parentNode.removeChild(el); + } + } + else { + throw new Error(`need roles! Like v-roles-permission="['admin','editor']"`); + } +} +export default { + mounted(el, binding) { + checkPermission(el, binding); + }, + componentUpdated(el, binding) { + checkPermission(el, binding); + } +}; diff --git a/ts-out-dir/src/hooks/use-common.d.ts b/ts-out-dir/src/hooks/use-common.d.ts new file mode 100644 index 0000000..1415f2f --- /dev/null +++ b/ts-out-dir/src/hooks/use-common.d.ts @@ -0,0 +1,10 @@ +export declare const sleepTimeout: (time: number) => Promise; +export declare const useCommon: () => { + totalPage: import("vue").Ref; + startEndArr: import("vue").Ref; + searchForm: import("vue").Ref<{}>; + dialogTitle: import("vue").Ref; + detailDialog: import("vue").Ref; +}; +export declare function cloneDeep(value: any): any; +export declare const copyValueToClipboard: (value: any) => void; diff --git a/ts-out-dir/src/hooks/use-common.js b/ts-out-dir/src/hooks/use-common.js new file mode 100644 index 0000000..d57a6a4 --- /dev/null +++ b/ts-out-dir/src/hooks/use-common.js @@ -0,0 +1,31 @@ +import { reactive, toRefs } from 'vue'; +import useClipboard from 'vue-clipboard3'; +import { ElMessage } from 'element-plus'; +export const sleepTimeout = (time) => { + return new Promise((resolve) => { + const timer = setTimeout(() => { + clearTimeout(timer); + resolve(null); + }, time); + }); +}; +export const useCommon = () => { + const state = reactive({ + totalPage: 0, + startEndArr: [], + searchForm: {}, + dialogTitle: '', + detailDialog: false + }); + return { + ...toRefs(state) + }; +}; +export function cloneDeep(value) { + return JSON.parse(JSON.stringify(value)); +} +const { toClipboard } = useClipboard(); +export const copyValueToClipboard = (value) => { + toClipboard(JSON.stringify(value)); + ElMessage.success('复制成功'); +}; diff --git a/ts-out-dir/src/hooks/use-element.d.ts b/ts-out-dir/src/hooks/use-element.d.ts new file mode 100644 index 0000000..8425fea --- /dev/null +++ b/ts-out-dir/src/hooks/use-element.d.ts @@ -0,0 +1,67 @@ +import type { EpPropMergeType } from 'element-plus/es/utils'; +export declare const useElement: () => { + tableData: import("vue").Ref; + rowDeleteIdArr: import("vue").Ref; + loadingId: import("vue").Ref; + formModel: import("vue").Ref<{}>; + subForm: import("vue").Ref<{}>; + searchForm: import("vue").Ref<{}>; + formRules: import("vue").Ref<{ + isNull: (msg: string) => { + required: boolean; + message: string; + trigger: string; + }[]; + isNotNull: (msg: string) => { + required: boolean; + message: string; + trigger: string; + }[]; + upZeroInt: (msg: string) => { + required: boolean; + validator: (rule: any, value: any, callback: any) => void; + trigger: string; + }[]; + zeroInt: (msg: string) => { + required: boolean; + validator: (rule: any, value: any, callback: any) => void; + trigger: string; + }[]; + money: (msg: string) => { + required: boolean; + validator: (rule: any, value: any, callback: any) => void; + trigger: string; + }[]; + phone: (msg: string) => { + required: boolean; + validator: (rule: any, value: any, callback: any) => void; + trigger: string; + }[]; + email: (msg: string) => { + required: boolean; + validator: (rule: any, value: any, callback: any) => void; + trigger: string; + }[]; + }>; + datePickerOptions: import("vue").Ref<{ + disabledDate: (time: any) => boolean; + }>; + startEndArr: import("vue").Ref; + dialogTitle: import("vue").Ref; + detailDialog: import("vue").Ref; + isDialogEdit: import("vue").Ref; + dialogVisible: import("vue").Ref; + tableLoading: import("vue").Ref; + treeData: import("vue").Ref; + defaultProps: import("vue").Ref<{ + children: string; + label: string; + }>; +}; +export declare const elMessage: (message: string, type?: any) => void; +export declare const elLoading: () => void; +export declare const closeLoading: () => void; +export declare const elNotify: (message: string, type: EpPropMergeType | undefined, title: string, duration: number) => void; +export declare const elConfirmNoCancelBtn: (title: string, message: string) => Promise; +export declare const elConfirm: (title: string, message: string) => Promise; +export declare const casHandleChange: () => void; diff --git a/ts-out-dir/src/hooks/use-element.js b/ts-out-dir/src/hooks/use-element.js new file mode 100644 index 0000000..cff3a2f --- /dev/null +++ b/ts-out-dir/src/hooks/use-element.js @@ -0,0 +1,158 @@ +import { reactive, ref, toRefs } from 'vue'; +import { ElLoading, ElMessage, ElMessageBox, ElNotification } from 'element-plus'; +export const useElement = () => { + const upZeroInt = (rule, value, callback, msg) => { + if (!value) { + callback(new Error(`${msg}不能为空`)); + } + if (/^\+?[1-9]\d*$/.test(value)) { + callback(); + } + else { + callback(new Error(`${msg}输入有误`)); + } + }; + const zeroInt = (rule, value, callback, msg) => { + if (!value) { + callback(new Error(`${msg}不能为空`)); + } + if (/^\+?[0-9]\d*$/.test(value)) { + callback(); + } + else { + callback(new Error(`${msg}输入有误`)); + } + }; + const money = (rule, value, callback, msg) => { + if (!value) { + callback(new Error(`${msg}不能为空`)); + } + if (/((^[1-9]\d*)|^0)(\.\d{0,2}){0,1}$/.test(value)) { + callback(); + } + else { + callback(new Error(`${msg}输入有误`)); + } + }; + const phone = (rule, value, callback, msg) => { + if (!value) { + callback(new Error(`${msg}不能为空`)); + } + if (/^0?1[0-9]{10}$/.test(value)) { + callback(); + } + else { + callback(new Error(`${msg}输入有误`)); + } + }; + const email = (rule, value, callback, msg) => { + if (!value) { + callback(new Error(`${msg}不能为空`)); + } + if (/(^([a-zA-Z]|[0-9])(\w|-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4}))$/.test(value)) { + callback(); + } + else { + callback(new Error(`${msg}`)); + } + }; + const state = reactive({ + tableData: [], + rowDeleteIdArr: [], + loadingId: null, + formModel: {}, + subForm: {}, + searchForm: {}, + formRules: { + isNull: (msg) => [{ required: false, message: `${msg}`, trigger: 'blur' }], + isNotNull: (msg) => [{ required: true, message: `${msg}`, trigger: 'blur' }], + upZeroInt: (msg) => [ + { required: true, validator: (rule, value, callback) => upZeroInt(rule, value, callback, msg), trigger: 'blur' } + ], + zeroInt: (msg) => [ + { required: true, validator: (rule, value, callback) => zeroInt(rule, value, callback, msg), trigger: 'blur' } + ], + money: (msg) => [ + { required: true, validator: (rule, value, callback) => money(rule, value, callback, msg), trigger: 'blur' } + ], + phone: (msg) => [ + { required: true, validator: (rule, value, callback) => phone(rule, value, callback, msg), trigger: 'blur' } + ], + email: (msg) => [ + { required: true, validator: (rule, value, callback) => email(rule, value, callback, msg), trigger: 'blur' } + ] + }, + datePickerOptions: { + disabledDate: (time) => { + return time.getTime() < Date.now() - 86400000; + } + }, + startEndArr: [], + dialogTitle: '添加', + detailDialog: false, + isDialogEdit: false, + dialogVisible: false, + tableLoading: false, + treeData: [], + defaultProps: { + children: 'children', + label: 'label' + } + }); + return { + ...toRefs(state) + }; +}; +export const elMessage = (message, type) => { + ElMessage({ + showClose: true, + message: message || '成功', + type: type || 'success', + center: false + }); +}; +let loadingId = null; +export const elLoading = () => { + loadingId = ElLoading.service({ + lock: true, + text: '数据载入中', + spinner: 'el-icon-loading', + background: 'rgba(0, 0, 0, 0.1)' + }); +}; +export const closeLoading = () => { + loadingId.close(); +}; +export const elNotify = (message, type, title, duration) => { + ElNotification({ + title: title || '提示', + type: type || 'success', + message: message || '请传入提示消息', + position: 'top-right', + duration: duration || 2500, + offset: 40 + }); +}; +export const elConfirmNoCancelBtn = (title, message) => { + return ElMessageBox({ + message: message || '你确定要删除吗', + title: title || '确认框', + confirmButtonText: '确定', + cancelButtonText: '取消', + showCancelButton: false, + type: 'warning' + }); +}; +export const elConfirm = (title, message) => { + return ElMessageBox({ + message: message || '你确定要删除吗', + title: title || '确认框', + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }); +}; +const cascaderKey = ref(); +export const casHandleChange = () => { + cascaderKey.value += cascaderKey.value; +}; diff --git a/ts-out-dir/src/hooks/use-error-log.d.ts b/ts-out-dir/src/hooks/use-error-log.d.ts new file mode 100644 index 0000000..195f730 --- /dev/null +++ b/ts-out-dir/src/hooks/use-error-log.d.ts @@ -0,0 +1 @@ +export declare const useErrorLog: () => void; diff --git a/ts-out-dir/src/hooks/use-error-log.js b/ts-out-dir/src/hooks/use-error-log.js new file mode 100644 index 0000000..1095008 --- /dev/null +++ b/ts-out-dir/src/hooks/use-error-log.js @@ -0,0 +1,28 @@ +import { jsErrorCollection } from 'js-error-collection'; +import pack from '../../package.json'; +import settings from '@/settings'; +import bus from '@/utils/bus'; +import axiosReq from '@/utils/axios-req'; +const reqUrl = '/integration-front/errorCollection/insert'; +const errorLogReq = (errLog) => { + axiosReq({ + url: reqUrl, + data: { + pageUrl: window.location.href, + errorLog: errLog, + browserType: navigator.userAgent, + version: pack.version + }, + method: 'post' + }).then(() => { + bus.emit('reloadErrorPage', {}); + }); +}; +export const useErrorLog = () => { + if (settings.errorLog?.includes(import.meta.env.VITE_APP_ENV)) { + jsErrorCollection({ runtimeError: true, rejectError: true, consoleError: true }, (errLog) => { + if (!errLog.includes(reqUrl)) + errorLogReq(errLog); + }); + } +}; diff --git a/ts-out-dir/src/hooks/use-layout.d.ts b/ts-out-dir/src/hooks/use-layout.d.ts new file mode 100644 index 0000000..b5b118b --- /dev/null +++ b/ts-out-dir/src/hooks/use-layout.d.ts @@ -0,0 +1,2 @@ +export declare function isExternal(path: any): boolean; +export declare function resizeHandler(): void; diff --git a/ts-out-dir/src/hooks/use-layout.js b/ts-out-dir/src/hooks/use-layout.js new file mode 100644 index 0000000..f473fb2 --- /dev/null +++ b/ts-out-dir/src/hooks/use-layout.js @@ -0,0 +1,38 @@ +import { onBeforeMount, onBeforeUnmount, onMounted } from 'vue'; +import { useBasicStore } from '@/store/basic'; +export function isExternal(path) { + return /^(https?:|mailto:|tel:)/.test(path); +} +export function resizeHandler() { + const { body } = document; + const WIDTH = 992; + const basicStore = useBasicStore(); + const isMobile = () => { + const rect = body.getBoundingClientRect(); + return rect.width - 1 < WIDTH; + }; + const resizeHandler = () => { + if (!document.hidden) { + if (isMobile()) { + basicStore.setSidebarOpen(false); + } + else { + basicStore.setSidebarOpen(true); + } + } + }; + onBeforeMount(() => { + window.addEventListener('resize', resizeHandler); + }); + onMounted(() => { + if (isMobile()) { + basicStore.setSidebarOpen(false); + } + else { + basicStore.setSidebarOpen(true); + } + }); + onBeforeUnmount(() => { + window.removeEventListener('resize', resizeHandler); + }); +} diff --git a/ts-out-dir/src/hooks/use-permission.d.ts b/ts-out-dir/src/hooks/use-permission.d.ts new file mode 100644 index 0000000..fae8b27 --- /dev/null +++ b/ts-out-dir/src/hooks/use-permission.d.ts @@ -0,0 +1,15 @@ +import type { RouterTypes } from '~/basic'; +import 'nprogress/nprogress.css'; +export declare const filterAsyncRoutesByMenuList: (menuList: any) => RouterTypes; +export declare function filterAsyncRoutesByRoles(routes: any, roles: any): RouterTypes; +export declare function filterAsyncRouterByCodes(codesRoutes: any, codes: any): RouterTypes; +export declare function filterAsyncRouter({ menuList, roles, codes }: { + menuList: any; + roles: any; + codes: any; +}): void; +export declare function resetRouter(): void; +export declare function resetState(): void; +export declare function freshRouter(data: any): void; +export declare const progressStart: () => void; +export declare const progressClose: () => void; diff --git a/ts-out-dir/src/hooks/use-permission.js b/ts-out-dir/src/hooks/use-permission.js new file mode 100644 index 0000000..bf4c572 --- /dev/null +++ b/ts-out-dir/src/hooks/use-permission.js @@ -0,0 +1,146 @@ +import NProgress from 'nprogress'; +import Layout from '@/layout/index.vue'; +import router, { asyncRoutes, constantRoutes, roleCodeRoutes } from '@/router'; +import 'nprogress/nprogress.css'; +import { useBasicStore } from '@/store/basic'; +const buttonCodes = []; +export const filterAsyncRoutesByMenuList = (menuList) => { + const filterRouter = []; + menuList.forEach((route) => { + if (route.category === 3) { + buttonCodes.push(route.code); + } + else { + const itemFromReqRouter = getRouteItemFromReqRouter(route); + if (route.children?.length) { + itemFromReqRouter.children = filterAsyncRoutesByMenuList(route.children); + } + filterRouter.push(itemFromReqRouter); + } + }); + return filterRouter; +}; +const getRouteItemFromReqRouter = (route) => { + const tmp = { meta: { title: '' } }; + const routeKeyArr = ['path', 'component', 'redirect', 'alwaysShow', 'name', 'hidden']; + const metaKeyArr = ['title', 'activeMenu', 'elSvgIcon', 'icon']; + const modules = import.meta.glob('../views/**/**.vue'); + routeKeyArr.forEach((fItem) => { + if (fItem === 'component') { + if (route[fItem] === 'Layout') { + tmp[fItem] = Layout; + } + else { + tmp[fItem] = modules[`../views/${route[fItem]}`]; + } + } + else if (fItem === 'path' && route.parentId === 0) { + tmp[fItem] = `/${route[fItem]}`; + } + else if (['hidden', 'alwaysShow'].includes(fItem)) { + tmp[fItem] = !!route[fItem]; + } + else if (['name'].includes(fItem)) { + tmp[fItem] = route['code']; + } + else if (route[fItem]) { + tmp[fItem] = route[fItem]; + } + }); + metaKeyArr.forEach((fItem) => { + if (route[fItem] && tmp.meta) + tmp.meta[fItem] = route[fItem]; + }); + if (route.extra) { + Object.entries(route.extra.parse(route.extra)).forEach(([key, value]) => { + if (key === 'meta' && tmp.meta) { + tmp.meta[key] = value; + } + else { + tmp[key] = value; + } + }); + } + return tmp; +}; +export function filterAsyncRoutesByRoles(routes, roles) { + const res = []; + routes.forEach((route) => { + const tmp = { ...route }; + if (hasPermission(roles, tmp)) { + if (tmp.children) { + tmp.children = filterAsyncRoutesByRoles(tmp.children, roles); + } + res.push(tmp); + } + }); + return res; +} +function hasPermission(roles, route) { + if (route?.meta?.roles) { + return roles?.some((role) => route.meta.roles.includes(role)); + } + else { + return true; + } +} +export function filterAsyncRouterByCodes(codesRoutes, codes) { + const filterRouter = []; + codesRoutes.forEach((routeItem) => { + if (hasCodePermission(codes, routeItem)) { + if (routeItem.children) + routeItem.children = filterAsyncRouterByCodes(routeItem.children, codes); + filterRouter.push(routeItem); + } + }); + return filterRouter; +} +function hasCodePermission(codes, routeItem) { + if (routeItem.meta?.code) { + return codes.includes(routeItem.meta.code) || routeItem.hidden; + } + else { + return true; + } +} +export function filterAsyncRouter({ menuList, roles, codes }) { + const basicStore = useBasicStore(); + let accessRoutes = []; + const permissionMode = basicStore.settings?.permissionMode; + if (permissionMode === 'rbac') { + accessRoutes = filterAsyncRoutesByMenuList(menuList); + } + else if (permissionMode === 'roles') { + accessRoutes = filterAsyncRoutesByRoles(roleCodeRoutes, roles); + } + else { + accessRoutes = filterAsyncRouterByCodes(roleCodeRoutes, codes); + } + accessRoutes.forEach((route) => router.addRoute(route)); + asyncRoutes.forEach((item) => router.addRoute(item)); + basicStore.setFilterAsyncRoutes(accessRoutes); +} +export function resetRouter() { + const routeNameSet = new Set(); + router.getRoutes().forEach((fItem) => { + if (fItem.name) + routeNameSet.add(fItem.name); + }); + routeNameSet.forEach((setItem) => router.removeRoute(setItem)); + constantRoutes.forEach((feItem) => router.addRoute(feItem)); +} +export function resetState() { + resetRouter(); + useBasicStore().resetState(); +} +export function freshRouter(data) { + resetRouter(); + filterAsyncRouter(data); +} +NProgress.configure({ showSpinner: false }); +export const progressStart = () => { + NProgress.start(); +}; +export const progressClose = () => { + NProgress.done(); +}; diff --git a/ts-out-dir/src/hooks/use-self-router.d.ts b/ts-out-dir/src/hooks/use-self-router.d.ts new file mode 100644 index 0000000..597ef0b --- /dev/null +++ b/ts-out-dir/src/hooks/use-self-router.d.ts @@ -0,0 +1,4 @@ +export declare const getQueryParam: () => any; +export declare const routerPush: (name: any, params: any) => void; +export declare const routerReplace: (name: any, params: any) => void; +export declare const routerBack: () => void; diff --git a/ts-out-dir/src/hooks/use-self-router.js b/ts-out-dir/src/hooks/use-self-router.js new file mode 100644 index 0000000..adc4c4c --- /dev/null +++ b/ts-out-dir/src/hooks/use-self-router.js @@ -0,0 +1,40 @@ +import router from '@/router'; +export const getQueryParam = () => { + const route = router.currentRoute; + if (route.value?.query.params) { + return JSON.parse(route.value.query.params); + } +}; +export const routerPush = (name, params) => { + let data = {}; + if (params) { + data = { + params: JSON.stringify(params) + }; + } + else { + data = {}; + } + router.push({ + name, + query: data + }); +}; +export const routerReplace = (name, params) => { + let data = {}; + if (params) { + data = { + params: JSON.stringify(params) + }; + } + else { + data = {}; + } + router.replace({ + name, + query: data + }); +}; +export const routerBack = () => { + router.go(-1); +}; diff --git a/ts-out-dir/src/hooks/use-table.d.ts b/ts-out-dir/src/hooks/use-table.d.ts new file mode 100644 index 0000000..69ce9c0 --- /dev/null +++ b/ts-out-dir/src/hooks/use-table.d.ts @@ -0,0 +1,15 @@ +export declare const useTable: (searchForm: any, selectPageReq: any) => { + pageNum: import("vue").Ref; + pageSize: import("vue").Ref; + totalPage: import("vue").Ref; + tableListData: import("vue").Ref; + tableListReq: (config: any) => import("axios").AxiosPromise; + dateRangePacking: (timeArr: any) => void; + multipleSelection: import("vue").Ref; + handleSelectionChange: (val: any) => void; + handleCurrentChange: (val: any) => void; + handleSizeChange: (val: any) => void; + resetPageReq: () => void; + multiDelBtnDill: (reqConfig: any) => void; + tableDelDill: (row: any, reqConfig: any) => void; +}; diff --git a/ts-out-dir/src/hooks/use-table.js b/ts-out-dir/src/hooks/use-table.js new file mode 100644 index 0000000..12e188f --- /dev/null +++ b/ts-out-dir/src/hooks/use-table.js @@ -0,0 +1,106 @@ +import { ref } from 'vue'; +import momentMini from 'moment-mini'; +import { elConfirm, elMessage } from './use-element'; +export const useTable = (searchForm, selectPageReq) => { + const tableListData = ref([]); + const totalPage = ref(0); + const pageNum = ref(1); + const pageSize = ref(20); + const tableListReq = (config) => { + const data = Object.assign({ + pageNum: pageNum.value, + pageSize: pageSize.value + }, JSON.parse(JSON.stringify(searchForm))); + Object.keys(data).forEach((fItem) => { + if (['', null, undefined, Number.NaN].includes(data[fItem])) + delete data[fItem]; + if (config.method === 'get') { + if (Array.isArray(data[fItem])) + delete data[fItem]; + if (data[fItem] instanceof Object) + delete data[fItem]; + } + }); + const reqConfig = { + data, + ...config + }; + return axiosReq(reqConfig); + }; + const dateRangePacking = (timeArr) => { + if (timeArr && timeArr.length === 2) { + searchForm.startTime = timeArr[0]; + if (searchForm.endTime) { + searchForm.endTime = momentMini(timeArr[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss'); + } + } + else { + searchForm.startTime = ''; + searchForm.endTime = ''; + } + }; + const handleCurrentChange = (val) => { + pageNum.value = val; + selectPageReq(); + }; + const handleSizeChange = (val) => { + pageSize.value = val; + selectPageReq(); + }; + const resetPageReq = () => { + pageNum.value = 1; + selectPageReq(); + }; + const multipleSelection = ref([]); + const handleSelectionChange = (val) => { + multipleSelection.value = val; + }; + const multiDelBtnDill = (reqConfig) => { + let rowDeleteIdArr = []; + let deleteNameTitle = ''; + rowDeleteIdArr = multipleSelection.value.map((mItem) => { + deleteNameTitle = `${deleteNameTitle + mItem.id},`; + return mItem.id; + }); + if (rowDeleteIdArr.length === 0) { + elMessage('表格选项不能为空', 'warning'); + return; + } + const stringLength = deleteNameTitle.length - 1; + elConfirm('删除', `您确定要删除【${deleteNameTitle.slice(0, stringLength)}】吗`).then(() => { + const data = rowDeleteIdArr; + axiosReq({ + data, + method: 'DELETE', + bfLoading: true, + ...reqConfig + }).then(() => { + elMessage('删除成功'); + resetPageReq(); + }); + }); + }; + const tableDelDill = (row, reqConfig) => { + elConfirm('确定', `您确定要删除【${row.id}】吗?`).then(() => { + axiosReq(reqConfig).then(() => { + resetPageReq(); + elMessage(`【${row.id}】删除成功`); + }); + }); + }; + return { + pageNum, + pageSize, + totalPage, + tableListData, + tableListReq, + dateRangePacking, + multipleSelection, + handleSelectionChange, + handleCurrentChange, + handleSizeChange, + resetPageReq, + multiDelBtnDill, + tableDelDill + }; +}; diff --git a/ts-out-dir/src/lib/element-plus.d.ts b/ts-out-dir/src/lib/element-plus.d.ts new file mode 100644 index 0000000..74987fc --- /dev/null +++ b/ts-out-dir/src/lib/element-plus.d.ts @@ -0,0 +1 @@ +export default function (app: any): void; diff --git a/ts-out-dir/src/lib/element-plus.js b/ts-out-dir/src/lib/element-plus.js new file mode 100644 index 0000000..daa4459 --- /dev/null +++ b/ts-out-dir/src/lib/element-plus.js @@ -0,0 +1,7 @@ +import * as AllComponent from 'element-plus'; +const elementPlusComponentNameArr = ['ElButton']; +export default function (app) { + elementPlusComponentNameArr.forEach((component) => { + app.component(component, AllComponent[component]); + }); +} diff --git a/ts-out-dir/src/main.d.ts b/ts-out-dir/src/main.d.ts new file mode 100644 index 0000000..83aa19c --- /dev/null +++ b/ts-out-dir/src/main.d.ts @@ -0,0 +1,6 @@ +import '@/styles/index.scss'; +import 'virtual:svg-icons-register'; +import './permission'; +import './theme/index.scss'; +import 'uno.css'; +import 'element-plus/dist/index.css'; diff --git a/ts-out-dir/src/main.js b/ts-out-dir/src/main.js new file mode 100644 index 0000000..18a23e2 --- /dev/null +++ b/ts-out-dir/src/main.js @@ -0,0 +1,22 @@ +import { createApp } from 'vue'; +import App from './App.vue'; +const app = createApp(App); +import router from './router'; +import '@/styles/index.scss'; +import 'virtual:svg-icons-register'; +import svgIcon from '@/icons/SvgIcon.vue'; +import directive from '@/directives'; +import './permission'; +import './theme/index.scss'; +import 'uno.css'; +import ElementPlus from 'element-plus'; +import 'element-plus/dist/index.css'; +app.use(ElementPlus); +app.component('SvgIcon', svgIcon); +directive(app); +import { createPinia } from 'pinia'; +import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'; +const pinia = createPinia(); +pinia.use(piniaPluginPersistedstate); +app.use(pinia); +app.use(router).mount('#app'); diff --git a/ts-out-dir/src/permission.d.ts b/ts-out-dir/src/permission.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/ts-out-dir/src/permission.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/ts-out-dir/src/permission.js b/ts-out-dir/src/permission.js new file mode 100644 index 0000000..74e3ffe --- /dev/null +++ b/ts-out-dir/src/permission.js @@ -0,0 +1,44 @@ +import router from '@/router'; +import { filterAsyncRouter, progressClose, progressStart } from '@/hooks/use-permission'; +import { useBasicStore } from '@/store/basic'; +import { userInfoReq } from '@/api/user'; +const whiteList = ['/login', '/404', '/401']; +router.beforeEach(async (to) => { + progressStart(); + const basicStore = useBasicStore(); + if (basicStore.token) { + if (to.path === '/login') { + return '/'; + } + else { + if (!basicStore.getUserInfo) { + try { + const userData = await userInfoReq(); + filterAsyncRouter(userData); + basicStore.setUserInfo(userData); + return { ...to, replace: true }; + } + catch (e) { + console.error(`route permission error${e}`); + basicStore.resetState(); + progressClose(); + return `/login?redirect=${to.path}`; + } + } + else { + return true; + } + } + } + else { + if (!whiteList.includes(to.path)) { + return `/login?redirect=${to.path}`; + } + else { + return true; + } + } +}); +router.afterEach(() => { + progressClose(); +}); diff --git a/ts-out-dir/src/router/index.d.ts b/ts-out-dir/src/router/index.d.ts new file mode 100644 index 0000000..4025bef --- /dev/null +++ b/ts-out-dir/src/router/index.d.ts @@ -0,0 +1,6 @@ +import type { RouterTypes } from '~/basic'; +export declare const constantRoutes: RouterTypes; +export declare const roleCodeRoutes: RouterTypes; +export declare const asyncRoutes: RouterTypes; +declare const router: import("vue-router").Router; +export default router; diff --git a/ts-out-dir/src/router/index.js b/ts-out-dir/src/router/index.js new file mode 100644 index 0000000..cace407 --- /dev/null +++ b/ts-out-dir/src/router/index.js @@ -0,0 +1,203 @@ +import { createRouter, createWebHashHistory } from 'vue-router'; +import Layout from '@/layout/index.vue'; +export const constantRoutes = [ + { + path: '/redirect', + component: Layout, + hidden: true, + children: [ + { + path: '/redirect/:path(.*)', + component: () => import('@/views/redirect') + } + ] + }, + { + path: '/login', + component: () => import('@/views/login/index.vue'), + hidden: true + }, + { + path: '/404', + component: () => import('@/views/error-page/404.vue'), + hidden: true + }, + { + path: '/401', + component: () => import('@/views/error-page/401.vue'), + hidden: true + }, + { + path: '/', + component: Layout, + redirect: '/dashboard', + children: [ + { + path: 'dashboard', + name: 'Dashboard', + component: () => import('@/views/dashboard/index.vue'), + meta: { title: 'Dashboard', elSvgIcon: 'Fold' } + } + ] + }, + { + path: '/setting-switch', + component: Layout, + children: [ + { + path: 'index', + component: () => import('@/views/setting-switch/index.vue'), + name: 'SettingSwitch', + meta: { title: 'Setting Switch', icon: 'example', affix: true } + } + ] + }, + { + path: '/error-collection', + component: Layout, + meta: { title: 'Error Collection', icon: 'eye' }, + alwaysShow: true, + children: [ + { + path: 'error-collection-table-query', + component: () => import('@/views/error-collection/ErrorCollectionTableQuery.vue'), + name: 'ErrorCollectionTableQuery', + meta: { title: 'Index' } + }, + { + path: 'error-log-test', + component: () => import('@/views/error-log/ErrorLogTest.vue'), + name: 'ErrorLogTest', + meta: { title: 'ErrorLog Test' } + } + ] + }, + { + path: '/nested', + component: Layout, + redirect: '/nested/menu1', + name: 'Nested', + meta: { + title: 'Nested', + icon: 'nested' + }, + children: [ + { + path: 'menu1', + component: () => import('@/views/nested/menu1/index.vue'), + name: 'Menu1', + meta: { title: 'Menu1' }, + children: [ + { + path: 'menu1-1', + component: () => import('@/views/nested/menu1/menu1-1/index.vue'), + name: 'Menu1-1', + meta: { title: 'Menu1-1' } + }, + { + path: 'menu1-2', + component: () => import('@/views/nested/menu1/menu1-2/index.vue'), + name: 'Menu1-2', + meta: { title: 'Menu1-2' }, + children: [ + { + path: 'menu1-2-1', + component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1/index.vue'), + name: 'Menu1-2-1', + meta: { title: 'Menu1-2-1' } + }, + { + path: 'menu1-2-2', + component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2/index.vue'), + name: 'Menu1-2-2', + meta: { title: 'Menu1-2-2' } + } + ] + }, + { + path: 'menu1-3', + component: () => import('@/views/nested/menu1/menu1-3/index.vue'), + name: 'Menu1-3', + meta: { title: 'Menu1-3' } + } + ] + }, + { + path: 'menu2', + component: () => import('@/views/nested/menu2/index.vue'), + name: 'Menu2', + meta: { title: 'menu2' } + } + ] + }, + { + path: '/external-link', + component: Layout, + children: [ + { + component: () => { }, + path: 'https://github.com/jzfai/vue3-admin-ts.git', + meta: { title: 'External Link', icon: 'link' } + } + ] + } +]; +export const roleCodeRoutes = [ + { + path: '/roles-codes', + component: Layout, + redirect: '/roles-codes/page', + alwaysShow: true, + name: 'Permission', + meta: { + title: 'Permission', + icon: 'lock', + roles: ['admin', 'editor'] + }, + children: [ + { + path: 'index', + component: () => import('@/views/roles-codes/index.vue'), + name: 'RolesCodes', + meta: { + title: 'index' + } + }, + { + path: 'roleIndex', + component: () => import('@/views/roles-codes/role-index.vue'), + name: 'RoleIndex', + meta: { + title: 'Role Index', + roles: ['admin'] + } + }, + { + path: 'code-index', + component: () => import('@/views/roles-codes/code-index.vue'), + name: 'CodeIndex', + meta: { + title: 'Code Index', + code: 16 + } + }, + { + path: 'button-permission', + component: () => import('@/views/roles-codes/button-permission.vue'), + name: 'ButtonPermission', + meta: { + title: 'Button Permission' + } + } + ] + } +]; +export const asyncRoutes = [ + { path: '/:catchAll(.*)', name: 'CatchAll', redirect: '/404', hidden: true } +]; +const router = createRouter({ + history: createWebHashHistory(), + scrollBehavior: () => ({ top: 0 }), + routes: constantRoutes +}); +export default router; diff --git a/ts-out-dir/src/settings.d.ts b/ts-out-dir/src/settings.d.ts new file mode 100644 index 0000000..3884993 --- /dev/null +++ b/ts-out-dir/src/settings.d.ts @@ -0,0 +1,3 @@ +import type { SettingsConfig } from '~/basic'; +declare const settings: SettingsConfig; +export default settings; diff --git a/ts-out-dir/src/settings.js b/ts-out-dir/src/settings.js new file mode 100644 index 0000000..fc38610 --- /dev/null +++ b/ts-out-dir/src/settings.js @@ -0,0 +1,21 @@ +const settings = { + title: 'Vue3 Admin Template', + sidebarLogo: true, + showNavbarTitle: false, + ShowDropDown: true, + showHamburger: true, + showLeftMenu: true, + showTagsView: true, + tagsViewNum: 6, + showTopNavbar: true, + mainNeedAnimation: true, + isNeedNprogress: true, + isNeedLogin: true, + permissionMode: 'roles', + openProdMock: true, + errorLog: ['prod'], + delWindowHeight: '210px', + tmpToken: 'tmp_token', + viteBasePath: './' +}; +export default settings; diff --git a/ts-out-dir/src/store/basic.d.ts b/ts-out-dir/src/store/basic.d.ts new file mode 100644 index 0000000..aa9e833 --- /dev/null +++ b/ts-out-dir/src/store/basic.d.ts @@ -0,0 +1,41 @@ +import type { RouterTypes } from '~/basic'; +export declare const useBasicStore: import("pinia").StoreDefinition<"basic", { + token: string; + getUserInfo: boolean; + userInfo: { + username: string; + avatar: string; + }; + allRoutes: RouterTypes; + buttonCodes: never[]; + filterAsyncRoutes: never[]; + roles: string[]; + codes: number[]; + cachedViews: string[]; + cachedViewsDeep: string[]; + sidebar: { + opened: boolean; + }; + axiosPromiseArr: ObjKeys[]; + settings: import("~/basic").SettingsConfig; +}, {}, { + setToken(data: any): void; + setFilterAsyncRoutes(routes: any): void; + setUserInfo({ userInfo, roles, codes }: { + userInfo: any; + roles: any; + codes: any; + }): void; + resetState(): void; + resetStateAndToLogin(): void; + M_settings(data: any): void; + setSidebarOpen(data: any): void; + setToggleSideBar(): void; + addCachedView(view: any): void; + delCachedView(view: any): void; + M_RESET_CACHED_VIEW(): void; + addCachedViewDeep(view: any): void; + setCacheViewDeep(view: any): void; + M_RESET_CACHED_VIEW_DEEP(): void; + A_sidebar_opened(data: any): void; +}>; diff --git a/ts-out-dir/src/store/basic.js b/ts-out-dir/src/store/basic.js new file mode 100644 index 0000000..20bc683 --- /dev/null +++ b/ts-out-dir/src/store/basic.js @@ -0,0 +1,124 @@ +import { nextTick } from 'vue'; +import { defineStore } from 'pinia'; +import defaultSettings from '@/settings'; +import router, { constantRoutes } from '@/router'; +export const useBasicStore = defineStore('basic', { + state: () => { + return { + token: '', + getUserInfo: false, + userInfo: { + username: '', + avatar: '' + }, + allRoutes: [], + buttonCodes: [], + filterAsyncRoutes: [], + roles: [], + codes: [], + cachedViews: [], + cachedViewsDeep: [], + sidebar: { opened: true }, + axiosPromiseArr: [], + settings: defaultSettings + }; + }, + persist: { + storage: localStorage, + paths: ['token'] + }, + actions: { + setToken(data) { + this.token = data; + }, + setFilterAsyncRoutes(routes) { + this.$patch((state) => { + state.filterAsyncRoutes = routes; + state.allRoutes = constantRoutes.concat(routes); + }); + }, + setUserInfo({ userInfo, roles, codes }) { + const { username, avatar } = userInfo; + this.$patch((state) => { + state.roles = roles; + state.codes = codes; + state.getUserInfo = true; + state.userInfo.username = username; + state.userInfo.avatar = avatar; + }); + }, + resetState() { + this.$patch((state) => { + state.token = ''; + state.roles = []; + state.codes = []; + state.allRoutes = []; + state.buttonCodes = []; + state.filterAsyncRoutes = []; + state.userInfo.username = ''; + state.userInfo.avatar = ''; + }); + this.getUserInfo = false; + }, + resetStateAndToLogin() { + this.resetState(); + nextTick(() => { + router.push({ path: '/login' }); + }); + }, + M_settings(data) { + this.$patch((state) => { + state.settings = { ...state.settings, ...data }; + }); + }, + setSidebarOpen(data) { + this.$patch((state) => { + state.sidebar.opened = data; + }); + }, + setToggleSideBar() { + this.$patch((state) => { + state.sidebar.opened = !state.sidebar.opened; + }); + }, + addCachedView(view) { + this.$patch((state) => { + if (state.cachedViews.includes(view)) + return; + state.cachedViews.push(view); + }); + }, + delCachedView(view) { + this.$patch((state) => { + const index = state.cachedViews.indexOf(view); + index > -1 && state.cachedViews.splice(index, 1); + }); + }, + M_RESET_CACHED_VIEW() { + this.$patch((state) => { + state.cachedViews = []; + }); + }, + addCachedViewDeep(view) { + this.$patch((state) => { + if (state.cachedViewsDeep.includes(view)) + return; + state.cachedViewsDeep.push(view); + }); + }, + setCacheViewDeep(view) { + this.$patch((state) => { + const index = state.cachedViewsDeep.indexOf(view); + index > -1 && state.cachedViewsDeep.splice(index, 1); + }); + }, + M_RESET_CACHED_VIEW_DEEP() { + this.$patch((state) => { + state.cachedViewsDeep = []; + }); + }, + A_sidebar_opened(data) { + this.setSidebarOpen(data); + } + } +}); diff --git a/ts-out-dir/src/store/tagsView.d.ts b/ts-out-dir/src/store/tagsView.d.ts new file mode 100644 index 0000000..f20ee72 --- /dev/null +++ b/ts-out-dir/src/store/tagsView.d.ts @@ -0,0 +1,8 @@ +export declare const useTagsViewStore: import("pinia").StoreDefinition<"tagsView", { + visitedViews: never[]; +}, {}, { + addVisitedView(view: any): void; + delVisitedView(view: any): Promise; + delOthersVisitedViews(view: any): Promise; + delAllVisitedViews(): Promise; +}>; diff --git a/ts-out-dir/src/store/tagsView.js b/ts-out-dir/src/store/tagsView.js new file mode 100644 index 0000000..2e13710 --- /dev/null +++ b/ts-out-dir/src/store/tagsView.js @@ -0,0 +1,59 @@ +import { defineStore } from 'pinia'; +import setting from '@/settings'; +export const useTagsViewStore = defineStore('tagsView', { + state: () => { + return { + visitedViews: [] + }; + }, + actions: { + addVisitedView(view) { + this.$patch((state) => { + if (state.visitedViews.some((v) => v.path === view.path)) + return; + if (state.visitedViews.length >= setting.tagsViewNum) { + state.visitedViews.pop(); + state.visitedViews.push(Object.assign({}, view, { + title: view.meta.title || 'no-name' + })); + } + else { + state.visitedViews.push(Object.assign({}, view, { + title: view.meta.title || 'no-name' + })); + } + }); + }, + delVisitedView(view) { + return new Promise((resolve) => { + this.$patch((state) => { + for (const [i, v] of state.visitedViews.entries()) { + if (v.path === view.path) { + state.visitedViews.splice(i, 1); + break; + } + } + resolve([...state.visitedViews]); + }); + }); + }, + delOthersVisitedViews(view) { + return new Promise((resolve) => { + this.$patch((state) => { + state.visitedViews = state.visitedViews.filter((v) => { + return v.meta.affix || v.path === view.path; + }); + resolve([...state.visitedViews]); + }); + }); + }, + delAllVisitedViews() { + return new Promise((resolve) => { + this.$patch((state) => { + state.visitedViews = state.visitedViews.filter((tag) => tag.meta?.affix); + resolve([...state.visitedViews]); + }); + }); + } + } +}); diff --git a/ts-out-dir/src/utils/axios-req.d.ts b/ts-out-dir/src/utils/axios-req.d.ts new file mode 100644 index 0000000..054391c --- /dev/null +++ b/ts-out-dir/src/utils/axios-req.d.ts @@ -0,0 +1 @@ +export default function axiosReq(config: any): import("axios").AxiosPromise; diff --git a/ts-out-dir/src/utils/axios-req.js b/ts-out-dir/src/utils/axios-req.js new file mode 100644 index 0000000..0a91c23 --- /dev/null +++ b/ts-out-dir/src/utils/axios-req.js @@ -0,0 +1,52 @@ +import axios from 'axios'; +import { ElMessage, ElMessageBox } from 'element-plus'; +import { useBasicStore } from '@/store/basic'; +const service = axios.create(); +service.interceptors.request.use((req) => { + const { token, axiosPromiseArr } = useBasicStore(); + req.cancelToken = new axios.CancelToken((cancel) => { + axiosPromiseArr.push({ + url: req.url, + cancel + }); + }); + req.headers['AUTHORIZE_TOKEN'] = token; + if ('get'.includes(req.method?.toLowerCase())) + req.params = req.data; + return req; +}, (err) => { + Promise.reject(err); +}); +service.interceptors.response.use((res) => { + const { code } = res.data; + const successCode = '0,200,20000'; + const noAuthCode = '401,403'; + if (successCode.includes(code)) { + return res.data; + } + else { + if (noAuthCode.includes(code) && !location.href.includes('/login')) { + ElMessageBox.confirm('请重新登录', { + confirmButtonText: '重新登录', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + useBasicStore().resetStateAndToLogin(); + }); + } + return Promise.reject(res.data); + } +}, (err) => { + ElMessage.error({ + message: err, + duration: 2 * 1000 + }); + return Promise.reject(err); +}); +export default function axiosReq(config) { + return service({ + baseURL: import.meta.env.VITE_APP_BASE_URL, + timeout: 8000, + ...config + }); +} diff --git a/ts-out-dir/src/utils/bus.d.ts b/ts-out-dir/src/utils/bus.d.ts new file mode 100644 index 0000000..f36c03c --- /dev/null +++ b/ts-out-dir/src/utils/bus.d.ts @@ -0,0 +1,2 @@ +declare const _default: import("mitt").Emitter>; +export default _default; diff --git a/ts-out-dir/src/utils/bus.js b/ts-out-dir/src/utils/bus.js new file mode 100644 index 0000000..4f1430d --- /dev/null +++ b/ts-out-dir/src/utils/bus.js @@ -0,0 +1,2 @@ +import mitt from 'mitt'; +export default mitt(); diff --git a/ts-out-dir/src/utils/common-util.d.ts b/ts-out-dir/src/utils/common-util.d.ts new file mode 100644 index 0000000..e6cc1fe --- /dev/null +++ b/ts-out-dir/src/utils/common-util.d.ts @@ -0,0 +1,16 @@ +declare const _default: { + getWeek(): string; + mobilePhone(str: any): boolean; + toSplitNumFor(num: any, numToSpace: any): any; + bankCardNo(str: any): boolean; + regEmail(str: any): boolean; + idCardNumber(str: any): boolean; + deleteArrItem(arr: any, arrItem: any): void; + arrToRepeat(arr: any): any; + deRepeatArr(seriesArr: any): unknown[]; + byArrObjDeleteArrObj2(arrObj: any, arrObj2: any, objKey: any): any; + deleteArrObjByKey(arrObj: any, objKey: any, value: any): any; + findArrObjByKey(arrObj: any, objKey: any, value: any): any; + byArrObjFindArrObj2(arrObj: any, arrObj2: any, objKey: any): any[]; +}; +export default _default; diff --git a/ts-out-dir/src/utils/common-util.js b/ts-out-dir/src/utils/common-util.js new file mode 100644 index 0000000..5796341 --- /dev/null +++ b/ts-out-dir/src/utils/common-util.js @@ -0,0 +1,66 @@ +export default { + getWeek() { + return `星期${'日一二三四五六'.charAt(new Date().getDay())}`; + }, + mobilePhone(str) { + const reg = /^0?1[0-9]{10}$/; + return reg.test(str); + }, + toSplitNumFor(num, numToSpace) { + return num.replace(/(.{4})/g, '$1 '); + }, + bankCardNo(str) { + const reg = /^\d{15,20}$/; + return reg.test(str); + }, + regEmail(str) { + const reg = /^([a-zA-Z]|[0-9])(\w|-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/; + return reg.test(str); + }, + idCardNumber(str) { + const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/; + return reg.test(str); + }, + deleteArrItem(arr, arrItem) { + arr.splice(arr.indexOf(arrItem), 1); + }, + arrToRepeat(arr) { + return arr.filter((ele, index, thisArr) => { + return thisArr.indexOf(ele) === index; + }); + }, + deRepeatArr(seriesArr) { + return [...new Set(seriesArr)]; + }, + byArrObjDeleteArrObj2(arrObj, arrObj2, objKey) { + arrObj + .map((value) => { + return value[objKey]; + }) + .forEach((value2) => { + arrObj2.splice(arrObj2.findIndex((item) => item[objKey] === value2), 1); + }); + return arrObj2; + }, + deleteArrObjByKey(arrObj, objKey, value) { + arrObj.splice(arrObj.findIndex((item) => item[objKey] === value), 1); + return arrObj; + }, + findArrObjByKey(arrObj, objKey, value) { + return arrObj[arrObj.findIndex((item) => item[objKey] == value)]; + }, + byArrObjFindArrObj2(arrObj, arrObj2, objKey) { + const arrObj3 = []; + arrObj + .map((value) => { + return value[objKey]; + }) + .forEach((value2) => { + const arrIndex = arrObj2.findIndex((item) => item[objKey] === value2); + if (arrIndex !== -1) { + arrObj3.push(arrObj2[arrIndex]); + } + }); + return arrObj3; + } +}; diff --git a/ts-out-dir/src/views/redirect/index.d.ts b/ts-out-dir/src/views/redirect/index.d.ts new file mode 100644 index 0000000..43bf108 --- /dev/null +++ b/ts-out-dir/src/views/redirect/index.d.ts @@ -0,0 +1,2 @@ +declare const _default: import("vue").DefineComponent<{}, () => JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly>, {}>; +export default _default; diff --git a/ts-out-dir/src/views/redirect/index.jsx b/ts-out-dir/src/views/redirect/index.jsx new file mode 100644 index 0000000..d555a02 --- /dev/null +++ b/ts-out-dir/src/views/redirect/index.jsx @@ -0,0 +1,13 @@ +import { defineComponent } from 'vue'; +export default defineComponent({ + setup() { + const route = useRoute(); + const router = useRouter(); + onBeforeMount(() => { + const { params, query } = route; + const { path } = params; + router.replace({ path: `/${path}`, query }); + }); + return () =>
; + } +}); diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..85bbac9 --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,50 @@ +{ + //设置files为空,则不会自动扫描默认目录,也就是只会扫描include配置的目录 + "files": [], + "compilerOptions": { + "target": "esnext", + "module": "esnext", + //启用所有严格类型检查选项。 + //启用 --strict相当于启用 --noImplicitAny, --noImplicitThis, --alwaysStrict, --strictNullChecks和 --strictFunctionTypes和--strictPropertyInitialization。 + "strict": true, + // 允许编译器编译JS,JSX文件 + "allowJs": false, + // 允许在JS文件中报错,通常与allowJS一起使用 + "checkJs": false, + // 允许使用jsx + "jsx": "preserve", + "declaration": true, + //移除注解 + "removeComments": true, + //不可以忽略any + "noImplicitAny": false, + //关闭 this 类型注解提示 + "noImplicitThis": true, + //null/undefined不能作为其他类型的子类型: + //let a: number = null; //这里会报错. + "strictNullChecks": true, + //生成枚举的映射代码 + "preserveConstEnums": true, + //根目录 + //输出目录 + "outDir": "./ts-out-dir", + //是否输出src2.js.map文件 + "sourceMap": false, + //变量定义了但是未使用 + "noUnusedLocals": false, + //是否允许把json文件当做模块进行解析 + "resolveJsonModule": true, + //和noUnusedLocals一样,针对func + "noUnusedParameters": false, + // 模块解析策略,ts默认用node的解析策略,即相对的方式导入 + "moduleResolution": "node", + //允许export=导出,由import from 导入 + "esModuleInterop": true, + //忽略所有的声明文件( *.d.ts)的类型检查。 + "skipLibCheck": true, + "baseUrl": ".", + //指定默认读取的目录 + //"typeRoots": ["./node_modules/@types/", "./types"], + "lib": ["ES2018", "DOM"] + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..91851f8 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "paths": { + "@/*": ["src/*"], + "~/*": ["typings/*"] + } + }, + "include": ["src", "typings"], + "exclude": ["node_modules", "**/dist"] +} diff --git a/typings/auto-imports.d.ts b/typings/auto-imports.d.ts new file mode 100644 index 0000000..53b92fb --- /dev/null +++ b/typings/auto-imports.d.ts @@ -0,0 +1,116 @@ +// Generated by 'unplugin-auto-import' +export {} +declare global { + const EffectScope: typeof import('vue')['EffectScope'] + const axiosReq: typeof import('../src/utils/axios-req')['default'] + const bus: typeof import('../src/utils/bus')['default'] + const buttonCodes: typeof import('../src/directives/button-codes')['default'] + const casHandleChange: typeof import('../src/hooks/use-element')['casHandleChange'] + const clickoutside: typeof import('../src/directives/example/clickoutside.js')['default'] + const cloneDeep: typeof import('../src/hooks/use-common')['cloneDeep'] + const closeElLoading: typeof import('../src/hooks/use-element')['closeElLoading'] + const codesPermission: typeof import('../src/directives/codes-permission')['default'] + const commonUtil: typeof import('../src/utils/common-util')['default'] + const computed: typeof import('vue')['computed'] + const copy: typeof import('../src/directives/example/copy.js')['default'] + const copyValueToClipboard: typeof import('../src/hooks/use-common')['copyValueToClipboard'] + const createApp: typeof import('vue')['createApp'] + const customRef: typeof import('vue')['customRef'] + const debounce: typeof import('../src/directives/example/debounce.js')['default'] + const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] + const defineComponent: typeof import('vue')['defineComponent'] + const directives: typeof import('../src/directives/index')['default'] + const effectScope: typeof import('vue')['effectScope'] + const elConfirm: typeof import('../src/hooks/use-element')['elConfirm'] + const elConfirmNoCancelBtn: typeof import('../src/hooks/use-element')['elConfirmNoCancelBtn'] + const elLoading: typeof import('../src/hooks/use-element')['elLoading'] + const elMessage: typeof import('../src/hooks/use-element')['elMessage'] + const elNotify: typeof import('../src/hooks/use-element')['elNotify'] + const filterAsyncRouter: typeof import('../src/hooks/use-permission')['filterAsyncRouter'] + const filterAsyncRouterByCodes: typeof import('../src/hooks/use-permission')['filterAsyncRouterByCodes'] + const filterAsyncRoutesByMenuList: typeof import('../src/hooks/use-permission')['filterAsyncRoutesByMenuList'] + const filterAsyncRoutesByRoles: typeof import('../src/hooks/use-permission')['filterAsyncRoutesByRoles'] + const freshRouter: typeof import('../src/hooks/use-permission')['freshRouter'] + const getCurrentInstance: typeof import('vue')['getCurrentInstance'] + const getCurrentScope: typeof import('vue')['getCurrentScope'] + const getLangInstance: typeof import('../src/hooks/use-common')['getLangInstance'] + const getQueryParam: typeof import('../src/hooks/use-self-router')['getQueryParam'] + const h: typeof import('vue')['h'] + const inject: typeof import('vue')['inject'] + const isExternal: typeof import('../src/hooks/use-layout')['isExternal'] + const isProxy: typeof import('vue')['isProxy'] + const isReactive: typeof import('vue')['isReactive'] + const isReadonly: typeof import('vue')['isReadonly'] + const isRef: typeof import('vue')['isRef'] + const lang: typeof import('../src/directives/lang')['default'] + const langTitle: typeof import('../src/hooks/use-common')['langTitle'] + const loginOutReq: typeof import('../src/api/user')['loginOutReq'] + const loginReq: typeof import('../src/api/user')['loginReq'] + const longpress: typeof import('../src/directives/example/longpress.js')['default'] + const markRaw: typeof import('vue')['markRaw'] + const mockAxiosReq: typeof import('../src/utils/mock-axios-req')['default'] + const nextTick: typeof import('vue')['nextTick'] + const onActivated: typeof import('vue')['onActivated'] + const onBeforeMount: typeof import('vue')['onBeforeMount'] + const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave'] + const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate'] + const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'] + const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] + const onDeactivated: typeof import('vue')['onDeactivated'] + const onErrorCaptured: typeof import('vue')['onErrorCaptured'] + const onMounted: typeof import('vue')['onMounted'] + const onRenderTracked: typeof import('vue')['onRenderTracked'] + const onRenderTriggered: typeof import('vue')['onRenderTriggered'] + const onScopeDispose: typeof import('vue')['onScopeDispose'] + const onServerPrefetch: typeof import('vue')['onServerPrefetch'] + const onUnmounted: typeof import('vue')['onUnmounted'] + const onUpdated: typeof import('vue')['onUpdated'] + const progressClose: typeof import('../src/hooks/use-permission')['progressClose'] + const progressStart: typeof import('../src/hooks/use-permission')['progressStart'] + const provide: typeof import('vue')['provide'] + const reactive: typeof import('vue')['reactive'] + const readonly: typeof import('vue')['readonly'] + const ref: typeof import('vue')['ref'] + const resetRouter: typeof import('../src/hooks/use-permission')['resetRouter'] + const resetState: typeof import('../src/hooks/use-permission')['resetState'] + const resizeHandler: typeof import('../src/hooks/use-layout')['resizeHandler'] + const resolveComponent: typeof import('vue')['resolveComponent'] + const resolveDirective: typeof import('vue')['resolveDirective'] + const rolesPermission: typeof import('../src/directives/roles-permission')['default'] + const routeInfo: typeof import('../src/hooks/use-self-router')['routeInfo'] + const routerBack: typeof import('../src/hooks/use-self-router')['routerBack'] + const routerPush: typeof import('../src/hooks/use-self-router')['routerPush'] + const routerReplace: typeof import('../src/hooks/use-self-router')['routerReplace'] + const searchUser: typeof import('../src/api/remote-search')['searchUser'] + const shallowReactive: typeof import('vue')['shallowReactive'] + const shallowReadonly: typeof import('vue')['shallowReadonly'] + const shallowRef: typeof import('vue')['shallowRef'] + const sleepTimeout: typeof import('../src/hooks/use-common')['sleepTimeout'] + const storeToRefs: typeof import('pinia/dist/pinia')['storeToRefs'] + const toRaw: typeof import('vue')['toRaw'] + const toRef: typeof import('vue')['toRef'] + const toRefs: typeof import('vue')['toRefs'] + const transactionList: typeof import('../src/api/remote-search')['transactionList'] + const triggerRef: typeof import('vue')['triggerRef'] + const unref: typeof import('vue')['unref'] + const useAttrs: typeof import('vue')['useAttrs'] + const useBasicStore: typeof import('../src/store/basic')['useBasicStore'] + const useConfigStore: typeof import('../src/store/config')['useConfigStore'] + const useCssModule: typeof import('vue')['useCssModule'] + const useCssVars: typeof import('vue')['useCssVars'] + const useElement: typeof import('../src/hooks/use-element')['useElement'] + const useErrorLog: typeof import('../src/hooks/use-error-log')['useErrorLog'] + const useLink: typeof import('vue-router')['useLink'] + const useRoute: typeof import('vue-router')['useRoute'] + const useRouter: typeof import('vue-router')['useRouter'] + const useSlots: typeof import('vue')['useSlots'] + const useTable: typeof import('../src/hooks/use-table')['useTable'] + const useTagsViewStore: typeof import('../src/store/tags-view')['useTagsViewStore'] + const userInfoReq: typeof import('../src/api/user')['userInfoReq'] + const watch: typeof import('vue')['watch'] + const watchEffect: typeof import('vue')['watchEffect'] + const watchPostEffect: typeof import('vue')['watchPostEffect'] + const watchSyncEffect: typeof import('vue')['watchSyncEffect'] + const watermark: typeof import('../src/directives/example/watermark.js')['default'] + const waves: typeof import('../src/directives/example/waves.js')['default'] +} diff --git a/typings/basic.d.ts b/typings/basic.d.ts new file mode 100644 index 0000000..d322486 --- /dev/null +++ b/typings/basic.d.ts @@ -0,0 +1,66 @@ +/* + * 声明.d.ts文件规范 + * 导出的类型以大写开头 + * 对象:config + * 数组:options + * 枚举:emu + * 函数:Fn + * 属性:props + * 实例:instance + * */ + +/*router*/ +import type { RouteRecordRaw } from 'vue-router' +export interface rawConfig { + hidden?: boolean + alwaysShow?: boolean + code?: number + name?: string + fullPath?: string + path?: string + meta?: { + title: string + icon?: string + affix?: boolean + activeMenu?: string + breadcrumb?: boolean + roles?: Array + elSvgIcon?: string + code?: number + cachePage?: boolean + leaveRmCachePage?: boolean + closeTabRmCache?: boolean + } + children?: RouterOptions + redirect?: string +} +export type RouteRawConfig = RouteRecordRaw & rawConfig +export type RouterTypes = Array + +/*settings*/ +export interface SettingsConfig { + title: string + sidebarLogo: boolean + showLeftMenu: boolean + ShowDropDown: boolean + showHamburger: boolean + isNeedLogin: boolean + isNeedNprogress: boolean + showTagsView: boolean + tagsViewNum: number + openProdMock: boolean + errorLog: string | Array + permissionMode: string + delWindowHeight: string + tmpToken: string + showNavbarTitle: boolean + showTopNavbar: boolean + mainNeedAnimation: boolean + viteBasePath: string + defaultLanguage: string + defaultSize: string + defaultTheme: string + plateFormId: number +} + +export {} diff --git a/typings/components.d.ts b/typings/components.d.ts new file mode 100644 index 0000000..c838304 --- /dev/null +++ b/typings/components.d.ts @@ -0,0 +1,16 @@ +// generated by unplugin-vue-components +// We suggest you to commit this file into source control +// Read more: https://github.com/vuejs/core/pull/3399 +import '@vue/runtime-core' + +export {} + +declare module '@vue/runtime-core' { + export interface GlobalComponents { + ElSvgIcon: typeof import('./../src/components/ElSvgIcon.vue')['default'] + RouterLink: typeof import('vue-router')['RouterLink'] + RouterView: typeof import('vue-router')['RouterView'] + SvgIcon: typeof import('./../src/icons/SvgIcon.vue')['default'] + TestUnit: typeof import('./../src/components/TestUnit.vue')['default'] + } +} diff --git a/typings/env.d.ts b/typings/env.d.ts new file mode 100644 index 0000000..e4d89b4 --- /dev/null +++ b/typings/env.d.ts @@ -0,0 +1,12 @@ +declare global { + interface ImportMetaEnv { + readonly VITE_APP_BASE_URL: string + readonly VITE_APP_IMAGE_URL: string + readonly VITE_APP_ENV: string + // 更多环境变量... + } + interface ImportMeta { + readonly env: ImportMetaEnv + } +} +export {} diff --git a/typings/global.d.ts b/typings/global.d.ts new file mode 100644 index 0000000..3fe6871 --- /dev/null +++ b/typings/global.d.ts @@ -0,0 +1,10 @@ +import type { defineOptions as _defineOptions } from 'unplugin-vue-define-options/macros.d.ts' +declare global { + interface ObjKeys { + [propName: string]: any + } + const GLOBAL_VAR: String + const defineOptions: typeof _defineOptions + const $ref: any +} +export {} diff --git a/typings/shims-vue.d.ts b/typings/shims-vue.d.ts new file mode 100644 index 0000000..683baad --- /dev/null +++ b/typings/shims-vue.d.ts @@ -0,0 +1,6 @@ +/*fix the import warning issue of vue file*/ +declare module '*.vue' { + import { DefineComponent } from 'vue' + const component: DefineComponent<{}, {}, any> + export default component +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..5b8a4c9 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,123 @@ +import { resolve } from 'path' +import { defineConfig, loadEnv } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueJsx from '@vitejs/plugin-vue-jsx' +import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' +import { viteMockServe } from 'vite-plugin-mock' +import Components from 'unplugin-vue-components/vite' +import UnoCSS from 'unocss/vite' +import { presetAttributify, presetIcons, presetUno } from 'unocss' +import mkcert from 'vite-plugin-mkcert' +import AutoImport from 'unplugin-auto-import/vite' +import setting from './src/settings' +const prodMock = setting.openProdMock +import vitePluginSetupExtend from './src/plugins/vite-plugin-setup-extend' +// import { visualizer } from 'rollup-plugin-visualizer' +const pathSrc = resolve(__dirname, 'src') +export default defineConfig(({ command, mode }) => { + //const env = loadEnv(mode, process.cwd(), '') //获取环境变量 + return { + base: setting.viteBasePath, + define: { + //define global var + GLOBAL_STRING: JSON.stringify('i am global var from vite.config.js define'), + GLOBAL_VAR: { test: 'i am global var from vite.config.js define' } + }, + clearScreen: false, //设为 false 可以避免 Vite 清屏而错过在终端中打印某些关键信息 + server: { + hmr: { overlay: false }, //设置 server.hmr.overlay 为 false 可以禁用开发服务器错误的屏蔽。方便错误查看 + port: 5005, // 类型: number 指定服务器端口; + open: false, // 类型: boolean | string在服务器启动时自动在浏览器中打开应用程序; + host: true, + https: false + }, + preview: { + port: 5006, + host: true, + strictPort: true + }, + plugins: [ + vue({ reactivityTransform: true }), + vueJsx(), + UnoCSS({ + presets: [presetUno(), presetAttributify(), presetIcons()] + }), + mkcert(), + //compatible with old browsers + // legacy({ + // targets: ['chrome 52'], + // additionalLegacyPolyfills: ['regenerator-runtime/runtime'] + // }), + createSvgIconsPlugin({ + iconDirs: [resolve(process.cwd(), 'src/icons/common'), resolve(process.cwd(), 'src/icons/nav-bar')], + symbolId: 'icon-[dir]-[name]' + }), + //https://github.com/anncwb/vite-plugin-mock/blob/HEAD/README.zh_CN.md + viteMockServe({ + supportTs: true, + mockPath: 'mock', + localEnabled: command === 'serve', + prodEnabled: prodMock, + injectCode: ` + import { setupProdMockServer } from '../mock-prod-server'; + setupProdMockServer(); + `, + logger: true + }), + // VueSetupExtend(),using DefineOptions instant of it + //https://github.com/antfu/unplugin-auto-import/blob/HEAD/src/types.ts + Components({ + dirs: ['src/components', 'src/icons'], + extensions: ['vue'], + deep: true, + dts: './typings/components.d.ts' + }), + AutoImport({ + imports: [ + 'vue', + 'vue-router', + { + 'pinia/dist/pinia': ['storeToRefs'] + } + ], + //配置后会自动扫描目录下的文件 + dirs: ['src/hooks/**', 'src/utils/**', 'src/store/**', 'src/api/**', 'src/directives/**'], + eslintrc: { + enabled: true, // Default `false` + filepath: './eslintrc/.eslintrc-auto-import.json', // Default `./.eslintrc-auto-import.json` + globalsPropValue: true // Default `true`, (true | false | 'readonly' | 'readable' | 'writable' | 'writeable') + }, + dts: './typings/auto-imports.d.ts' + }), + + vitePluginSetupExtend({ inject: { title: setting.title } }) + //依赖分析插件 + // visualizer({ + // open: true, + // gzipSize: true, + // brotliSize: true + // }) + ], + build: { + chunkSizeWarningLimit: 10000, //消除触发警告的 chunk, 默认500k + assetsDir: 'static/assets', + rollupOptions: { + output: { + chunkFileNames: 'static/js/[name]-[hash].js', + entryFileNames: 'static/js/[name]-[hash].js', + assetFileNames: 'static/[ext]/[name]-[hash].[ext]' + } + } + }, + resolve: { + alias: { + '@/': `${pathSrc}/`, + 'vue-i18n': 'vue-i18n/dist/vue-i18n.cjs.js' //remove i18n waring + } + }, + optimizeDeps: { + //include: [...optimizeDependencies,...optimizeElementPlus] //on-demand element-plus use this + include: ['moment-mini'] + } + } +}) diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..7924b8c --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from 'vitest/config' +import Vue from '@vitejs/plugin-vue' +import VueJsx from '@vitejs/plugin-vue-jsx' +import DefineOptions from 'unplugin-vue-define-options/vite' +export default defineConfig({ + plugins: [Vue(), VueJsx(), DefineOptions()], + optimizeDeps: { + disabled: true + }, + test: { + clearMocks: true, + environment: 'jsdom', + //setup 文件的路径。它们将运行在每个测试文件之前。 + setupFiles: ['./vitest.setup.ts'], + transformMode: { + web: [/\.[jt]sx$/] + } + } +}) diff --git a/vitest.setup.ts b/vitest.setup.ts new file mode 100644 index 0000000..8ce1df3 --- /dev/null +++ b/vitest.setup.ts @@ -0,0 +1,5 @@ +import { config } from '@vue/test-utils' +import { vi } from 'vitest' +import ResizeObserver from 'resize-observer-polyfill' +vi.stubGlobal('ResizeObserver', ResizeObserver) +config.global.stubs = {}