├── .editorconfig
├── .env.build
├── .env.build-test
├── .env.serve-dev
├── .env.serve-test
├── .eslintignore
├── .eslintrc-auto-import.json
├── .eslintrc.json
├── .gitignore
├── .husky
├── commit-msg
└── pre-commit
├── .npmrc
├── .prettierrc
├── .vscode
├── extensions.json
└── settings.json
├── .yarnrc
├── App.vue
├── README.md
├── auto-imports.d.ts
├── build
├── afterPack.js
├── icons
│ ├── 256x256.png
│ ├── icon.icns
│ └── icon.ico
└── script
│ └── installer.nsh
├── electron-main.ts
├── electron
├── html
│ └── renderer2.html
├── main
│ ├── MainRendererComm.js
│ ├── globalShortcut.js
│ ├── menu.js
│ └── tray.js
├── renderer
│ └── renderer2.js
├── static
│ ├── empty.ico
│ ├── favicon2.ico
│ └── lover.png
└── utils
│ ├── commentUtils.js
│ └── node-fs.js
├── eslintrc
├── .eslintrc-auto-import.json
└── eslint-config.js
├── index.html
├── loading.html
├── main.ts
├── mock-prod-server.ts
├── mock
├── example.ts
└── system.ts
├── nedbStore.db
├── nodemon.json
├── optimize-include.ts
├── package.json
├── public
└── favicon.ico
├── settings.ts
├── src
├── App.vue
├── api
│ └── system.ts
├── assets
│ ├── 401_images
│ │ └── 401.gif
│ ├── 404_images
│ │ ├── 404.png
│ │ └── 404_cloud.png
│ └── gif
│ │ └── dianchi.gif
├── components
│ ├── ElSvgIcon.vue
│ ├── TestUnit.vue
│ └── __tests__
│ │ └── el-svgIcon.test.jsx
├── directives
│ ├── button-codes.ts
│ ├── codes-permission.ts
│ ├── index.ts
│ ├── lang.ts
│ └── roles-permission.ts
├── hooks
│ ├── use-common.ts
│ ├── use-element.ts
│ ├── use-error-log.ts
│ ├── use-layout.ts
│ ├── use-permission.ts
│ ├── use-self-router.ts
│ └── use-table.ts
├── icons
│ ├── SvgIcon.vue
│ ├── common
│ │ ├── 404.svg
│ │ ├── bug.svg
│ │ ├── chart.svg
│ │ ├── clipboard.svg
│ │ ├── component.svg
│ │ ├── dashboard.svg
│ │ ├── demo.svg
│ │ ├── documentation.svg
│ │ ├── drag.svg
│ │ ├── edit.svg
│ │ ├── education.svg
│ │ ├── email.svg
│ │ ├── example.svg
│ │ ├── excel.svg
│ │ ├── exit-fullscreen.svg
│ │ ├── eye-open.svg
│ │ ├── eye.svg
│ │ ├── form.svg
│ │ ├── fullscreen.svg
│ │ ├── guide.svg
│ │ ├── hamburger.svg
│ │ ├── icon.svg
│ │ ├── international.svg
│ │ ├── language.svg
│ │ ├── link.svg
│ │ ├── list.svg
│ │ ├── lock.svg
│ │ ├── message.svg
│ │ ├── money.svg
│ │ ├── nested.svg
│ │ ├── password.svg
│ │ ├── pdf.svg
│ │ ├── people.svg
│ │ ├── peoples.svg
│ │ ├── qq.svg
│ │ ├── search.svg
│ │ ├── shopping.svg
│ │ ├── sidebar-logo.svg
│ │ ├── size.svg
│ │ ├── skill.svg
│ │ ├── star.svg
│ │ ├── tab.svg
│ │ ├── table.svg
│ │ ├── theme.svg
│ │ ├── tree-table.svg
│ │ ├── tree.svg
│ │ ├── user.svg
│ │ ├── wechat.svg
│ │ └── zip.svg
│ └── nav-bar
│ │ ├── dashboard.svg
│ │ ├── example.svg
│ │ ├── eye-open.svg
│ │ ├── eye.svg
│ │ ├── form.svg
│ │ ├── language.svg
│ │ ├── link.svg
│ │ ├── nested.svg
│ │ ├── password.svg
│ │ ├── table.svg
│ │ ├── theme-icon.svg
│ │ ├── tree.svg
│ │ └── user.svg
├── lang
│ ├── en.ts
│ ├── index.ts
│ └── zh.ts
├── layout
│ ├── app-main
│ │ ├── Breadcrumb.vue
│ │ ├── Hamburger.vue
│ │ ├── Navbar.vue
│ │ ├── TagsView.vue
│ │ └── index.vue
│ ├── index.vue
│ └── sidebar
│ │ ├── Link.vue
│ │ ├── Logo.vue
│ │ ├── MenuIcon.vue
│ │ ├── SidebarItem.vue
│ │ └── index.vue
├── lib
│ ├── el-svg-icon.ts
│ └── element-plus.ts
├── main.ts
├── mock-prod-server.ts
├── permission.ts
├── plugins
│ └── vite-plugin-setup-extend
│ │ └── index.ts
├── router
│ ├── index.ts
│ └── modules
│ │ ├── basic-demo.ts
│ │ └── electron.ts
├── settings.ts
├── store
│ ├── basic.ts
│ ├── config.ts
│ └── tags-view.ts
├── styles
│ ├── index.scss
│ ├── init-loading.css
│ ├── reset-elemenet-plus-style.scss
│ ├── scss-suger.scss
│ └── transition.scss
├── theme
│ ├── base
│ │ ├── custom
│ │ │ └── ct-css-vars.scss
│ │ ├── element-plus
│ │ │ ├── button.scss
│ │ │ ├── checkbox.scss
│ │ │ ├── css-vars.scss
│ │ │ ├── form.scss
│ │ │ ├── pagination.scss
│ │ │ ├── redio.scss
│ │ │ ├── table.scss
│ │ │ └── var.scss
│ │ └── index.scss
│ ├── china-red
│ │ ├── custom
│ │ │ └── ct-css-vars.scss
│ │ ├── element-plus
│ │ │ ├── button.scss
│ │ │ ├── checkbox.scss
│ │ │ ├── css-vars.scss
│ │ │ ├── form.scss
│ │ │ ├── pagination.scss
│ │ │ ├── redio.scss
│ │ │ ├── table.scss
│ │ │ └── var.scss
│ │ └── index.scss
│ ├── dark
│ │ ├── custom
│ │ │ └── ct-css-vars.scss
│ │ ├── element-plus
│ │ │ ├── button.scss
│ │ │ ├── checkbox.scss
│ │ │ ├── css-vars.css
│ │ │ ├── css-vars.css.map
│ │ │ ├── css-vars.scss
│ │ │ ├── form.scss
│ │ │ ├── pagination.scss
│ │ │ ├── redio.scss
│ │ │ ├── table.scss
│ │ │ └── var.scss
│ │ └── index.scss
│ ├── index.scss
│ ├── lighting
│ │ ├── custom
│ │ │ └── ct-css-vars.scss
│ │ ├── element-plus
│ │ │ ├── button.scss
│ │ │ ├── checkbox.scss
│ │ │ ├── css-vars.css
│ │ │ ├── css-vars.css.map
│ │ │ ├── css-vars.scss
│ │ │ ├── form.scss
│ │ │ ├── pagination.scss
│ │ │ ├── redio.scss
│ │ │ ├── table.scss
│ │ │ └── var.scss
│ │ └── index.scss
│ ├── mixins
│ │ ├── _var.scss
│ │ ├── config.scss
│ │ ├── function.scss
│ │ └── mixins.scss
│ └── utils
│ │ ├── change-theme.ts
│ │ └── index.ts
├── utils
│ ├── axios-req.ts
│ ├── bus.ts
│ └── common-util.ts
└── views
│ ├── basic-demo
│ ├── hook
│ │ └── index.vue
│ ├── keep-alive
│ │ ├── index.vue
│ │ ├── second-child.vue
│ │ ├── tab-keep-alive.vue
│ │ ├── third-child.vue
│ │ ├── third-children
│ │ │ ├── SecondChildren.vue
│ │ │ └── ThirdChildren.vue
│ │ └── third-keep-alive.vue
│ ├── mock
│ │ └── index.vue
│ ├── parent-children
│ │ ├── Children.vue
│ │ ├── SubChildren.vue
│ │ └── index.vue
│ ├── pinia
│ │ └── index.vue
│ ├── svg-icon
│ │ └── index.vue
│ ├── vue3-template
│ │ └── Vue3Template.vue
│ └── worker
│ │ └── index.vue
│ ├── dashboard
│ └── index.vue
│ ├── electron
│ ├── ElectronDemo.vue
│ ├── ElectronDemoBak.vue
│ ├── FsExtra.vue
│ ├── IndexDbDemo.vue
│ ├── MainRendererComm.vue
│ ├── NedbDemo.vue
│ └── NotifyNetListen.vue
│ ├── error-page
│ ├── 401.vue
│ └── 404.vue
│ ├── login
│ └── index.vue
│ ├── nested
│ ├── menu1
│ │ ├── index.vue
│ │ ├── menu1-1
│ │ │ └── index.vue
│ │ ├── menu1-2
│ │ │ ├── index.vue
│ │ │ ├── menu1-2-1
│ │ │ │ └── index.vue
│ │ │ └── menu1-2-2
│ │ │ │ └── index.vue
│ │ └── menu1-3
│ │ │ └── index.vue
│ └── menu2
│ │ └── index.vue
│ ├── redirect
│ └── index.tsx
│ └── setting-switch
│ ├── SettingSwitch.vue
│ └── index.vue
├── tsconfig.base.json
├── tsconfig.json
├── typings
├── auto-imports.d.ts
├── basic.d.ts
├── common.d.ts
├── components.d.ts
├── env.d.ts
├── global.d.ts
└── shims-vue.d.ts
├── vite.config.ts
├── vitest.config.ts
└── vitest.setup.ts
/.editorconfig:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jzfai/vue3-admin-electron/130309705772261805160c23c3b9dd0424c68fe1/.editorconfig
--------------------------------------------------------------------------------
/.env.build:
--------------------------------------------------------------------------------
1 | #The defined variable must start with VITE_APP_
2 | #notes: login use mock api
3 |
4 | VITE_APP_ENV = 'dev'
5 | VITE_APP_BASE_URL = ''
6 |
7 | #image or oss address
8 | VITE_APP_IMAGE_URL = ''
9 |
10 | #proxy, use this to test proxy
11 | #VITE_APP_BASE_URL = '/api'
12 |
--------------------------------------------------------------------------------
/.env.build-test:
--------------------------------------------------------------------------------
1 | #The defined variable must start with VITE_APP_
2 | #notes: login use mock api
3 |
4 | VITE_APP_ENV = 'dev'
5 | VITE_APP_BASE_URL = ''
6 |
7 | #image or oss address
8 | VITE_APP_IMAGE_URL = ''
9 |
10 | #proxy,use this to test proxy
11 | #VITE_APP_BASE_URL = '/api'
12 |
--------------------------------------------------------------------------------
/.env.serve-dev:
--------------------------------------------------------------------------------
1 | #The defined variable must start with VITE_APP_
2 | #notes: login use mock api
3 |
4 | VITE_APP_ENV = 'dev'
5 | VITE_APP_BASE_URL = ''
6 |
7 | #image or oss address
8 | VITE_APP_IMAGE_URL = ''
9 |
10 | #proxy, use this to test proxy
11 | #VITE_APP_BASE_URL = '/api'
12 |
--------------------------------------------------------------------------------
/.env.serve-test:
--------------------------------------------------------------------------------
1 | #The defined variable must start with VITE_APP_
2 | #notes: login use mock api
3 |
4 | VITE_APP_ENV = 'dev'
5 | VITE_APP_BASE_URL = ''
6 |
7 | #image or oss address
8 | VITE_APP_IMAGE_URL = ''
9 |
10 | #proxy, use this to test proxy
11 | #VITE_APP_BASE_URL = '/api'
12 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | public
2 | node_modules
3 | .history
4 | .husky
5 | dist
6 | *.d.ts
7 |
--------------------------------------------------------------------------------
/.eslintrc-auto-import.json:
--------------------------------------------------------------------------------
1 | {
2 | "globals": {
3 | "axiosReq": true,
4 | "computed": true,
5 | "createApp": true,
6 | "createLogger": true,
7 | "createNamespacedHelpers": true,
8 | "createStore": true,
9 | "customRef": true,
10 | "defineAsyncComponent": true,
11 | "defineComponent": true,
12 | "effectScope": true,
13 | "EffectScope": true,
14 | "getCurrentInstance": true,
15 | "getCurrentScope": true,
16 | "h": true,
17 | "inject": true,
18 | "isReadonly": true,
19 | "isRef": true,
20 | "mapActions": true,
21 | "mapGetters": true,
22 | "mapMutations": true,
23 | "mapState": true,
24 | "markRaw": true,
25 | "nextTick": true,
26 | "onActivated": true,
27 | "onBeforeMount": true,
28 | "onBeforeUnmount": true,
29 | "onBeforeUpdate": true,
30 | "onDeactivated": true,
31 | "onErrorCaptured": true,
32 | "onMounted": true,
33 | "onRenderTracked": true,
34 | "onRenderTriggered": true,
35 | "onScopeDispose": true,
36 | "onServerPrefetch": true,
37 | "onUnmounted": true,
38 | "onUpdated": true,
39 | "provide": true,
40 | "reactive": true,
41 | "readonly": true,
42 | "ref": true,
43 | "resolveComponent": true,
44 | "shallowReactive": true,
45 | "shallowReadonly": true,
46 | "shallowRef": true,
47 | "toRaw": true,
48 | "toRef": true,
49 | "toRefs": true,
50 | "triggerRef": true,
51 | "unref": true,
52 | "useAttrs": true,
53 | "useCommon": true,
54 | "useCssModule": true,
55 | "useCssVars": true,
56 | "useElement": true,
57 | "useRoute": true,
58 | "useRouter": true,
59 | "useSlots": true,
60 | "useStore": true,
61 | "useVueRouter": true,
62 | "watch": true,
63 | "watchEffect": true
64 | }
65 | }
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "extends": ["./eslintrc/eslint-config.js", "./eslintrc/.eslintrc-auto-import.json"]
4 | }
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # compiled output
2 | /dist
3 | /dist-ssr
4 | /node_modules
5 |
6 | #lock
7 | pnpm-lock.yaml
8 |
9 | # Logs
10 | logs
11 | *.log
12 | npm-debug.log*
13 | pnpm-debug.log*
14 | yarn-debug.log*
15 | yarn-error.log*
16 | lerna-debug.log*
17 |
18 | # OS
19 | .DS_Store
20 |
21 | # Tests
22 | /coverage
23 | /.nyc_output
24 |
25 | # IDEs and editors
26 | /.idea
27 | .project
28 | .classpath
29 | .c9/
30 | *.launch
31 | .settings/
32 | *.sublime-workspace
33 |
34 | # IDE - VSCode
35 | .vscode/*
36 | !.vscode/settings.json
37 | !.vscode/tasks.json
38 | !.vscode/launch.json
39 | !.vscode/extensions.json
40 |
41 | # Other
42 | .history
43 | *.local
44 | yarn*
45 | pnpm*
46 |
47 |
48 | #.eslintrc-auto-import.json
49 | #auto-imports.d.ts
50 | #components.d.ts
51 | stats.html
52 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #. "$(dirname "$0")/_/husky.sh"
3 | #在项目中我们会使用commit-msg这个git hook来校验我们commit时添加的备注信息是否符合规范。在以前的我们通常是这样配置:
4 | #--no-install 参数表示强制npx使用项目中node_modules目录中的commitlint包(如果需要开启,注意:需要安装npx)
5 | #npx --no-install commitlint --edit $1
6 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | #推送之前运行eslint检查
5 | npm run lint
6 | #推送之前运行单元测试检查
7 | #npm run test:unit
8 |
9 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | shamefully-hoist=true
2 | strict-peer-dependencies=false
3 |
4 | ###aliyun address
5 | registry = https://registry.npmmirror.com
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "useTabs": false,
3 | "tabWidth": 2,
4 | "printWidth": 120,
5 | "singleQuote": true,
6 | "trailingComma": "none",
7 | "bracketSpacing": true,
8 | "semi": false,
9 | "htmlWhitespaceSensitivity": "ignore"
10 | }
11 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["johnsoncodehk.volar", "esbenp.prettier-vscode","dbaeumer.vscode-eslint"]
3 | }
4 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.defaultFormatter": "esbenp.prettier-vscode",
3 | "npm.packageManager": "yarn"
4 | }
5 |
--------------------------------------------------------------------------------
/.yarnrc:
--------------------------------------------------------------------------------
1 | registry "https://registry.npm.taobao.org"
2 |
3 | sass_binary_site "https://npm.taobao.org/mirrors/node-sass/"
4 | phantomjs_cdnurl "http://cnpmjs.org/downloads"
5 | electron_mirror "https://npm.taobao.org/mirrors/electron/"
6 | sqlite3_binary_host_mirror "https://foxgis.oss-cn-shanghai.aliyuncs.com/"
7 | profiler_binary_host_mirror "https://npm.taobao.org/mirrors/node-inspector/"
8 | chromedriver_cdnurl "https://cdn.npm.taobao.org/dist/chromedriver"
9 |
--------------------------------------------------------------------------------
/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
40 |
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue3-admin-electron
2 |
3 | > This is a basic vue3 admin electron desktop platform. Contains the most basic electron development and construction steps and the use of demo, a set of codes can be packaged for win, mac, linux platform applications at the same time.
4 |
5 | A new generation Cross-desktop framework using electron13+vue3(setup-script)+vite2+element-plus ,It's fast!
6 |
7 | Use eslint+prettier+gitHooks format and verification code to improve code standardization and development efficiency
8 |
9 |
10 |
11 | ## Related items
12 |
13 | The framework is available in js, ts, plus and electron versions
14 | - electron version: [vue3-admin-electron](https://github.com/jzfai/vue3-admin-electron.git)
15 | - js version:[vue3-element-admin](https://github.com/jzfai/vue3-admin-electron.git)
16 | - ts version:[vue3-element-ts](https://github.com/jzfai/vue3-admin-ts.git)
17 | - js version for plus:[vue3-element-plus](https://github.com/jzfai/vue3-admin-plus.git)
18 | - java Micro-service background data:[micro-service-single](https://github.com/jzfai/micro-service-single)
19 | > development and experience:two words Really fragrant!!!!!
20 |
21 | ## Build Setup
22 |
23 | ```bash
24 | git clone https://github.com/jzfai/vue3-admin-electron.git
25 |
26 | cd vue3-admin-electron
27 |
28 | # install dependency(Recommend use yarn)
29 | yarn
30 |
31 | yarn run electron:dev
32 | ```
33 |
34 | ## Build
35 |
36 | ```bash
37 | # build for production environment
38 | yarn run electron:build
39 | > Note: The packaged exe is packaged with the windows system, and the packaged dmg is packaged with the mac system. Separate as much as possible
40 | ```
41 |
42 | ## Others
43 |
44 | ```bash
45 | # code format check
46 | yarn run lint
47 |
48 | ```
49 |
50 | ## Extra
51 |
52 | Architecture development is not easy. If you feel good, please give me a compliment. The architecture is still being improved. Welcome to join me in development and become Contributors together! ! ! !
53 |
54 |
55 | ## License
56 |
57 | [MIT](https://github.com/jzfai/vue3-admin-electron/blob/master/LICENSE) license.
58 |
59 | Copyright (c) 2023-present kuanghua
60 |
--------------------------------------------------------------------------------
/build/afterPack.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const path = require('path')
3 | async function afterPack(context) {
4 | // 删除 README 文件,使其不加入 Setup 包中。
5 | let readmePath = path.join(context.appOutDir, 'resources/app.asar.unpacked/README.md')
6 | if (fs.existsSync(readmePath)) {
7 | fs.unlinkSync(readmePath)
8 | }
9 | }
10 | module.exports = afterPack
11 |
--------------------------------------------------------------------------------
/build/icons/256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jzfai/vue3-admin-electron/130309705772261805160c23c3b9dd0424c68fe1/build/icons/256x256.png
--------------------------------------------------------------------------------
/build/icons/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jzfai/vue3-admin-electron/130309705772261805160c23c3b9dd0424c68fe1/build/icons/icon.icns
--------------------------------------------------------------------------------
/build/icons/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jzfai/vue3-admin-electron/130309705772261805160c23c3b9dd0424c68fe1/build/icons/icon.ico
--------------------------------------------------------------------------------
/build/script/installer.nsh:
--------------------------------------------------------------------------------
1 | ; Script generated by the HM NIS Edit Script Wizard.
2 |
3 | ; HM NIS Edit Wizard helper defines custom install default dir
4 | !macro preInit
5 | SetRegView 64
6 | WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "D:\electron-builder-start-exe"
7 | WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "D:\electron-builder-start-exe"
8 | SetRegView 32
9 | WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "D:\electron-builder-start-exe"
10 | WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "D:\electron-builder-start-exe"
11 | !macroend
--------------------------------------------------------------------------------
/electron-main.ts:
--------------------------------------------------------------------------------
1 | const { BrowserWindow, app } = require('electron')
2 | const isDev = require('electron-is-dev')
3 | const createWindow = () => {
4 | const mainWindow = new BrowserWindow({
5 | width: 1280,
6 | height: 800,
7 | webPreferences: {
8 | nodeIntegration: true, //渲染进程中使用nodejs
9 | contextIsolation: false,
10 | enableRemoteModule: true //渲染线程中使用remote模块
11 | }
12 | })
13 | //dev development
14 | const waitOn = require('wait-on')
15 | if (isDev) {
16 | mainWindow.loadFile('loading.html')
17 | // wait for http://localhost:5006 to load
18 | // detail to using look https://github.com/jeffbski/wait-on
19 | const opts = {
20 | resources: ['http://127.0.0.1:5008/index.html'],
21 | delay: 1000, // initial delay in ms, default 0
22 | timeout: 6000 // timeout in ms, default Infinity
23 | }
24 | waitOn(opts, (err) => {
25 | if (err) {
26 | console.error(err)
27 | return
28 | }
29 | mainWindow.loadURL('http://localhost:5008')
30 | //open devTools
31 | mainWindow.webContents.openDevTools({ mode: 'bottom' })
32 | })
33 | } else {
34 | mainWindow.loadFile('dist/index.html')
35 | }
36 | //开启remote
37 | require('@electron/remote/main').initialize()
38 | require('@electron/remote/main').enable(mainWindow.webContents)
39 | //引入相应的主线程
40 | require('./electron/main/MainRendererComm')
41 | //import menu
42 | //require('./electron/main/menu')
43 | //import tray
44 | require('./electron/main/tray')
45 | //import tray
46 | require('./electron/main/globalShortcut')
47 | }
48 | app.on('ready', createWindow)
49 | //监听窗口关闭的事件,关闭的时候退出应用,macOs 需要排除(mac相关)
50 | app.on('window-all-closed', () => {
51 | if (process.platform !== 'darwin') {
52 | app.quit()
53 | }
54 | })
55 | //Macos 中点击 dock 中的应用图标的时候重新创建窗口
56 | app.on('activate', () => {
57 | if (BrowserWindow.getAllWindows().length === 0) {
58 | createWindow()
59 | }
60 | })
61 |
--------------------------------------------------------------------------------
/electron/html/renderer2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Document
7 |
8 |
9 | renderer2页面
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/electron/main/MainRendererComm.js:
--------------------------------------------------------------------------------
1 | const { BrowserWindow, ipcMain } = require('electron')
2 | const path = require('path')
3 |
4 | //first way
5 | ipcMain.on('send1', (event, args) => {
6 | console.log(args)
7 | event.sender.send('reply1', 'reply1')
8 | })
9 |
10 | //send way(sync)
11 | ipcMain.on('send2', (event) => {
12 | event.returnValue = 'send2'
13 | })
14 |
15 | //three way
16 | let renderer1Id = null
17 | ipcMain.on('renderer2', () => {
18 | //在打开renderer2窗口前保存renderer1的id
19 | renderer1Id = BrowserWindow.getFocusedWindow().id
20 | const newsWindow = new BrowserWindow({
21 | width: 800,
22 | height: 500,
23 | webPreferences: {
24 | nodeIntegration: true, //开启渲染进程中使用nodejs
25 | contextIsolation: false, //开启渲染进程中使用nodejs In Electron 12, the default will bechanged to `true
26 | enableRemoteModule: true //启用Remote模块
27 | }
28 | })
29 | newsWindow.loadFile(path.join(__dirname, '../html/renderer2.html'))
30 | //open devTools
31 | newsWindow.webContents.openDevTools({ mode: 'bottom' })
32 | newsWindow.webContents.on('did-finish-load', () => {
33 | BrowserWindow.getFocusedWindow().webContents.send('toRenderer2', 'toRenderer2')
34 | })
35 | })
36 | ipcMain.on('renderer1', () => {
37 | let renderer1Win = BrowserWindow.fromId(renderer1Id)
38 | renderer1Win.webContents.send('toRenderer1', 'toRenderer1')
39 | })
40 |
--------------------------------------------------------------------------------
/electron/main/globalShortcut.js:
--------------------------------------------------------------------------------
1 | const { globalShortcut, app } = require('electron')
2 | const commentUtils = require('../utils/commentUtils')
3 | app.whenReady().then(() => {
4 | //注册全局快捷键
5 | globalShortcut.register('ctrl+e', () => {
6 | commentUtils.dialogMessage('快捷键 "ctrl+e被点击了').then(() => {})
7 | //检测快捷键是否注册功能
8 | console.log(globalShortcut.isRegistered('ctrl+e'))
9 | })
10 | })
11 |
12 | //注销全局快捷键的监听
13 | app.on('will-quit', () => {
14 | globalShortcut.unregister('ctrl+e')
15 | })
16 |
--------------------------------------------------------------------------------
/electron/main/menu.js:
--------------------------------------------------------------------------------
1 | const { Menu } = require('electron')
2 | let menuTemplate = [
3 | {
4 | label: '文件',
5 | submenu: [
6 | {
7 | label: '新建文件',
8 | accelerator: 'ctrl+n',
9 | click: function () {
10 | console.log('ctrl+n')
11 | }
12 | },
13 | {
14 | label: '新建窗口',
15 | click: function () {
16 | console.log('new window')
17 | }
18 | }
19 | ]
20 | },
21 | {
22 | label: '编辑',
23 | submenu: [
24 | { label: '复制', role: 'copy' },
25 | { label: '截切', role: 'cut' }
26 | ]
27 | }
28 | ]
29 |
30 | const menuBuilder = Menu.buildFromTemplate(menuTemplate)
31 | Menu.setApplicationMenu(menuBuilder)
32 |
--------------------------------------------------------------------------------
/electron/main/tray.js:
--------------------------------------------------------------------------------
1 | const { Menu, Tray, app, BrowserWindow } = require('electron')
2 | const path = require('path')
3 |
4 | const appIcon = new Tray(path.join(__dirname, '../static/lover.png'))
5 | const menu = Menu.buildFromTemplate([
6 | { label: '设置', click: function () {} },
7 | { label: '帮助', click: function () {} },
8 | { label: '关于', click: function () {} },
9 | {
10 | label: '退出',
11 | click: function () {
12 | app.quit()
13 | }
14 | }
15 | ])
16 | let timeout = setTimeout(() => {
17 | appIcon.setImage(path.join(__dirname, '../static/lover.png'))
18 | clearTimeout(timeout)
19 | }, 1000)
20 | appIcon.setToolTip('vue3-admin-electron')
21 | appIcon.setContextMenu(menu)
22 |
23 |
24 |
25 | //win relative
26 | if(process.platform==="win32"){
27 | //监听任务栏图标的单击、双击事件
28 | let win = BrowserWindow.getFocusedWindow()
29 | appIcon.on('double-click', () => {
30 | console.log(win)
31 | win.show()
32 | })
33 |
34 | //Electron 点击右上角关闭按钮隐藏任务栏图标
35 | win.on('close', (e) => {
36 | console.log(win.isFocused())
37 | if (!win.isFocused()) {
38 | win = null
39 | } else {
40 | e.preventDefault()
41 | win.hide()
42 | }
43 | })
44 |
45 | //Electron 实现任务栏闪烁图标
46 | let count = 0
47 | const timer = setInterval(function () {
48 | count++
49 | if (count % 2 === 0) {
50 | appIcon.setPressedImage(path.join(__dirname, '../static/lover.png'))
51 | // appIcon.setImage(path.join(__dirname, '../static/lover.ico'))
52 | } else {
53 | appIcon.setImage(path.join(__dirname, '../static/lover.png'))
54 | }
55 | }, 500)
56 |
57 | }
58 |
59 |
--------------------------------------------------------------------------------
/electron/renderer/renderer2.js:
--------------------------------------------------------------------------------
1 | const { ipcRenderer } = require('electron')
2 | ipcRenderer.on('toRenderer2', (e, data) => {
3 | console.log(data)
4 | })
5 |
6 | window.onload = () => {
7 | let btnDom = document.querySelector('#btn')
8 | btnDom.onclick = () => {
9 | ipcRenderer.send('renderer1', 'renderer1')
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/electron/static/empty.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jzfai/vue3-admin-electron/130309705772261805160c23c3b9dd0424c68fe1/electron/static/empty.ico
--------------------------------------------------------------------------------
/electron/static/favicon2.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jzfai/vue3-admin-electron/130309705772261805160c23c3b9dd0424c68fe1/electron/static/favicon2.ico
--------------------------------------------------------------------------------
/electron/static/lover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jzfai/vue3-admin-electron/130309705772261805160c23c3b9dd0424c68fe1/electron/static/lover.png
--------------------------------------------------------------------------------
/electron/utils/commentUtils.js:
--------------------------------------------------------------------------------
1 | const { dialog } = require('electron')
2 |
3 | module.exports = {
4 | dialogError(content, title) {
5 | dialog.showErrorBox(title || 'error', content)
6 | },
7 | dialogMessage(content, type, title) {
8 | return new Promise((resolve, reject) => {
9 | return dialog
10 | .showMessageBox({ type: type || 'info', title: title || '提示', message: content, buttons: ['ok', 'no'] })
11 | .then((res) => {
12 | if (res.response === 0) {
13 | resolve()
14 | } else {
15 | reject()
16 | }
17 | })
18 | .catch((err) => {
19 | console.log('catch', err)
20 | })
21 | })
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/electron/utils/node-fs.js:
--------------------------------------------------------------------------------
1 | //node fs 模块 对文件的增删改查
2 | const fs = require('fs')
3 | /**
4 | * 异步使用流的形式写文件,该方案比上述方法更为安全
5 | * filePath:文件存放地址
6 | * jsonstring 所以文件内容对象
7 | * */
8 | export const writeFileWithStream = (filePath, jsonstring, cb) => {
9 | let streamWrite = fs.createWriteStream(filePath)
10 | streamWrite.write(jsonstring)
11 | streamWrite.end()
12 | streamWrite.on('error', (err) => {
13 | cb(`写入${filePath}异常:${err}`)
14 | })
15 | streamWrite.on('finish', () => {
16 | cb()
17 | })
18 | }
19 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= title %>
9 |
10 |
11 |
12 |
13 |

14 |
正在加载系统资源,请耐心等待
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/loading.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 | 服务启动中......
9 |
10 |
11 |
--------------------------------------------------------------------------------
/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import { createPinia } from 'pinia'
3 | import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
4 | import ElementPlus from 'element-plus'
5 | import App from './App.vue'
6 | import router from './router'
7 |
8 | //import theme
9 | import './theme/index.scss'
10 |
11 | //import unocss
12 | import 'uno.css'
13 |
14 | //i18n
15 | import { setupI18n } from '@/lang'
16 |
17 | import '@/styles/index.scss' // global css
18 |
19 | //svg-icon
20 | import 'virtual:svg-icons-register'
21 | import svgIcon from '@/icons/SvgIcon.vue'
22 | import directive from '@/directives'
23 |
24 | //import router intercept
25 | import './permission'
26 |
27 | //import element-plus
28 | import 'element-plus/dist/index.css'
29 | const app = createApp(App)
30 |
31 | //router
32 | app.use(router)
33 |
34 | //pinia
35 | const pinia = createPinia()
36 | pinia.use(piniaPluginPersistedstate)
37 | app.use(pinia)
38 |
39 | //i18n
40 | app.use(setupI18n)
41 | app.component('SvgIcon', svgIcon)
42 | directive(app)
43 |
44 | //element-plus
45 | app.use(ElementPlus)
46 |
47 | app.mount('#app')
48 |
--------------------------------------------------------------------------------
/mock-prod-server.ts:
--------------------------------------------------------------------------------
1 | import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'
2 | //https://cn.vitejs.dev/guide/features.html#glob-import
3 | // @ts-ignore
4 | const modulesFiles = import.meta.glob('../mock/*', { eager: true })
5 | let modules = []
6 | for (const filePath in modulesFiles) {
7 | //读取文件内容到 modules
8 | modules = modules.concat(modulesFiles[filePath].default)
9 | }
10 | export function setupProdMockServer() {
11 | //创建prod mock server
12 | createProdMockServer([...modules])
13 | }
14 |
--------------------------------------------------------------------------------
/mock/example.ts:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | url: '/getMapInfo',
4 | method: 'get',
5 | response: () => {
6 | return {
7 | code: 200,
8 | title: 'mock请求测试'
9 | }
10 | }
11 | }
12 | ]
13 |
--------------------------------------------------------------------------------
/mock/system.ts:
--------------------------------------------------------------------------------
1 | const system = {
2 | url: '/mock/login',
3 | method: 'post',
4 | response: () => {
5 | return {
6 | code: 20000,
7 | jwtToken:"666666"
8 | }
9 | }
10 | }
11 |
12 | const loginOut = {
13 | url: '/mock/loginOut',
14 | method: 'post',
15 | response: () => {
16 | return {
17 | code: 200,
18 | title: 'mock请求测试'
19 | }
20 | }
21 | }
22 |
23 | export default [
24 | system,loginOut
25 | ]
26 |
--------------------------------------------------------------------------------
/nedbStore.db:
--------------------------------------------------------------------------------
1 | {"name":"","age":"","_id":"2a9H6ypIAD6ZVDia"}
2 | {"name":"","age":"","_id":"CdQJoiYSP7gWobjQ"}
3 | {"name":"","age":"","_id":"PpvyYzNUwXdnX3MB"}
4 | {"name":"","age":"","_id":"Vbz5Qy8j8kc1xH6d"}
5 | {"name":"","age":"","_id":"ciMTWeWe1pQIZGMr"}
6 | {"name":"","age":"","_id":"h2IbNY5Yv65JPZaf"}
7 | {"name":"","age":"","_id":"yYymdGWiUIJziEns"}
8 |
--------------------------------------------------------------------------------
/nodemon.json:
--------------------------------------------------------------------------------
1 | {
2 | "watch":["electron","electron-main.js"],
3 | "ext": "ts,js,html,css",
4 | "ignore": ["node_modules","src","dist",".husky","mock",".husky"]
5 | }
6 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jzfai/vue3-admin-electron/130309705772261805160c23c3b9dd0424c68fe1/public/favicon.ico
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
40 |
46 |
--------------------------------------------------------------------------------
/src/api/system.ts:
--------------------------------------------------------------------------------
1 | //获取用户信息
2 | import axiosReq from 'axios'
3 | // export const userInfoReq = (): Promise => {
4 | // return new Promise((resolve) => {
5 | // const reqConfig = {
6 | // url: '/basis-func/user/getUserInfo',
7 | // params: { plateFormId: 2 },
8 | // method: 'post'
9 | // }
10 | // axiosReq(reqConfig).then(({ data }) => {
11 | // resolve(data)
12 | // })
13 | // })
14 | // }
15 |
16 | //登录
17 | export const loginReq = (subForm) => {
18 | return axiosReq({
19 | url: '/mock/login',
20 | params: subForm,
21 | method: 'post'
22 | })
23 | }
24 |
25 | //退出登录
26 | export const loginOutReq = () => {
27 | return axiosReq({
28 | url: '/mock/loginOut',
29 | method: 'post'
30 | })
31 | }
32 |
--------------------------------------------------------------------------------
/src/assets/401_images/401.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jzfai/vue3-admin-electron/130309705772261805160c23c3b9dd0424c68fe1/src/assets/401_images/401.gif
--------------------------------------------------------------------------------
/src/assets/404_images/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jzfai/vue3-admin-electron/130309705772261805160c23c3b9dd0424c68fe1/src/assets/404_images/404.png
--------------------------------------------------------------------------------
/src/assets/404_images/404_cloud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jzfai/vue3-admin-electron/130309705772261805160c23c3b9dd0424c68fe1/src/assets/404_images/404_cloud.png
--------------------------------------------------------------------------------
/src/assets/gif/dianchi.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jzfai/vue3-admin-electron/130309705772261805160c23c3b9dd0424c68fe1/src/assets/gif/dianchi.gif
--------------------------------------------------------------------------------
/src/components/ElSvgIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
27 |
28 |
37 |
--------------------------------------------------------------------------------
/src/components/TestUnit.vue:
--------------------------------------------------------------------------------
1 |
2 | TestUnit.vue
3 |
4 |
5 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/directives/button-codes.ts:
--------------------------------------------------------------------------------
1 | import { useBasicStore } from '@/store/basic'
2 |
3 | function checkPermission(el, { value }) {
4 | if (value && Array.isArray(value)) {
5 | if (value.length) {
6 | const permissionRoles = value
7 | const hasPermission = useBasicStore().buttonCodes?.some((code) => permissionRoles.includes(code))
8 | if (!hasPermission) el.parentNode && el.parentNode.removeChild(el)
9 | }
10 | } else {
11 | throw new Error(`need roles! Like v-permission="['admin','editor']"`)
12 | }
13 | }
14 | export default {
15 | mounted(el, binding) {
16 | checkPermission(el, binding)
17 | },
18 | componentUpdated(el, binding) {
19 | checkPermission(el, binding)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/directives/codes-permission.ts:
--------------------------------------------------------------------------------
1 | import { useBasicStore } from '@/store/basic'
2 | function checkPermission(el, { value }) {
3 | if (value && Array.isArray(value)) {
4 | if (value.length > 0) {
5 | const permissionRoles = value
6 | const hasPermission = useBasicStore().codes?.some((role) => permissionRoles.includes(role))
7 | if (!hasPermission) el.parentNode && el.parentNode.removeChild(el)
8 | }
9 | } else {
10 | throw new Error(`need codes! Like v-codes-permission="['admin','editor']"`)
11 | }
12 | }
13 | export default {
14 | mounted(el, binding) {
15 | checkPermission(el, binding)
16 | },
17 | componentUpdated(el, binding) {
18 | checkPermission(el, binding)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/directives/index.ts:
--------------------------------------------------------------------------------
1 | import buttonCodes from './button-codes'
2 | import codesPermission from './codes-permission'
3 | import rolesPermission from './roles-permission'
4 | import lang from './lang'
5 | export default function (app) {
6 | app.directive('ButtonCodes', buttonCodes)
7 | app.directive('CodesPermission', codesPermission)
8 | app.directive('RolesPermission', rolesPermission)
9 | app.directive('lang', lang)
10 | }
11 |
--------------------------------------------------------------------------------
/src/directives/lang.ts:
--------------------------------------------------------------------------------
1 | import { watch } from 'vue'
2 | import { storeToRefs } from 'pinia/dist/pinia'
3 | import { langTitle } from '@/hooks/use-common'
4 | import { useConfigStore } from '@/store/config'
5 | //element-plus
6 | const componentToProps = {
7 | ElInput: 'placeholder',
8 | ElTableColumn: 'label'
9 | }
10 |
11 | function checkPermission(el, { value }) {
12 | let saveOriginTitle = ''
13 | const { language } = storeToRefs(useConfigStore())
14 | //save the original title
15 | const name = el.__vueParentComponent?.type?.name
16 | const nameTitle = el.__vueParentComponent?.props[componentToProps[name]]
17 | saveOriginTitle = nameTitle || el.innerText
18 | watch(
19 | () => language.value,
20 | () => {
21 | //element tag or component
22 | if (name?.startsWith('EL')) {
23 | //self cunstrom
24 | if (Object.keys(componentToProps).includes(name)) {
25 | const props = el.__vueParentComponent.props
26 | props[componentToProps[name]] = langTitle(saveOriginTitle)
27 | } else {
28 | el.innerText = langTitle(saveOriginTitle)
29 | }
30 | } else {
31 | //common tag such as div span output so on;
32 | if (el.__vnode?.type) {
33 | el.innerText = langTitle(saveOriginTitle)
34 | }
35 | }
36 | },
37 | { immediate: true }
38 | )
39 | }
40 | export default {
41 | mounted(el, binding) {
42 | checkPermission(el, binding)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/directives/roles-permission.ts:
--------------------------------------------------------------------------------
1 | import { useBasicStore } from '@/store/basic'
2 | function checkPermission(el, { value }) {
3 | if (value && Array.isArray(value)) {
4 | if (value.length > 0) {
5 | const permissionRoles = value
6 | const hasPermission = useBasicStore().roles?.some((role) => permissionRoles.includes(role))
7 | if (!hasPermission) el.parentNode && el.parentNode.removeChild(el)
8 | }
9 | } else {
10 | throw new Error(`need roles! Like v-roles-permission="['admin','editor']"`)
11 | }
12 | }
13 | export default {
14 | mounted(el, binding) {
15 | checkPermission(el, binding)
16 | },
17 | componentUpdated(el, binding) {
18 | checkPermission(el, binding)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/hooks/use-common.ts:
--------------------------------------------------------------------------------
1 | //复制文本
2 | import useClipboard from 'vue-clipboard3'
3 | import { ElMessage } from 'element-plus'
4 |
5 | // i18n language match title
6 | import { i18n } from '@/lang'
7 | // the keys using zh file
8 | import langEn from '@/lang/zh'
9 | import settings from '@/settings'
10 |
11 | export const sleepTimeout = (time: number) => {
12 | return new Promise((resolve) => {
13 | const timer = setTimeout(() => {
14 | clearTimeout(timer)
15 | resolve(null)
16 | }, time)
17 | })
18 | }
19 |
20 | //深拷贝
21 | export function cloneDeep(value) {
22 | return JSON.parse(JSON.stringify(value))
23 | }
24 |
25 | //copyValueToClipboard
26 | const { toClipboard } = useClipboard()
27 | export const copyValueToClipboard = (value: any) => {
28 | toClipboard(JSON.stringify(value))
29 | ElMessage.success('复制成功')
30 | }
31 | const { t, te } = i18n.global
32 | export const langTitle = (title) => {
33 | if (!title) {
34 | return settings.title
35 | }
36 | for (const key of Object.keys(langEn)) {
37 | if (te(`${key}.${title}`) && t(`${key}.${title}`)) {
38 | return t(`${key}.${title}`)
39 | }
40 | }
41 | return title
42 | }
43 |
44 | //get i18n instance
45 | export const getLangInstance = () => {
46 | return i18n.global as ObjKeys
47 | }
48 |
--------------------------------------------------------------------------------
/src/hooks/use-error-log.ts:
--------------------------------------------------------------------------------
1 | /*js 错误日志收集*/
2 | import { jsErrorCollection } from 'js-error-collection'
3 | import pack from '../../package.json'
4 | import settings from '@/settings'
5 | import bus from '@/utils/bus'
6 | //此处不要使用utils下的axios
7 | import axiosReq from 'axios'
8 | const reqUrl = '/integration-front/errorCollection/insert'
9 | let repeatErrorLogJudge = ''
10 | const errorLogReq = (errLog: string) => {
11 | axiosReq({
12 | url: import.meta.env.VITE_APP_BASE_URL+reqUrl,
13 | data: {
14 | pageUrl: window.location.href,
15 | errorLog: errLog,
16 | browserType: navigator.userAgent,
17 | version: pack.version
18 | },
19 | method: 'post'
20 | }).then(() => {
21 | //通知错误列表页面更新数据
22 | bus.emit('reloadErrorPage', {})
23 | })
24 | }
25 |
26 | export const useErrorLog = () => {
27 | //判断该环境是否需要收集错误日志,由settings配置决定
28 | if (settings.errorLog?.includes(import.meta.env.VITE_APP_ENV)) {
29 | jsErrorCollection({ runtimeError: true, rejectError: true, consoleError: true }, (errLog) => {
30 | if (!repeatErrorLogJudge || !errLog.includes(repeatErrorLogJudge)) {
31 | errorLogReq(errLog)
32 | //移除重复日志,fix重复提交错误日志,避免造成死循环
33 | repeatErrorLogJudge = errLog.slice(0, 20)
34 | }
35 | })
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/hooks/use-layout.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 判断是否是外链
3 | * @param {string} path
4 | * @returns {Boolean}
5 | */
6 | import { onBeforeMount, onBeforeUnmount, onMounted } from 'vue'
7 | import { useBasicStore } from '@/store/basic'
8 | export function isExternal(path) {
9 | return /^(https?:|mailto:|tel:)/.test(path)
10 | }
11 |
12 | /*判断窗口变化控制侧边栏收起或展开*/
13 | export function resizeHandler() {
14 | const { body } = document
15 | const WIDTH = 992
16 | const basicStore = useBasicStore()
17 | const isMobile = () => {
18 | const rect = body.getBoundingClientRect()
19 | return rect.width - 1 < WIDTH
20 | }
21 | const resizeHandler = () => {
22 | if (!document.hidden) {
23 | if (isMobile()) {
24 | /*此处只做根据window尺寸关闭sideBar功能*/
25 | basicStore.setSidebarOpen(false)
26 | } else {
27 | basicStore.setSidebarOpen(true)
28 | }
29 | }
30 | }
31 | onBeforeMount(() => {
32 | window.addEventListener('resize', resizeHandler)
33 | })
34 | onMounted(() => {
35 | if (isMobile()) {
36 | basicStore.setSidebarOpen(false)
37 | } else {
38 | basicStore.setSidebarOpen(true)
39 | }
40 | })
41 | onBeforeUnmount(() => {
42 | window.removeEventListener('resize', resizeHandler)
43 | })
44 | }
45 |
--------------------------------------------------------------------------------
/src/hooks/use-self-router.ts:
--------------------------------------------------------------------------------
1 | import router from '@/router'
2 | export const getQueryParam = () => {
3 | const route: any = router.currentRoute
4 | if (route.value?.query.params) {
5 | return JSON.parse(route.value.query.params)
6 | }
7 | }
8 | // vue router
9 | export const routerPush = (name, params) => {
10 | let data = {}
11 | if (params) {
12 | data = {
13 | params: JSON.stringify(params)
14 | }
15 | } else {
16 | data = {}
17 | }
18 | router.push({
19 | name,
20 | query: data
21 | })
22 | }
23 | export const routerReplace = (name, params) => {
24 | let data = {}
25 | if (params) {
26 | data = {
27 | params: JSON.stringify(params)
28 | }
29 | } else {
30 | data = {}
31 | }
32 | router.replace({
33 | name,
34 | query: data
35 | })
36 | }
37 |
38 | export const routeInfo = () => {
39 | return router.currentRoute
40 | }
41 | export const routerBack = () => {
42 | router.go(-1)
43 | }
44 |
--------------------------------------------------------------------------------
/src/icons/SvgIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
32 |
33 |
42 |
--------------------------------------------------------------------------------
/src/icons/common/404.svg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jzfai/vue3-admin-electron/130309705772261805160c23c3b9dd0424c68fe1/src/icons/common/404.svg
--------------------------------------------------------------------------------
/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:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/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/search.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/common/shopping.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/common/sidebar-logo.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/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:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jzfai/vue3-admin-electron/130309705772261805160c23c3b9dd0424c68fe1/src/icons/common/zip.svg
--------------------------------------------------------------------------------
/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/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:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/src/icons/nav-bar/tree.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/nav-bar/user.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/lang/index.ts:
--------------------------------------------------------------------------------
1 | import { createI18n } from 'vue-i18n'
2 | import en from './en'
3 | import zh from './zh'
4 | import settings from '@/settings'
5 | const messages = { en, zh }
6 |
7 | const localeData = {
8 | globalInjection: true, //如果设置true, $t() 函数将注册到全局
9 | legacy: false, //如果想在composition api中使用需要设置为false
10 | locale: settings.defaultLanguage,
11 | messages // set locale messages
12 | }
13 |
14 | export const i18n = createI18n(localeData)
15 | export const setupI18n = {
16 | install(app) {
17 | app.use(i18n)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/layout/app-main/Hamburger.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
21 |
22 |
34 |
--------------------------------------------------------------------------------
/src/layout/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
30 |
31 |
69 |
--------------------------------------------------------------------------------
/src/layout/sidebar/Link.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
32 |
--------------------------------------------------------------------------------
/src/layout/sidebar/Logo.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
38 |
39 |
79 |
--------------------------------------------------------------------------------
/src/layout/sidebar/MenuIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
15 |
16 |
25 |
--------------------------------------------------------------------------------
/src/layout/sidebar/SidebarItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{ langTitle(onlyOneChild.meta?.title) }}
8 |
9 |
10 |
11 |
12 |
13 |
14 | {{ langTitle(item.meta.title) }}
15 |
16 |
23 |
24 |
25 |
26 |
27 |
83 |
--------------------------------------------------------------------------------
/src/layout/sidebar/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
38 |
47 |
48 |
49 |
52 |
53 |
--------------------------------------------------------------------------------
/src/lib/el-svg-icon.ts:
--------------------------------------------------------------------------------
1 | import * as components from '@element-plus/icons-vue'
2 |
3 | export default {
4 | install: (app) => {
5 | for (const key in components) {
6 | const componentConfig = components[key];
7 | app.component(componentConfig.name, componentConfig);
8 | }
9 | },
10 | };
11 |
--------------------------------------------------------------------------------
/src/lib/element-plus.ts:
--------------------------------------------------------------------------------
1 | import * as AllComponent from 'element-plus'
2 | //element-plus中按需引入会引起首次加载过慢
3 | const elementPlusComponentNameArr = ['ElButton']
4 | export default function (app) {
5 | elementPlusComponentNameArr.forEach((component) => {
6 | app.component(component, AllComponent[component])
7 | })
8 | }
9 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import { createPinia } from 'pinia'
3 | import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
4 | import ElementPlus from 'element-plus'
5 | import App from './App.vue'
6 | import router from './router'
7 |
8 | //import theme
9 | import './theme/index.scss'
10 |
11 | //import unocss
12 | import 'uno.css'
13 |
14 | //i18n
15 | import { setupI18n } from '@/lang'
16 |
17 | import '@/styles/index.scss' // global css
18 |
19 | //svg-icon
20 | import 'virtual:svg-icons-register'
21 | import svgIcon from '@/icons/SvgIcon.vue'
22 | import directive from '@/directives'
23 |
24 | //import router intercept
25 | import './permission'
26 |
27 | //import element-plus
28 | import 'element-plus/dist/index.css'
29 | const app = createApp(App)
30 |
31 | //import element-plus svg icon
32 | import ElSvgIcon from "@/lib/el-svg-icon"
33 | app.use(ElSvgIcon)
34 |
35 |
36 | //router
37 | app.use(router)
38 |
39 | //pinia
40 | const pinia = createPinia()
41 | pinia.use(piniaPluginPersistedstate)
42 | app.use(pinia)
43 |
44 | //i18n
45 | app.use(setupI18n)
46 | app.component('SvgIcon', svgIcon)
47 | directive(app)
48 |
49 | //element-plus
50 | app.use(ElementPlus)
51 |
52 | app.mount('#app')
53 |
--------------------------------------------------------------------------------
/src/mock-prod-server.ts:
--------------------------------------------------------------------------------
1 | import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'
2 | //https://cn.vitejs.dev/guide/features.html#glob-import
3 | // @ts-ignore
4 | const modulesFiles = import.meta.glob('../mock/*', { eager: true })
5 | let modules = []
6 | for (const filePath in modulesFiles) {
7 | //读取文件内容到 modules
8 | modules = modules.concat(modulesFiles[filePath].default)
9 | }
10 | export function setupProdMockServer() {
11 | //创建prod mock server
12 | createProdMockServer([...modules])
13 | }
14 |
--------------------------------------------------------------------------------
/src/permission.ts:
--------------------------------------------------------------------------------
1 | import router from '@/router'
2 | import {progressClose, progressStart } from '@/hooks/use-permission'
3 | import { useBasicStore } from '@/store/basic'
4 | import { langTitle } from '@/hooks/use-common'
5 | import settings from "@/settings";
6 |
7 | //路由进入前拦截
8 | //to:将要进入的页面 vue-router4.0 不推荐使用next()
9 | const whiteList = ['/login', '/404', '/401'] // no redirect whitelist
10 | router.beforeEach(async (to) => {
11 | progressStart()
12 | document.title = langTitle(to.meta?.title) // i18 page title
13 | const basicStore = useBasicStore()
14 | //not login
15 | if (!settings.isNeedLogin) {
16 | basicStore.setFilterAsyncRoutes([])
17 | return true
18 | }
19 | //1.判断token
20 | if (basicStore.token) {
21 | if (to.path === '/login') {
22 | return '/'
23 | } else {
24 | basicStore.setFilterAsyncRoutes([])
25 | return true
26 | }
27 | } else {
28 | if (!whiteList.includes(to.path)) {
29 | return `/login?redirect=${to.path}`
30 | } else {
31 | return true
32 | }
33 | }
34 | })
35 | //路由进入后拦截
36 | router.afterEach(() => {
37 | progressClose()
38 | })
39 |
--------------------------------------------------------------------------------
/src/plugins/vite-plugin-setup-extend/index.ts:
--------------------------------------------------------------------------------
1 | import { parse } from '@vue/compiler-sfc'
2 | import { render } from 'ejs'
3 | import type { Plugin } from 'vite'
4 | export default ({ inject }): Plugin => {
5 | return {
6 | name: 'vite-plugin-setup-extend',
7 | enforce: 'pre',
8 | // configResolved(resolvedConfig) {
9 | // viteConfig = resolvedConfig
10 | // },
11 | async transformIndexHtml(html) {
12 | const result = await render(html, { ...inject })
13 | return result
14 | },
15 | transform(code, id) {
16 | if (/\.vue$/.test(id)) {
17 | const { descriptor } = parse(code)
18 | if (!descriptor?.scriptSetup?.setup) {
19 | return null
20 | }
21 | const { lang, name } = descriptor.scriptSetup?.attrs || {}
22 | const dillStr = headString(lang, name)
23 | code += dillStr
24 | return code
25 | }
26 | }
27 | }
28 | }
29 |
30 | const headString = (lang, name) => {
31 | return `\n`
37 | }
38 |
--------------------------------------------------------------------------------
/src/router/modules/electron.ts:
--------------------------------------------------------------------------------
1 | import Layout from '@/layout/index.vue'
2 | const electron = {
3 | path: '/electron',
4 | component: Layout,
5 | meta: { title: 'electron', icon: 'user' },
6 | alwaysShow: true,
7 | children: [
8 | {
9 | path: 'main-renderer-comm',
10 | component: () => import('@/views/electron/MainRendererComm.vue'),
11 | name: 'MainRenderer',
12 | meta: { title: 'Main Renderer' }
13 | },
14 | {
15 | path: 'electron-demo',
16 | component: () => import('@/views/electron/ElectronDemo.vue'),
17 | name: 'ElectronDemo',
18 | meta: { title: 'Electron Demo' }
19 | },
20 | {
21 | path: 'fs-extra',
22 | component: () => import('@/views/electron/FsExtra.vue'),
23 | name: 'FsExtra',
24 | meta: { title: 'fs-extra' }
25 | },
26 | {
27 | path: 'notify-netListen',
28 | component: () => import('@/views/electron/NotifyNetListen.vue'),
29 | name: 'NotifyNetListen',
30 | meta: { title: 'Notify Net' }
31 | },
32 | {
33 | path: 'nedb-demo',
34 | component: () => import('@/views/electron/NedbDemo.vue'),
35 | name: 'NedbDemo',
36 | meta: { title: 'NedbDemo' }
37 | },
38 | {
39 | path: 'indexDb-demo.vue',
40 | component: () => import('@/views/electron/IndexDbDemo.vue'),
41 | name: 'IndexDbDemo',
42 | meta: { title: 'IndexDbDemo' }
43 | }
44 | ]
45 | }
46 |
47 | export default electron
48 |
--------------------------------------------------------------------------------
/src/store/config.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia'
2 | import { langTitle } from '@/hooks/use-common'
3 | import settings from '@/settings'
4 | import { toggleHtmlClass } from '@/theme/utils'
5 | import { i18n } from '@/lang'
6 | export const useConfigStore = defineStore('config', {
7 | state: () => {
8 | return {
9 | language: settings.defaultLanguage,
10 | theme: settings.defaultTheme,
11 | size: settings.defaultSize
12 | }
13 | },
14 | persist: {
15 | storage: localStorage,
16 | paths: ['language', 'theme', 'size']
17 | },
18 | actions: {
19 | setTheme(data: string) {
20 | this.theme = data
21 | toggleHtmlClass(data)
22 | },
23 | setSize(data: string) {
24 | this.size = data
25 | },
26 | setLanguage(lang: string, title) {
27 | const { locale }: any = i18n.global
28 | this.language = lang
29 | locale.value = lang
30 | document.title = langTitle(title) // i18 page title
31 | }
32 | }
33 | })
34 |
--------------------------------------------------------------------------------
/src/store/tags-view.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia'
2 | import setting from '@/settings'
3 | export const useTagsViewStore = defineStore('tagsView', {
4 | state: () => {
5 | return {
6 | visitedViews: [] //tag标签数组
7 | }
8 | },
9 | actions: {
10 | addVisitedView(view) {
11 | this.$patch((state: any) => {
12 | //判断添加的标签存在直接返回
13 | if (state.visitedViews.some((v) => v.path === view.path)) return
14 | //添加的数量如果大于 setting.tagsViewNum,则替换最后一个元素,否则在visitedViews数组后插入一个元素
15 | if (state.visitedViews.length >= setting.tagsViewNum) {
16 | state.visitedViews.pop()
17 | state.visitedViews.push(
18 | Object.assign({}, view, {
19 | title: view.meta.title || 'no-name'
20 | })
21 | )
22 | } else {
23 | state.visitedViews.push(
24 | Object.assign({}, view, {
25 | title: view.meta.title || 'no-name'
26 | })
27 | )
28 | }
29 | })
30 | },
31 | delVisitedView(view) {
32 | return new Promise((resolve) => {
33 | this.$patch((state: any) => {
34 | //匹配view.path元素将其删除
35 | for (const [i, v] of state.visitedViews.entries()) {
36 | if (v.path === view.path) {
37 | state.visitedViews.splice(i, 1)
38 | break
39 | }
40 | }
41 | resolve([...state.visitedViews])
42 | })
43 | })
44 | },
45 | delOthersVisitedViews(view) {
46 | return new Promise((resolve) => {
47 | this.$patch((state) => {
48 | state.visitedViews = state.visitedViews.filter((v: ObjKeys) => {
49 | return v.meta.affix || v.path === view.path
50 | })
51 | resolve([...state.visitedViews])
52 | })
53 | })
54 | },
55 | delAllVisitedViews() {
56 | return new Promise((resolve) => {
57 | this.$patch((state) => {
58 | // keep affix tags
59 | state.visitedViews = state.visitedViews.filter((tag: ObjKeys) => tag.meta?.affix)
60 | resolve([...state.visitedViews])
61 | })
62 | })
63 | }
64 | }
65 | })
66 |
--------------------------------------------------------------------------------
/src/styles/index.scss:
--------------------------------------------------------------------------------
1 | //scss 语法糖包含常用的布局方式 flex column
2 | @import './scss-suger.scss';
3 | //重置 element-plus 样式
4 | @import './reset-elemenet-plus-style.scss';
5 | //动画文件
6 | @import './transition.scss';
7 |
8 | //reset style
9 | body {
10 | height: 100%;
11 | margin: 0;
12 | padding: 0;
13 | font-size: 14px;
14 | }
15 | * {
16 | box-sizing: border-box;
17 | }
18 | *::before,
19 | *::after {
20 | box-sizing: border-box;
21 | }
22 | a:focus,
23 | a:active {
24 | outline: none;
25 | }
26 | a,
27 | a:focus,
28 | a:hover {
29 | cursor: pointer;
30 | color: inherit;
31 | text-decoration: none;
32 | }
33 |
34 | h1,
35 | h2,
36 | h3,
37 | h4,
38 | h5,
39 | h6 {
40 | line-height: 1;
41 | font-weight: 400;
42 | margin: 0;
43 | padding: 0;
44 | }
45 | span,
46 | output {
47 | display: inline-block;
48 | line-height: 1;
49 | }
50 |
51 | //scroll
52 | @mixin main-show-wh() {
53 | /* css 声明 */
54 | //height: calc(100vh - #{$navBarHeight} - #{$tagViewHeight} - #{$appMainPadding * 2});
55 | height: calc(100vh - #{var(--nav-bar-height)} - #{var(--tag-view-height)} - #{calc(var(--app-main-padding) * 2)});
56 | width: 100%;
57 | }
58 | .scroll-y {
59 | @include main-show-wh();
60 | overflow-y: auto;
61 | }
62 | .scroll-x {
63 | @include main-show-wh();
64 | overflow-x: auto;
65 | }
66 | .scroll-xy {
67 | @include main-show-wh();
68 | overflow: auto;
69 | }
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/styles/init-loading.css:
--------------------------------------------------------------------------------
1 | /*开屏loading样式设置*/
2 | .loader-wrapper{
3 | display: flex;
4 | flex-direction: column;
5 | justify-content: center;
6 | align-items: center;
7 | height: 80vh;
8 | }
9 |
10 | .loading-gif{
11 |
12 | }
13 |
14 | .load_title{
15 | margin-top: 30px;
16 | font-size: 16px;
17 | }
18 |
--------------------------------------------------------------------------------
/src/styles/reset-elemenet-plus-style.scss:
--------------------------------------------------------------------------------
1 | //leave the padding of el-scroll sidebar
2 | .el-scrollbar__view {
3 | padding-bottom: 80px;
4 | }
5 |
6 |
7 | .el-scrollbar{
8 | --el-menu-base-level-padding:15px;
9 | }
10 |
--------------------------------------------------------------------------------
/src/styles/transition.scss:
--------------------------------------------------------------------------------
1 | // vue global transition css define
2 | /* sidebar-logo-fade */
3 | .sidebar-logo-fade-enter-active {
4 | transition: opacity var(--logo-switch-duration);
5 | }
6 | .sidebar-logo-fade-enter-from,
7 | .sidebar-logo-fade-leave-to {
8 | opacity: 0;
9 | }
10 |
11 | /* fade-transform AppMain*/
12 | .fade-transform-leave-active,
13 | .fade-transform-enter-active {
14 | transition: all var(--page-transform-duration);
15 | }
16 |
17 | .fade-transform-enter-from {
18 | opacity: 0;
19 | transform: translateX(-10px);
20 | }
21 |
22 | .fade-transform-leave-to {
23 | opacity: 0;
24 | transform: translateX(10px);
25 | }
26 | .fade-transform-active {
27 | position: absolute;
28 | }
29 |
30 | /* breadcrumb transition */
31 | .breadcrumb-enter-active,
32 | .breadcrumb-leave-active {
33 | transition: all var(--breadcrumb-change-duration);
34 | }
35 |
36 | .breadcrumb-enter-from,
37 | .breadcrumb-leave-active {
38 | opacity: 0;
39 | transform: translateX(10px);
40 | }
41 |
42 | .breadcrumb-leave-active {
43 | position: absolute;
44 | }
45 |
--------------------------------------------------------------------------------
/src/theme/base/custom/ct-css-vars.scss:
--------------------------------------------------------------------------------
1 | html.base-theme {
2 | /*element-plus section */
3 | --el-menu-active-color: #409eff;
4 | --el-menu-text-color: #bfcbd9;
5 | --el-menu-hover-text-color: var(--el-color-primary);
6 | --el-menu-bg-color: #304156;
7 | --el-menu-hover-bg-color: #263445;
8 | --el-menu-item-height: 56px;
9 | --el-menu-border-color: none;
10 | /*layout section*/
11 | //layout
12 | --layout-border-left-color: #ddd;
13 | //Breadcrumb
14 | --breadcrumb-no-redirect: #97a8be;
15 | //Hamburger
16 | --hamburger-color: #2b2f3a;
17 | --hamburger-width: 20px;
18 | --hamburger-height: 20px;
19 | //Sidebar
20 | --sidebar-el-icon-size: 20px;
21 | --sidebar-logo-background: #2b2f3a;
22 | --sidebar-logo-color: #ff9901;
23 | --sidebar-logo-width: 32px;
24 | --sidebar-logo-height: 32px;
25 | --sidebar-logo-title-color: #fff;
26 | --side-bar-width: 210px;
27 | --side-bar-border-right-color: #eee;
28 | //TagsView
29 | --tags-view-background: #fff;
30 | --tags-view-border-bottom: #eee;
31 | --tags-view-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);
32 | --tags-view-item-background: #fff;
33 | --tags-view-item-border-color: #d8dce5;
34 | --tags-view-item-color: #495060;
35 | --tag-view-height: 32px;
36 | --tags-view-item-active-background: #42b983;
37 | --tags-view-item-active-color: #fff;
38 | --tags-view-item-active-border-color: #42b983;
39 | --tags-view-contextmenu-background: #fff;
40 | --tags-view-contextmenu-color: #333;
41 | --tags-view-contextmenu-box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
42 | --tags-view-contextmenu-hover-background: #eee;
43 | //close-icon
44 | --tags-view-close-icon-hover-background: #b4bccc;
45 | --tags-view-close-icon-hover-color: #fff;
46 | //AppMain.vue
47 | --app-main-padding: 10px;
48 | --app-main-background: #fff;
49 | //Navbar.vue
50 | --nav-bar-height: 50px;
51 | --nav-bar-background: #fff;
52 | --nav-bar-box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
53 | --nav-bar-right-menu-background: #fff;
54 |
55 | //transition 动画
56 | //侧边栏切换动画时长
57 | --sideBar-switch-duration: 0.2s;
58 | //logo切换动画时长
59 | --logo-switch-duration: 1s;
60 | //页面动画时长
61 | --page-transform-duration: 0.2s;
62 | //面包屑导航动画时长
63 | --breadcrumb-change-duration: 0.2s;
64 |
65 | //进度条颜色
66 | --pregress-bar-color: #409eff;
67 | }
68 |
--------------------------------------------------------------------------------
/src/theme/base/element-plus/checkbox.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | .el-checkbox {
3 | --el-checkbox-font-size: 14px;
4 | --el-checkbox-font-weight: var(--el-font-weight-primary);
5 | --el-checkbox-text-color: #262626;
6 | --el-checkbox-input-height: 14px;
7 | --el-checkbox-input-width: 14px;
8 | --el-checkbox-border-radius: var(--el-border-radius-small);
9 | --el-checkbox-bg-color: var(--el-fill-color-blank);
10 | --el-checkbox-input-border: var(--el-border);
11 |
12 | //disabled
13 | --el-checkbox-disabled-border-color: var(--el-border-color);
14 | --el-checkbox-disabled-input-fill: var(--el-fill-color-light);
15 | --el-checkbox-disabled-icon-color: var(--el-text-color-placeholder);
16 | --el-checkbox-disabled-checked-input-fill: var(--el-border-color-extra-light);
17 | --el-checkbox-disabled-checked-input-border-color: var(--el-border-color);
18 | --el-checkbox-disabled-checked-icon-color: var(--el-text-color-placeholder);
19 |
20 | //check
21 | --el-checkbox-checked-text-color: #262626;
22 | --el-checkbox-checked-input-border-color: transparent;
23 | --el-checkbox-checked-bg-color: #c72210;
24 | --el-checkbox-checked-icon-color: #ffffff;
25 | --el-checkbox-input-border-color-hover: #c72210;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/theme/base/element-plus/css-vars.scss:
--------------------------------------------------------------------------------
1 | @use 'sass:map';
2 |
3 | @use './var' as *;
4 | @use '../../mixins/var' as *;
5 | @use '../../mixins/mixins' as *;
6 |
7 | html.china-red {
8 | color-scheme: china-red;
9 | @each $type in (primary, success, warning, danger, error, info) {
10 | @include set-css-color-rgb($colors, $type);
11 | }
12 |
13 | @each $type in (primary, success, warning, danger, error, info) {
14 | @include set-css-color-type($colors, $type);
15 | }
16 | //--el-color-primary: #c72210;
17 | }
18 |
--------------------------------------------------------------------------------
/src/theme/base/element-plus/form.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | //date
3 | .el-date-range-picker {
4 | --el-datepicker-text-color: var(--el-text-color-regular);
5 | --el-datepicker-off-text-color: var(--el-text-color-placeholder);
6 | --el-datepicker-header-text-color: var(--el-text-color-regular);
7 | --el-datepicker-icon-color: var(--el-text-color-primary);
8 | --el-datepicker-border-color: var(--el-disabled-border-color);
9 | --el-datepicker-inner-border-color: var(--el-border-color-light);
10 | --el-datepicker-inrange-bg-color: #ffece6;
11 | --el-datepicker-inrange-hover-bg-color: var(--el-border-color-extra-light);
12 | --el-datepicker-active-color: var(--el-color-primary);
13 | --el-datepicker-hover-text-color: var(--el-color-primary);
14 | }
15 |
16 | .el-select-dropdown__item.hover,
17 | .el-select-dropdown__item:hover {
18 | background-color: #ffece6;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/theme/base/element-plus/pagination.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | .el-pagination {
3 | --el-text-color-regular: #8c8c8c;
4 | --el-pagination-font-size: 14px;
5 | --el-pagination-bg-color: var(--el-fill-color-blank);
6 | --el-pagination-text-color: var(--el-text-color-primary);
7 | --el-pagination-border-radius: 3px;
8 | --el-pagination-button-color: var(--el-text-color-primary);
9 | --el-pagination-button-width: 32px;
10 | --el-pagination-button-height: 32px;
11 | --el-pagination-button-disabled-color: var(--el-text-color-placeholder);
12 | --el-pagination-button-disabled-bg-color: var(--el-fill-color-blank);
13 | --el-pagination-button-bg-color: var(--el-fill-color);
14 | --el-pagination-hover-color: var(--el-color-primary);
15 | --el-pagination-height-extra-small: 24px;
16 | --el-pagination-line-height-extra-small: var(--el-pagination-height-extra-small);
17 | white-space: nowrap;
18 | padding: 2px 5px;
19 | color: var(--el-pagination-text-color);
20 | font-weight: 400;
21 | display: flex;
22 | align-items: center;
23 | }
24 |
25 | .el-pagination__total {
26 | margin-right: 16px;
27 | font-weight: 400;
28 | color: var(--el-text-color-regular);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/theme/base/element-plus/redio.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | .el-radio {
3 | --el-radio-font-size: var(--el-font-size-base);
4 | --el-radio-text-color: #262626;
5 | --el-radio-font-weight: var(--el-font-weight-primary);
6 | --el-radio-input-height: 14px;
7 | --el-radio-input-width: 14px;
8 | --el-radio-input-border-radius: var(--el-border-radius-circle);
9 | --el-radio-input-bg-color: var(--el-fill-color-blank);
10 | --el-radio-input-border: var(--el-border);
11 | --el-radio-input-border-color: transparent;
12 | //--el-radio-input-border-color-hover: transparent;
13 | }
14 |
15 | .el-radio__input.is-checked + .el-radio__label {
16 | color: #262626;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/theme/base/element-plus/table.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | .el-table {
3 | --el-table-border-color: #f0f0f0;
4 | --el-table-border: 1px solid #f0f0f0;
5 | --el-table-text-color: var(--el-text-color-regular);
6 | --el-table-header-text-color: var(--el-text-color-secondary);
7 | --el-table-row-hover-bg-color: #ffece6;
8 | --el-table-current-row-bg-color: var(--el-color-primary-light-9);
9 | --el-table-header-bg-color: #fafafa;
10 | --el-table-fixed-box-shadow: var(--el-box-shadow-light);
11 | --el-table-bg-color: var(--el-fill-color-blank);
12 | --el-table-tr-bg-color: var(--el-fill-color-blank);
13 | --el-table-expanded-cell-bg-color: var(--el-fill-color-blank);
14 | --el-table-fixed-left-column: inset 10px 0 10px -10px rgba(0, 0, 0, 0.15);
15 | --el-table-fixed-right-column: inset -10px 0 10px -10px rgba(0, 0, 0, 0.15);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/theme/base/element-plus/var.scss:
--------------------------------------------------------------------------------
1 | /* Element Chalk Variables */
2 | @use 'sass:math';
3 | @use 'sass:map';
4 | @use '../../mixins/function.scss' as *;
5 |
6 | // types
7 | $types: primary, success, warning, danger, error, info;
8 |
9 | // change color
10 | $colors: () !default;
11 | $colors: map.deep-merge(
12 | (
13 | 'white': #ffffff,
14 | 'black': #000000,
15 | 'primary': (
16 | 'base': #c72210//#409eff
17 | ),
18 | 'success': (
19 | 'base': #45b207
20 | ),
21 | 'warning': (
22 | 'base': #ec8828
23 | ),
24 | 'danger': (
25 | 'base': #f56c6c
26 | ),
27 | 'error': (
28 | 'base': #d24934
29 | ),
30 | 'info': (
31 | 'base': #909399
32 | )
33 | ),
34 | $colors
35 | );
36 |
37 | $color-white: map.get($colors, 'white') !default;
38 | $color-black: map.get($colors, 'black') !default;
39 | $color-primary: map.get($colors, 'primary', 'base') !default;
40 | $color-success: map.get($colors, 'success', 'base') !default;
41 | $color-warning: map.get($colors, 'warning', 'base') !default;
42 | $color-danger: map.get($colors, 'danger', 'base') !default;
43 | $color-error: map.get($colors, 'error', 'base') !default;
44 | $color-info: map.get($colors, 'info', 'base') !default;
45 |
46 | //$colors添加 --el-color-primary-light-7
47 | @mixin set-color-mix-level($type, $number, $mode: 'light', $mix-color: $color-white) {
48 | $colors: map.deep-merge(
49 | (
50 | $type: (
51 | '#{$mode}-#{$number}': mix($mix-color, map.get($colors, $type, 'base'), math.percentage(math.div($number, 10)))
52 | )
53 | ),
54 | $colors
55 | ) !global;
56 | }
57 |
58 | // $colors.primary.light-i
59 | @each $type in $types {
60 | @for $i from 1 through 9 {
61 | @include set-color-mix-level($type, $i, 'light', $color-white);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/theme/base/index.scss:
--------------------------------------------------------------------------------
1 | /*china-red*/
2 | //element-plus
3 | @use "./element-plus/css-vars";
4 | @use "./element-plus/var";
5 | @use "./element-plus/button";
6 | @use "./element-plus/checkbox";
7 | @use "./element-plus/redio";
8 | @use "./element-plus/pagination";
9 | @use "./element-plus/form";
10 | @use "./element-plus/table";
11 |
12 | //custom
13 | @use "./custom/ct-css-vars";
14 |
--------------------------------------------------------------------------------
/src/theme/china-red/element-plus/checkbox.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | .el-checkbox {
3 | --el-checkbox-font-size: 14px;
4 | --el-checkbox-font-weight: var(--el-font-weight-primary);
5 | --el-checkbox-text-color: #262626;
6 | --el-checkbox-input-height: 14px;
7 | --el-checkbox-input-width: 14px;
8 | --el-checkbox-border-radius: var(--el-border-radius-small);
9 | --el-checkbox-bg-color: var(--el-fill-color-blank);
10 | --el-checkbox-input-border: var(--el-border);
11 |
12 | //disabled
13 | --el-checkbox-disabled-border-color: var(--el-border-color);
14 | --el-checkbox-disabled-input-fill: var(--el-fill-color-light);
15 | --el-checkbox-disabled-icon-color: var(--el-text-color-placeholder);
16 | --el-checkbox-disabled-checked-input-fill: var(--el-border-color-extra-light);
17 | --el-checkbox-disabled-checked-input-border-color: var(--el-border-color);
18 | --el-checkbox-disabled-checked-icon-color: var(--el-text-color-placeholder);
19 |
20 | //check
21 | --el-checkbox-checked-text-color: #262626;
22 | --el-checkbox-checked-input-border-color: transparent;
23 | --el-checkbox-checked-bg-color: #c72210;
24 | --el-checkbox-checked-icon-color: #ffffff;
25 | --el-checkbox-input-border-color-hover: #c72210;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/theme/china-red/element-plus/css-vars.scss:
--------------------------------------------------------------------------------
1 | @use 'sass:map';
2 |
3 | @use './var' as *;
4 | @use '../../mixins/var' as *;
5 | @use '../../mixins/mixins' as *;
6 |
7 | html.china-red {
8 | color-scheme: china-red;
9 | @each $type in (primary, success, warning, danger, error, info) {
10 | @include set-css-color-rgb($colors, $type);
11 | }
12 |
13 | @each $type in (primary, success, warning, danger, error, info) {
14 | @include set-css-color-type($colors, $type);
15 | }
16 | //--el-color-primary: #c72210;
17 | }
18 |
--------------------------------------------------------------------------------
/src/theme/china-red/element-plus/form.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | //date
3 | .el-date-range-picker {
4 | --el-datepicker-text-color: var(--el-text-color-regular);
5 | --el-datepicker-off-text-color: var(--el-text-color-placeholder);
6 | --el-datepicker-header-text-color: var(--el-text-color-regular);
7 | --el-datepicker-icon-color: var(--el-text-color-primary);
8 | --el-datepicker-border-color: var(--el-disabled-border-color);
9 | --el-datepicker-inner-border-color: var(--el-border-color-light);
10 | --el-datepicker-inrange-bg-color: #ffece6;
11 | --el-datepicker-inrange-hover-bg-color: var(--el-border-color-extra-light);
12 | --el-datepicker-active-color: var(--el-color-primary);
13 | --el-datepicker-hover-text-color: var(--el-color-primary);
14 | }
15 |
16 | .el-select-dropdown__item.hover,
17 | .el-select-dropdown__item:hover {
18 | background-color: #ffece6;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/theme/china-red/element-plus/pagination.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | .el-pagination {
3 | --el-text-color-regular: #8c8c8c;
4 | --el-pagination-font-size: 14px;
5 | --el-pagination-bg-color: var(--el-fill-color-blank);
6 | --el-pagination-text-color: var(--el-text-color-primary);
7 | --el-pagination-border-radius: 3px;
8 | --el-pagination-button-color: var(--el-text-color-primary);
9 | --el-pagination-button-width: 32px;
10 | --el-pagination-button-height: 32px;
11 | --el-pagination-button-disabled-color: var(--el-text-color-placeholder);
12 | --el-pagination-button-disabled-bg-color: var(--el-fill-color-blank);
13 | --el-pagination-button-bg-color: var(--el-fill-color);
14 | --el-pagination-hover-color: var(--el-color-primary);
15 | --el-pagination-height-extra-small: 24px;
16 | --el-pagination-line-height-extra-small: var(--el-pagination-height-extra-small);
17 | white-space: nowrap;
18 | padding: 2px 5px;
19 | color: var(--el-pagination-text-color);
20 | font-weight: 400;
21 | display: flex;
22 | align-items: center;
23 | }
24 |
25 | .el-pagination__total {
26 | margin-right: 16px;
27 | font-weight: 400;
28 | color: var(--el-text-color-regular);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/theme/china-red/element-plus/redio.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | .el-radio {
3 | --el-radio-font-size: var(--el-font-size-base);
4 | --el-radio-text-color: #262626;
5 | --el-radio-font-weight: var(--el-font-weight-primary);
6 | --el-radio-input-height: 14px;
7 | --el-radio-input-width: 14px;
8 | --el-radio-input-border-radius: var(--el-border-radius-circle);
9 | --el-radio-input-bg-color: var(--el-fill-color-blank);
10 | --el-radio-input-border: var(--el-border);
11 | --el-radio-input-border-color: transparent;
12 | //--el-radio-input-border-color-hover: transparent;
13 | }
14 |
15 | .el-radio__input.is-checked + .el-radio__label {
16 | color: #262626;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/theme/china-red/element-plus/table.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | .el-table {
3 | --el-table-border-color: #f0f0f0;
4 | --el-table-border: 1px solid #f0f0f0;
5 | --el-table-text-color: var(--el-text-color-regular);
6 | --el-table-header-text-color: var(--el-text-color-secondary);
7 | --el-table-row-hover-bg-color: #ffece6;
8 | --el-table-current-row-bg-color: var(--el-color-primary-light-9);
9 | --el-table-header-bg-color: #fafafa;
10 | --el-table-fixed-box-shadow: var(--el-box-shadow-light);
11 | --el-table-bg-color: var(--el-fill-color-blank);
12 | --el-table-tr-bg-color: var(--el-fill-color-blank);
13 | --el-table-expanded-cell-bg-color: var(--el-fill-color-blank);
14 | --el-table-fixed-left-column: inset 10px 0 10px -10px rgba(0, 0, 0, 0.15);
15 | --el-table-fixed-right-column: inset -10px 0 10px -10px rgba(0, 0, 0, 0.15);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/theme/china-red/element-plus/var.scss:
--------------------------------------------------------------------------------
1 | /* Element Chalk Variables */
2 | @use 'sass:math';
3 | @use 'sass:map';
4 | @use '../../mixins/function.scss' as *;
5 |
6 | // types
7 | $types: primary, success, warning, danger, error, info;
8 |
9 | // change color
10 | $colors: () !default;
11 | $colors: map.deep-merge(
12 | (
13 | 'white': #ffffff,
14 | 'black': #000000,
15 | 'primary': (
16 | 'base': #c72210//#409eff
17 | ),
18 | 'success': (
19 | 'base': #45b207
20 | ),
21 | 'warning': (
22 | 'base': #ec8828
23 | ),
24 | 'danger': (
25 | 'base': #f56c6c
26 | ),
27 | 'error': (
28 | 'base': #d24934
29 | ),
30 | 'info': (
31 | 'base': #909399
32 | )
33 | ),
34 | $colors
35 | );
36 |
37 | $color-white: map.get($colors, 'white') !default;
38 | $color-black: map.get($colors, 'black') !default;
39 | $color-primary: map.get($colors, 'primary', 'base') !default;
40 | $color-success: map.get($colors, 'success', 'base') !default;
41 | $color-warning: map.get($colors, 'warning', 'base') !default;
42 | $color-danger: map.get($colors, 'danger', 'base') !default;
43 | $color-error: map.get($colors, 'error', 'base') !default;
44 | $color-info: map.get($colors, 'info', 'base') !default;
45 |
46 | //$colors添加 --el-color-primary-light-7
47 | @mixin set-color-mix-level($type, $number, $mode: 'light', $mix-color: $color-white) {
48 | $colors: map.deep-merge(
49 | (
50 | $type: (
51 | '#{$mode}-#{$number}': mix($mix-color, map.get($colors, $type, 'base'), math.percentage(math.div($number, 10)))
52 | )
53 | ),
54 | $colors
55 | ) !global;
56 | }
57 |
58 | // $colors.primary.light-i
59 | @each $type in $types {
60 | @for $i from 1 through 9 {
61 | @include set-color-mix-level($type, $i, 'light', $color-white);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/theme/china-red/index.scss:
--------------------------------------------------------------------------------
1 | /*china-red*/
2 | //element-plus
3 | @use "./element-plus/css-vars";
4 | @use "./element-plus/var";
5 | @use "./element-plus/button";
6 | @use "./element-plus/checkbox";
7 | @use "./element-plus/redio";
8 | @use "./element-plus/pagination";
9 | @use "./element-plus/form";
10 | @use "./element-plus/table";
11 |
12 | //custom
13 | @use "./custom/ct-css-vars";
14 |
--------------------------------------------------------------------------------
/src/theme/dark/custom/ct-css-vars.scss:
--------------------------------------------------------------------------------
1 | html.dark {
2 | /*element-plus section */
3 | --el-menu-active-color: #409eff;
4 | --el-menu-text-color: #bfcbd9;
5 | --el-menu-hover-text-color: var(--el-color-primary);
6 | --el-menu-bg-color: #304156;
7 | --el-menu-hover-bg-color: #263445;
8 | --el-menu-item-height: 56px;
9 | --el-menu-border-color: none;
10 | /*layout section*/
11 | //layout
12 | --layout-border-left-color: #ddd;
13 | //Breadcrumb
14 | --breadcrumb-no-redirect: #97a8be;
15 | //Hamburger
16 | --hamburger-color: #fff;
17 | --hamburger-width: 20px;
18 | --hamburger-height: 20px;
19 | --el-text-color-primary: #fff;
20 | //Sidebar
21 | --sidebar-el-icon-size: 20px;
22 | --sidebar-logo-background: #2b2f3a;
23 | --sidebar-logo-color: #ff9901;
24 | --sidebar-logo-width: 32px;
25 | --sidebar-logo-height: 32px;
26 | --sidebar-logo-title-color: #fff;
27 | --side-bar-width: 210px;
28 | --side-bar-border-right-color: #2b2f3a;
29 | //TagsView
30 | --tags-view-background: #304156;
31 | --tags-view-border-bottom: #2b2f3a;
32 | --tags-view-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);
33 | --tags-view-item-background: #fff;
34 | --tags-view-item-border-color: #d8dce5;
35 | --tags-view-item-color: #495060;
36 | --tag-view-height: 32px;
37 | --tags-view-item-active-background: #42b983;
38 | --tags-view-item-active-color: #fff;
39 | --tags-view-item-active-border-color: #42b983;
40 | --tags-view-contextmenu-background: #fff;
41 | --tags-view-contextmenu-color: #333;
42 | --tags-view-contextmenu-box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
43 | --tags-view-contextmenu-hover-background: #eee;
44 | //close-icon
45 | --tags-view-close-icon-hover-background: #b4bccc;
46 | --tags-view-close-icon-hover-color: #fff;
47 | //AppMain.vue
48 | --app-main-padding: 10px;
49 | --app-main-background: #304156;
50 | //Navbar.vue
51 | --nav-bar-height: 50px;
52 | --nav-bar-background: #2b2f3a;
53 | --nav-bar-box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
54 | --nav-bar-right-menu-background: #2b2f3a;
55 |
56 | //transition 动画
57 | //侧边栏切换动画时长
58 | --sideBar-switch-duration: 0.2s;
59 | //logo切换动画时长
60 | --logo-switch-duration: 1s;
61 | //页面动画时长
62 | --page-transform-duration: 0.2s;
63 | //面包屑导航动画时长
64 | --breadcrumb-change-duration: 0.2s;
65 |
66 | //进度条颜色
67 | --pregress-bar-color: #409eff;
68 | }
69 |
--------------------------------------------------------------------------------
/src/theme/dark/element-plus/checkbox.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | .el-checkbox {
3 | --el-checkbox-font-size: 14px;
4 | --el-checkbox-font-weight: var(--el-font-weight-primary);
5 | --el-checkbox-text-color: #262626;
6 | --el-checkbox-input-height: 14px;
7 | --el-checkbox-input-width: 14px;
8 | --el-checkbox-border-radius: var(--el-border-radius-small);
9 | --el-checkbox-bg-color: var(--el-fill-color-blank);
10 | --el-checkbox-input-border: var(--el-border);
11 |
12 | //disabled
13 | --el-checkbox-disabled-border-color: var(--el-border-color);
14 | --el-checkbox-disabled-input-fill: var(--el-fill-color-light);
15 | --el-checkbox-disabled-icon-color: var(--el-text-color-placeholder);
16 | --el-checkbox-disabled-checked-input-fill: var(--el-border-color-extra-light);
17 | --el-checkbox-disabled-checked-input-border-color: var(--el-border-color);
18 | --el-checkbox-disabled-checked-icon-color: var(--el-text-color-placeholder);
19 |
20 | //check
21 | --el-checkbox-checked-text-color: #262626;
22 | --el-checkbox-checked-input-border-color: transparent;
23 | --el-checkbox-checked-bg-color: #c72210;
24 | --el-checkbox-checked-icon-color: #ffffff;
25 | --el-checkbox-input-border-color-hover: #c72210;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/theme/dark/element-plus/css-vars.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jzfai/vue3-admin-electron/130309705772261805160c23c3b9dd0424c68fe1/src/theme/dark/element-plus/css-vars.css
--------------------------------------------------------------------------------
/src/theme/dark/element-plus/css-vars.css.map:
--------------------------------------------------------------------------------
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"}
--------------------------------------------------------------------------------
/src/theme/dark/element-plus/css-vars.scss:
--------------------------------------------------------------------------------
1 | @use 'sass:map';
2 |
3 | @use './var' as *;
4 | @use '../../mixins/var' as *;
5 | @use '../../mixins/mixins' as *;
6 |
7 | html.china-red {
8 | color-scheme: china-red;
9 | @each $type in (primary, success, warning, danger, error, info) {
10 | @include set-css-color-rgb($colors, $type);
11 | }
12 |
13 | @each $type in (primary, success, warning, danger, error, info) {
14 | @include set-css-color-type($colors, $type);
15 | }
16 | //--el-color-primary: #c72210;
17 | }
18 |
--------------------------------------------------------------------------------
/src/theme/dark/element-plus/form.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | //date
3 | .el-date-range-picker {
4 | --el-datepicker-text-color: var(--el-text-color-regular);
5 | --el-datepicker-off-text-color: var(--el-text-color-placeholder);
6 | --el-datepicker-header-text-color: var(--el-text-color-regular);
7 | --el-datepicker-icon-color: var(--el-text-color-primary);
8 | --el-datepicker-border-color: var(--el-disabled-border-color);
9 | --el-datepicker-inner-border-color: var(--el-border-color-light);
10 | --el-datepicker-inrange-bg-color: #ffece6;
11 | --el-datepicker-inrange-hover-bg-color: var(--el-border-color-extra-light);
12 | --el-datepicker-active-color: var(--el-color-primary);
13 | --el-datepicker-hover-text-color: var(--el-color-primary);
14 | }
15 |
16 | .el-select-dropdown__item.hover,
17 | .el-select-dropdown__item:hover {
18 | background-color: #ffece6;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/theme/dark/element-plus/pagination.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | .el-pagination {
3 | --el-text-color-regular: #8c8c8c;
4 | --el-pagination-font-size: 14px;
5 | --el-pagination-bg-color: var(--el-fill-color-blank);
6 | --el-pagination-text-color: var(--el-text-color-primary);
7 | --el-pagination-border-radius: 3px;
8 | --el-pagination-button-color: var(--el-text-color-primary);
9 | --el-pagination-button-width: 32px;
10 | --el-pagination-button-height: 32px;
11 | --el-pagination-button-disabled-color: var(--el-text-color-placeholder);
12 | --el-pagination-button-disabled-bg-color: var(--el-fill-color-blank);
13 | --el-pagination-button-bg-color: var(--el-fill-color);
14 | --el-pagination-hover-color: var(--el-color-primary);
15 | --el-pagination-height-extra-small: 24px;
16 | --el-pagination-line-height-extra-small: var(--el-pagination-height-extra-small);
17 | white-space: nowrap;
18 | padding: 2px 5px;
19 | color: var(--el-pagination-text-color);
20 | font-weight: 400;
21 | display: flex;
22 | align-items: center;
23 | }
24 |
25 | .el-pagination__total {
26 | margin-right: 16px;
27 | font-weight: 400;
28 | color: var(--el-text-color-regular);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/theme/dark/element-plus/redio.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | .el-radio {
3 | --el-radio-font-size: var(--el-font-size-base);
4 | --el-radio-text-color: #262626;
5 | --el-radio-font-weight: var(--el-font-weight-primary);
6 | --el-radio-input-height: 14px;
7 | --el-radio-input-width: 14px;
8 | --el-radio-input-border-radius: var(--el-border-radius-circle);
9 | --el-radio-input-bg-color: var(--el-fill-color-blank);
10 | --el-radio-input-border: var(--el-border);
11 | --el-radio-input-border-color: transparent;
12 | //--el-radio-input-border-color-hover: transparent;
13 | }
14 |
15 | .el-radio__input.is-checked + .el-radio__label {
16 | color: #262626;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/theme/dark/element-plus/table.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | .el-table {
3 | --el-table-border-color: #f0f0f0;
4 | --el-table-border: 1px solid #f0f0f0;
5 | --el-table-text-color: var(--el-text-color-regular);
6 | --el-table-header-text-color: var(--el-text-color-secondary);
7 | --el-table-row-hover-bg-color: #ffece6;
8 | --el-table-current-row-bg-color: var(--el-color-primary-light-9);
9 | --el-table-header-bg-color: #fafafa;
10 | --el-table-fixed-box-shadow: var(--el-box-shadow-light);
11 | --el-table-bg-color: var(--el-fill-color-blank);
12 | --el-table-tr-bg-color: var(--el-fill-color-blank);
13 | --el-table-expanded-cell-bg-color: var(--el-fill-color-blank);
14 | --el-table-fixed-left-column: inset 10px 0 10px -10px rgba(0, 0, 0, 0.15);
15 | --el-table-fixed-right-column: inset -10px 0 10px -10px rgba(0, 0, 0, 0.15);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/theme/dark/element-plus/var.scss:
--------------------------------------------------------------------------------
1 | /* Element Chalk Variables */
2 | @use 'sass:math';
3 | @use 'sass:map';
4 | @use '../../mixins/function.scss' as *;
5 |
6 | // types
7 | $types: primary, success, warning, danger, error, info;
8 |
9 | // change color
10 | $colors: () !default;
11 | $colors: map.deep-merge(
12 | (
13 | 'white': #ffffff,
14 | 'black': #000000,
15 | 'primary': (
16 | 'base': #c72210//#409eff
17 | ),
18 | 'success': (
19 | 'base': #45b207
20 | ),
21 | 'warning': (
22 | 'base': #ec8828
23 | ),
24 | 'danger': (
25 | 'base': #f56c6c
26 | ),
27 | 'error': (
28 | 'base': #d24934
29 | ),
30 | 'info': (
31 | 'base': #909399
32 | )
33 | ),
34 | $colors
35 | );
36 |
37 | $color-white: map.get($colors, 'white') !default;
38 | $color-black: map.get($colors, 'black') !default;
39 | $color-primary: map.get($colors, 'primary', 'base') !default;
40 | $color-success: map.get($colors, 'success', 'base') !default;
41 | $color-warning: map.get($colors, 'warning', 'base') !default;
42 | $color-danger: map.get($colors, 'danger', 'base') !default;
43 | $color-error: map.get($colors, 'error', 'base') !default;
44 | $color-info: map.get($colors, 'info', 'base') !default;
45 |
46 | //$colors添加 --el-color-primary-light-7
47 | @mixin set-color-mix-level($type, $number, $mode: 'light', $mix-color: $color-white) {
48 | $colors: map.deep-merge(
49 | (
50 | $type: (
51 | '#{$mode}-#{$number}': mix($mix-color, map.get($colors, $type, 'base'), math.percentage(math.div($number, 10)))
52 | )
53 | ),
54 | $colors
55 | ) !global;
56 | }
57 |
58 | // $colors.primary.light-i
59 | @each $type in $types {
60 | @for $i from 1 through 9 {
61 | @include set-color-mix-level($type, $i, 'light', $color-white);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/theme/dark/index.scss:
--------------------------------------------------------------------------------
1 | /*china-red*/
2 | //element-plus
3 | //@use "./element-plus/css-vars";
4 | //@use "./element-plus/var";
5 | //@use "./element-plus/button";
6 | //@use "./element-plus/checkbox";
7 | //@use "./element-plus/redio";
8 | //@use "./element-plus/pagination";
9 | //@use "./element-plus/form";
10 | //@use "./element-plus/table";
11 |
12 | //custom
13 | @use "./custom/ct-css-vars";
14 |
--------------------------------------------------------------------------------
/src/theme/index.scss:
--------------------------------------------------------------------------------
1 | // we can add this to custom namespace, default is 'el'
2 | //@forward "element-plus/theme-chalk/src/mixins/config.scss" with (
3 | // $namespace: "el"
4 | //);
5 |
6 | //base-theme
7 | @use "./base";
8 | //theme style such as dark-theme lighting
9 | @use "./dark";
10 | @use "./lighting";
11 | @use "./china-red";
12 |
--------------------------------------------------------------------------------
/src/theme/lighting/custom/ct-css-vars.scss:
--------------------------------------------------------------------------------
1 | html.lighting-theme {
2 | /*element-plus section */
3 | //--el-menu-active-color: #409eff;
4 | //--el-menu-text-color: #bfcbd9;
5 | //--el-menu-hover-text-color: var(--el-color-primary);
6 | //--el-menu-bg-color: #304156;
7 | //--el-menu-hover-bg-color: #263445;
8 | //--el-menu-item-height: 56px;
9 | --el-menu-border-color: none;
10 | /*layout section*/
11 | //layout
12 | --layout-border-left-color: #ddd;
13 | //Breadcrumb
14 | --breadcrumb-no-redirect: #97a8be;
15 | //Hamburger
16 | --hamburger-color: #2b2f3a;
17 | --hamburger-width: 20px;
18 | --hamburger-height: 20px;
19 | //Sidebar
20 | --sidebar-el-icon-size: 20px;
21 | --sidebar-logo-background: #fff;
22 | --sidebar-logo-color: #ff9901;
23 | --sidebar-logo-width: 32px;
24 | --sidebar-logo-height: 32px;
25 | --sidebar-logo-title-color: #2b2f3a;
26 | --side-bar-width: 210px;
27 | --side-bar-border-right-color: #eee;
28 | //TagsView
29 | --tags-view-background: #fff;
30 | --tags-view-border-bottom: #d8dce5;
31 | --tags-view-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);
32 | --tags-view-item-background: #fff;
33 | --tags-view-item-border-color: #d8dce5;
34 | --tags-view-item-color: #495060;
35 | --tag-view-height: 32px;
36 | --tags-view-item-active-background: #42b983;
37 | --tags-view-item-active-color: #fff;
38 | --tags-view-item-active-border-color: #42b983;
39 | --tags-view-contextmenu-background: #fff;
40 | --tags-view-contextmenu-color: #333;
41 | --tags-view-contextmenu-box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
42 | --tags-view-contextmenu-hover-background: #eee;
43 | //close-icon
44 | --tags-view-close-icon-hover-background: #b4bccc;
45 | --tags-view-close-icon-hover-color: #fff;
46 | //AppMain.vue
47 | --app-main-padding: 10px;
48 | --app-main-background: #fff;
49 | //Navbar.vue
50 | --nav-bar-height: 50px;
51 | --nav-bar-background: #fff;
52 | --nav-bar-box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
53 | --nav-bar-right-menu-background: #fff;
54 |
55 | //transition 动画
56 | //侧边栏切换动画时长
57 | --sideBar-switch-duration: 0.2s;
58 | //logo切换动画时长
59 | --logo-switch-duration: 0.5s;
60 | //页面动画时长
61 | --page-transform-duration: 0.2s;
62 | //面包屑导航动画时长
63 | --breadcrumb-change-duration: 0.2s;
64 |
65 | //进度条颜色
66 | --pregress-bar-color: #409eff;
67 | }
68 |
--------------------------------------------------------------------------------
/src/theme/lighting/element-plus/checkbox.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | .el-checkbox {
3 | --el-checkbox-font-size: 14px;
4 | --el-checkbox-font-weight: var(--el-font-weight-primary);
5 | --el-checkbox-text-color: #262626;
6 | --el-checkbox-input-height: 14px;
7 | --el-checkbox-input-width: 14px;
8 | --el-checkbox-border-radius: var(--el-border-radius-small);
9 | --el-checkbox-bg-color: var(--el-fill-color-blank);
10 | --el-checkbox-input-border: var(--el-border);
11 |
12 | //disabled
13 | --el-checkbox-disabled-border-color: var(--el-border-color);
14 | --el-checkbox-disabled-input-fill: var(--el-fill-color-light);
15 | --el-checkbox-disabled-icon-color: var(--el-text-color-placeholder);
16 | --el-checkbox-disabled-checked-input-fill: var(--el-border-color-extra-light);
17 | --el-checkbox-disabled-checked-input-border-color: var(--el-border-color);
18 | --el-checkbox-disabled-checked-icon-color: var(--el-text-color-placeholder);
19 |
20 | //check
21 | --el-checkbox-checked-text-color: #262626;
22 | --el-checkbox-checked-input-border-color: transparent;
23 | --el-checkbox-checked-bg-color: #c72210;
24 | --el-checkbox-checked-icon-color: #ffffff;
25 | --el-checkbox-input-border-color-hover: #c72210;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/theme/lighting/element-plus/css-vars.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jzfai/vue3-admin-electron/130309705772261805160c23c3b9dd0424c68fe1/src/theme/lighting/element-plus/css-vars.css
--------------------------------------------------------------------------------
/src/theme/lighting/element-plus/css-vars.css.map:
--------------------------------------------------------------------------------
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"}
--------------------------------------------------------------------------------
/src/theme/lighting/element-plus/css-vars.scss:
--------------------------------------------------------------------------------
1 | @use 'sass:map';
2 |
3 | @use './var' as *;
4 | @use '../../mixins/var' as *;
5 | @use '../../mixins/mixins' as *;
6 |
7 | html.china-red {
8 | color-scheme: china-red;
9 | @each $type in (primary, success, warning, danger, error, info) {
10 | @include set-css-color-rgb($colors,$type);
11 | }
12 |
13 | @each $type in (primary, success, warning, danger, error, info) {
14 | @include set-css-color-type($colors, $type);
15 | }
16 | //--el-color-primary: #c72210;
17 | }
18 |
--------------------------------------------------------------------------------
/src/theme/lighting/element-plus/form.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | //date
3 | .el-date-range-picker {
4 | --el-datepicker-text-color: var(--el-text-color-regular);
5 | --el-datepicker-off-text-color: var(--el-text-color-placeholder);
6 | --el-datepicker-header-text-color: var(--el-text-color-regular);
7 | --el-datepicker-icon-color: var(--el-text-color-primary);
8 | --el-datepicker-border-color: var(--el-disabled-border-color);
9 | --el-datepicker-inner-border-color: var(--el-border-color-light);
10 | --el-datepicker-inrange-bg-color: #ffece6;
11 | --el-datepicker-inrange-hover-bg-color: var(--el-border-color-extra-light);
12 | --el-datepicker-active-color: var(--el-color-primary);
13 | --el-datepicker-hover-text-color: var(--el-color-primary);
14 | }
15 |
16 | .el-select-dropdown__item.hover,
17 | .el-select-dropdown__item:hover {
18 | background-color: #ffece6;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/theme/lighting/element-plus/pagination.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | .el-pagination {
3 | --el-text-color-regular: #8c8c8c;
4 | --el-pagination-font-size: 14px;
5 | --el-pagination-bg-color: var(--el-fill-color-blank);
6 | --el-pagination-text-color: var(--el-text-color-primary);
7 | --el-pagination-border-radius: 3px;
8 | --el-pagination-button-color: var(--el-text-color-primary);
9 | --el-pagination-button-width: 32px;
10 | --el-pagination-button-height: 32px;
11 | --el-pagination-button-disabled-color: var(--el-text-color-placeholder);
12 | --el-pagination-button-disabled-bg-color: var(--el-fill-color-blank);
13 | --el-pagination-button-bg-color: var(--el-fill-color);
14 | --el-pagination-hover-color: var(--el-color-primary);
15 | --el-pagination-height-extra-small: 24px;
16 | --el-pagination-line-height-extra-small: var(--el-pagination-height-extra-small);
17 | white-space: nowrap;
18 | padding: 2px 5px;
19 | color: var(--el-pagination-text-color);
20 | font-weight: 400;
21 | display: flex;
22 | align-items: center;
23 | }
24 |
25 | .el-pagination__total {
26 | margin-right: 16px;
27 | font-weight: 400;
28 | color: var(--el-text-color-regular);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/theme/lighting/element-plus/redio.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | .el-radio {
3 | --el-radio-font-size: var(--el-font-size-base);
4 | --el-radio-text-color: #262626;
5 | --el-radio-font-weight: var(--el-font-weight-primary);
6 | --el-radio-input-height: 14px;
7 | --el-radio-input-width: 14px;
8 | --el-radio-input-border-radius: var(--el-border-radius-circle);
9 | --el-radio-input-bg-color: var(--el-fill-color-blank);
10 | --el-radio-input-border: var(--el-border);
11 | --el-radio-input-border-color: transparent;
12 | //--el-radio-input-border-color-hover: transparent;
13 | }
14 |
15 | .el-radio__input.is-checked + .el-radio__label {
16 | color: #262626;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/theme/lighting/element-plus/table.scss:
--------------------------------------------------------------------------------
1 | html.china-red {
2 | .el-table {
3 | --el-table-border-color: #f0f0f0;
4 | --el-table-border: 1px solid #f0f0f0;
5 | --el-table-text-color: var(--el-text-color-regular);
6 | --el-table-header-text-color: var(--el-text-color-secondary);
7 | --el-table-row-hover-bg-color: #ffece6;
8 | --el-table-current-row-bg-color: var(--el-color-primary-light-9);
9 | --el-table-header-bg-color: #fafafa;
10 | --el-table-fixed-box-shadow: var(--el-box-shadow-light);
11 | --el-table-bg-color: var(--el-fill-color-blank);
12 | --el-table-tr-bg-color: var(--el-fill-color-blank);
13 | --el-table-expanded-cell-bg-color: var(--el-fill-color-blank);
14 | --el-table-fixed-left-column: inset 10px 0 10px -10px rgba(0, 0, 0, 0.15);
15 | --el-table-fixed-right-column: inset -10px 0 10px -10px rgba(0, 0, 0, 0.15);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/theme/lighting/element-plus/var.scss:
--------------------------------------------------------------------------------
1 | /* Element Chalk Variables */
2 | @use 'sass:math';
3 | @use 'sass:map';
4 | @use '../../mixins/function.scss' as *;
5 |
6 | // types
7 | $types: primary, success, warning, danger, error, info;
8 |
9 | // change color
10 | $colors: () !default;
11 | $colors: map.deep-merge(
12 | (
13 | 'white': #ffffff,
14 | 'black': #000000,
15 | 'primary': (
16 | 'base': #c72210//#409eff
17 | ),
18 | 'success': (
19 | 'base': #45b207
20 | ),
21 | 'warning': (
22 | 'base': #ec8828
23 | ),
24 | 'danger': (
25 | 'base': #f56c6c
26 | ),
27 | 'error': (
28 | 'base': #d24934
29 | ),
30 | 'info': (
31 | 'base': #909399
32 | )
33 | ),
34 | $colors
35 | );
36 |
37 | $color-white: map.get($colors, 'white') !default;
38 | $color-black: map.get($colors, 'black') !default;
39 | $color-primary: map.get($colors, 'primary', 'base') !default;
40 | $color-success: map.get($colors, 'success', 'base') !default;
41 | $color-warning: map.get($colors, 'warning', 'base') !default;
42 | $color-danger: map.get($colors, 'danger', 'base') !default;
43 | $color-error: map.get($colors, 'error', 'base') !default;
44 | $color-info: map.get($colors, 'info', 'base') !default;
45 |
46 | //$colors添加 --el-color-primary-light-7
47 | @mixin set-color-mix-level($type, $number, $mode: 'light', $mix-color: $color-white) {
48 | $colors: map.deep-merge(
49 | (
50 | $type: (
51 | '#{$mode}-#{$number}': mix($mix-color, map.get($colors, $type, 'base'), math.percentage(math.div($number, 10)))
52 | )
53 | ),
54 | $colors
55 | ) !global;
56 | }
57 |
58 | // $colors.primary.light-i
59 | @each $type in $types {
60 | @for $i from 1 through 9 {
61 | @include set-color-mix-level($type, $i, 'light', $color-white);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/theme/lighting/index.scss:
--------------------------------------------------------------------------------
1 | /*china-red*/
2 | //element-plus
3 | //@use "./element-plus/css-vars";
4 | //@use "./element-plus/var";
5 | //@use "./element-plus/button";
6 | //@use "./element-plus/checkbox";
7 | //@use "./element-plus/redio";
8 | //@use "./element-plus/pagination";
9 | //@use "./element-plus/form";
10 | //@use "./element-plus/table";
11 |
12 | //custom
13 | @use "./custom/ct-css-vars";
14 |
--------------------------------------------------------------------------------
/src/theme/mixins/_var.scss:
--------------------------------------------------------------------------------
1 | /*var mixin*/
2 | @use 'sass:map';
3 |
4 | @use 'config';
5 | @use 'function' as *;
6 |
7 | // set css var value, because we need translate value to string
8 | // for example:
9 | // @include set-css-var-value(('color', 'primary'), red);
10 | // --el-color: red;
11 | // --el-$name-: $value;
12 | @mixin set-css-var-value($name, $value) {
13 | #{joinVarName($name)}: #{$value};
14 | }
15 |
16 | @mixin set-css-color-type($colors, $type) {
17 | @include set-css-var-value(('color', $type), map.get($colors, $type, 'base'));
18 | @each $i in (3, 5, 7, 8, 9) {
19 | // --el-color-primary-light-7: #c6e2ff;
20 | @include set-css-var-value(('color', $type, 'light', $i), map.get($colors, $type, 'light-#{$i}'));
21 | }
22 |
23 | //@include set-css-var-value(
24 | // ('color', $type, 'dark-2'),
25 | // map.get($colors, $type, 'dark-2')
26 | //);
27 | }
28 |
29 | //el-$name-$attribute-$value
30 | @mixin set-component-css-var($name, $variables) {
31 | @each $attribute, $value in $variables {
32 | @if $attribute == 'default' {
33 | #{getCssVarName($name)}: #{$value};
34 | } @else {
35 | #{getCssVarName($name, $attribute)}: #{$value};
36 | }
37 | }
38 | }
39 |
40 | // --el-color-error-rgb: 245, 108, 108;
41 | // --el-color-$type-rgb: 245, 108, 108;
42 | @mixin set-css-color-rgb($colors, $type) {
43 | $color: map.get($colors, $type, 'base');
44 | @include set-css-var-value(('color', $type, 'rgb'), #{red($color), green($color), blue($color)});
45 | }
46 |
47 | // generate css var from existing css var
48 | // for example:
49 | // @include css-var-from-global(('button', 'text-color'), ('color', $type))
50 | // --el-button-text-color: var(--el-color-#{$type});
51 | @mixin css-var-from-global($var, $gVar) {
52 | $varName: joinVarName($var);
53 | $gVarName: joinVarName($gVar);
54 | #{$varName}: var(#{$gVarName});
55 | }
56 |
--------------------------------------------------------------------------------
/src/theme/mixins/config.scss:
--------------------------------------------------------------------------------
1 | $namespace: 'el' !default;
2 | $common-separator: '-' !default;
3 | $element-separator: '__' !default;
4 | $modifier-separator: '--' !default;
5 | $state-prefix: 'is-' !default;
6 |
--------------------------------------------------------------------------------
/src/theme/mixins/function.scss:
--------------------------------------------------------------------------------
1 | @use 'config';
2 |
3 | // getCssVarName('button', 'text-color') => '--el-button-text-color'
4 | @function getCssVarName($args...) {
5 | @return joinVarName($args);
6 | }
7 |
8 | // getCssVar('button', 'text-color') => var(--el-button-text-color)
9 | @function getCssVar($args...) {
10 | @return var(#{joinVarName($args)});
11 | }
12 |
13 | @function selectorToString($selector) {
14 | $selector: inspect($selector);
15 | $selector: str-slice($selector, 2, -2);
16 | @return $selector;
17 | }
18 |
19 | @function containsModifier($selector) {
20 | $selector: selectorToString($selector);
21 |
22 | @if str-index($selector, config.$modifier-separator) {
23 | @return true;
24 | } @else {
25 | @return false;
26 | }
27 | }
28 | @function hitAllSpecialNestRule($selector) {
29 | @return containsModifier($selector) or containWhenFlag($selector) or containPseudoClass($selector);
30 | }
31 | @function containWhenFlag($selector) {
32 | $selector: selectorToString($selector);
33 |
34 | @if str-index($selector, '.' + config.$state-prefix) {
35 | @return true;
36 | } @else {
37 | @return false;
38 | }
39 | }
40 | @function containPseudoClass($selector) {
41 | $selector: selectorToString($selector);
42 |
43 | @if str-index($selector, ':') {
44 | @return true;
45 | } @else {
46 | @return false;
47 | }
48 | }
49 |
50 | // join var name
51 | // joinVarName(('button', 'text-color')) => '--el-button-text-color'
52 | @function joinVarName($list) {
53 | $name: '--' + config.$namespace;
54 | @each $item in $list {
55 | @if $item != '' {
56 | $name: $name + '-' + $item;
57 | }
58 | }
59 | @return $name;
60 | }
61 |
--------------------------------------------------------------------------------
/src/theme/mixins/mixins.scss:
--------------------------------------------------------------------------------
1 | //input function
2 | @use 'function' as *;
3 | @forward 'function';
4 |
5 | @forward 'config';
6 | @use 'config' as *;
7 | // el-button{}
8 | @mixin b($block) {
9 | $B: $namespace + '-' + $block !global;
10 |
11 | .#{$B} {
12 | @content;
13 | }
14 | }
15 | @mixin e($element) {
16 | $E: $element !global;
17 | $selector: &;
18 | $currentSelector: '';
19 | @each $unit in $element {
20 | //el-button__text
21 | $currentSelector: #{$currentSelector + '.' + $B + $element-separator + $unit + ','};
22 | }
23 |
24 | @if hitAllSpecialNestRule($selector) {
25 | @at-root {
26 | #{$selector} {
27 | #{$currentSelector} {
28 | @content;
29 | }
30 | }
31 | }
32 | } @else {
33 | @at-root {
34 | #{$currentSelector} {
35 | @content;
36 | }
37 | }
38 | }
39 | }
40 |
41 | @mixin m($modifier) {
42 | $selector: &;
43 | $currentSelector: '';
44 | @each $unit in $modifier {
45 | $currentSelector: #{$currentSelector + $selector + $modifier-separator + $unit + ','};
46 | }
47 |
48 | @at-root {
49 | #{$currentSelector} {
50 | @content;
51 | }
52 | }
53 | }
54 |
55 | @mixin when($state) {
56 | @at-root {
57 | &.#{$state-prefix + $state} {
58 | @content;
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/theme/utils/change-theme.ts:
--------------------------------------------------------------------------------
1 | export const toggleHtmlClass = (className) => {
2 | document.querySelectorAll('html')[0].className = className
3 | }
4 |
--------------------------------------------------------------------------------
/src/theme/utils/index.ts:
--------------------------------------------------------------------------------
1 | export * from './change-theme'
2 |
--------------------------------------------------------------------------------
/src/utils/bus.ts:
--------------------------------------------------------------------------------
1 | //bus even
2 | import mitt from 'mitt'
3 | export default mitt()
4 |
--------------------------------------------------------------------------------
/src/views/basic-demo/hook/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
引入use-common.ts中的copyValueToClipboard
4 |
执行hook方法
5 |
6 |
7 |
8 |
15 |
--------------------------------------------------------------------------------
/src/views/basic-demo/keep-alive/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
39 |
--------------------------------------------------------------------------------
/src/views/basic-demo/keep-alive/second-child.vue:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/views/basic-demo/keep-alive/tab-keep-alive.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
20 |
--------------------------------------------------------------------------------
/src/views/basic-demo/keep-alive/third-child.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
third-level.vue
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | 返回
13 |
14 |
15 |
16 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/views/basic-demo/keep-alive/third-children/SecondChildren.vue:
--------------------------------------------------------------------------------
1 |
2 | I Am SecondChildren.vue
3 |
4 |
5 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/views/basic-demo/keep-alive/third-children/ThirdChildren.vue:
--------------------------------------------------------------------------------
1 |
2 | I Am ThirdChildren.vue
3 |
4 |
5 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/views/basic-demo/keep-alive/third-keep-alive.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
third-keep-alive demo
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/views/basic-demo/mock/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/views/basic-demo/parent-children/Children.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
call father method
4 |
emitFather
5 |
getFatherMethod
6 |
7 |
8 |
9 | slot using
10 |
11 |
12 |
13 | 没传内容
14 |
15 |
16 |
17 | 没传header插槽
18 |
19 |
20 |
21 | 没传footer插槽
22 |
23 |
24 | v-model sync using
25 | {{ childrenTitle }}
26 | changeParentValue
27 |
28 |
29 |
77 |
--------------------------------------------------------------------------------
/src/views/basic-demo/parent-children/SubChildren.vue:
--------------------------------------------------------------------------------
1 |
2 | provide and inject using
3 | {{ title }}
4 |
5 | Teleport Using
6 |
10 |
11 |
12 |
13 |
14 |
15 | to container
16 | Close
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | showModalOpen
25 |
26 |
27 |
35 |
--------------------------------------------------------------------------------
/src/views/basic-demo/parent-children/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
21 |
22 |
23 |
55 |
--------------------------------------------------------------------------------
/src/views/basic-demo/pinia/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
由于使用了 AutoImport 插件 可以直接引入pinia里的api
4 |
switch sidebar.opened
5 |
6 |
7 |
8 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/views/basic-demo/svg-icon/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/src/views/basic-demo/vue3-template/Vue3Template.vue:
--------------------------------------------------------------------------------
1 |
2 | vue3推荐模板可以集成在你们的vscode或webstorm中,有助于快速开发
3 |
4 |
5 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/views/basic-demo/worker/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
the recommend using way of worker
4 |
计算结果:{{ showPageRef }}
5 |
6 |
7 |
46 |
--------------------------------------------------------------------------------
/src/views/dashboard/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
38 |
39 |
52 |
--------------------------------------------------------------------------------
/src/views/electron/ElectronDemo.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/src/views/electron/ElectronDemoBak.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/src/views/electron/NedbDemo.vue:
--------------------------------------------------------------------------------
1 |
2 |
24 |
25 |
26 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/src/views/electron/NotifyNetListen.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/src/views/nested/menu1/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/views/nested/menu1/menu1-1/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/views/nested/menu1/menu1-2/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/views/nested/menu1/menu1-2/menu1-2-1/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/views/nested/menu1/menu1-2/menu1-2-2/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/views/nested/menu1/menu1-3/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/views/nested/menu2/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/views/redirect/index.tsx:
--------------------------------------------------------------------------------
1 | import { defineComponent } from 'vue'
2 | export default defineComponent({
3 | setup() {
4 | const route = useRoute()
5 | const router = useRouter()
6 | onBeforeMount(() => {
7 | const { params, query } = route
8 | const { path } = params
9 | router.replace({ path: `/${path}`, query })
10 | })
11 | return () =>
12 | }
13 | })
14 |
--------------------------------------------------------------------------------
/src/views/setting-switch/SettingSwitch.vue:
--------------------------------------------------------------------------------
1 |
2 |
46 |
47 |
48 |
51 |
--------------------------------------------------------------------------------
/src/views/setting-switch/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
46 |
47 |
48 |
51 |
--------------------------------------------------------------------------------
/tsconfig.base.json:
--------------------------------------------------------------------------------
1 | {
2 | //设置files为空,则不会自动扫描默认目录,也就是只会扫描include配置的目录
3 | "files": [],
4 | "compilerOptions": {
5 | "target": "esnext",
6 | "module": "esnext",
7 | //启用所有严格类型检查选项。
8 | //启用 --strict相当于启用 --noImplicitAny, --noImplicitThis, --alwaysStrict, --strictNullChecks和 --strictFunctionTypes和--strictPropertyInitialization。
9 | "strict": true,
10 | // 允许编译器编译JS,JSX文件
11 | "allowJs": false,
12 | // 允许在JS文件中报错,通常与allowJS一起使用
13 | "checkJs": false,
14 | // 允许使用jsx
15 | "jsx": "preserve",
16 | "declaration": true,
17 | //移除注解
18 | "removeComments": true,
19 | //不可以忽略any
20 | "noImplicitAny": false,
21 | //关闭 this 类型注解提示
22 | "noImplicitThis": true,
23 | //null/undefined不能作为其他类型的子类型:
24 | //let a: number = null; //这里会报错.
25 | "strictNullChecks": true,
26 | //生成枚举的映射代码
27 | "preserveConstEnums": true,
28 | //根目录
29 | //输出目录
30 | "outDir": "./ts-out-dir",
31 | //是否输出src2.js.map文件
32 | "sourceMap": false,
33 | //变量定义了但是未使用
34 | "noUnusedLocals": false,
35 | //是否允许把json文件当做模块进行解析
36 | "resolveJsonModule": true,
37 | //和noUnusedLocals一样,针对func
38 | "noUnusedParameters": false,
39 | // 模块解析策略,ts默认用node的解析策略,即相对的方式导入
40 | "moduleResolution": "node",
41 | //允许export=导出,由import from 导入
42 | "esModuleInterop": true,
43 | //忽略所有的声明文件( *.d.ts)的类型检查。
44 | "skipLibCheck": true,
45 | "baseUrl": ".",
46 | //指定默认读取的目录
47 | //"typeRoots": ["./node_modules/@types/", "./types"],
48 | "lib": ["ES2018", "DOM"]
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.base.json",
3 | "compilerOptions": {
4 | "paths": {
5 | "@/*": ["src/*"],
6 | "~/*": ["typings/*"]
7 | }
8 | },
9 | "include": ["src", "typings"],
10 | "exclude": ["node_modules", "**/dist"]
11 | }
12 |
--------------------------------------------------------------------------------
/typings/basic.d.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * 声明.d.ts文件规范
3 | * 导出的类型以大写开头
4 | * 对象:config
5 | * 数组:options
6 | * 枚举:emu
7 | * 函数:Fn
8 | * 属性:props
9 | * 实例:instance
10 | * */
11 |
12 | /*router*/
13 | import type { RouteRecordRaw } from 'vue-router'
14 | export interface rawConfig {
15 | hidden?: boolean
16 | alwaysShow?: boolean
17 | code?: number
18 | name?: string
19 | fullPath?: string
20 | path?: string
21 | meta?: {
22 | title: string
23 | icon?: string
24 | affix?: boolean
25 | activeMenu?: string
26 | breadcrumb?: boolean
27 | roles?: Array
28 | elSvgIcon?: string
29 | code?: number
30 | cachePage?: boolean
31 | leaveRmCachePage?: boolean
32 | closeTabRmCache?: boolean
33 | }
34 | children?: RouterOptions
35 | redirect?: string
36 | }
37 | export type RouteRawConfig = RouteRecordRaw & rawConfig
38 | export type RouterTypes = Array
39 |
40 | /*settings*/
41 | export interface SettingsConfig {
42 | title: string
43 | sidebarLogo: boolean
44 | showLeftMenu: boolean
45 | ShowDropDown: boolean
46 | showHamburger: boolean
47 | isNeedLogin: boolean
48 | isNeedNprogress: boolean
49 | showTagsView: boolean
50 | tagsViewNum: number
51 | openProdMock: boolean
52 | errorLog: string | Array
53 | permissionMode: string
54 | delWindowHeight: string
55 | tmpToken: string
56 | showNavbarTitle: boolean
57 | showTopNavbar: boolean
58 | mainNeedAnimation: boolean
59 | viteBasePath: string
60 | defaultLanguage: string
61 | defaultSize: string
62 | defaultTheme: string
63 | plateFormId: number
64 | }
65 |
66 | export {}
67 |
--------------------------------------------------------------------------------
/typings/common.d.ts:
--------------------------------------------------------------------------------
1 | //common type file, you can not export the type in common.d.ts
2 | //not export can use
3 | interface ObjTy {
4 | [propName: string]: any
5 | }
6 |
7 | /*axiosReq请求配置*/
8 | import { AxiosRequestConfig } from 'axios'
9 | interface AxiosReqTy extends AxiosRequestConfig {
10 | url?: string
11 | method?: string
12 | data?: ObjTy
13 | isParams?: boolean
14 | bfLoading?: boolean
15 | afHLoading?: boolean
16 | isUploadFile?: boolean
17 | isDownLoadFile?: boolean
18 | isAlertErrorMsg?: boolean
19 | baseURL?: string
20 | timeout?: number
21 | }
22 | interface AxiosConfigTy {
23 | url?: string
24 | method?: string
25 | data?: ObjTy
26 | isParams?: boolean
27 | bfLoading?: boolean
28 | afHLoading?: boolean
29 | isUploadFile?: boolean
30 | isDownLoadFile?: boolean
31 | isAlertErrorMsg?: boolean
32 | baseURL?: string
33 | timeout?: number
34 | }
35 |
--------------------------------------------------------------------------------
/typings/components.d.ts:
--------------------------------------------------------------------------------
1 | // generated by unplugin-vue-components
2 | // We suggest you to commit this file into source control
3 | // Read more: https://github.com/vuejs/core/pull/3399
4 | import '@vue/runtime-core'
5 |
6 | export {}
7 |
8 | declare module '@vue/runtime-core' {
9 | export interface GlobalComponents {
10 | ElSvgIcon: typeof import('./../src/components/ElSvgIcon.vue')['default']
11 | RouterLink: typeof import('vue-router')['RouterLink']
12 | RouterView: typeof import('vue-router')['RouterView']
13 | SvgIcon: typeof import('./../src/icons/SvgIcon.vue')['default']
14 | TestUnit: typeof import('./../src/components/TestUnit.vue')['default']
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/typings/env.d.ts:
--------------------------------------------------------------------------------
1 | declare global {
2 | interface ImportMetaEnv {
3 | readonly VITE_APP_BASE_URL: string
4 | readonly VITE_APP_IMAGE_URL: string
5 | readonly VITE_APP_ENV: string
6 | // 更多环境变量...
7 | }
8 | interface ImportMeta {
9 | readonly env: ImportMetaEnv
10 | }
11 | }
12 | export {}
13 |
--------------------------------------------------------------------------------
/typings/global.d.ts:
--------------------------------------------------------------------------------
1 | import type { defineOptions as _defineOptions } from 'unplugin-vue-define-options/macros.d.ts'
2 | declare global {
3 | interface ObjKeys {
4 | [propName: string]: any
5 | }
6 | const GLOBAL_VAR: String
7 | const defineOptions: typeof _defineOptions
8 | const $ref: any
9 | }
10 | export {}
11 |
--------------------------------------------------------------------------------
/typings/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | /*fix the import warning issue of vue file*/
2 | declare module '*.vue' {
3 | import { DefineComponent } from 'vue'
4 | const component: DefineComponent<{}, {}, any>
5 | export default component
6 | }
7 |
--------------------------------------------------------------------------------
/vitest.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vitest/config'
2 | import Vue from '@vitejs/plugin-vue'
3 | import VueJsx from '@vitejs/plugin-vue-jsx'
4 | import DefineOptions from 'unplugin-vue-define-options/vite'
5 | export default defineConfig({
6 | plugins: [Vue(), VueJsx(), DefineOptions()],
7 | optimizeDeps: {
8 | disabled: true
9 | },
10 | test: {
11 | clearMocks: true,
12 | environment: 'jsdom',
13 | //setup 文件的路径。它们将运行在每个测试文件之前。
14 | setupFiles: ['./vitest.setup.ts'],
15 | transformMode: {
16 | web: [/\.[jt]sx$/]
17 | }
18 | }
19 | })
20 |
--------------------------------------------------------------------------------
/vitest.setup.ts:
--------------------------------------------------------------------------------
1 | import { config } from '@vue/test-utils'
2 | import { vi } from 'vitest'
3 | import ResizeObserver from 'resize-observer-polyfill'
4 |
5 | vi.stubGlobal('ResizeObserver', ResizeObserver)
6 |
7 | config.global.stubs = {}
8 |
--------------------------------------------------------------------------------