chore: prettier & lint

Former-commit-id: 486f65e137
This commit is contained in:
Jachin 2023-08-04 17:50:25 +08:00
parent a240ff04d2
commit f797606c44
72 changed files with 1234 additions and 484 deletions

View File

@ -5,4 +5,10 @@ NODE_ENV='development'
VITE_APP_TITLE = 'vue3-element-admin' VITE_APP_TITLE = 'vue3-element-admin'
VITE_APP_PORT = 3000 VITE_APP_PORT = 3000
# API请求前缀
VITE_APP_BASE_API = '/dev-api' VITE_APP_BASE_API = '/dev-api'
# proxy代理配置
VITE_APP_TARGET_URL = 'http://localhost:3000'
VITE_APP_TARGET_BASE_API = ''

View File

@ -2,4 +2,10 @@
VITE_APP_TITLE = 'vue3-element-admin' VITE_APP_TITLE = 'vue3-element-admin'
VITE_APP_PORT = 3000 VITE_APP_PORT = 3000
VITE_APP_BASE_API = '/prod-api'
# API请求前缀
VITE_APP_BASE_API = 'http://vapi.youlai.tech'
# proxy代理配置
VITE_APP_TARGET_URL = "http://vapi.youlai.tech"
VITE_APP_TARGET_BASE_API = ''

View File

@ -3,4 +3,6 @@ NODE_ENV='staging'
VITE_APP_TITLE = 'vue3-element-admin' VITE_APP_TITLE = 'vue3-element-admin'
VITE_APP_PORT = 3000 VITE_APP_PORT = 3000
VITE_APP_TARGET_URL = 'http://localhost:3000';
VITE_APP_BASE_API = '/prod--api' VITE_APP_BASE_API = '/prod--api'

View File

@ -266,4 +266,4 @@
"watchWithFilter": true, "watchWithFilter": true,
"whenever": true "whenever": true
} }
} }

View File

@ -1,4 +1,5 @@
module.exports = { module.exports = {
root: true,
env: { env: {
browser: true, browser: true,
es2021: true, es2021: true,
@ -10,11 +11,16 @@ module.exports = {
"plugin:vue/vue3-recommended", "plugin:vue/vue3-recommended",
"./.eslintrc-auto-import.json", "./.eslintrc-auto-import.json",
"prettier", "prettier",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
], ],
parserOptions: { parserOptions: {
ecmaVersion: "latest", ecmaVersion: "latest",
sourceType: "module", sourceType: "module",
parser: "@typescript-eslint/parser", parser: "@typescript-eslint/parser",
project: "./tsconfig.*?.json",
createDefaultProgram: false,
extraFileExtensions: [".vue"],
}, },
plugins: ["vue", "@typescript-eslint"], plugins: ["vue", "@typescript-eslint"],
rules: { rules: {
@ -23,6 +29,41 @@ module.exports = {
"@typescript-eslint/no-explicit-any": "off", // 关闭any类型的警告 "@typescript-eslint/no-explicit-any": "off", // 关闭any类型的警告
"vue/no-v-model-argument": "off", "vue/no-v-model-argument": "off",
"@typescript-eslint/no-non-null-assertion": "off", "@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/ban-ts-ignore": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"vue/script-setup-uses-vars": "error",
"vue/no-reserved-component-names": "off",
"vue/custom-event-name-casing": "off",
"vue/attributes-order": "off",
"vue/one-component-per-file": "off",
"vue/html-closing-bracket-newline": "off",
"vue/max-attributes-per-line": "off",
"vue/multiline-html-element-content-newline": "off",
"vue/singleline-html-element-content-newline": "off",
"vue/attribute-hyphenation": "off",
"vue/require-default-prop": "off",
"vue/require-explicit-emits": "off",
"vue/html-self-closing": [
"error",
{
html: {
void: "always",
normal: "never",
component: "always",
},
svg: "always",
math: "always",
},
],
"vue/multi-word-component-names": "off",
}, },
// eslint不能对html文件生效 // eslint不能对html文件生效
overrides: [ overrides: [

2
.gitignore vendored
View File

@ -6,7 +6,6 @@ dist-ssr
# Editor directories and files # Editor directories and files
.idea .idea
.vscode
*.suo *.suo
*.ntvs* *.ntvs*
*.njsproj *.njsproj
@ -15,3 +14,4 @@ dist-ssr
package-lock.json package-lock.json
pnpm-lock.yaml pnpm-lock.yaml
stats.html

View File

@ -8,3 +8,4 @@ public
*.md *.md
src/assets src/assets
stats.html

View File

@ -8,3 +8,4 @@ public
*.md *.md
src/assets src/assets
stats.html

3
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar"]
}

146
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,146 @@
{
"typescript.tsdk": "./node_modules/typescript/lib",
"npm.packageManager": "pnpm",
"editor.tabSize": 2,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"files.eol": "\n",
"search.exclude": {
"**/node_modules": true,
"**/*.log": true,
"**/*.log*": true,
"**/bower_components": true,
"**/dist": true,
"**/elehukouben": true,
"**/.git": true,
"**/.gitignore": true,
"**/.svn": true,
"**/.DS_Store": true,
"**/.idea": true,
"**/.vscode": false,
"**/yarn.lock": true,
"**/tmp": true,
"out": true,
"dist": true,
"node_modules": true,
"CHANGELOG.md": true,
"examples": true,
"res": true,
"screenshots": true,
"yarn-error.log": true,
"**/.yarn": true
},
"files.exclude": {
"**/.cache": true,
"**/.editorconfig": true,
"**/.eslintcache": true,
"**/bower_components": true,
"**/.idea": true,
"**/tmp": true,
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true
},
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/.vscode/**": true,
"**/node_modules/**": true,
"**/tmp/**": true,
"**/bower_components/**": true,
"**/dist/**": true,
"**/yarn.lock": true
},
"material-icon-theme.folders.color": "#42a5f5",
"material-icon-theme.folders.theme": "specific",
"material-icon-theme.activeIconPack": "vue_vuex",
"path-intellisense.mappings": {
"@/": "${workspaceRoot}/src/"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[less]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"[vue]": {
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.fixAll.stylelint": true
},
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"i18n-ally.localesPaths": ["src/locales/lang"],
"i18n-ally.keystyle": "nested",
"i18n-ally.sortKeys": true,
"i18n-ally.namespace": true,
"i18n-ally.pathMatcher": "{locale}/{namespaces}.{ext}",
"i18n-ally.enabledParsers": ["ts"],
"i18n-ally.sourceLanguage": "en",
"i18n-ally.displayLanguage": "zh-CN",
"i18n-ally.enabledFrameworks": ["vue", "react"],
"cSpell.words": [
"antd",
"antv",
"brotli",
"browserslist",
"codemirror",
"commitlint",
"cropperjs",
"echarts",
"ERUDA",
"esnext",
"esno",
"iconify",
"INTLIFY",
"lint-staged",
"lintstagedrc",
"logicflow",
"mkcert",
"mockjs",
"nprogress",
"persistedstate",
"pinia",
"pnpm",
"qrcode",
"sider",
"sortablejs",
"stylelint",
"tailwindcss",
"tdesign",
"tinymce",
"unocss",
"unplugin",
"vben",
"vditor",
"Vite",
"vitejs",
"vueuse",
"windi",
"windicss",
"zxcvbn"
],
}

341
mock/router.ts Normal file
View File

@ -0,0 +1,341 @@
import { MockMethod } from "vite-plugin-mock";
const url = "/api/v1/menus/routes";
const method = "get";
const data = {
code: "00000",
data: [
{
path: "/system",
component: "Layout",
redirect: "/system/user",
meta: {
title: "系统管理",
icon: "system",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
children: [
{
path: "user",
component: "system/user/index",
name: "User",
meta: {
title: "用户管理",
icon: "user",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
{
path: "role",
component: "system/role/index",
name: "Role",
meta: {
title: "角色管理",
icon: "role",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
{
path: "menu",
component: "system/menu/index",
name: "Menu",
meta: {
title: "菜单管理",
icon: "menu",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
{
path: "dept",
component: "system/dept/index",
name: "Dept",
meta: {
title: "部门管理",
icon: "tree",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
{
path: "dict",
component: "system/dict/index",
name: "Dict",
meta: {
title: "字典管理",
icon: "dict",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
],
},
{
path: "/api",
component: "Layout",
meta: {
title: "接口",
icon: "api",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
children: [
{
path: "apidoc",
component: "demo/api-doc",
name: "Apidoc",
meta: {
title: "接口文档",
icon: "api",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
],
},
{
path: "/external-link",
component: "Layout",
redirect: "noredirect",
meta: {
title: "外部链接",
icon: "link",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
children: [
{
path: "https://juejin.cn/post/7228990409909108793",
meta: {
title: "document",
icon: "document",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
],
},
{
path: "/multi-level",
component: "Layout",
redirect: "/multi-level/multi-level1",
meta: {
title: "多级菜单",
icon: "multi_level",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
children: [
{
path: "multi-level1",
component: "demo/multi-level/level1",
redirect: "/multi-level/multi-level2",
meta: {
title: "菜单一级",
icon: "",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
children: [
{
path: "multi-level2",
component: "demo/multi-level/children/level2",
redirect: "/multi-level/multi-level2/multi-level3-1",
meta: {
title: "菜单二级",
icon: "",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
children: [
{
path: "multi-level3-1",
component: "demo/multi-level/children/children/level3-1",
name: "MultiLevel31",
meta: {
title: "菜单三级-1",
icon: "",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
{
path: "multi-level3-2",
component: "demo/multi-level/children/children/level3-2",
name: "MultiLevel32",
meta: {
title: "菜单三级-2",
icon: "",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
],
},
],
},
],
},
{
path: "/component",
component: "Layout",
meta: {
title: "组件封装",
icon: "menu",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
children: [
{
path: "wang-editor",
component: "demo/wang-editor",
name: "WangEditor",
meta: {
title: "富文本编辑器",
icon: "",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
{
path: "upload",
component: "demo/upload",
name: "Upload",
meta: {
title: "图片上传",
icon: "",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
{
path: "icon-selector",
component: "demo/icon-selector",
name: "IconSelector",
meta: {
title: "图标选择器",
icon: "",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
{
path: "dict-demo",
component: "demo/dict",
name: "DictDemo",
meta: {
title: "字典组件",
icon: "",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
{
path: "taginput",
component: "demo/taginput",
name: "Taginput",
meta: {
title: "标签输入框",
icon: "",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
{
path: "signature",
component: "demo/signature",
name: "Signature",
meta: {
title: "签名",
icon: "",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
{
path: "table",
component: "demo/table",
name: "Table",
meta: {
title: "表格",
icon: "",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
],
},
{
path: "/function",
component: "Layout",
meta: {
title: "功能演示",
icon: "menu",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
children: [
{
path: "websocket",
component: "demo/websocket",
name: "Websocket",
meta: {
title: "Websocket",
icon: "",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
{
path: "other",
component: "demo/other",
meta: {
title: "敬请期待...",
icon: "",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
],
},
],
msg: "一切ok",
};
export default [
{
url: url,
method: method,
response: () => {
return data;
},
},
] as MockMethod[];

95
mock/user.ts Normal file
View File

@ -0,0 +1,95 @@
import { MockMethod } from "vite-plugin-mock";
export default [
{
url: "/api/hello_world",
method: "get",
response: (request) => {
return {
msg: "hello world",
headers: request.headers,
};
},
},
{
url: "/api/v1/auth/captcha",
method: "get",
response: () => {
return {
code: "00000",
data: {
verifyCodeKey: "534b8ef2b0a24121bec76391ddd159f9",
verifyCodeBase64:
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAAkCAIAAADNSmkJAAAFKUlEQVR4Xu2ZXUwcVRiGV70wMWo08V5NvPXCrDbFaGpMaZW2hqQxaoiJTRsaMBCNSYtpa2JTKiFSelFa+Q/QZcMWqEhBlh+htbEpZhMrBQrlJ0hBywLLyrJ0WZbje3bqOvPNLHPWrDvdOE9ONmfe78zkzMs335wzWJhJQrBQweS/wTQ6QWgYHdoIOcecOe05O+t2WkutO+p2ZF3Ksg/YV9ZW6FATYajR3nveg60H9327r3O8c35lHgp+r05dPdJzBL73TPSQ8SaCKIxGLsPlop+K0JHrEkPuoT31e5qGmmjARACF0agYyGVNlyVm/pzZXrN9fHGcBkz0UBid+31u93i3XFFT80vN8cvHqWqih8Lo1NpUqS5vwh3vnd223VQ10UNh9NbyrcFQUK6oCawHUipSqGqiB83oBf+CXFGDMp1mS6OqiR4Ko7FexkpOrqhpHGw82nOUqiZ6KIzGrkRuorW0dJMmOy+hOCfYGzb2RBFv6HRO0gEJw/U7y+pgL1bwmTxexN6sZ31TdEwEhdG+gA+7EqyXpUO1uZH20cWL8hMTRt1N9tBXzCJrOIRoCPJpSO2RAp4HmtCdIfZ+2JWgEBN9LbR28seTGU0Zue1tMLp+YIAMSADzfvbkKX4/eb28j4YODiGin3heqmIlLja5hAUCu+nmGY3JWKvpMAlqNGgebsauBOvlqSX+JEx7p7EbTLen53XlzfmWUioqXikrc68Y8N2juJ/fyVsNChGHEE//rBANYWaZz+TRQqpLaBgNsPfDrgSpbS21YtV87IdjrlkX9JZbt5DOma2t9ITo5F+5glN22WwL/n+yDv00mw06orKxOqQ5+J04hhViwzAXETIcJDVm8uxZqktoGx2Nj9t43Wgaul/ERQiGQvtbWnDWgZYW9CXlQFjZ/7ciyHNn+Z2MexTimIeLz59TiIln0M1e+IbPpOAaDUnEYPTi6iqKxpbycs/qKo1tCslfKcffPn9enuMiPPY1vxO/ckeFQ4h46cdGqUWoidE/y54q5tPY5WDrGzQqIXot4BgchEE57e00IMCw2/1qZSVO/7SjA78o9INzcxsbrL+fnTnDDh9mmZn8F30oG1Hm+nABv5mQMopDS/h1HxtqTzWbABMe9sxpPoe9zezeOo1GELqWhPS8t46M0IAYHbdvR1aHbaOjbjfLz2eFhez6dba4yAfgF30o0BFVE8+Mjh/wFxPI+I5mAEHU6Ls+38vhTFwOBGhMDF8gkFpbC5ffsdv/uBs6dIj19dExEtARVXv9YNbop8NFY3aZ6gRRo+tu3IBHnzmdNCBMXldXJKPfL74WzWUJRE+coDUknqsOdZXQbAJYwluVTbOZI3Qt8GFzMwxyjo3RgBiN4fr+elXVpZGRLWXl6PdOTtJBSlBDUK/lnIrjOlrtqWYTQDJaF6FrTXu9sOa1ysrVoM5HVE1GFxZQcyJ/p+xzv6K/rbr6N6+XDpUBl0tKFIrbz78qWB6YnWFMCBld4XLBms+7df75ook/GNzb0GCV7U1Qfz9p64TyQWNjYD3qe9rj4SMJtQP3MyjSDPzWIRHPjH7X4YAvfXoPuyZf9Pbi3PcuXIh4mp3NllYC6XY79C+jl2o8PBipxjnBttn4MgMNnWgfcRJGPI2OL8hTj3LloIlmRicvBhiNykvecpqoa3RSY4DRcLAwyicuOepVR1JjgNFYHWONHL04czTX0UmNAUYD7Pr+xc4wqTHGaBb2OtZvHUmNYUazcA2J6etdUmOk0f8rTKMTxF91RG0D1SwYGwAAAABJRU5ErkJggg==",
},
msg: "一切ok",
};
},
},
{
url: "/api/v1/auth/login",
method: "post",
response: () => {
return {
code: "00000",
data: {
accessToken:
"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImp0aSI6IjE2YWJkNTlkOTAxNzQwZDliYmI3ZjczODBhZDkyNzNhIiwidXNlcklkIjoyLCJ1c2VybmFtZSI6ImFkbWluIiwiZGVwdElkIjoxLCJkYXRhU2NvcGUiOjEsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iXSwiZXhwIjoxNjkxMTAzMzgyfQ.P4cuIfmPepl3HuguhMS7NXn5a7IUPpsLbmtA_rHOhHk",
tokenType: "Bearer",
refreshToken: null,
expires: null,
},
msg: "一切ok",
};
},
},
{
url: "/api/v1/users/me",
method: "get",
response: () => {
return {
code: "00000",
data: {
userId: 2,
nickname: "系统管理员",
avatar:
"https://oss.youlai.tech/youlai-boot/2023/05/16/811270ef31f548af9cffc026dfc3777b.gif",
roles: ["ADMIN"],
perms: [
"sys:menu:delete",
"sys:dept:edit",
"sys:dict_type:add",
"sys:dict:edit",
"sys:dict:delete",
"sys:dict_type:edit",
"sys:menu:add",
"sys:user:add",
"sys:role:edit",
"sys:dept:delete",
"sys:user:edit",
"sys:user:delete",
"sys:user:reset_pwd",
"sys:dept:add",
"sys:role:delete",
"sys:dict_type:delete",
"sys:menu:edit",
"sys:dict:add",
"sys:role:add",
],
},
msg: "一切ok",
};
},
},
{
url: "/api/v1/auth/logout",
method: "delete",
response: () => {
return {
code: "00000",
data: {},
msg: "string",
};
},
},
] as MockMethod[];

View File

@ -2,11 +2,10 @@
"name": "vue3-element-admin", "name": "vue3-element-admin",
"private": true, "private": true,
"version": "2.4.1", "version": "2.4.1",
"type": "module",
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
"dev": "vite serve --mode development", "dev": "vite serve --mode development",
"build:prod": "vite build --mode production &&vue-tsc --noEmit", "build:prod": "vite build --mode production && vue-tsc --noEmit",
"prepare": "husky install", "prepare": "husky install",
"lint:eslint": "eslint --fix --ext .ts,.js,.vue ./src ", "lint:eslint": "eslint --fix --ext .ts,.js,.vue ./src ",
"lint:prettier": "prettier --write \"**/*.{js,cjs,ts,json,tsx,css,less,scss,vue,html,md}\"", "lint:prettier": "prettier --write \"**/*.{js,cjs,ts,json,tsx,css,less,scss,vue,html,md}\"",
@ -68,7 +67,6 @@
"@types/lodash": "^4.14.195", "@types/lodash": "^4.14.195",
"@types/nprogress": "^0.2.0", "@types/nprogress": "^0.2.0",
"@types/path-browserify": "^1.0.0", "@types/path-browserify": "^1.0.0",
"@types/xlsx": "^0.0.36",
"@typescript-eslint/eslint-plugin": "^5.59.6", "@typescript-eslint/eslint-plugin": "^5.59.6",
"@typescript-eslint/parser": "^5.59.6", "@typescript-eslint/parser": "^5.59.6",
"autoprefixer": "^10.4.14", "autoprefixer": "^10.4.14",
@ -76,6 +74,7 @@
"cz-git": "^1.6.1", "cz-git": "^1.6.1",
"eslint": "^8.40.0", "eslint": "^8.40.0",
"eslint-config-prettier": "^8.8.0", "eslint-config-prettier": "^8.8.0",
"eslint-plugin-import": "^2.28.0",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.13.0", "eslint-plugin-vue": "^9.13.0",
"fast-glob": "^3.2.11", "fast-glob": "^3.2.11",
@ -85,14 +84,15 @@
"postcss-html": "^1.5.0", "postcss-html": "^1.5.0",
"postcss-scss": "^4.0.6", "postcss-scss": "^4.0.6",
"prettier": "^2.8.8", "prettier": "^2.8.8",
"rollup-plugin-visualizer": "^5.9.2",
"sass": "^1.58.3", "sass": "^1.58.3",
"stylelint": "^15.7.0", "stylelint": "^15.10.2",
"stylelint-config-html": "^1.1.0", "stylelint-config-html": "^1.1.0",
"stylelint-config-recess-order": "^4.0.0", "stylelint-config-recess-order": "^4.0.0",
"stylelint-config-recommended-scss": "11.0.0 ", "stylelint-config-recommended-scss": "^12.0.0",
"stylelint-config-recommended-vue": "^1.4.0", "stylelint-config-recommended-vue": "^1.5.0",
"stylelint-config-standard": "^33.0.0", "stylelint-config-standard": "^34.0.0",
"stylelint-config-standard-scss": "^9.0.0", "stylelint-config-standard-scss": "^10.0.0",
"typescript": "^5.0.4", "typescript": "^5.0.4",
"unocss": "^0.51.13", "unocss": "^0.51.13",
"unplugin-auto-import": "^0.15.3", "unplugin-auto-import": "^0.15.3",
@ -100,8 +100,9 @@
"unplugin-vue-components": "^0.24.1", "unplugin-vue-components": "^0.24.1",
"vite": "^4.4.2", "vite": "^4.4.2",
"vite-plugin-compression": "^0.5.1", "vite-plugin-compression": "^0.5.1",
"vite-plugin-mock": "^3.0.0",
"vite-plugin-svg-icons": "^2.0.1", "vite-plugin-svg-icons": "^2.0.1",
"vue-tsc": "^1.6.5 " "vue-tsc": "^1.7.0 "
}, },
"repository": "https://gitee.com/youlaiorg/vue3-element-admin.git", "repository": "https://gitee.com/youlaiorg/vue3-element-admin.git",
"author": "有来开源组织", "author": "有来开源组织",

View File

@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ElConfigProvider } from 'element-plus'; import { ElConfigProvider } from "element-plus";
import { useAppStore } from '@/store/modules/app'; import { useAppStore } from "@/store/modules/app";
const appStore = useAppStore(); const appStore = useAppStore();
</script> </script>

View File

@ -1,6 +1,6 @@
import request from '@/utils/request'; import request from "@/utils/request";
import { AxiosPromise } from 'axios'; import { AxiosPromise } from "axios";
import { DeptForm, DeptQuery, DeptVO } from './types'; import { DeptForm, DeptQuery, DeptVO } from "./types";
/** /**
* *
@ -9,9 +9,9 @@ import { DeptForm, DeptQuery, DeptVO } from './types';
*/ */
export function listDepts(queryParams?: DeptQuery): AxiosPromise<DeptVO[]> { export function listDepts(queryParams?: DeptQuery): AxiosPromise<DeptVO[]> {
return request({ return request({
url: '/api/v1/dept', url: "/api/v1/dept",
method: 'get', method: "get",
params: queryParams params: queryParams,
}); });
} }
@ -20,8 +20,8 @@ export function listDepts(queryParams?: DeptQuery): AxiosPromise<DeptVO[]> {
*/ */
export function listDeptOptions(): AxiosPromise<[]> { export function listDeptOptions(): AxiosPromise<[]> {
return request({ return request({
url: '/api/v1/dept/options', url: "/api/v1/dept/options",
method: 'get' method: "get",
}); });
} }
@ -32,8 +32,8 @@ export function listDeptOptions(): AxiosPromise<[]> {
*/ */
export function getDeptForm(id: number): AxiosPromise<DeptForm> { export function getDeptForm(id: number): AxiosPromise<DeptForm> {
return request({ return request({
url: '/api/v1/dept/' + id + '/form', url: "/api/v1/dept/" + id + "/form",
method: 'get' method: "get",
}); });
} }
@ -44,9 +44,9 @@ export function getDeptForm(id: number): AxiosPromise<DeptForm> {
*/ */
export function addDept(data: DeptForm) { export function addDept(data: DeptForm) {
return request({ return request({
url: '/api/v1/dept', url: "/api/v1/dept",
method: 'post', method: "post",
data: data data: data,
}); });
} }
@ -58,9 +58,9 @@ export function addDept(data: DeptForm) {
*/ */
export function updateDept(id: number, data: DeptForm) { export function updateDept(id: number, data: DeptForm) {
return request({ return request({
url: '/api/v1/dept/' + id, url: "/api/v1/dept/" + id,
method: 'put', method: "put",
data: data data: data,
}); });
} }
@ -71,7 +71,7 @@ export function updateDept(id: number, data: DeptForm) {
*/ */
export function deleteDept(ids: string) { export function deleteDept(ids: string) {
return request({ return request({
url: '/api/v1/dept/' + ids, url: "/api/v1/dept/" + ids,
method: 'delete' method: "delete",
}); });
} }

View File

@ -1,6 +1,6 @@
import request from '@/utils/request'; import request from "@/utils/request";
import { AxiosPromise } from 'axios'; import { AxiosPromise } from "axios";
import { FileInfo } from './types'; import { FileInfo } from "./types";
/** /**
* *
@ -9,14 +9,14 @@ import { FileInfo } from './types';
*/ */
export function uploadFileApi(file: File): AxiosPromise<FileInfo> { export function uploadFileApi(file: File): AxiosPromise<FileInfo> {
const formData = new FormData(); const formData = new FormData();
formData.append('file', file); formData.append("file", file);
return request({ return request({
url: '/api/v1/files', url: "/api/v1/files",
method: 'post', method: "post",
data: formData, data: formData,
headers: { headers: {
'Content-Type': 'multipart/form-data' "Content-Type": "multipart/form-data",
} },
}); });
} }
@ -27,8 +27,8 @@ export function uploadFileApi(file: File): AxiosPromise<FileInfo> {
*/ */
export function deleteFileApi(filePath?: string) { export function deleteFileApi(filePath?: string) {
return request({ return request({
url: '/api/v1/files', url: "/api/v1/files",
method: 'delete', method: "delete",
params: { filePath: filePath } params: { filePath: filePath },
}); });
} }

View File

@ -1,14 +1,14 @@
import request from '@/utils/request'; import request from "@/utils/request";
import { AxiosPromise } from 'axios'; import { AxiosPromise } from "axios";
import { MenuQuery, MenuVO, MenuForm } from './types'; import { MenuQuery, MenuVO, MenuForm } from "./types";
/** /**
* *
*/ */
export function listRoutes() { export function listRoutes() {
return request({ return request({
url: '/api/v1/menus/routes', url: "/api/v1/menus/routes",
method: 'get' method: "get",
}); });
} }
@ -19,9 +19,9 @@ export function listRoutes() {
*/ */
export function listMenus(queryParams: MenuQuery): AxiosPromise<MenuVO[]> { export function listMenus(queryParams: MenuQuery): AxiosPromise<MenuVO[]> {
return request({ return request({
url: '/api/v1/menus', url: "/api/v1/menus",
method: 'get', method: "get",
params: queryParams params: queryParams,
}); });
} }
@ -30,8 +30,8 @@ export function listMenus(queryParams: MenuQuery): AxiosPromise<MenuVO[]> {
*/ */
export function listMenuOptions(): AxiosPromise<OptionType[]> { export function listMenuOptions(): AxiosPromise<OptionType[]> {
return request({ return request({
url: '/api/v1/menus/options', url: "/api/v1/menus/options",
method: 'get' method: "get",
}); });
} }
@ -42,8 +42,8 @@ export function listMenuOptions(): AxiosPromise<OptionType[]> {
*/ */
export function getMenuForm(id: number): AxiosPromise<MenuForm> { export function getMenuForm(id: number): AxiosPromise<MenuForm> {
return request({ return request({
url: '/api/v1/menus/' + id + '/form', url: "/api/v1/menus/" + id + "/form",
method: 'get' method: "get",
}); });
} }
@ -54,9 +54,9 @@ export function getMenuForm(id: number): AxiosPromise<MenuForm> {
*/ */
export function addMenu(data: MenuForm) { export function addMenu(data: MenuForm) {
return request({ return request({
url: '/api/v1/menus', url: "/api/v1/menus",
method: 'post', method: "post",
data: data data: data,
}); });
} }
@ -68,9 +68,9 @@ export function addMenu(data: MenuForm) {
*/ */
export function updateMenu(id: string, data: MenuForm) { export function updateMenu(id: string, data: MenuForm) {
return request({ return request({
url: '/api/v1/menus/' + id, url: "/api/v1/menus/" + id,
method: 'put', method: "put",
data: data data: data,
}); });
} }
@ -81,7 +81,7 @@ export function updateMenu(id: string, data: MenuForm) {
*/ */
export function deleteMenu(id: number) { export function deleteMenu(id: number) {
return request({ return request({
url: '/api/v1/menus/' + id, url: "/api/v1/menus/" + id,
method: 'delete' method: "delete",
}); });
} }

View File

@ -1,4 +1,4 @@
import { MenuTypeEnum } from '@/enums/MenuTypeEnum'; import { MenuTypeEnum } from "@/enums/MenuTypeEnum";
/** /**
* *

View File

@ -1,6 +1,6 @@
import request from '@/utils/request'; import request from "@/utils/request";
import { AxiosPromise } from 'axios'; import { AxiosPromise } from "axios";
import { RoleQuery, RolePageResult, RoleForm } from './types'; import { RoleQuery, RolePageResult, RoleForm } from "./types";
/** /**
* *
@ -11,9 +11,9 @@ export function getRolePage(
queryParams?: RoleQuery queryParams?: RoleQuery
): AxiosPromise<RolePageResult> { ): AxiosPromise<RolePageResult> {
return request({ return request({
url: '/api/v1/roles/page', url: "/api/v1/roles/page",
method: 'get', method: "get",
params: queryParams params: queryParams,
}); });
} }
@ -26,9 +26,9 @@ export function listRoleOptions(
queryParams?: RoleQuery queryParams?: RoleQuery
): AxiosPromise<OptionType[]> { ): AxiosPromise<OptionType[]> {
return request({ return request({
url: '/api/v1/roles/options', url: "/api/v1/roles/options",
method: 'get', method: "get",
params: queryParams params: queryParams,
}); });
} }
@ -39,8 +39,8 @@ export function listRoleOptions(
*/ */
export function getRoleMenuIds(roleId: number): AxiosPromise<number[]> { export function getRoleMenuIds(roleId: number): AxiosPromise<number[]> {
return request({ return request({
url: '/api/v1/roles/' + roleId + '/menuIds', url: "/api/v1/roles/" + roleId + "/menuIds",
method: 'get' method: "get",
}); });
} }
@ -54,9 +54,9 @@ export function updateRoleMenus(
data: number[] data: number[]
): AxiosPromise<any> { ): AxiosPromise<any> {
return request({ return request({
url: '/api/v1/roles/' + roleId + '/menus', url: "/api/v1/roles/" + roleId + "/menus",
method: 'put', method: "put",
data: data data: data,
}); });
} }
@ -67,8 +67,8 @@ export function updateRoleMenus(
*/ */
export function getRoleForm(id: number): AxiosPromise<RoleForm> { export function getRoleForm(id: number): AxiosPromise<RoleForm> {
return request({ return request({
url: '/api/v1/roles/' + id + '/form', url: "/api/v1/roles/" + id + "/form",
method: 'get' method: "get",
}); });
} }
@ -79,9 +79,9 @@ export function getRoleForm(id: number): AxiosPromise<RoleForm> {
*/ */
export function addRole(data: RoleForm) { export function addRole(data: RoleForm) {
return request({ return request({
url: '/api/v1/roles', url: "/api/v1/roles",
method: 'post', method: "post",
data: data data: data,
}); });
} }
@ -93,9 +93,9 @@ export function addRole(data: RoleForm) {
*/ */
export function updateRole(id: number, data: RoleForm) { export function updateRole(id: number, data: RoleForm) {
return request({ return request({
url: '/api/v1/roles/' + id, url: "/api/v1/roles/" + id,
method: 'put', method: "put",
data: data data: data,
}); });
} }
@ -106,7 +106,7 @@ export function updateRole(id: number, data: RoleForm) {
*/ */
export function deleteRoles(ids: string) { export function deleteRoles(ids: string) {
return request({ return request({
url: '/api/v1/roles/' + ids, url: "/api/v1/roles/" + ids,
method: 'delete' method: "delete",
}); });
} }

View File

@ -1,14 +1,14 @@
import request from '@/utils/request'; import request from "@/utils/request";
import { AxiosPromise } from 'axios'; import { AxiosPromise } from "axios";
import { UserForm, UserInfo, UserPageVO, UserQuery } from './types'; import { UserForm, UserInfo, UserPageVO, UserQuery } from "./types";
/** /**
* *
*/ */
export function getUserInfo(): AxiosPromise<UserInfo> { export function getUserInfo(): AxiosPromise<UserInfo> {
return request({ return request({
url: '/api/v1/users/me', url: "/api/v1/users/me",
method: 'get' method: "get",
}); });
} }
@ -21,9 +21,9 @@ export function getUserPage(
queryParams: UserQuery queryParams: UserQuery
): AxiosPromise<PageResult<UserPageVO[]>> { ): AxiosPromise<PageResult<UserPageVO[]>> {
return request({ return request({
url: '/api/v1/users/page', url: "/api/v1/users/page",
method: 'get', method: "get",
params: queryParams params: queryParams,
}); });
} }
@ -34,8 +34,8 @@ export function getUserPage(
*/ */
export function getUserForm(userId: number): AxiosPromise<UserForm> { export function getUserForm(userId: number): AxiosPromise<UserForm> {
return request({ return request({
url: '/api/v1/users/' + userId + '/form', url: "/api/v1/users/" + userId + "/form",
method: 'get' method: "get",
}); });
} }
@ -46,9 +46,9 @@ export function getUserForm(userId: number): AxiosPromise<UserForm> {
*/ */
export function addUser(data: any) { export function addUser(data: any) {
return request({ return request({
url: '/api/v1/users', url: "/api/v1/users",
method: 'post', method: "post",
data: data data: data,
}); });
} }
@ -60,9 +60,9 @@ export function addUser(data: any) {
*/ */
export function updateUser(id: number, data: UserForm) { export function updateUser(id: number, data: UserForm) {
return request({ return request({
url: '/api/v1/users/' + id, url: "/api/v1/users/" + id,
method: 'put', method: "put",
data: data data: data,
}); });
} }
@ -74,9 +74,9 @@ export function updateUser(id: number, data: UserForm) {
*/ */
export function updateUserStatus(id: number, status: number) { export function updateUserStatus(id: number, status: number) {
return request({ return request({
url: '/api/v1/users/' + id + '/status', url: "/api/v1/users/" + id + "/status",
method: 'patch', method: "patch",
params: { status: status } params: { status: status },
}); });
} }
@ -88,9 +88,9 @@ export function updateUserStatus(id: number, status: number) {
*/ */
export function updateUserPassword(id: number, password: string) { export function updateUserPassword(id: number, password: string) {
return request({ return request({
url: '/api/v1/users/' + id + '/password', url: "/api/v1/users/" + id + "/password",
method: 'patch', method: "patch",
params: { password: password } params: { password: password },
}); });
} }
@ -101,8 +101,8 @@ export function updateUserPassword(id: number, password: string) {
*/ */
export function deleteUsers(ids: string) { export function deleteUsers(ids: string) {
return request({ return request({
url: '/api/v1/users/' + ids, url: "/api/v1/users/" + ids,
method: 'delete' method: "delete",
}); });
} }
@ -113,9 +113,9 @@ export function deleteUsers(ids: string) {
*/ */
export function downloadTemplateApi() { export function downloadTemplateApi() {
return request({ return request({
url: '/api/v1/users/template', url: "/api/v1/users/template",
method: 'get', method: "get",
responseType: 'arraybuffer' responseType: "arraybuffer",
}); });
} }
@ -127,10 +127,10 @@ export function downloadTemplateApi() {
*/ */
export function exportUser(queryParams: UserQuery) { export function exportUser(queryParams: UserQuery) {
return request({ return request({
url: '/api/v1/users/_export', url: "/api/v1/users/_export",
method: 'get', method: "get",
params: queryParams, params: queryParams,
responseType: 'arraybuffer' responseType: "arraybuffer",
}); });
} }
@ -141,14 +141,14 @@ export function exportUser(queryParams: UserQuery) {
*/ */
export function importUser(deptId: number, file: File) { export function importUser(deptId: number, file: File) {
const formData = new FormData(); const formData = new FormData();
formData.append('file', file); formData.append("file", file);
return request({ return request({
url: '/api/v1/users/_import', url: "/api/v1/users/_import",
method: 'post', method: "post",
params: { deptId: deptId }, params: { deptId: deptId },
data: formData, data: formData,
headers: { headers: {
'Content-Type': 'multipart/form-data' "Content-Type": "multipart/form-data",
} },
}); });
} }

View File

@ -11,7 +11,7 @@
:key="option.value" :key="option.value"
:label="option.label" :label="option.label"
:value="option.value" :value="option.value"
></el-option> />
</el-select> </el-select>
</div> </div>
</template> </template>

View File

@ -89,8 +89,8 @@ onMounted(() => {
class="cursor-pointer text-[#999] absolute right-[10px] top-0 height-[32px] leading-[32px]" class="cursor-pointer text-[#999] absolute right-[10px] top-0 height-[32px] leading-[32px]"
@click="visible = !visible" @click="visible = !visible"
> >
<i-ep-caret-top v-show="visible"></i-ep-caret-top> <i-ep-caret-top v-show="visible" />
<i-ep-caret-bottom v-show="!visible"></i-ep-caret-bottom> <i-ep-caret-bottom v-show="!visible" />
</div> </div>
</template> </template>

View File

@ -54,7 +54,7 @@ onBeforeUnmount(() => {
<template> <template>
<div ref="rightPanel" :class="{ show: show }"> <div ref="rightPanel" :class="{ show: show }">
<div class="right-panel-overlay" /> <div class="right-panel-overlay"></div>
<div class="right-panel-container"> <div class="right-panel-container">
<div <div
class="right-panel-btn" class="right-panel-btn"
@ -67,7 +67,7 @@ onBeforeUnmount(() => {
<i-ep-setting v-show="!show" /> <i-ep-setting v-show="!show" />
</div> </div>
<div> <div>
<slot /> <slot></slot>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,17 +1,17 @@
<script setup lang="ts"> <script setup lang="ts">
import { useAppStore } from '@/store/modules/app'; import { useAppStore } from "@/store/modules/app";
const appStore = useAppStore(); const appStore = useAppStore();
const sizeOptions = ref([ const sizeOptions = ref([
{ label: '默认', value: 'default' }, { label: "默认", value: "default" },
{ label: '大型', value: 'large' }, { label: "大型", value: "large" },
{ label: '小型', value: 'small' } { label: "小型", value: "small" },
]); ]);
function handleSizeChange(size: string) { function handleSizeChange(size: string) {
appStore.changeSize(size); appStore.changeSize(size);
ElMessage.success('切换布局大小成功'); ElMessage.success("切换布局大小成功");
} }
</script> </script>

View File

@ -1,34 +1,34 @@
/** /**
* getRePosFromStr * getRePosFromStr
* */ * */
export function getRePosFromStr(text: any = '', re: any = /\$.+?\$/g) { export function getRePosFromStr(text: any = "", re: any = /\$.+?\$/g) {
const lines = text.split('\n') const lines = text.split("\n");
const positions: any = [] const positions: any = [];
let m let m;
for (let i = 0; i < lines.length; i++) { for (let i = 0; i < lines.length; i++) {
const l = lines[i] const l = lines[i];
while ((m = re.exec(l)) !== null) { while ((m = re.exec(l)) !== null) {
var tag = m[0].substring(1, m[0].length - 1) const tag = m[0].substring(1, m[0].length - 1);
positions.push({ positions.push({
line: i, line: i,
start: m.index, start: m.index,
stop: m.index + m[0].length, stop: m.index + m[0].length,
tag, tag,
}) });
}
} }
return positions }
return positions;
} }
/** /**
* *
*/ */
export enum MODE { export enum MODE {
// 文本 // 文本
TEXT = 1, TEXT = 1,
// 公式 // 公式
FORMULA, FORMULA,
// 只允许选择tag // 只允许选择tag
ONLYTAG, ONLYTAG,
// 日期 // 日期
DATE DATE,
} }

View File

@ -71,4 +71,4 @@ onBeforeUnmount(() => {
}); });
</script> </script>
<style src="@wangeditor/editor/dist/css/style.css"></style> <style src="@wangeditor/editor/dist/css/style.css"></style>

View File

@ -1,9 +1,9 @@
import type { App } from 'vue'; import type { App } from "vue";
import { hasPerm } from './permission'; import { hasPerm } from "./permission";
// 全局注册 directive // 全局注册 directive
export function setupDirective(app: App<Element>) { export function setupDirective(app: App<Element>) {
// 使 v-hasPerm 在所有组件中都可用 // 使 v-hasPerm 在所有组件中都可用
app.directive('hasPerm', hasPerm); app.directive("hasPerm", hasPerm);
} }

View File

@ -1,5 +1,5 @@
import { useUserStoreHook } from '@/store/modules/user'; import { useUserStoreHook } from "@/store/modules/user";
import { Directive, DirectiveBinding } from 'vue'; import { Directive, DirectiveBinding } from "vue";
/** /**
* *
@ -8,7 +8,7 @@ export const hasPerm: Directive = {
mounted(el: HTMLElement, binding: DirectiveBinding) { mounted(el: HTMLElement, binding: DirectiveBinding) {
// 「超级管理员」拥有所有的按钮权限 // 「超级管理员」拥有所有的按钮权限
const { roles, perms } = useUserStoreHook(); const { roles, perms } = useUserStoreHook();
if (roles.includes('ROOT')) { if (roles.includes("ROOT")) {
return true; return true;
} }
// 「其他角色」按钮权限校验 // 「其他角色」按钮权限校验
@ -16,7 +16,7 @@ export const hasPerm: Directive = {
if (value) { if (value) {
const requiredPerms = value; // DOM绑定需要的按钮权限标识 const requiredPerms = value; // DOM绑定需要的按钮权限标识
const hasPerm = perms?.some(perm => { const hasPerm = perms?.some((perm) => {
return requiredPerms.includes(perm); return requiredPerms.includes(perm);
}); });
@ -28,7 +28,7 @@ export const hasPerm: Directive = {
"need perms! Like v-has-perm=\"['sys:user:add','sys:user:edit']\"" "need perms! Like v-has-perm=\"['sys:user:add','sys:user:edit']\""
); );
} }
} },
}; };
/** /**
@ -41,7 +41,7 @@ export const hasRole: Directive = {
if (value) { if (value) {
const requiredRoles = value; // DOM绑定需要的角色编码 const requiredRoles = value; // DOM绑定需要的角色编码
const { roles } = useUserStoreHook(); const { roles } = useUserStoreHook();
const hasRole = roles.some(perm => { const hasRole = roles.some((perm) => {
return requiredRoles.includes(perm); return requiredRoles.includes(perm);
}); });
@ -51,5 +51,5 @@ export const hasRole: Directive = {
} else { } else {
throw new Error("need roles! Like v-has-role=\"['admin','test']\""); throw new Error("need roles! Like v-has-role=\"['admin','test']\"");
} }
} },
}; };

View File

@ -2,18 +2,18 @@ export enum MenuTypeEnum {
/** /**
* *
*/ */
CATALOG = 'CATALOG', CATALOG = "CATALOG",
/** /**
* *
*/ */
MENU = 'MENU', MENU = "MENU",
/** /**
* *
*/ */
BUTTON = 'BUTTON', BUTTON = "BUTTON",
/** /**
* *
*/ */
EXTLINK = 'EXTLINK' EXTLINK = "EXTLINK",
} }

View File

@ -1,25 +1,25 @@
import { createI18n } from 'vue-i18n'; import { createI18n } from "vue-i18n";
import { useAppStore } from '@/store/modules/app'; import { useAppStore } from "@/store/modules/app";
// 本地语言包
import enLocale from "./package/en";
import zhCnLocale from "./package/zh-cn";
const appStore = useAppStore(); const appStore = useAppStore();
// 本地语言包
import enLocale from './package/en';
import zhCnLocale from './package/zh-cn';
const messages = { const messages = {
'zh-cn': { "zh-cn": {
...zhCnLocale ...zhCnLocale,
}, },
en: { en: {
...enLocale ...enLocale,
} },
}; };
const i18n = createI18n({ const i18n = createI18n({
legacy: false, legacy: false,
locale: appStore.language, locale: appStore.language,
messages: messages, messages: messages,
globalInjection: true globalInjection: true,
}); });
export default i18n; export default i18n;

View File

@ -1,22 +1,22 @@
export default { export default {
// 路由国际化 // 路由国际化
route: { route: {
dashboard: 'Dashboard', dashboard: "Dashboard",
document: 'Document' document: "Document",
}, },
// 登录页面国际化 // 登录页面国际化
login: { login: {
title: 'vue3-element-admin', title: "vue3-element-admin",
username: 'Username', username: "Username",
password: 'Password', password: "Password",
login: 'Login', login: "Login",
verifyCode: 'Verify Code', verifyCode: "Verify Code",
}, },
// 导航栏国际化 // 导航栏国际化
navbar: { navbar: {
dashboard: 'Dashboard', dashboard: "Dashboard",
logout: 'Logout', logout: "Logout",
document: 'Document', document: "Document",
gitee: 'Gitee' gitee: "Gitee",
} },
}; };

View File

@ -1,22 +1,22 @@
export default { export default {
// 路由国际化 // 路由国际化
route: { route: {
dashboard: '首页', dashboard: "首页",
document: '项目文档' document: "项目文档",
}, },
// 登录页面国际化 // 登录页面国际化
login: { login: {
title: 'vue3-element-admin', title: "vue3-element-admin",
username: '用户名', username: "用户名",
password: '密码', password: "密码",
login: '登 录', login: "登 录",
verifyCode: '验证码' verifyCode: "验证码",
}, },
// 导航栏国际化 // 导航栏国际化
navbar: { navbar: {
dashboard: '首页', dashboard: "首页",
logout: '注销', logout: "注销",
document: '项目文档', document: "项目文档",
gitee: '码云' gitee: "码云",
} },
}; };

View File

@ -84,7 +84,7 @@ onMounted(() => {
class="inline-block w-[30px] h-[30px] cursor-pointer" class="inline-block w-[30px] h-[30px] cursor-pointer"
:style="{ background: color }" :style="{ background: color }"
@click="changeThemeColor(color)" @click="changeThemeColor(color)"
/> ></li>
</ul> </ul>
<el-divider>导航设置</el-divider> <el-divider>导航设置</el-divider>
@ -98,8 +98,8 @@ onMounted(() => {
" "
@click="changeLayout('left')" @click="changeLayout('left')"
> >
<div /> <div></div>
<div /> <div></div>
</li> </li>
</el-tooltip> </el-tooltip>
<el-tooltip content="顶部模式" placement="bottom"> <el-tooltip content="顶部模式" placement="bottom">
@ -110,8 +110,8 @@ onMounted(() => {
" "
@click="changeLayout('top')" @click="changeLayout('top')"
> >
<div /> <div></div>
<div /> <div></div>
</li> </li>
</el-tooltip> </el-tooltip>
<el-tooltip content="混合模式" placement="bottom"> <el-tooltip content="混合模式" placement="bottom">
@ -122,8 +122,8 @@ onMounted(() => {
" "
@click="changeLayout('mix')" @click="changeLayout('mix')"
> >
<div /> <div></div>
<div /> <div></div>
</li> </li>
</el-tooltip> </el-tooltip>
</ul> </ul>

View File

@ -1,9 +1,10 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed } from 'vue'; import { computed } from "vue";
import { isExternal } from '@/utils/index'; import { isExternal } from "@/utils/index";
import { useRouter } from 'vue-router'; import { useRouter } from "vue-router";
import { useAppStore } from "@/store/modules/app";
import { useAppStore } from '@/store/modules/app';
const appStore = useAppStore(); const appStore = useAppStore();
const sidebar = computed(() => appStore.sidebar); const sidebar = computed(() => appStore.sidebar);
@ -12,16 +13,16 @@ const device = computed(() => appStore.device);
const props = defineProps({ const props = defineProps({
to: { to: {
type: String, type: String,
required: true required: true,
} },
}); });
const router = useRouter(); const router = useRouter();
function push() { function push() {
if (device.value === 'mobile' && sidebar.value.opened == true) { if (device.value === "mobile" && sidebar.value.opened == true) {
appStore.closeSideBar(false); appStore.closeSideBar(false);
} }
router.push(props.to).catch(err => { router.push(props.to).catch((err) => {
console.error(err); console.error(err);
}); });
} }
@ -29,9 +30,9 @@ function push() {
<template> <template>
<a v-if="isExternal(to)" :href="to" target="_blank" rel="noopener"> <a v-if="isExternal(to)" :href="to" target="_blank" rel="noopener">
<slot /> <slot></slot>
</a> </a>
<div v-else @click="push"> <div v-else @click="push">
<slot /> <slot></slot>
</div> </div>
</template> </template>

View File

@ -1,13 +1,13 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useSettingsStore } from '@/store/modules/settings'; import { useSettingsStore } from "@/store/modules/settings";
const settingsStore = useSettingsStore(); const settingsStore = useSettingsStore();
defineProps({ defineProps({
collapse: { collapse: {
type: Boolean, type: Boolean,
required: true required: true,
} },
}); });
const logo = ref(new URL(`../../../assets/logo.png`, import.meta.url).href); const logo = ref(new URL(`../../../assets/logo.png`, import.meta.url).href);

View File

@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import path from 'path-browserify'; import path from "path-browserify";
import { isExternal } from '@/utils/index'; import { isExternal } from "@/utils/index";
import AppLink from './Link.vue'; import AppLink from "./Link.vue";
import { translateRouteTitleI18n } from '@/utils/i18n'; import { translateRouteTitleI18n } from "@/utils/i18n";
import SvgIcon from '@/components/SvgIcon/index.vue'; import SvgIcon from "@/components/SvgIcon/index.vue";
const props = defineProps({ const props = defineProps({
/** /**
@ -12,7 +12,7 @@ const props = defineProps({
*/ */
item: { item: {
type: Object, type: Object,
required: true required: true,
}, },
/** /**
@ -20,8 +20,8 @@ const props = defineProps({
*/ */
basePath: { basePath: {
type: String, type: String,
required: true required: true,
} },
}); });
const onlyOneChild = ref(); // const onlyOneChild = ref(); //
@ -53,7 +53,7 @@ function hasOneShowingChild(children = [], parent: any) {
// 2, true // 2, true
if (showingChildren.length === 0) { if (showingChildren.length === 0) {
onlyOneChild.value = { ...parent, path: '', noShowingChildren: true }; onlyOneChild.value = { ...parent, path: "", noShowingChildren: true };
return true; return true;
} }
return false; return false;

View File

@ -99,7 +99,7 @@ defineExpose({
:vertical="false" :vertical="false"
@wheel.prevent="handleScroll" @wheel.prevent="handleScroll"
> >
<slot /> <slot></slot>
</el-scrollbar> </el-scrollbar>
</template> </template>

View File

@ -1,12 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { import { getCurrentInstance, ComponentInternalInstance } from "vue";
getCurrentInstance,
nextTick,
ref,
watch,
onMounted,
ComponentInternalInstance,
} from "vue";
import { storeToRefs } from "pinia"; import { storeToRefs } from "pinia";
import path from "path-browserify"; import path from "path-browserify";

View File

@ -1,4 +1,4 @@
export { default as Navbar } from './Navbar.vue'; export { default as Navbar } from "./Navbar.vue";
export { default as AppMain } from './AppMain.vue'; export { default as AppMain } from "./AppMain.vue";
export { default as Settings } from './Settings/index.vue'; export { default as Settings } from "./Settings/index.vue";
export { default as TagsView } from './TagsView/index.vue'; export { default as TagsView } from "./TagsView/index.vue";

View File

@ -1,21 +1,21 @@
import { createApp } from 'vue'; import { createApp } from "vue";
import App from './App.vue'; import App from "./App.vue";
import router from '@/router'; import router from "@/router";
import { setupStore } from '@/store'; import { setupStore } from "@/store";
import { setupDirective } from '@/directive'; import { setupDirective } from "@/directive";
import '@/permission'; import "@/permission";
// 本地SVG图标 // 本地SVG图标
import 'virtual:svg-icons-register'; import "virtual:svg-icons-register";
// 国际化 // 国际化
import i18n from '@/lang/index'; import i18n from "@/lang/index";
// 样式 // 样式
import 'element-plus/theme-chalk/dark/css-vars.css'; import "element-plus/theme-chalk/dark/css-vars.css";
import '@/styles/index.scss'; import "@/styles/index.scss";
import 'uno.css'; import "uno.css";
const app = createApp(App); const app = createApp(App);
// 全局注册 自定义指令(directive) // 全局注册 自定义指令(directive)
@ -23,4 +23,4 @@ setupDirective(app);
// 全局注册 状态管理(store) // 全局注册 状态管理(store)
setupStore(app); setupStore(app);
app.use(router).use(i18n).mount('#app'); app.use(router).use(i18n).mount("#app");

View File

@ -4,6 +4,7 @@ import { usePermissionStoreHook } from "@/store/modules/permission";
import NProgress from "nprogress"; import NProgress from "nprogress";
import "nprogress/nprogress.css"; import "nprogress/nprogress.css";
NProgress.configure({ showSpinner: false }); // 进度条 NProgress.configure({ showSpinner: false }); // 进度条
const permissionStore = usePermissionStoreHook(); const permissionStore = usePermissionStoreHook();

View File

@ -46,17 +46,35 @@ export const constantRoutes: RouteRecordRaw[] = [
], ],
}, },
{
path: "/ext",
component: Layout,
children: [
{
path: "google",
component: import("@/views/demo/google.vue"),
name: "google",
meta: {
title: "Google",
icon: "client",
hidden: false,
roles: ["ADMIN"],
keepAlive: true,
},
},
],
},
// 外部链接 // 外部链接
/*{ // {
path: '/external-link', // path: "/external-link",
component: Layout, // component: Layout,
children: [ // children: [ {
{ // component: () => import("@/views/external-link/index.vue"),
path: 'https://www.cnblogs.com/haoxianrui/', // path: "https://www.cnblogs.com/haoxianrui/",
meta: { title: '外部链接', icon: 'link' } // meta: { title: "外部链接", icon: "link" },
} // },
] // ],
}*/ // },
// 多级嵌套路由 // 多级嵌套路由
/* { /* {
path: '/nested', path: '/nested',

2
src/shims-vue.d.ts vendored
View File

@ -1 +1 @@
declare module 'xlsx/xlsx.mjs' declare module "xlsx/xlsx.mjs";

View File

@ -1,5 +1,5 @@
import type { App } from 'vue'; import type { App } from "vue";
import { createPinia } from 'pinia'; import { createPinia } from "pinia";
const store = createPinia(); const store = createPinia();

View File

@ -19,7 +19,7 @@ html.dark {
--w-e-textarea-bg-color: var(--el-bg-color-overlay); --w-e-textarea-bg-color: var(--el-bg-color-overlay);
--w-e-textarea-color: var(--el-text-color-regulary); --w-e-textarea-color: var(--el-text-color-regulary);
--w-e-textarea-slight-border-color: var(--el-color-primary); --w-e-textarea-slight-border-color: var(--el-color-primary);
--w-e-textarea-slight-bg-color: rgba(var(--el-color-primary-rgb), .1); --w-e-textarea-slight-bg-color: rgb(var(--el-color-primary-rgb) 0.1);
--w-e-textarea-selected-border-color: var(--el-color-primary); --w-e-textarea-selected-border-color: var(--el-color-primary);
--w-e-textarea-border-color: var(--el-color-info-light-5); --w-e-textarea-border-color: var(--el-color-info-light-5);

View File

@ -1,6 +1,6 @@
// 导出 variables.module.scss 变量提供给TypeScript使用 // 导出 variables.module.scss 变量提供给TypeScript使用
:export { :export {
menuBg: $menuBg; menuBg: $menuBg;
menuText: $menuText; menuText: $menuText;
menuActiveText: $menuActiveText menuActiveText: $menuActiveText;
} }

View File

@ -11,7 +11,7 @@
// wang-editor textarea // wang-editor textarea
--w-e-textarea-slight-border-color: var(--el-color-primary); --w-e-textarea-slight-border-color: var(--el-color-primary);
--w-e-textarea-slight-bg-color: rgba(var(--el-color-primary-rgb), .1); --w-e-textarea-slight-bg-color: rgb(var(--el-color-primary-rgb) 0.1);
--w-e-textarea-selected-border-color: var(--el-color-primary); --w-e-textarea-selected-border-color: var(--el-color-primary);
} }

View File

@ -1,11 +1,11 @@
// translate router.meta.title, be used in breadcrumb sidebar tagsview // translate router.meta.title, be used in breadcrumb sidebar tagsview
import i18n from '@/lang/index'; import i18n from "@/lang/index";
export function translateRouteTitleI18n(title: any) { export function translateRouteTitleI18n(title: any) {
// 判断是否存在国际化配置,如果没有原生返回 // 判断是否存在国际化配置,如果没有原生返回
const hasKey = i18n.global.te('route.' + title); const hasKey = i18n.global.te("route." + title);
if (hasKey) { if (hasKey) {
const translatedTitle = i18n.global.t('route.' + title); const translatedTitle = i18n.global.t("route." + title);
return translatedTitle; return translatedTitle;
} }
return title; return title;

View File

@ -1,11 +1,11 @@
import axios, { InternalAxiosRequestConfig, AxiosResponse } from 'axios'; import axios, { InternalAxiosRequestConfig, AxiosResponse } from "axios";
import { useUserStoreHook } from '@/store/modules/user'; import { useUserStoreHook } from "@/store/modules/user";
// 创建 axios 实例 // 创建 axios 实例
const service = axios.create({ const service = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API, baseURL: import.meta.env.VITE_APP_BASE_API,
timeout: 50000, timeout: 50000,
headers: { 'Content-Type': 'application/json;charset=utf-8' } headers: { "Content-Type": "application/json;charset=utf-8" },
}); });
// 请求拦截器 // 请求拦截器
@ -26,7 +26,7 @@ service.interceptors.request.use(
service.interceptors.response.use( service.interceptors.response.use(
(response: AxiosResponse) => { (response: AxiosResponse) => {
const { code, msg } = response.data; const { code, msg } = response.data;
if (code === '00000') { if (code === "00000") {
return response.data; return response.data;
} }
// 响应数据为二进制流处理(Excel导出) // 响应数据为二进制流处理(Excel导出)
@ -34,23 +34,23 @@ service.interceptors.response.use(
return response; return response;
} }
ElMessage.error(msg || '系统出错'); ElMessage.error(msg || "系统出错");
return Promise.reject(new Error(msg || 'Error')); return Promise.reject(new Error(msg || "Error"));
}, },
(error: any) => { (error: any) => {
if (error.response.data) { if (error.response.data) {
const { code, msg } = error.response.data; const { code, msg } = error.response.data;
// token 过期,重新登录 // token 过期,重新登录
if (code === 'A0230') { if (code === "A0230") {
ElMessageBox.confirm('当前页面已失效,请重新登录', '提示', { ElMessageBox.confirm("当前页面已失效,请重新登录", "提示", {
confirmButtonText: '确定', confirmButtonText: "确定",
type: 'warning' type: "warning",
}).then(() => { }).then(() => {
localStorage.clear(); localStorage.clear();
window.location.href = '/'; window.location.href = "/";
}); });
} else { } else {
ElMessage.error(msg || '系统出错'); ElMessage.error(msg || "系统出错");
} }
} }
return Promise.reject(error.message); return Promise.reject(error.message);

View File

@ -47,7 +47,7 @@ export const scrollTo = (to: number, duration: number, callback?: any) => {
const change = to - start; const change = to - start;
const increment = 20; const increment = 20;
let currentTime = 0; let currentTime = 0;
duration = typeof duration === 'undefined' ? 500 : duration; duration = typeof duration === "undefined" ? 500 : duration;
const animateScroll = function () { const animateScroll = function () {
// increment the time // increment the time
currentTime += increment; currentTime += increment;
@ -59,7 +59,7 @@ export const scrollTo = (to: number, duration: number, callback?: any) => {
if (currentTime < duration) { if (currentTime < duration) {
requestAnimFrame(animateScroll); requestAnimFrame(animateScroll);
} else { } else {
if (callback && typeof callback === 'function') { if (callback && typeof callback === "function") {
// the animation is done so lets callback // the animation is done so lets callback
callback(); callback();
} }

View File

@ -5,15 +5,12 @@
<div class="title"> <div class="title">
业绩柱状图 业绩柱状图
<el-tooltip effect="dark" content="点击试试下载" placement="bottom"> <el-tooltip effect="dark" content="点击试试下载" placement="bottom">
<i-ep-download <i-ep-download class="download" @click="downloadEchart" />
class="download"
@click="downloadEchart"
></i-ep-download>
</el-tooltip> </el-tooltip>
</div> </div>
</template> </template>
<div :id="id" :class="className" :style="{ height, width }" /> <div :id="id" :class="className" :style="{ height, width }"></div>
</el-card> </el-card>
</template> </template>

View File

@ -1,96 +1,96 @@
<!-- 漏斗图 --> <!-- 漏斗图 -->
<template> <template>
<div :id="id" :class="className" :style="{ height, width }" /> <div :id="id" :class="className" :style="{ height, width }"></div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import * as echarts from 'echarts'; import * as echarts from "echarts";
const props = defineProps({ const props = defineProps({
id: { id: {
type: String, type: String,
default: 'funnelChart' default: "funnelChart",
}, },
className: { className: {
type: String, type: String,
default: '' default: "",
}, },
width: { width: {
type: String, type: String,
default: '200px', default: "200px",
required: true required: true,
}, },
height: { height: {
type: String, type: String,
default: '200px', default: "200px",
required: true required: true,
} },
}); });
const options = { const options = {
title: { title: {
show: true, show: true,
text: '订单线索转化漏斗图', text: "订单线索转化漏斗图",
x: 'center', x: "center",
padding: 15, padding: 15,
textStyle: { textStyle: {
fontSize: 18, fontSize: 18,
fontStyle: 'normal', fontStyle: "normal",
fontWeight: 'bold', fontWeight: "bold",
color: '#337ecc' color: "#337ecc",
} },
}, },
grid: { grid: {
left: '2%', left: "2%",
right: '2%', right: "2%",
bottom: '10%', bottom: "10%",
containLabel: true containLabel: true,
}, },
legend: { legend: {
x: 'center', x: "center",
y: 'bottom', y: "bottom",
data: ['Show', 'Click', 'Visit', 'Inquiry', 'Order'] data: ["Show", "Click", "Visit", "Inquiry", "Order"],
}, },
series: [ series: [
{ {
name: 'Funnel', name: "Funnel",
type: 'funnel', type: "funnel",
left: '20%', left: "20%",
top: 60, top: 60,
bottom: 60, bottom: 60,
width: '60%', width: "60%",
sort: 'descending', sort: "descending",
gap: 2, gap: 2,
label: { label: {
show: true, show: true,
position: 'inside' position: "inside",
}, },
labelLine: { labelLine: {
length: 10, length: 10,
lineStyle: { lineStyle: {
width: 1, width: 1,
type: 'solid' type: "solid",
} },
}, },
itemStyle: { itemStyle: {
borderColor: '#fff', borderColor: "#fff",
borderWidth: 1 borderWidth: 1,
}, },
emphasis: { emphasis: {
label: { label: {
fontSize: 20 fontSize: 20,
} },
}, },
data: [ data: [
{ value: 60, name: 'Visit' }, { value: 60, name: "Visit" },
{ value: 40, name: 'Inquiry' }, { value: 40, name: "Inquiry" },
{ value: 20, name: 'Order' }, { value: 20, name: "Order" },
{ value: 80, name: 'Click' }, { value: 80, name: "Click" },
{ value: 100, name: 'Show' } { value: 100, name: "Show" },
] ],
} },
] ],
}; };
onMounted(() => { onMounted(() => {
@ -99,7 +99,7 @@ onMounted(() => {
); );
chart.setOption(options); chart.setOption(options);
window.addEventListener('resize', () => { window.addEventListener("resize", () => {
chart.resize(); chart.resize();
}); });
}); });

View File

@ -2,69 +2,69 @@
<template> <template>
<el-card> <el-card>
<template #header> 产品分类饼图 </template> <template #header> 产品分类饼图 </template>
<div :id="id" :class="className" :style="{ height, width }" /> <div :id="id" :class="className" :style="{ height, width }"></div>
</el-card> </el-card>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import * as echarts from 'echarts'; import * as echarts from "echarts";
const props = defineProps({ const props = defineProps({
id: { id: {
type: String, type: String,
default: 'pieChart' default: "pieChart",
}, },
className: { className: {
type: String, type: String,
default: '' default: "",
}, },
width: { width: {
type: String, type: String,
default: '200px', default: "200px",
required: true required: true,
}, },
height: { height: {
type: String, type: String,
default: '200px', default: "200px",
required: true required: true,
} },
}); });
const options = { const options = {
grid: { grid: {
left: '2%', left: "2%",
right: '2%', right: "2%",
bottom: '10%', bottom: "10%",
containLabel: true containLabel: true,
}, },
legend: { legend: {
top: 'bottom', top: "bottom",
textStyle: { textStyle: {
color: '#999' color: "#999",
} },
}, },
series: [ series: [
{ {
name: 'Nightingale Chart', name: "Nightingale Chart",
type: 'pie', type: "pie",
radius: [50, 130], radius: [50, 130],
center: ['50%', '50%'], center: ["50%", "50%"],
roseType: 'area', roseType: "area",
itemStyle: { itemStyle: {
borderRadius: 1, borderRadius: 1,
color: function (params: any) { color: function (params: any) {
// //
const colorList = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C']; const colorList = ["#409EFF", "#67C23A", "#E6A23C", "#F56C6C"];
return colorList[params.dataIndex]; return colorList[params.dataIndex];
} },
}, },
data: [ data: [
{ value: 26, name: '家用电器' }, { value: 26, name: "家用电器" },
{ value: 27, name: '户外运动' }, { value: 27, name: "户外运动" },
{ value: 24, name: '汽车用品' }, { value: 24, name: "汽车用品" },
{ value: 23, name: '手机数码' } { value: 23, name: "手机数码" },
] ],
} },
] ],
}; };
onMounted(() => { onMounted(() => {
@ -72,7 +72,7 @@ onMounted(() => {
document.getElementById(props.id) as HTMLDivElement document.getElementById(props.id) as HTMLDivElement
); );
chart.setOption(options); chart.setOption(options);
window.addEventListener('resize', () => { window.addEventListener("resize", () => {
chart.resize(); chart.resize();
}); });
}); });

View File

@ -2,89 +2,89 @@
<template> <template>
<el-card> <el-card>
<template #header> 订单状态雷达图 </template> <template #header> 订单状态雷达图 </template>
<div :id="id" :class="className" :style="{ height, width }" /> <div :id="id" :class="className" :style="{ height, width }"></div>
</el-card> </el-card>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import * as echarts from 'echarts'; import * as echarts from "echarts";
const props = defineProps({ const props = defineProps({
id: { id: {
type: String, type: String,
default: 'radarChart' default: "radarChart",
}, },
className: { className: {
type: String, type: String,
default: '' default: "",
}, },
width: { width: {
type: String, type: String,
default: '200px', default: "200px",
required: true required: true,
}, },
height: { height: {
type: String, type: String,
default: '200px', default: "200px",
required: true required: true,
} },
}); });
const options = { const options = {
grid: { grid: {
left: '2%', left: "2%",
right: '2%', right: "2%",
bottom: '10%', bottom: "10%",
containLabel: true containLabel: true,
}, },
legend: { legend: {
x: 'center', x: "center",
y: 'bottom', y: "bottom",
data: ['预定数量', '下单数量', '发货数量'], data: ["预定数量", "下单数量", "发货数量"],
textStyle: { textStyle: {
color: '#999' color: "#999",
} },
}, },
radar: { radar: {
// shape: 'circle', // shape: 'circle',
radius: '60%', radius: "60%",
indicator: [ indicator: [
{ name: '家用电器' }, { name: "家用电器" },
{ name: '服装箱包' }, { name: "服装箱包" },
{ name: '运动户外' }, { name: "运动户外" },
{ name: '手机数码' }, { name: "手机数码" },
{ name: '汽车用品' }, { name: "汽车用品" },
{ name: '家具厨具' } { name: "家具厨具" },
] ],
}, },
series: [ series: [
{ {
name: 'Budget vs spending', name: "Budget vs spending",
type: 'radar', type: "radar",
itemStyle: { itemStyle: {
borderRadius: 6, borderRadius: 6,
color: function (params: any) { color: function (params: any) {
// //
const colorList = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C']; const colorList = ["#409EFF", "#67C23A", "#E6A23C", "#F56C6C"];
return colorList[params.dataIndex]; return colorList[params.dataIndex];
} },
}, },
data: [ data: [
{ {
value: [400, 400, 400, 400, 400, 400], value: [400, 400, 400, 400, 400, 400],
name: '预定数量' name: "预定数量",
}, },
{ {
value: [300, 300, 300, 300, 300, 300], value: [300, 300, 300, 300, 300, 300],
name: '下单数量' name: "下单数量",
}, },
{ {
value: [200, 200, 200, 200, 200, 200], value: [200, 200, 200, 200, 200, 200],
name: '发货数量' name: "发货数量",
} },
] ],
} },
] ],
}; };
onMounted(() => { onMounted(() => {
@ -93,7 +93,7 @@ onMounted(() => {
); );
chart.setOption(options); chart.setOption(options);
window.addEventListener('resize', () => { window.addEventListener("resize", () => {
chart.resize(); chart.resize();
}); });
}); });

View File

@ -1,13 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { useUserStore } from "@/store/modules/user";
import { useTransition, TransitionPresets } from "@vueuse/core";
defineOptions({ defineOptions({
// eslint-disable-next-line vue/no-reserved-component-names // eslint-disable-next-line vue/no-reserved-component-names
name: "Dashboard", name: "Dashboard",
inheritAttrs: false, inheritAttrs: false,
}); });
import { useUserStore } from "@/store/modules/user";
import { useTransition, TransitionPresets } from "@vueuse/core";
const userStore = useUserStore(); const userStore = useUserStore();
const date: Date = new Date(); const date: Date = new Date();

27
src/views/demo/google.vue Normal file
View File

@ -0,0 +1,27 @@
<!-- 接口文档 -->
<template>
<div class="app-container">
<iframe
src="https://creator.xiaohongshu.com/"
width="100%"
height="100%"
frameborder="0"
></iframe>
</div>
</template>
<style lang="scss" scoped>
.app-container {
display: flex;
flex-direction: column;
/* 84 = navbar + tags-view = 50 + 34 */
height: calc(100vh - 50px);
}
.hasTagsView {
.app-container {
height: calc(100vh - 84px);
}
}
</style>

View File

@ -15,8 +15,8 @@
<div class="label-wrap" @click="handleClickHead(oneCol)"> <div class="label-wrap" @click="handleClickHead(oneCol)">
<div>{{ oneCol.label }}</div> <div>{{ oneCol.label }}</div>
<template v-if="oneCol.order"> <template v-if="oneCol.order">
<i-ep-sort-up v-if="oneCol.order === 'asc'"></i-ep-sort-up> <i-ep-sort-up v-if="oneCol.order === 'asc'" />
<i-ep-sort-down v-else></i-ep-sort-down> <i-ep-sort-down v-else />
</template> </template>
</div> </div>
@ -24,7 +24,7 @@
trigger="click" trigger="click"
@command="(command: string) => handleCommand(command, oneCol)" @command="(command: string) => handleCommand(command, oneCol)"
> >
<i-ep-arrow-down class="action-more"></i-ep-arrow-down> <i-ep-arrow-down class="action-more" />
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<template v-if="oneCol.prop === 'id'"> <template v-if="oneCol.prop === 'id'">
@ -56,7 +56,7 @@
action="" action=""
:http-request="handleUploadFile" :http-request="handleUploadFile"
> >
<i-ep-upload-filled class="icon"></i-ep-upload-filled> <i-ep-upload-filled class="icon" />
<div class="el-upload__text">拖拽excel到这里</div> <div class="el-upload__text">拖拽excel到这里</div>
</el-upload> </el-upload>
<div v-loading="loading" class="excel-table-wrap"> <div v-loading="loading" class="excel-table-wrap">

View File

@ -1,6 +1,7 @@
<!-- wangEditor富文本编辑器示例 --> <!-- wangEditor富文本编辑器示例 -->
<script setup lang="ts"> <script setup lang="ts">
import Editor from "@/components/WangEditor/index.vue"; import Editor from "@/components/WangEditor/index.vue";
const value = ref("初始内容"); const value = ref("初始内容");
</script> </script>

View File

@ -1,18 +1,18 @@
<!-- websocket 示例 --> <!-- websocket 示例 -->
<script setup lang="ts"> <script setup lang="ts">
import { sendToAll, sendToUser } from "@/api/websocket"; import { sendToAll, sendToUser } from "@/api/websocket"; //
import { useUserStore } from "@/store/modules/user";
import { useWebSocket } from "@vueuse/core";
const inputVal = ref("初始内容"); const inputVal = ref("初始内容");
const topicMsgs = ref<string[]>(["接收到一条主题消息"]); // const topicMsgs = ref<string[]>(["接收到一条主题消息"]); //
const p2pMsgs = ref<string[]>(["接收到一条点对线消息"]); // const p2pMsgs = ref<string[]>(["接收到一条点对线消息"]);
import { useUserStore } from "@/store/modules/user";
const userId = useUserStore().userId; const userId = useUserStore().userId;
import { useWebSocket } from "@vueuse/core";
const { data, status, close, send, open } = useWebSocket( const { data, status, close, send, open } = useWebSocket(
"ws://localhost:8989/ws", "ws://localhost:8989/ws",
{ {

View File

@ -1,14 +1,13 @@
<!-- setup 无法设置组件名称组件名称keepAlive必须 -->
<script lang="ts">
export default {
name: "Page401",
};
</script>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, toRefs } from "vue"; import { reactive, toRefs } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { defineComponent } from "vue";
defineComponent({
name: "Page401",
});
const state = reactive({ const state = reactive({
errGif: new URL(`../../assets/401_images/401.gif`, import.meta.url).href, errGif: new URL(`../../assets/401_images/401.gif`, import.meta.url).href,

View File

@ -0,0 +1,27 @@
<template>
<div>
<div style="margin-bottom: 15px">Your roles: {{ roles }}</div>
Switch roles:
<el-radio-group v-model="switchRoles">
<el-radio-button label="EDITOR" />
<el-radio-button label="ADMIN" />
</el-radio-group>
</div>
</template>
<script setup lang="ts">
import { useUserStoreHook } from "@/store/modules/user";
import { storeToRefs } from "pinia";
const emit = defineEmits(["change"]);
const store = storeToRefs(useUserStoreHook());
const { roles } = store;
const switchRoles = computed({
get: () => roles.value[0],
set: (val) => {
roles.value = [val];
emit("change");
},
});
</script>

View File

@ -0,0 +1,21 @@
<template>
<div class="app-container">
<switch-roles @change="handleRolesChange" />
</div>
</template>
<script setup lang="ts">
import router from "@/router";
import SwitchRoles from "./components/SwitchRoles.vue";
defineOptions({
// eslint-disable-next-line
name: "PagePermission",
inheritAttrs: false,
});
function handleRolesChange() {
console.log("roles changed");
router.push({ path: "/permission/page?" + new Date() });
}
</script>

View File

@ -1,9 +1,9 @@
<template> <template>
<div /> <div></div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from "vue-router";
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
@ -11,5 +11,5 @@ const router = useRouter();
const { params, query } = route; const { params, query } = route;
const { path } = params; const { path } = params;
router.replace({ path: '/' + path, query }); router.replace({ path: "/" + path, query });
</script> </script>

View File

@ -1,9 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
defineOptions({
name: "Dept",
inheritAttrs: false,
});
import { import {
getDeptForm, getDeptForm,
deleteDept, deleteDept,
@ -15,6 +10,11 @@ import {
import { DeptVO, DeptForm, DeptQuery } from "@/api/dept/types"; import { DeptVO, DeptForm, DeptQuery } from "@/api/dept/types";
defineOptions({
name: "Dept",
inheritAttrs: false,
});
const queryFormRef = ref(ElForm); const queryFormRef = ref(ElForm);
const deptFormRef = ref(ElForm); const deptFormRef = ref(ElForm);

View File

@ -1,10 +1,5 @@
<!-- 字典数据 --> <!-- 字典数据 -->
<script setup lang="ts"> <script setup lang="ts">
defineOptions({
name: "DictData",
inheritAttrs: false,
});
import { import {
getDictPage, getDictPage,
getDictFormData, getDictFormData,
@ -14,6 +9,11 @@ import {
} from "@/api/dict"; } from "@/api/dict";
import { DictPageVO, DictForm, DictQuery } from "@/api/dict/types"; import { DictPageVO, DictForm, DictQuery } from "@/api/dict/types";
defineOptions({
name: "DictData",
inheritAttrs: false,
});
const props = defineProps({ const props = defineProps({
typeCode: { typeCode: {
type: String, type: String,
@ -311,7 +311,7 @@ onMounted(() => {
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="备注" prop="remark"> <el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" type="textarea"></el-input> <el-input v-model="formData.remark" type="textarea" />
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>

View File

@ -1,10 +1,5 @@
<!--字典类型--> <!--字典类型-->
<script setup lang="ts"> <script setup lang="ts">
defineOptions({
name: "DictType",
inheritAttrs: false,
});
import { import {
getDictTypePage, getDictTypePage,
getDictTypeForm, getDictTypeForm,
@ -17,6 +12,11 @@ import DictData from "@/views/system/dict/DictData.vue";
import { DictTypePageVO, DictTypeQuery, DictTypeForm } from "@/api/dict/types"; import { DictTypePageVO, DictTypeQuery, DictTypeForm } from "@/api/dict/types";
defineOptions({
name: "DictType",
inheritAttrs: false,
});
const queryFormRef = ref(ElForm); const queryFormRef = ref(ElForm);
const dataFormRef = ref(ElForm); const dataFormRef = ref(ElForm);

View File

@ -1,10 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
defineOptions({
// eslint-disable-next-line vue/no-reserved-component-names
name: "Menu",
inheritAttrs: false,
});
import { MenuQuery, MenuForm, MenuVO } from "@/api/menu/types"; import { MenuQuery, MenuForm, MenuVO } from "@/api/menu/types";
import { import {
listMenus, listMenus,
@ -20,6 +14,12 @@ import { MenuTypeEnum } from "@/enums/MenuTypeEnum";
import SvgIcon from "@/components/SvgIcon/index.vue"; import SvgIcon from "@/components/SvgIcon/index.vue";
import IconSelect from "@/components/IconSelect/index.vue"; import IconSelect from "@/components/IconSelect/index.vue";
defineOptions({
// eslint-disable-next-line vue/no-reserved-component-names
name: "Menu",
inheritAttrs: false,
});
const queryFormRef = ref(ElForm); const queryFormRef = ref(ElForm);
const menuFormRef = ref(ElForm); const menuFormRef = ref(ElForm);

View File

@ -1,9 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
defineOptions({
name: "Role",
inheritAttrs: false,
});
import { import {
getRolePage, getRolePage,
updateRole, updateRole,
@ -17,6 +12,11 @@ import { listMenuOptions } from "@/api/menu";
import { RolePageVO, RoleForm, RoleQuery } from "@/api/role/types"; import { RolePageVO, RoleForm, RoleQuery } from "@/api/role/types";
defineOptions({
name: "Role",
inheritAttrs: false,
});
const queryFormRef = ref(ElForm); const queryFormRef = ref(ElForm);
const roleFormRef = ref(ElForm); const roleFormRef = ref(ElForm);
const menuRef = ref(ElTree); const menuRef = ref(ElTree);

View File

@ -2,10 +2,6 @@
/** /**
* @see {@link https://vuejs.org/api/sfc-script-setup.html#defineoptions} * @see {@link https://vuejs.org/api/sfc-script-setup.html#defineoptions}
*/ */
defineOptions({
name: "User",
inheritAttrs: false,
});
import { UploadFile } from "element-plus"; import { UploadFile } from "element-plus";
import { import {
getUserPage, getUserPage,
@ -24,6 +20,11 @@ import { listRoleOptions } from "@/api/role";
import { UserForm, UserQuery, UserPageVO } from "@/api/user/types"; import { UserForm, UserQuery, UserPageVO } from "@/api/user/types";
defineOptions({
name: "User",
inheritAttrs: false,
});
const deptTreeRef = ref(ElTree); // const deptTreeRef = ref(ElTree); //
const queryFormRef = ref(ElForm); // const queryFormRef = ref(ElForm); //
const userFormRef = ref(ElForm); // const userFormRef = ref(ElForm); //
@ -383,7 +384,7 @@ onMounted(() => {
:filter-node-method="handleDeptFilter" :filter-node-method="handleDeptFilter"
default-expand-all default-expand-all
@node-click="handleDeptNodeClick" @node-click="handleDeptNodeClick"
></el-tree> />
</el-card> </el-card>
</el-col> </el-col>
@ -524,7 +525,7 @@ onMounted(() => {
align="center" align="center"
prop="createTime" prop="createTime"
width="180" width="180"
></el-table-column> />
<el-table-column label="操作" fixed="right" width="220"> <el-table-column label="操作" fixed="right" width="220">
<template #default="scope"> <template #default="scope">
<el-button <el-button

View File

@ -5,6 +5,7 @@
"module": "esnext", "module": "esnext",
"moduleResolution": "node", "moduleResolution": "node",
"strict": true, "strict": true,
"noLib": false,
"jsx": "preserve", "jsx": "preserve",
"sourceMap": true, "sourceMap": true,
"resolveJsonModule": true, "resolveJsonModule": true,
@ -20,7 +21,13 @@
"allowSyntheticDefaultImports": true /* */, "allowSyntheticDefaultImports": true /* */,
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */ "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */
}, },
"include": ["src/**/*.ts", "src/**/*.vue", "src/types/**/*.d.ts"], "include": [
"exclude": ["node_modules", "dist", "**/*.js"], "src/**/*.ts",
"references": [{ "path": "./tsconfig.node.json" }] "src/**/*.vue",
"src/types/**/*.d.ts",
"mock/**/*.ts",
"vite.config.ts"
],
"exclude": ["node_modules", "dist", "**/*.js"]
// "references": [{ "path": "./tsconfig.node.json" }]
} }

View File

@ -1,9 +0,0 @@
{
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

View File

@ -11,6 +11,9 @@ import IconsResolver from "unplugin-icons/resolver";
import { createSvgIconsPlugin } from "vite-plugin-svg-icons"; import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
import { viteMockServe } from "vite-plugin-mock";
import visualizer from "rollup-plugin-visualizer";
import UnoCSS from "unocss/vite"; import UnoCSS from "unocss/vite";
import path from "path"; import path from "path";
@ -20,6 +23,7 @@ const pathSrc = path.resolve(__dirname, "src");
export default defineConfig(({ mode }: ConfigEnv): UserConfig => { export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
const env = loadEnv(mode, process.cwd()); const env = loadEnv(mode, process.cwd());
return { return {
resolve: { resolve: {
alias: { alias: {
@ -45,11 +49,15 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
proxy: { proxy: {
// 反向代理解决跨域 // 反向代理解决跨域
[env.VITE_APP_BASE_API]: { [env.VITE_APP_BASE_API]: {
target: "http://vapi.youlai.tech", // 线上接口地址 // target: "http://vapi.youlai.tech", // 线上接口地址
// target: 'http://localhost:8989', // 本地接口地址 , 后端工程仓库地址https://gitee.com/youlaiorg/youlai-boot // target: 'http://localhost:3001', // 本地接口地址 , 后端工程仓库地址https://gitee.com/youlaiorg/youlai-boot
target: env.VITE_APP_TARGET_URL,
changeOrigin: true, changeOrigin: true,
rewrite: (path) => rewrite: (path) =>
path.replace(new RegExp("^" + env.VITE_APP_BASE_API), ""), // 替换 /dev-api 为 target 接口地址 path.replace(
new RegExp("^" + env.VITE_APP_BASE_API),
env.VITE_APP_TARGET_BASE_API
), // 替换 /dev-api 为 target 接口地址
}, },
}, },
}, },
@ -112,6 +120,20 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
algorithm: "gzip", // 压缩算法 algorithm: "gzip", // 压缩算法
ext: ".gz", // 文件类型 ext: ".gz", // 文件类型
}), }),
viteMockServe({
ignore: /^\_/,
mockPath: "mock",
enable: mode === "development",
// https://github.com/anncwb/vite-plugin-mock/issues/9
}),
visualizer({
filename: "./stats.html",
open: false,
gzipSize: true,
brotliSize: true,
}),
], ],
// 预加载项目必需的组件 // 预加载项目必需的组件
optimizeDeps: { optimizeDeps: {