“feat:数字农业产业运营平台”
25
.gitignore
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
.history
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
9
main/.editorconfig
Normal file
@ -0,0 +1,9 @@
|
||||
root = true
|
||||
|
||||
[*.{js,jsx,ts,tsx,vue}]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
end_of_line = auto
|
8
main/.env.development
Normal file
@ -0,0 +1,8 @@
|
||||
# 开发环境
|
||||
VITE_PORT = 9000
|
||||
VITE_APP_NAME = 'daimp-front-main'
|
||||
VITE_APP_BASE_API = "https://mock.mengxuegu.com/mock/664ef7fee45d2156fa209ee4/api-qiankun"
|
||||
VITE_APP_BASE_URL = 'http://192.168.18.158:9080'
|
||||
VITE_APP_SUB_VUE = '//localhost:9526/sub-vue/'
|
||||
VITE_APP_SUB_ADMIN = '//localhost:9527/sub-admin/'
|
||||
|
6
main/.env.production
Normal file
@ -0,0 +1,6 @@
|
||||
# 正式环境
|
||||
VITE_APP_NAME = 'daimp-front-main'
|
||||
VITE_APP_BASE_API = ""
|
||||
VITE_APP_BASE_URL = ''
|
||||
VITE_APP_SUB_VUE = '//localhost:9526/sub-vue/'
|
||||
VITE_APP_SUB_ADMIN = '//localhost:9527/sub-admin/'
|
14
main/.eslintignore
Normal file
@ -0,0 +1,14 @@
|
||||
*.sh
|
||||
*.md
|
||||
*.woff
|
||||
*.ttf
|
||||
.vscode
|
||||
.idea
|
||||
.husky
|
||||
.local
|
||||
dist
|
||||
src/assets
|
||||
node_modules
|
||||
Dockerfile
|
||||
stats.html
|
||||
tailwind.config.js
|
48
main/.eslintrc.cjs
Normal file
@ -0,0 +1,48 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
node: true,
|
||||
},
|
||||
extends: [
|
||||
'eslint-config-prettier',
|
||||
'eslint:recommended',
|
||||
// 'plugin:@typescript-eslint/recommended',
|
||||
'plugin:vue/vue3-recommended',
|
||||
'plugin:vue/vue3-essential',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
overrides: [
|
||||
{
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
files: ['.eslintrc.{js,cjs}'],
|
||||
parserOptions: {
|
||||
sourceType: 'script',
|
||||
},
|
||||
},
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
requireConfigFile: false,
|
||||
parser: '@babel/eslint-parser',
|
||||
// parser: '@typescript-eslint/parser',
|
||||
},
|
||||
plugins: ['vue', 'prettier'],
|
||||
globals: {
|
||||
defineProps: 'readonly',
|
||||
defineEmits: 'readonly',
|
||||
defineExpose: 'readonly',
|
||||
withDefaults: 'readonly',
|
||||
},
|
||||
// 这里时配置规则的,自己看情况配置
|
||||
rules: {
|
||||
'prettier/prettier': 'error',
|
||||
'no-debugger': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/no-unused-vars': 'off',
|
||||
},
|
||||
};
|
25
main/.gitignore
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
.history
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
20
main/.prettierignore
Normal file
@ -0,0 +1,20 @@
|
||||
## OS
|
||||
.DS_Store
|
||||
node_modules
|
||||
.idea
|
||||
.editorconfig
|
||||
package-lock.json
|
||||
.npmrc
|
||||
|
||||
# Ignored suffix
|
||||
*.log
|
||||
*.md
|
||||
*.svg
|
||||
*.png
|
||||
*ignore
|
||||
|
||||
## Local
|
||||
|
||||
## Built-files
|
||||
.cache
|
||||
dist
|
21
main/.prettierrc.cjs
Normal file
@ -0,0 +1,21 @@
|
||||
module.exports = {
|
||||
printWidth: 150,
|
||||
tabWidth: 2,
|
||||
useTabs: false,
|
||||
semi: true,
|
||||
singleQuote: true,
|
||||
quoteProps: 'as-needed',
|
||||
jsxSingleQuote: false,
|
||||
trailingComma: 'es5',
|
||||
bracketSpacing: true,
|
||||
jsxBracketSameLine: false,
|
||||
arrowParens: 'always',
|
||||
rangeStart: 0,
|
||||
rangeEnd: Infinity,
|
||||
requirePragma: false,
|
||||
insertPragma: false,
|
||||
proseWrap: 'preserve',
|
||||
htmlWhitespaceSensitivity: 'css',
|
||||
vueIndentScriptAndStyle: false,
|
||||
endOfLine: 'auto',
|
||||
};
|
17
main/.stylelintignore
Normal file
@ -0,0 +1,17 @@
|
||||
# .stylelintignore
|
||||
# 旧的不需打包的样式库
|
||||
*.min.css
|
||||
|
||||
# 其他类型文件
|
||||
*.js
|
||||
*.jpg
|
||||
*.png
|
||||
*.eot
|
||||
*.ttf
|
||||
*.woff
|
||||
*.json
|
||||
|
||||
# 测试和打包目录
|
||||
/dist/*
|
||||
/node_modules/*
|
||||
/src/assets/*
|
124
main/.stylelintrc.cjs
Normal file
@ -0,0 +1,124 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
plugins: ['stylelint-order', 'stylelint-scss'],
|
||||
extends: [
|
||||
'stylelint-config-standard',
|
||||
'stylelint-config-standard-scss',
|
||||
'stylelint-config-prettier',
|
||||
'stylelint-config-html/vue',
|
||||
'stylelint-config-recommended-vue',
|
||||
'stylelint-config-recommended-scss',
|
||||
],
|
||||
overrides: [
|
||||
{
|
||||
files: ['**/*.{html,vue}'],
|
||||
customSyntax: 'postcss-html',
|
||||
},
|
||||
],
|
||||
rules: {
|
||||
indentation: 2,
|
||||
'selector-pseudo-element-no-unknown': [
|
||||
true,
|
||||
{
|
||||
ignorePseudoElements: ['v-deep', ':deep'],
|
||||
},
|
||||
],
|
||||
'number-leading-zero': 'always',
|
||||
'no-descending-specificity': null,
|
||||
'function-url-quotes': 'always',
|
||||
'string-quotes': 'single',
|
||||
'unit-case': null,
|
||||
'color-hex-case': 'lower',
|
||||
'color-hex-length': 'long',
|
||||
'rule-empty-line-before': 'never',
|
||||
'font-family-no-missing-generic-family-keyword': null,
|
||||
'selector-type-no-unknown': null,
|
||||
'block-opening-brace-space-before': 'always',
|
||||
'at-rule-no-unknown': null,
|
||||
'no-duplicate-selectors': null,
|
||||
'property-no-unknown': null,
|
||||
'no-empty-source': null,
|
||||
'selector-class-pattern': null,
|
||||
'keyframes-name-pattern': null,
|
||||
'selector-pseudo-class-no-unknown': [true, { ignorePseudoClasses: ['global', 'deep'] }],
|
||||
'function-no-unknown': null,
|
||||
'order/properties-order': [
|
||||
'position',
|
||||
'top',
|
||||
'right',
|
||||
'bottom',
|
||||
'left',
|
||||
'z-index',
|
||||
'display',
|
||||
'justify-content',
|
||||
'align-items',
|
||||
'float',
|
||||
'clear',
|
||||
'overflow',
|
||||
'overflow-x',
|
||||
'overflow-y',
|
||||
'margin',
|
||||
'margin-top',
|
||||
'margin-right',
|
||||
'margin-bottom',
|
||||
'margin-left',
|
||||
'padding',
|
||||
'padding-top',
|
||||
'padding-right',
|
||||
'padding-bottom',
|
||||
'padding-left',
|
||||
'width',
|
||||
'min-width',
|
||||
'max-width',
|
||||
'height',
|
||||
'min-height',
|
||||
'max-height',
|
||||
'font-size',
|
||||
'font-family',
|
||||
'font-weight',
|
||||
'border',
|
||||
'border-style',
|
||||
'border-width',
|
||||
'border-color',
|
||||
'border-top',
|
||||
'border-top-style',
|
||||
'border-top-width',
|
||||
'border-top-color',
|
||||
'border-right',
|
||||
'border-right-style',
|
||||
'border-right-width',
|
||||
'border-right-color',
|
||||
'border-bottom',
|
||||
'border-bottom-style',
|
||||
'border-bottom-width',
|
||||
'border-bottom-color',
|
||||
'border-left',
|
||||
'border-left-style',
|
||||
'border-left-width',
|
||||
'border-left-color',
|
||||
'border-radius',
|
||||
'text-align',
|
||||
'text-justify',
|
||||
'text-indent',
|
||||
'text-overflow',
|
||||
'text-decoration',
|
||||
'white-space',
|
||||
'color',
|
||||
'background',
|
||||
'background-position',
|
||||
'background-repeat',
|
||||
'background-size',
|
||||
'background-color',
|
||||
'background-clip',
|
||||
'opacity',
|
||||
'filter',
|
||||
'list-style',
|
||||
'outline',
|
||||
'visibility',
|
||||
'box-shadow',
|
||||
'text-shadow',
|
||||
'resize',
|
||||
'transition',
|
||||
],
|
||||
},
|
||||
};
|
4
main/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# 英壹集团
|
||||
|
||||
|
||||
|
13
main/index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/logo.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
10
main/jsconfig.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"jsx": "preserve",
|
||||
"paths": {
|
||||
"@/*": ["src/*"],
|
||||
},
|
||||
},
|
||||
"exclude": ["node_modules", "dist"],
|
||||
}
|
82
main/package.json
Normal file
@ -0,0 +1,82 @@
|
||||
{
|
||||
"name": "daimp-front-main",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --mode development",
|
||||
"build": "vite build --mode production",
|
||||
"preview": "vite preview",
|
||||
"format": "prettier --write 'src/**/*.{vue,ts,tsx,js,jsx,css,less,scss,json,md}'",
|
||||
"eslint": "npx eslint --init",
|
||||
"lint": "npm run lint:script && npm run lint:style",
|
||||
"lint:style": "stylelint 'src/**/*.{vue,scss,css,sass,less}' --fix",
|
||||
"lint:script": "eslint --ext .js,.ts,.tsx,.vue --fix --quiet ./src",
|
||||
"commit": "git add -A && czg && git push",
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"axios": "^1.6.5",
|
||||
"dayjs": "^1.11.11",
|
||||
"element-plus": "^2.7.3",
|
||||
"file-saver": "^2.0.5",
|
||||
"js-base64": "^3.7.7",
|
||||
"js-cookie": "^3.0.5",
|
||||
"jszip": "^3.10.1",
|
||||
"jszip-utils": "^0.1.0",
|
||||
"lib-flexible-computer": "^1.0.2",
|
||||
"lodash": "^4.17.21",
|
||||
"nprogress": "^0.2.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"pinia": "^2.1.7",
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
"postcss-pxtorem": "^6.1.0",
|
||||
"qiankun": "^2.10.16",
|
||||
"screenfull": "^6.0.2",
|
||||
"vite-plugin-svg-icons": "^2.0.1",
|
||||
"vue": "^3.5.11",
|
||||
"vue-router": "^4.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.23.7",
|
||||
"@babel/eslint-parser": "^7.23.3",
|
||||
"@types/path-browserify": "^1.0.2",
|
||||
"@vitejs/plugin-vue": "^4.5.2",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-vue": "^9.20.1",
|
||||
"husky": "^9.0.6",
|
||||
"lint-staged": "^15.2.0",
|
||||
"postcss": "^8.4.33",
|
||||
"postcss-html": "^1.6.0",
|
||||
"postcss-import": "^16.0.0",
|
||||
"prettier": "^3.2.4",
|
||||
"sass": "^1.70.0",
|
||||
"stylelint": "^16.2.0",
|
||||
"stylelint-config-html": "^1.1.0",
|
||||
"stylelint-config-prettier": "^9.0.5",
|
||||
"stylelint-config-rational-order": "^0.1.2",
|
||||
"stylelint-config-recommended": "^14.0.0",
|
||||
"stylelint-config-recommended-scss": "^14.0.0",
|
||||
"stylelint-config-recommended-vue": "^1.5.0",
|
||||
"stylelint-config-standard": "^36.0.0",
|
||||
"stylelint-config-standard-scss": "^13.0.0",
|
||||
"stylelint-order": "^6.0.4",
|
||||
"stylelint-scss": "^6.1.0",
|
||||
"terser": "^5.27.0",
|
||||
"unplugin-auto-import": "^0.17.3",
|
||||
"unplugin-vue-components": "^0.26.0",
|
||||
"vite": "^5.0.8",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-eslint": "^1.8.1",
|
||||
"vite-plugin-html": "^3.2.2",
|
||||
"vite-plugin-progress": "^0.0.7",
|
||||
"vite-plugin-qiankun": "^1.0.15",
|
||||
"vite-plugin-vue-setup-extend": "^0.4.0"
|
||||
}
|
||||
}
|
BIN
main/public/logo.png
Normal file
After Width: | Height: | Size: 12 KiB |
1
main/public/vite.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
45
main/src/App.vue
Normal file
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<!-- <el-button v-for="item in microApps" :key="item.activeRule" type="primary" @click="gotoPage(item)">{{ item.name }}</el-button> -->
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="App">
|
||||
import { reactive, provide, nextTick } from 'vue';
|
||||
import { microApps } from '@/micro/app';
|
||||
import actions from '@/micro/actions';
|
||||
|
||||
const state = reactive({
|
||||
isRouterAlive: true,
|
||||
});
|
||||
|
||||
const gotoPage = (row) => {
|
||||
const data = {};
|
||||
switch (row.name) {
|
||||
case 'sub-vue':
|
||||
data.title = 'sub-vue';
|
||||
break;
|
||||
case 'sub-admin':
|
||||
data.title = 'sub-admin';
|
||||
break;
|
||||
}
|
||||
// 设置与子应用通信的值
|
||||
actions.setGlobalState({
|
||||
data: data,
|
||||
});
|
||||
window.history.pushState({}, row.name, row.activeRule);
|
||||
};
|
||||
|
||||
const reload = () => {
|
||||
state.isRouterAlive = false;
|
||||
nextTick(() => {
|
||||
state.isRouterAlive = true;
|
||||
});
|
||||
};
|
||||
|
||||
provide('reload', reload);
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import './styles/style.scss';
|
||||
</style>
|
33
main/src/apis/login.js
Normal file
@ -0,0 +1,33 @@
|
||||
import request from '@/utils/axios';
|
||||
|
||||
/**
|
||||
* @Title: 登录
|
||||
*/
|
||||
export function Login(data, token) {
|
||||
return request('/self/login', {
|
||||
method: 'POST',
|
||||
data,
|
||||
headers: {
|
||||
'Fairies-Captcha-Token': token,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @Title: 登出
|
||||
*/
|
||||
export function LogOut() {
|
||||
return request('/self/logout', {
|
||||
method: 'POST',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @Title: 验证码
|
||||
*/
|
||||
export function GetCaptcha() {
|
||||
return request('/self/captcha', {
|
||||
method: 'GET',
|
||||
responseType: 'arraybuffer',
|
||||
});
|
||||
}
|
539
main/src/assets/fonts/demo.css
Normal file
@ -0,0 +1,539 @@
|
||||
/* Logo 字体 */
|
||||
@font-face {
|
||||
font-family: "iconfont logo";
|
||||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
|
||||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-family: "iconfont logo";
|
||||
font-size: 160px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* tabs */
|
||||
.nav-tabs {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-more {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
#tabs {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
#tabs li {
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
border-bottom: 2px solid transparent;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-bottom: -1px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
|
||||
#tabs .active {
|
||||
border-bottom-color: #f00;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.tab-container .content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 页面布局 */
|
||||
.main {
|
||||
padding: 30px 100px;
|
||||
width: 960px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.main .logo {
|
||||
color: #333;
|
||||
text-align: left;
|
||||
margin-bottom: 30px;
|
||||
line-height: 1;
|
||||
height: 110px;
|
||||
margin-top: -50px;
|
||||
overflow: hidden;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
.main .logo a {
|
||||
font-size: 160px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.helps {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.helps pre {
|
||||
padding: 20px;
|
||||
margin: 10px 0;
|
||||
border: solid 1px #e7e1cd;
|
||||
background-color: #fffdef;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.icon_lists {
|
||||
width: 100% !important;
|
||||
overflow: hidden;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
.icon_lists li {
|
||||
width: 100px;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 20px;
|
||||
text-align: center;
|
||||
list-style: none !important;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.icon_lists li .code-name {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.icon_lists .icon {
|
||||
display: block;
|
||||
height: 100px;
|
||||
line-height: 100px;
|
||||
font-size: 42px;
|
||||
margin: 10px auto;
|
||||
color: #333;
|
||||
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
|
||||
-moz-transition: font-size 0.25s linear, width 0.25s linear;
|
||||
transition: font-size 0.25s linear, width 0.25s linear;
|
||||
}
|
||||
|
||||
.icon_lists .icon:hover {
|
||||
font-size: 100px;
|
||||
}
|
||||
|
||||
.icon_lists .svg-icon {
|
||||
/* 通过设置 font-size 来改变图标大小 */
|
||||
width: 1em;
|
||||
/* 图标和文字相邻时,垂直对齐 */
|
||||
vertical-align: -0.15em;
|
||||
/* 通过设置 color 来改变 SVG 的颜色/fill */
|
||||
fill: currentColor;
|
||||
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
|
||||
normalize.css 中也包含这行 */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.icon_lists li .name,
|
||||
.icon_lists li .code-name {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* markdown 样式 */
|
||||
.markdown {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.markdown img {
|
||||
vertical-align: middle;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.markdown h1 {
|
||||
color: #404040;
|
||||
font-weight: 500;
|
||||
line-height: 40px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.markdown h2,
|
||||
.markdown h3,
|
||||
.markdown h4,
|
||||
.markdown h5,
|
||||
.markdown h6 {
|
||||
color: #404040;
|
||||
margin: 1.6em 0 0.6em 0;
|
||||
font-weight: 500;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.markdown h1 {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.markdown h2 {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.markdown h3 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.markdown h4 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.markdown h5 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown h6 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown hr {
|
||||
height: 1px;
|
||||
border: 0;
|
||||
background: #e9e9e9;
|
||||
margin: 16px 0;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.markdown p {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.markdown>p,
|
||||
.markdown>blockquote,
|
||||
.markdown>.highlight,
|
||||
.markdown>ol,
|
||||
.markdown>ul {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.markdown ul>li {
|
||||
list-style: circle;
|
||||
}
|
||||
|
||||
.markdown>ul li,
|
||||
.markdown blockquote ul>li {
|
||||
margin-left: 20px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.markdown>ul li p,
|
||||
.markdown>ol li p {
|
||||
margin: 0.6em 0;
|
||||
}
|
||||
|
||||
.markdown ol>li {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
.markdown>ol li,
|
||||
.markdown blockquote ol>li {
|
||||
margin-left: 20px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.markdown code {
|
||||
margin: 0 3px;
|
||||
padding: 0 5px;
|
||||
background: #eee;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.markdown strong,
|
||||
.markdown b {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown>table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0px;
|
||||
empty-cells: show;
|
||||
border: 1px solid #e9e9e9;
|
||||
width: 95%;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.markdown>table th {
|
||||
white-space: nowrap;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown>table th,
|
||||
.markdown>table td {
|
||||
border: 1px solid #e9e9e9;
|
||||
padding: 8px 16px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.markdown>table th {
|
||||
background: #F7F7F7;
|
||||
}
|
||||
|
||||
.markdown blockquote {
|
||||
font-size: 90%;
|
||||
color: #999;
|
||||
border-left: 4px solid #e9e9e9;
|
||||
padding-left: 0.8em;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.markdown blockquote p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.markdown .anchor {
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.markdown .waiting {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.markdown h1:hover .anchor,
|
||||
.markdown h2:hover .anchor,
|
||||
.markdown h3:hover .anchor,
|
||||
.markdown h4:hover .anchor,
|
||||
.markdown h5:hover .anchor,
|
||||
.markdown h6:hover .anchor {
|
||||
opacity: 1;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.markdown>br,
|
||||
.markdown>p>br {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
background: white;
|
||||
padding: 0.5em;
|
||||
color: #333333;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-meta {
|
||||
color: #969896;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-variable,
|
||||
.hljs-template-variable,
|
||||
.hljs-strong,
|
||||
.hljs-emphasis,
|
||||
.hljs-quote {
|
||||
color: #df5000;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-selector-tag,
|
||||
.hljs-type {
|
||||
color: #a71d5d;
|
||||
}
|
||||
|
||||
.hljs-literal,
|
||||
.hljs-symbol,
|
||||
.hljs-bullet,
|
||||
.hljs-attribute {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-section,
|
||||
.hljs-name {
|
||||
color: #63a35c;
|
||||
}
|
||||
|
||||
.hljs-tag {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-attr,
|
||||
.hljs-selector-id,
|
||||
.hljs-selector-class,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-pseudo {
|
||||
color: #795da3;
|
||||
}
|
||||
|
||||
.hljs-addition {
|
||||
color: #55a532;
|
||||
background-color: #eaffea;
|
||||
}
|
||||
|
||||
.hljs-deletion {
|
||||
color: #bd2c00;
|
||||
background-color: #ffecec;
|
||||
}
|
||||
|
||||
.hljs-link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 代码高亮 */
|
||||
/* PrismJS 1.15.0
|
||||
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
|
||||
/**
|
||||
* prism.js default theme for JavaScript, CSS and HTML
|
||||
* Based on dabblet (http://dabblet.com)
|
||||
* @author Lea Verou
|
||||
*/
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: black;
|
||||
background: none;
|
||||
text-shadow: 0 1px white;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::-moz-selection,
|
||||
pre[class*="language-"] ::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection,
|
||||
code[class*="language-"] ::-moz-selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::selection,
|
||||
pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection,
|
||||
code[class*="language-"] ::selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
@media print {
|
||||
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
padding: 1em;
|
||||
margin: .5em 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:not(pre)>code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
background: #f5f2f0;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre)>code[class*="language-"] {
|
||||
padding: .1em;
|
||||
border-radius: .3em;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: slategray;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.namespace {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.tag,
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.deleted {
|
||||
color: #905;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.attr-name,
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.inserted {
|
||||
color: #690;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url,
|
||||
.language-css .token.string,
|
||||
.style .token.string {
|
||||
color: #9a6e3a;
|
||||
background: hsla(0, 0%, 100%, .5);
|
||||
}
|
||||
|
||||
.token.atrule,
|
||||
.token.attr-value,
|
||||
.token.keyword {
|
||||
color: #07a;
|
||||
}
|
||||
|
||||
.token.function,
|
||||
.token.class-name {
|
||||
color: #DD4A68;
|
||||
}
|
||||
|
||||
.token.regex,
|
||||
.token.important,
|
||||
.token.variable {
|
||||
color: #e90;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
1499
main/src/assets/fonts/demo_index.html
Normal file
14
main/src/assets/fonts/iconfont.css
Normal file
@ -0,0 +1,14 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 4709068 */
|
||||
src: url('iconfont.woff2?t=1729754563434') format('woff2'),
|
||||
url('iconfont.woff?t=1729754563434') format('woff'),
|
||||
url('iconfont.ttf?t=1729754563434') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
1
main/src/assets/fonts/iconfont.js
Normal file
408
main/src/assets/fonts/iconfont.json
Normal file
@ -0,0 +1,408 @@
|
||||
{
|
||||
"id": "4709068",
|
||||
"name": "sub-admin",
|
||||
"font_family": "iconfont",
|
||||
"css_prefix_text": "icon-",
|
||||
"description": "react/vue项目后台管理平台",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "588769",
|
||||
"name": "待付款",
|
||||
"font_class": "pay",
|
||||
"unicode": "e626",
|
||||
"unicode_decimal": 58918
|
||||
},
|
||||
{
|
||||
"icon_id": "653976",
|
||||
"name": "已完成",
|
||||
"font_class": "complete",
|
||||
"unicode": "e60d",
|
||||
"unicode_decimal": 58893
|
||||
},
|
||||
{
|
||||
"icon_id": "1001767",
|
||||
"name": "修改密码",
|
||||
"font_class": "edit",
|
||||
"unicode": "e618",
|
||||
"unicode_decimal": 58904
|
||||
},
|
||||
{
|
||||
"icon_id": "1068811",
|
||||
"name": "待发货",
|
||||
"font_class": "deliver",
|
||||
"unicode": "e622",
|
||||
"unicode_decimal": 58914
|
||||
},
|
||||
{
|
||||
"icon_id": "1313074",
|
||||
"name": "待收货",
|
||||
"font_class": "receive",
|
||||
"unicode": "e611",
|
||||
"unicode_decimal": 58897
|
||||
},
|
||||
{
|
||||
"icon_id": "2121739",
|
||||
"name": "品牌",
|
||||
"font_class": "brand",
|
||||
"unicode": "e60f",
|
||||
"unicode_decimal": 58895
|
||||
},
|
||||
{
|
||||
"icon_id": "2846231",
|
||||
"name": "商品规格",
|
||||
"font_class": "sku",
|
||||
"unicode": "e607",
|
||||
"unicode_decimal": 58887
|
||||
},
|
||||
{
|
||||
"icon_id": "3978297",
|
||||
"name": "退出",
|
||||
"font_class": "exit",
|
||||
"unicode": "e641",
|
||||
"unicode_decimal": 58945
|
||||
},
|
||||
{
|
||||
"icon_id": "8295386",
|
||||
"name": "商品类型",
|
||||
"font_class": "type",
|
||||
"unicode": "e87f",
|
||||
"unicode_decimal": 59519
|
||||
},
|
||||
{
|
||||
"icon_id": "8875707",
|
||||
"name": "收货地址",
|
||||
"font_class": "address",
|
||||
"unicode": "e666",
|
||||
"unicode_decimal": 58982
|
||||
},
|
||||
{
|
||||
"icon_id": "12797032",
|
||||
"name": "售后",
|
||||
"font_class": "post-sale",
|
||||
"unicode": "e63c",
|
||||
"unicode_decimal": 58940
|
||||
},
|
||||
{
|
||||
"icon_id": "21673621",
|
||||
"name": "商品分类",
|
||||
"font_class": "category",
|
||||
"unicode": "e602",
|
||||
"unicode_decimal": 58882
|
||||
},
|
||||
{
|
||||
"icon_id": "3703028",
|
||||
"name": "文章管理",
|
||||
"font_class": "article",
|
||||
"unicode": "e662",
|
||||
"unicode_decimal": 58978
|
||||
},
|
||||
{
|
||||
"icon_id": "1218184",
|
||||
"name": "销售明细",
|
||||
"font_class": "data4",
|
||||
"unicode": "e60c",
|
||||
"unicode_decimal": 58892
|
||||
},
|
||||
{
|
||||
"icon_id": "2230090",
|
||||
"name": "销售明细",
|
||||
"font_class": "data5",
|
||||
"unicode": "e6be",
|
||||
"unicode_decimal": 59070
|
||||
},
|
||||
{
|
||||
"icon_id": "6882983",
|
||||
"name": "充值记录",
|
||||
"font_class": "recharge-record",
|
||||
"unicode": "e614",
|
||||
"unicode_decimal": 58900
|
||||
},
|
||||
{
|
||||
"icon_id": "34611004",
|
||||
"name": "充值规则",
|
||||
"font_class": "recharge-rule",
|
||||
"unicode": "e628",
|
||||
"unicode_decimal": 58920
|
||||
},
|
||||
{
|
||||
"icon_id": "15562252",
|
||||
"name": "用户画像",
|
||||
"font_class": "user-profile",
|
||||
"unicode": "e783",
|
||||
"unicode_decimal": 59267
|
||||
},
|
||||
{
|
||||
"icon_id": "18747445",
|
||||
"name": "成就",
|
||||
"font_class": "achieve",
|
||||
"unicode": "e616",
|
||||
"unicode_decimal": 58902
|
||||
},
|
||||
{
|
||||
"icon_id": "33848542",
|
||||
"name": "我的-段位",
|
||||
"font_class": "activity-level",
|
||||
"unicode": "e61a",
|
||||
"unicode_decimal": 58906
|
||||
},
|
||||
{
|
||||
"icon_id": "20406821",
|
||||
"name": "皮肤",
|
||||
"font_class": "skins",
|
||||
"unicode": "e790",
|
||||
"unicode_decimal": 59280
|
||||
},
|
||||
{
|
||||
"icon_id": "2214847",
|
||||
"name": "积分商城",
|
||||
"font_class": "data1",
|
||||
"unicode": "e996",
|
||||
"unicode_decimal": 59798
|
||||
},
|
||||
{
|
||||
"icon_id": "14233304",
|
||||
"name": "价值投资",
|
||||
"font_class": "data2",
|
||||
"unicode": "e661",
|
||||
"unicode_decimal": 58977
|
||||
},
|
||||
{
|
||||
"icon_id": "23059951",
|
||||
"name": "费用统计",
|
||||
"font_class": "data3",
|
||||
"unicode": "e632",
|
||||
"unicode_decimal": 58930
|
||||
},
|
||||
{
|
||||
"icon_id": "2199049",
|
||||
"name": "数据报表",
|
||||
"font_class": "data",
|
||||
"unicode": "e64e",
|
||||
"unicode_decimal": 58958
|
||||
},
|
||||
{
|
||||
"icon_id": "36257316",
|
||||
"name": "游戏管理",
|
||||
"font_class": "game",
|
||||
"unicode": "e6d0",
|
||||
"unicode_decimal": 59088
|
||||
},
|
||||
{
|
||||
"icon_id": "11913396",
|
||||
"name": "banner",
|
||||
"font_class": "banner",
|
||||
"unicode": "e613",
|
||||
"unicode_decimal": 58899
|
||||
},
|
||||
{
|
||||
"icon_id": "35264323",
|
||||
"name": "核销码核销",
|
||||
"font_class": "verification",
|
||||
"unicode": "e601",
|
||||
"unicode_decimal": 58881
|
||||
},
|
||||
{
|
||||
"icon_id": "6514128",
|
||||
"name": "结算管理",
|
||||
"font_class": "balance",
|
||||
"unicode": "e6b9",
|
||||
"unicode_decimal": 59065
|
||||
},
|
||||
{
|
||||
"icon_id": "12025983",
|
||||
"name": "退货退款",
|
||||
"font_class": "refund",
|
||||
"unicode": "e7af",
|
||||
"unicode_decimal": 59311
|
||||
},
|
||||
{
|
||||
"icon_id": "1207908",
|
||||
"name": "wechat",
|
||||
"font_class": "wechat",
|
||||
"unicode": "e681",
|
||||
"unicode_decimal": 59009
|
||||
},
|
||||
{
|
||||
"icon_id": "27188513",
|
||||
"name": "alipay",
|
||||
"font_class": "alipay",
|
||||
"unicode": "e61e",
|
||||
"unicode_decimal": 58910
|
||||
},
|
||||
{
|
||||
"icon_id": "11111017",
|
||||
"name": "会员",
|
||||
"font_class": "user",
|
||||
"unicode": "e67f",
|
||||
"unicode_decimal": 59007
|
||||
},
|
||||
{
|
||||
"icon_id": "630079",
|
||||
"name": "我的优惠券",
|
||||
"font_class": "coupon",
|
||||
"unicode": "e65a",
|
||||
"unicode_decimal": 58970
|
||||
},
|
||||
{
|
||||
"icon_id": "2046370",
|
||||
"name": "会员等级",
|
||||
"font_class": "level",
|
||||
"unicode": "e7d8",
|
||||
"unicode_decimal": 59352
|
||||
},
|
||||
{
|
||||
"icon_id": "2569868",
|
||||
"name": "活动",
|
||||
"font_class": "activity",
|
||||
"unicode": "e67b",
|
||||
"unicode_decimal": 59003
|
||||
},
|
||||
{
|
||||
"icon_id": "2681698",
|
||||
"name": "门店",
|
||||
"font_class": "shop",
|
||||
"unicode": "e60a",
|
||||
"unicode_decimal": 58890
|
||||
},
|
||||
{
|
||||
"icon_id": "2811147",
|
||||
"name": "会员",
|
||||
"font_class": "member",
|
||||
"unicode": "e640",
|
||||
"unicode_decimal": 58944
|
||||
},
|
||||
{
|
||||
"icon_id": "4560182",
|
||||
"name": "会员充值",
|
||||
"font_class": "recharge",
|
||||
"unicode": "e799",
|
||||
"unicode_decimal": 59289
|
||||
},
|
||||
{
|
||||
"icon_id": "5880283",
|
||||
"name": "营销",
|
||||
"font_class": "marketing",
|
||||
"unicode": "e765",
|
||||
"unicode_decimal": 59237
|
||||
},
|
||||
{
|
||||
"icon_id": "6982618",
|
||||
"name": "商品规格",
|
||||
"font_class": "goods-sku",
|
||||
"unicode": "e6d7",
|
||||
"unicode_decimal": 59095
|
||||
},
|
||||
{
|
||||
"icon_id": "7307041",
|
||||
"name": "商家入驻",
|
||||
"font_class": "store",
|
||||
"unicode": "e62b",
|
||||
"unicode_decimal": 58923
|
||||
},
|
||||
{
|
||||
"icon_id": "11639867",
|
||||
"name": "小店商品库",
|
||||
"font_class": "goods-store",
|
||||
"unicode": "e6c6",
|
||||
"unicode_decimal": 59078
|
||||
},
|
||||
{
|
||||
"icon_id": "13872198",
|
||||
"name": "商家",
|
||||
"font_class": "storer",
|
||||
"unicode": "e64a",
|
||||
"unicode_decimal": 58954
|
||||
},
|
||||
{
|
||||
"icon_id": "577335",
|
||||
"name": "订单",
|
||||
"font_class": "order",
|
||||
"unicode": "e737",
|
||||
"unicode_decimal": 59191
|
||||
},
|
||||
{
|
||||
"icon_id": "736503",
|
||||
"name": "权限",
|
||||
"font_class": "permission",
|
||||
"unicode": "e612",
|
||||
"unicode_decimal": 58898
|
||||
},
|
||||
{
|
||||
"icon_id": "1727271",
|
||||
"name": "商品",
|
||||
"font_class": "goods",
|
||||
"unicode": "e889",
|
||||
"unicode_decimal": 59529
|
||||
},
|
||||
{
|
||||
"icon_id": "7587933",
|
||||
"name": "菜单",
|
||||
"font_class": "menu",
|
||||
"unicode": "e60e",
|
||||
"unicode_decimal": 58894
|
||||
},
|
||||
{
|
||||
"icon_id": "12758820",
|
||||
"name": "字典类型",
|
||||
"font_class": "dict-type",
|
||||
"unicode": "e652",
|
||||
"unicode_decimal": 58962
|
||||
},
|
||||
{
|
||||
"icon_id": "13768112",
|
||||
"name": "字典",
|
||||
"font_class": "dictionary",
|
||||
"unicode": "e600",
|
||||
"unicode_decimal": 58880
|
||||
},
|
||||
{
|
||||
"icon_id": "37734141",
|
||||
"name": "角色",
|
||||
"font_class": "role",
|
||||
"unicode": "e604",
|
||||
"unicode_decimal": 58884
|
||||
},
|
||||
{
|
||||
"icon_id": "1727563",
|
||||
"name": "全屏",
|
||||
"font_class": "fullscreen",
|
||||
"unicode": "e8fa",
|
||||
"unicode_decimal": 59642
|
||||
},
|
||||
{
|
||||
"icon_id": "1727566",
|
||||
"name": "退出全屏",
|
||||
"font_class": "exit-fullscreen",
|
||||
"unicode": "e8fb",
|
||||
"unicode_decimal": 59643
|
||||
},
|
||||
{
|
||||
"icon_id": "11641852",
|
||||
"name": "表格",
|
||||
"font_class": "table",
|
||||
"unicode": "e615",
|
||||
"unicode_decimal": 58901
|
||||
},
|
||||
{
|
||||
"icon_id": "20104468",
|
||||
"name": "测试",
|
||||
"font_class": "test",
|
||||
"unicode": "e610",
|
||||
"unicode_decimal": 58896
|
||||
},
|
||||
{
|
||||
"icon_id": "26686335",
|
||||
"name": "中英文",
|
||||
"font_class": "lang",
|
||||
"unicode": "e649",
|
||||
"unicode_decimal": 58953
|
||||
},
|
||||
{
|
||||
"icon_id": "37702310",
|
||||
"name": "文字大小",
|
||||
"font_class": "size",
|
||||
"unicode": "e660",
|
||||
"unicode_decimal": 58976
|
||||
}
|
||||
]
|
||||
}
|
BIN
main/src/assets/fonts/iconfont.ttf
Normal file
BIN
main/src/assets/fonts/iconfont.woff
Normal file
BIN
main/src/assets/fonts/iconfont.woff2
Normal file
BIN
main/src/assets/images/login/login.png
Normal file
After Width: | Height: | Size: 140 KiB |
BIN
main/src/assets/images/login/logo.png
Normal file
After Width: | Height: | Size: 73 KiB |
BIN
main/src/assets/images/login/nav_line-bg.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
main/src/assets/images/login/nav_system-bg.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
main/src/assets/images/logo.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
main/src/assets/images/platform/bg.png
Normal file
After Width: | Height: | Size: 5.7 MiB |
BIN
main/src/assets/images/platform/icon-admin.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
main/src/assets/images/platform/icon-app.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
main/src/assets/images/platform/icon-home.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
main/src/assets/images/platform/icon-screen.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
main/src/assets/images/platform/icon-yy.png
Normal file
After Width: | Height: | Size: 194 KiB |
BIN
main/src/assets/images/platform/icon-zw.png
Normal file
After Width: | Height: | Size: 167 KiB |
BIN
main/src/assets/images/platform/title.png
Normal file
After Width: | Height: | Size: 77 KiB |
1
main/src/assets/svgs/tree.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M126.713 90.023c.858.985 1.287 2.134 1.287 3.447v29.553c0 1.423-.429 2.6-1.287 3.53-.858.93-1.907 1.395-3.146 1.395H97.824c-1.145 0-2.146-.465-3.004-1.395-.858-.93-1.287-2.107-1.287-3.53V93.47c0-.875.19-1.696.572-2.462.382-.766.906-1.368 1.573-1.806a3.84 3.84 0 0 1 2.146-.657h9.725V69.007a3.84 3.84 0 0 0-.43-1.806 3.569 3.569 0 0 0-1.143-1.313 2.714 2.714 0 0 0-1.573-.492h-36.47v23.149h9.725c1.144 0 2.145.492 3.004 1.478.858.985 1.287 2.134 1.287 3.447v29.553c0 .876-.191 1.696-.573 2.463-.38.766-.905 1.368-1.573 1.806a3.84 3.84 0 0 1-2.145.656H51.915a3.84 3.84 0 0 1-2.145-.656c-.668-.438-1.216-1.04-1.645-1.806a4.96 4.96 0 0 1-.644-2.463V93.47c0-1.313.43-2.462 1.288-3.447.858-.986 1.907-1.478 3.146-1.478h9.582v-23.15h-37.9c-.953 0-1.74.356-2.359 1.068-.62.711-.93 1.56-.93 2.544v19.538h9.726c1.239 0 2.264.492 3.074 1.478.81.985 1.216 2.134 1.216 3.447v29.553c0 1.423-.405 2.6-1.216 3.53-.81.93-1.835 1.395-3.074 1.395H4.29c-.476 0-.93-.082-1.358-.246a4.1 4.1 0 0 1-1.144-.657 4.658 4.658 0 0 1-.93-1.067 5.186 5.186 0 0 1-.643-1.395 5.566 5.566 0 0 1-.215-1.56V93.47c0-.437.048-.875.143-1.313a3.95 3.95 0 0 1 .429-1.15c.19-.328.429-.656.715-.984.286-.329.572-.602.858-.821.286-.22.62-.383 1.001-.493.382-.11.763-.164 1.144-.164h9.726V61.619c0-.985.31-1.833.93-2.544.619-.712 1.358-1.068 2.216-1.068h44.335V39.62h-9.582c-1.24 0-2.288-.492-3.146-1.477a5.09 5.09 0 0 1-1.287-3.448V5.14c0-1.423.429-2.627 1.287-3.612.858-.985 1.907-1.477 3.146-1.477h25.743c.763 0 1.478.246 2.145.739a5.17 5.17 0 0 1 1.573 1.888c.382.766.573 1.587.573 2.462v29.553c0 1.313-.43 2.463-1.287 3.448-.859.985-1.86 1.477-3.004 1.477h-9.725v18.389h42.762c.954 0 1.74.355 2.36 1.067.62.711.93 1.56.93 2.545v26.925h9.582c1.239 0 2.288.492 3.146 1.478z"/></svg>
|
After Width: | Height: | Size: 1.8 KiB |
1
main/src/assets/svgs/user.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="130" height="130" xmlns="http://www.w3.org/2000/svg"><path d="M63.444 64.996c20.633 0 37.359-14.308 37.359-31.953 0-17.649-16.726-31.952-37.359-31.952-20.631 0-37.36 14.303-37.358 31.952 0 17.645 16.727 31.953 37.359 31.953zM80.57 75.65H49.434c-26.652 0-48.26 18.477-48.26 41.27v2.664c0 9.316 21.608 9.325 48.26 9.325H80.57c26.649 0 48.256-.344 48.256-9.325v-2.663c0-22.794-21.605-41.271-48.256-41.271z" stroke="#979797"/></svg>
|
After Width: | Height: | Size: 440 B |
1
main/src/assets/svgs/wechat.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="128" height="110" xmlns="http://www.w3.org/2000/svg"><path d="M86.635 33.334c1.467 0 2.917.113 4.358.283C87.078 14.392 67.58.111 45.321.111 20.44.111.055 17.987.055 40.687c0 13.104 6.781 23.863 18.115 32.209l-4.527 14.352 15.82-8.364c5.666 1.182 10.207 2.395 15.858 2.395 1.42 0 2.829-.073 4.227-.189-.886-3.19-1.398-6.53-1.398-9.996 0-20.845 16.98-37.76 38.485-37.76zm-24.34-12.936c3.407 0 5.665 2.363 5.665 5.954 0 3.576-2.258 5.97-5.666 5.97-3.392 0-6.795-2.395-6.795-5.97 0-3.591 3.403-5.954 6.795-5.954zM30.616 32.323c-3.393 0-6.818-2.395-6.818-5.971 0-3.591 3.425-5.954 6.818-5.954 3.392 0 5.65 2.363 5.65 5.954 0 3.576-2.258 5.97-5.65 5.97z"/><path d="M127.945 70.52c0-19.075-18.108-34.623-38.448-34.623-21.537 0-38.5 15.548-38.5 34.623 0 19.108 16.963 34.622 38.5 34.622 4.508 0 9.058-1.2 13.584-2.395l12.414 7.167-3.404-11.923c9.087-7.184 15.854-16.712 15.854-27.471zm-50.928-5.97c-2.254 0-4.53-2.362-4.53-4.773 0-2.378 2.276-4.771 4.53-4.771 3.422 0 5.665 2.393 5.665 4.771 0 2.41-2.243 4.773-5.665 4.773zm24.897 0c-2.24 0-4.498-2.362-4.498-4.773 0-2.378 2.258-4.771 4.498-4.771 3.392 0 5.665 2.393 5.665 4.771 0 2.41-2.273 4.773-5.665 4.773z"/></svg>
|
After Width: | Height: | Size: 1.1 KiB |
183
main/src/components/custom-rich-editor/index.vue
Normal file
@ -0,0 +1,183 @@
|
||||
<!--
|
||||
* @Description:
|
||||
* @Author: zenghua.wang
|
||||
* @Date: 2024-03-24 11:04:52
|
||||
* @LastEditors: zenghua.wang “1048523306@qq.com”
|
||||
* @LastEditTime: 2025-01-20 09:34:23
|
||||
-->
|
||||
<template>
|
||||
<section class="rich-editor">
|
||||
<Toolbar class="rich-editor-toolbar" :editor="refEditor" :default-config="options.toolbarConfig" :mode="mode" />
|
||||
<Editor
|
||||
v-model="valueHtml"
|
||||
class="rich-editor-toolbar"
|
||||
:style="styleEditor"
|
||||
:default-config="options.editorConfig"
|
||||
:mode="mode"
|
||||
@on-created="handleCreated"
|
||||
@on-change="handleChange"
|
||||
@on-destroyed="handleDestroyed"
|
||||
@on-focus="handleFocus"
|
||||
@on-blur="handleBlur"
|
||||
/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import '@wangeditor/editor/dist/css/style.css'; // 引入 css
|
||||
import { shallowRef, ref, computed, nextTick, onBeforeUnmount, onMounted } from 'vue';
|
||||
import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
|
||||
import { isEmpty } from '@/utils';
|
||||
// import { CommonUpload, UploadImageFromEditor } from '@/apis/common';
|
||||
|
||||
const { VITE_APP_OSS_URL } = import.meta.env;
|
||||
|
||||
export default {
|
||||
name: 'CustomRichEditor',
|
||||
components: { Editor, Toolbar },
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'default', //'default' 或 'simple'
|
||||
},
|
||||
readOnly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
toolbarConfig: {},
|
||||
editorConfig: {
|
||||
placeholder: '请输入内容...',
|
||||
readOnly: false,
|
||||
MENU_CONF: {
|
||||
uploadImage: {
|
||||
server: '',
|
||||
base64LimitSize: 10 * 1024, //10kb
|
||||
maxFileSize: 10 * 1024 * 1024, //10M
|
||||
maxNumberOfFiles: 10,
|
||||
allowedFileTypes: ['image/*'],
|
||||
async customUpload(file, insertFn) {
|
||||
// if (isEmpty(file.name)) return;
|
||||
// const data = {
|
||||
// key: file.name,
|
||||
// size: file.size,
|
||||
// contentType: file.type,
|
||||
// expiresInSecond: 3600,
|
||||
// };
|
||||
// const res = await UploadImageFromEditor(data);
|
||||
// if (res.code === 200) {
|
||||
// await CommonUpload({
|
||||
// url: res.data.url,
|
||||
// file,
|
||||
// });
|
||||
// insertFn(VITE_APP_OSS_URL + res.data.key, file.name, res.data.key);
|
||||
// }
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
emits: ['focus', 'blur', 'change'],
|
||||
setup(props, cxt) {
|
||||
const refEditor = shallowRef();
|
||||
const valueHtml = ref('');
|
||||
|
||||
const styleEditor = computed(() => {
|
||||
return {
|
||||
height: props.options.contentHeight || '300px',
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* 创建
|
||||
* @param {*} editor
|
||||
*/
|
||||
const handleCreated = (editor) => {
|
||||
refEditor.value = editor;
|
||||
props.readOnly ? editor.disable() : editor.enable();
|
||||
};
|
||||
/**
|
||||
* 组件内容变化
|
||||
* @param {*} editor
|
||||
*/
|
||||
const handleChange = (editor) => {
|
||||
cxt.emit('change', editor);
|
||||
};
|
||||
/**
|
||||
* 组件销毁
|
||||
* @param {*} editor
|
||||
*/
|
||||
const handleDestroyed = (editor) => {
|
||||
valueHtml.value = '';
|
||||
};
|
||||
/**
|
||||
* 光标处于编辑区
|
||||
* @param {*} editor
|
||||
*/
|
||||
const handleFocus = (editor) => {
|
||||
cxt.emit('focus', editor);
|
||||
};
|
||||
/**
|
||||
* 光标离开编辑区
|
||||
* @param {*} editor
|
||||
*/
|
||||
const handleBlur = (editor) => {
|
||||
cxt.emit('blur', editor);
|
||||
};
|
||||
/**
|
||||
* 挂载
|
||||
*/
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
if (props?.value) {
|
||||
valueHtml.value = props.value;
|
||||
}
|
||||
});
|
||||
});
|
||||
/**
|
||||
* 组件销毁时,也及时销毁编辑器
|
||||
*/
|
||||
onBeforeUnmount(() => {
|
||||
if (!refEditor?.value) return;
|
||||
refEditor.value.destroy();
|
||||
});
|
||||
|
||||
return {
|
||||
refEditor,
|
||||
valueHtml,
|
||||
styleEditor,
|
||||
handleCreated,
|
||||
handleChange,
|
||||
handleDestroyed,
|
||||
handleFocus,
|
||||
handleBlur,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.rich-editor {
|
||||
border: 1px solid $color-border;
|
||||
z-index: 9999;
|
||||
&-toolbar {
|
||||
border-bottom: 1px solid $color-border;
|
||||
:deep(.w-e-bar-divider) {
|
||||
width: 0;
|
||||
}
|
||||
}
|
||||
&-editor {
|
||||
overflow-y: hidden;
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
</style>
|
5
main/src/components/index.js
Normal file
@ -0,0 +1,5 @@
|
||||
import SvgIcon from './svg-icon';
|
||||
|
||||
import CustomRichEditor from './custom-rich-editor';
|
||||
|
||||
export { SvgIcon, CustomRichEditor };
|
81
main/src/components/svg-icon/index.vue
Normal file
@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" />
|
||||
<svg v-else :class="svgClass" aria-hidden="true" :style="styleSize()">
|
||||
<use :xlink:href="iconName" />
|
||||
<title v-if="title">{{ title }}</title>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script setup name="svg-icon">
|
||||
import { computed } from 'vue';
|
||||
import { setPx } from '@/utils';
|
||||
|
||||
const props = defineProps({
|
||||
// svg图片名称
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
size: {
|
||||
type: [Number, String],
|
||||
default: 16,
|
||||
},
|
||||
// class样式名称,如果svg标签需要添加class样式,那么就需要该属性来添加svg的样式
|
||||
className: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
|
||||
//是否外部链接
|
||||
const isExternal = computed(() => {
|
||||
return /^(https?:|mailto:|tel:)/.test(props.name);
|
||||
});
|
||||
|
||||
//svg图片名称计算属性
|
||||
const iconName = computed(() => {
|
||||
return `#icon-${props.name}`;
|
||||
});
|
||||
|
||||
//svg样式名称计算属性
|
||||
const svgClass = computed(() => {
|
||||
if (props.className) {
|
||||
return 'svg-icon ' + props.className;
|
||||
} else {
|
||||
return 'svg-icon';
|
||||
}
|
||||
});
|
||||
|
||||
const styleSize = () => {
|
||||
return {
|
||||
fontSize: setPx(props.size),
|
||||
};
|
||||
};
|
||||
|
||||
const styleExternalIcon = computed(() => {
|
||||
return {
|
||||
mask: `url(${props.name}) no-repeat 50% 50%`,
|
||||
'-webkit-mask': `url(${props.name}) no-repeat 50% 50%`,
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.svg-icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: -0.15em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.svg-external-icon {
|
||||
background-color: currentColor;
|
||||
mask-size: cover !important;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
219
main/src/config/index.js
Normal file
@ -0,0 +1,219 @@
|
||||
export const GenKey = (key, prefix = 'EGGY_TEAM_STORE_') => {
|
||||
return prefix ? prefix + key : key;
|
||||
};
|
||||
|
||||
export const CONSTANTS = {
|
||||
PREFIX: 'EGGY_TEAM_STORE_',
|
||||
PRIMARY: '#409eff',
|
||||
// 总部商品可编辑属性
|
||||
EDITLIST: ['amount', 'originalPrice', 'activityPrice', 'usePoints', 'points', 'status', 'sortOrder', 'perUseValue', 'displayChannelList'],
|
||||
// 活动管理
|
||||
LATITUDE: [
|
||||
{
|
||||
label: '副本【x】通关计分榜',
|
||||
value: 10,
|
||||
},
|
||||
{
|
||||
label: '副本【x】速通榜',
|
||||
value: 11,
|
||||
},
|
||||
{
|
||||
label: '副本【x】大师榜(失误最少)',
|
||||
value: 12,
|
||||
},
|
||||
{
|
||||
label: '副本【x】巅峰榜',
|
||||
value: 13,
|
||||
},
|
||||
{
|
||||
label: '最强闯关计分榜',
|
||||
value: 14,
|
||||
},
|
||||
{
|
||||
label: '挑战模式通关计分榜',
|
||||
value: 20,
|
||||
},
|
||||
{
|
||||
label: '挑战模式第【x】关速通榜',
|
||||
value: 21,
|
||||
},
|
||||
{
|
||||
label: '挑战模式大师榜(失误最少)',
|
||||
value: 22,
|
||||
},
|
||||
{
|
||||
label: '挑战模式巅峰榜',
|
||||
value: 23,
|
||||
},
|
||||
],
|
||||
// 维度说明
|
||||
LATITUDETIPS: {
|
||||
default: '榜单常驻,用户所有的游戏通关数据得分累计排列显示,不管用户参与什么模式,是否通关,只要游戏结束时候的分数累计进行排行',
|
||||
10: '在榜单发起时间内,指定某个副本的通关分数总和(不通关则不计入总分)',
|
||||
11: '在榜单发起时间内,指定某个副本的通关时间最快(只刷新计入最快的那次)',
|
||||
12: '在榜单发起时间内,指定某个副本的扣分最少(只刷新计入扣分最少的那次)',
|
||||
13: '在榜单发起时间内,指定某个副本的得分最高(只刷新计入得分最高的那次)',
|
||||
14: '在榜单发起时间内,任意副本的得分总和排名(不通关则不计入总分)',
|
||||
20: '在榜单发起时间内,挑战模式的通关分数总和(不通关则不计入总分)',
|
||||
21: '在榜单发起时间内,指定挑战模式的某些关卡的通关时间最快(只刷新计入最快的那次)',
|
||||
22: '在榜单发起时间内,挑战模式的扣分最少(只刷新计入扣分最少的那次)',
|
||||
23: '在榜单发起时间内,挑战模式的得分最高(只刷新计入得分最高的那次)',
|
||||
},
|
||||
// 支付方式
|
||||
PAYTYPE: {
|
||||
prop: 'payType',
|
||||
label: '支付方式',
|
||||
type: 'select',
|
||||
dicData: [
|
||||
{
|
||||
label: '余额',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: '微信',
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
label: '支付宝',
|
||||
value: 3,
|
||||
},
|
||||
{
|
||||
label: '商家券',
|
||||
value: 4,
|
||||
},
|
||||
{
|
||||
label: '平台券',
|
||||
value: 5,
|
||||
},
|
||||
{
|
||||
label: '商场券',
|
||||
value: 6,
|
||||
},
|
||||
{
|
||||
label: '积分',
|
||||
value: 7,
|
||||
},
|
||||
{
|
||||
label: '美团',
|
||||
value: 8,
|
||||
},
|
||||
{
|
||||
label: '现金',
|
||||
value: 9,
|
||||
},
|
||||
{
|
||||
label: '抖音',
|
||||
value: 10,
|
||||
},
|
||||
{
|
||||
label: '小红书',
|
||||
value: 11,
|
||||
},
|
||||
{
|
||||
label: '线下优惠券',
|
||||
value: 12,
|
||||
},
|
||||
{
|
||||
label: '首单立减',
|
||||
value: 13,
|
||||
},
|
||||
{
|
||||
label: '其它一',
|
||||
value: 20,
|
||||
},
|
||||
{
|
||||
label: '其它二',
|
||||
value: 21,
|
||||
},
|
||||
{
|
||||
label: '其它三',
|
||||
value: 22,
|
||||
},
|
||||
],
|
||||
formatter: (row) => {
|
||||
let value = '';
|
||||
switch (row.payType) {
|
||||
case 1: {
|
||||
value = '余额';
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
value = '微信';
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
value = '支付宝';
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
value = '商家券';
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
value = '平台券';
|
||||
break;
|
||||
}
|
||||
case 6: {
|
||||
value = '商场券';
|
||||
break;
|
||||
}
|
||||
case 7: {
|
||||
value = '积分';
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
value = '美团';
|
||||
break;
|
||||
}
|
||||
case 9: {
|
||||
value = '现金';
|
||||
break;
|
||||
}
|
||||
case 10: {
|
||||
value = '抖音';
|
||||
break;
|
||||
}
|
||||
case 11: {
|
||||
value = '小红书';
|
||||
break;
|
||||
}
|
||||
case 12: {
|
||||
value = '线下优惠券';
|
||||
break;
|
||||
}
|
||||
case 13: {
|
||||
value = '首单立减';
|
||||
break;
|
||||
}
|
||||
case 20: {
|
||||
value = '其它一';
|
||||
break;
|
||||
}
|
||||
case 21: {
|
||||
value = '其它二';
|
||||
break;
|
||||
}
|
||||
case 22: {
|
||||
value = '其它三';
|
||||
break;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
},
|
||||
},
|
||||
// 支付分类
|
||||
PAY_CATEGORIES: [
|
||||
{ prop: 'weixin', name: '微信' },
|
||||
{ prop: 'alipay', name: '支付宝' },
|
||||
{ prop: 'cash', name: '现金' },
|
||||
{ prop: 'balance', name: '余额' },
|
||||
{ prop: 'market', name: '商场券' },
|
||||
{ prop: 'platform', name: '平台券' },
|
||||
{ prop: 'store', name: '门店券' },
|
||||
{ prop: 'meituan', name: '美团' },
|
||||
{ prop: 'tiktok', name: '抖音' },
|
||||
{ prop: 'xiaohongshu', name: '小红书' },
|
||||
{ prop: 'offline', name: '线下优惠券' },
|
||||
{ prop: 'firstOrder', name: '首单立减' },
|
||||
],
|
||||
};
|
29
main/src/directives/auth.js
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @Description: 按钮权限
|
||||
* @Author: zenghua.wang
|
||||
* @Date: 2022-08-30 09:42:47
|
||||
* @LastEditors: zenghua.wang
|
||||
* @LastEditTime: 2024-06-08 19:50:47
|
||||
*/
|
||||
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
|
||||
export function useAuth(app) {
|
||||
app.directive('auth', (el, binding) => {
|
||||
const { value } = binding;
|
||||
const all_permission = '*:*:*';
|
||||
const UserStore = useUserStore();
|
||||
const permissions = UserStore.getAuths() ?? [];
|
||||
if (value && value instanceof Array && value.length > 0) {
|
||||
const permissionFlag = value;
|
||||
const hasAuth = permissions.some((permission) => {
|
||||
return all_permission === permission || permissionFlag.includes(permission);
|
||||
});
|
||||
if (!hasAuth) {
|
||||
el.parentNode && el.parentNode.removeChild(el);
|
||||
}
|
||||
} else {
|
||||
// console.log('button permissions are not supported.');
|
||||
}
|
||||
});
|
||||
}
|
8
main/src/directives/index.js
Normal file
@ -0,0 +1,8 @@
|
||||
import { useAuth } from './auth';
|
||||
|
||||
/**
|
||||
* 指令:v-auth
|
||||
*/
|
||||
export const registerDirective = (app) => {
|
||||
useAuth(app);
|
||||
};
|
5
main/src/hooks/index.js
Normal file
@ -0,0 +1,5 @@
|
||||
import { getCurrentInstance } from 'vue';
|
||||
|
||||
export const useApp = () => {
|
||||
return getCurrentInstance().appContext?.config?.globalProperties;
|
||||
};
|
22
main/src/hooks/useWrapComponents.js
Normal file
@ -0,0 +1,22 @@
|
||||
import { h } from 'vue';
|
||||
|
||||
const wrapperMap = new Map();
|
||||
|
||||
export const useWrapComponents = (Component, route) => {
|
||||
let wrapper;
|
||||
if (Component) {
|
||||
const wrapperName = route.name;
|
||||
if (wrapperMap.has(wrapperName)) {
|
||||
wrapper = wrapperMap.get(wrapperName);
|
||||
} else {
|
||||
wrapper = {
|
||||
name: wrapperName,
|
||||
render() {
|
||||
return h('div', { className: 'layout' }, Component);
|
||||
},
|
||||
};
|
||||
wrapperMap.set(wrapperName, wrapper);
|
||||
}
|
||||
return h(wrapper);
|
||||
}
|
||||
};
|
3
main/src/layouts/Views.vue
Normal file
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
<router-view />
|
||||
</template>
|
36
main/src/layouts/index.vue
Normal file
@ -0,0 +1,36 @@
|
||||
<!--
|
||||
* @Description:
|
||||
* @Author: zenghua.wang
|
||||
* @Date: 2023-06-20 14:29:45
|
||||
* @LastEditors: zenghua.wang “1048523306@qq.com”
|
||||
* @LastEditTime: 2025-01-17 16:36:25
|
||||
-->
|
||||
<template>
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<transition name="fade-slide" mode="out-in" appear>
|
||||
<keep-alive v-if="isReload" :include="cacheRoutes">
|
||||
<component :is="useWrapComponents(Component, route)" :key="route.path" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</router-view>
|
||||
</template>
|
||||
|
||||
<script setup name="layout">
|
||||
import { computed } from 'vue';
|
||||
import { useSettingStore } from '@/store/modules/setting';
|
||||
import { usePermissionStore } from '@/store/modules/permission';
|
||||
import { useWrapComponents } from '@/hooks/useWrapComponents';
|
||||
|
||||
const SettingStore = useSettingStore();
|
||||
const PermissionStore = usePermissionStore();
|
||||
const cacheRoutes = computed(() => PermissionStore.keepAliveRoutes);
|
||||
const isReload = computed(() => SettingStore.isReload);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.layout {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
15
main/src/main.js
Normal file
@ -0,0 +1,15 @@
|
||||
import 'virtual:svg-icons-register';
|
||||
import { createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
import router from './router';
|
||||
import pinia from './store';
|
||||
import ElementPlus from 'element-plus';
|
||||
import 'element-plus/dist/index.css';
|
||||
import { registerGlobalMicroApps } from './micro';
|
||||
import { registerElIcons } from './plugins/icon';
|
||||
import './utils/permission';
|
||||
|
||||
const app = createApp(App);
|
||||
app.use(pinia).use(router).use(ElementPlus).mount('#root');
|
||||
registerElIcons(app);
|
||||
registerGlobalMicroApps();
|
28
main/src/micro/actions.js
Normal file
@ -0,0 +1,28 @@
|
||||
import { initGlobalState } from 'qiankun';
|
||||
import { reactive } from 'vue';
|
||||
|
||||
const initialState = reactive({
|
||||
user: {
|
||||
name: 'admin',
|
||||
},
|
||||
menus: [],
|
||||
auths: [],
|
||||
});
|
||||
|
||||
const actions = initGlobalState(initialState);
|
||||
|
||||
actions.onGlobalStateChange((newState, prev) => {
|
||||
console.log('main change', newState, prev);
|
||||
for (const key in newState) {
|
||||
initialState[key] = newState[key];
|
||||
}
|
||||
});
|
||||
|
||||
// 有key,表示取globalState下的某个子级对象
|
||||
// 无key,表示取全部
|
||||
|
||||
actions.getGlobalState = (key) => {
|
||||
return key ? initialState[key] : initialState;
|
||||
};
|
||||
|
||||
export default actions;
|
30
main/src/micro/app.js
Normal file
@ -0,0 +1,30 @@
|
||||
import actions from './actions';
|
||||
|
||||
const { VITE_APP_SUB_VUE, VITE_APP_SUB_ADMIN } = import.meta.env;
|
||||
|
||||
export const microApps = [
|
||||
{
|
||||
name: 'suv-vue',
|
||||
entry: VITE_APP_SUB_VUE,
|
||||
activeRule: '/sub-vue/',
|
||||
title: '管理后台',
|
||||
},
|
||||
{
|
||||
name: 'sub-admin',
|
||||
entry: VITE_APP_SUB_ADMIN,
|
||||
activeRule: '/sub-admin/',
|
||||
},
|
||||
];
|
||||
|
||||
const apps = microApps.map((item) => {
|
||||
return {
|
||||
...item,
|
||||
container: '#app',
|
||||
props: {
|
||||
routerBase: item.activeRule,
|
||||
getGlobalState: actions.getGlobalState,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export default apps;
|
40
main/src/micro/index.js
Normal file
@ -0,0 +1,40 @@
|
||||
import { registerMicroApps, setDefaultMountApp, start, addGlobalUncaughtErrorHandler } from 'qiankun';
|
||||
import microApps from './app';
|
||||
|
||||
const registerGlobalMicroApps = () => {
|
||||
// 给子应用配置加上loader方法
|
||||
const apps = microApps.map((item) => {
|
||||
// console.log('registerGlobalMicroApps==', item);
|
||||
return {
|
||||
...item,
|
||||
};
|
||||
});
|
||||
|
||||
registerMicroApps(apps, {
|
||||
beforeLoad: (app) => {
|
||||
console.log('before load', app);
|
||||
switch (app.name) {
|
||||
case 'sub-vue':
|
||||
document.title = 'sub-vue';
|
||||
break;
|
||||
case 'sub-admin':
|
||||
document.title = 'sub-admin';
|
||||
break;
|
||||
}
|
||||
},
|
||||
beforeMount: [
|
||||
(app) => {
|
||||
console.log('before mount', app.name);
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
start({
|
||||
prefetch: false, // 取消预加载
|
||||
sandbox: { experimentalStyleIsolation: true },
|
||||
});
|
||||
|
||||
// addGlobalUncaughtErrorHandler((event) => console.log(event));
|
||||
};
|
||||
|
||||
export { registerGlobalMicroApps };
|
8
main/src/plugins/globalComponents.js
Normal file
@ -0,0 +1,8 @@
|
||||
// import * as components from '../../../global/components';
|
||||
|
||||
// // 全局注册组件
|
||||
// export const registerGlobalComponents = (app) => {
|
||||
// Object.keys(components).forEach((key) => {
|
||||
// app.component(key, components[key]);
|
||||
// });
|
||||
// };
|
8
main/src/plugins/icon.js
Normal file
@ -0,0 +1,8 @@
|
||||
import * as ElIconsModules from '@element-plus/icons-vue';
|
||||
|
||||
// 全局注册element-plus icon图标组件
|
||||
export const registerElIcons = (app) => {
|
||||
Object.keys(ElIconsModules).forEach((key) => {
|
||||
app.component(key, ElIconsModules[key]);
|
||||
});
|
||||
};
|
43
main/src/router/index.js
Normal file
@ -0,0 +1,43 @@
|
||||
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router';
|
||||
import Layout from '@/layouts/index.vue';
|
||||
|
||||
export const constantRoutes = [
|
||||
{
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
component: () => import('@/views/login/index.vue'),
|
||||
hidden: true,
|
||||
meta: {
|
||||
title: '登录',
|
||||
icon: 'Login',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
name: 'layout',
|
||||
component: Layout,
|
||||
redirect: '/platform',
|
||||
meta: { title: '平台入口', icon: 'House' },
|
||||
children: [
|
||||
{
|
||||
path: '/platform',
|
||||
component: () => import('@/views/index.vue'),
|
||||
name: 'platform',
|
||||
meta: { title: '平台入口', icon: 'House' },
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const notFoundRouter = {
|
||||
path: '/:pathMatch(.*)',
|
||||
name: 'notFound',
|
||||
redirect: '/404',
|
||||
};
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: constantRoutes,
|
||||
});
|
||||
|
||||
export default router;
|
18
main/src/store/index.js
Normal file
@ -0,0 +1,18 @@
|
||||
import { defineStore, createPinia } from 'pinia';
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
|
||||
|
||||
export const Store = defineStore({
|
||||
id: 'globalState',
|
||||
state: () => ({}),
|
||||
getters: {},
|
||||
actions: {},
|
||||
persist: {
|
||||
key: 'globalState',
|
||||
storage: window.sessionStorage, //localstorage
|
||||
},
|
||||
});
|
||||
|
||||
const pinia = createPinia();
|
||||
pinia.use(piniaPluginPersistedstate);
|
||||
|
||||
export default pinia;
|
52
main/src/store/modules/permission.js
Normal file
@ -0,0 +1,52 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { constantRoutes, notFoundRouter } from '@/router';
|
||||
import { createAsyncRoutes, filterAsyncRoutes, filterKeepAlive } from '@/utils/router';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { getTree } from '@/utils';
|
||||
|
||||
export const usePermissionStore = defineStore({
|
||||
id: 'permissionStore',
|
||||
state: () => ({
|
||||
// 路由
|
||||
routes: [],
|
||||
// 动态路由
|
||||
asyncRoutes: [],
|
||||
// 缓存路由
|
||||
cacheRoutes: {},
|
||||
}),
|
||||
getters: {
|
||||
permissionRoutes: (state) => {
|
||||
return state.routes;
|
||||
},
|
||||
keepAliveRoutes: (state) => {
|
||||
return filterKeepAlive(state.asyncRoutes);
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
generateRoutes(roles) {
|
||||
return new Promise((resolve) => {
|
||||
// 在这判断是否有权限,哪些角色拥有哪些权限
|
||||
const UserStore = useUserStore();
|
||||
this.asyncRoutes = createAsyncRoutes(getTree(UserStore.getMenus()));
|
||||
let accessedRoutes;
|
||||
if (roles && roles.length && !roles.includes('admin')) {
|
||||
accessedRoutes = filterAsyncRoutes(this.asyncRoutes, roles);
|
||||
} else {
|
||||
accessedRoutes = this.asyncRoutes || [];
|
||||
}
|
||||
accessedRoutes = accessedRoutes.concat(notFoundRouter);
|
||||
this.routes = constantRoutes.concat(accessedRoutes);
|
||||
resolve(accessedRoutes);
|
||||
});
|
||||
},
|
||||
clearRoutes() {
|
||||
this.routes = [];
|
||||
this.asyncRoutes = [];
|
||||
this.cacheRoutes = [];
|
||||
},
|
||||
getCacheRoutes() {
|
||||
this.cacheRoutes = filterKeepAlive(this.asyncRoutes);
|
||||
return this.cacheRoutes;
|
||||
},
|
||||
},
|
||||
});
|
69
main/src/store/modules/setting.js
Normal file
@ -0,0 +1,69 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { CONSTANTS } from '@/config';
|
||||
|
||||
export const useSettingStore = defineStore({
|
||||
id: 'settingStore',
|
||||
state: () => ({
|
||||
// menu 是否收缩
|
||||
isCollapse: true,
|
||||
//
|
||||
withoutAnimation: false,
|
||||
device: 'desktop',
|
||||
// 刷新当前页
|
||||
isReload: true,
|
||||
// 主题设置
|
||||
themeConfig: {
|
||||
// 显示设置
|
||||
showSetting: false,
|
||||
// 菜单展示模式 默认 vertical horizontal / vertical /columns
|
||||
mode: 'vertical',
|
||||
// tagsView 是否展示 默认展示
|
||||
showTag: true,
|
||||
// 页脚
|
||||
footer: true,
|
||||
// 深色模式 切换暗黑模式
|
||||
isDark: false,
|
||||
// 显示侧边栏Logo
|
||||
showLogo: true,
|
||||
// 主题颜色
|
||||
primary: CONSTANTS.PRIMARY,
|
||||
// element组件大小
|
||||
globalComSize: 'default',
|
||||
// 是否只保持一个子菜单的展开
|
||||
uniqueOpened: true,
|
||||
// 固定header
|
||||
fixedHeader: true,
|
||||
// 灰色模式
|
||||
gray: false,
|
||||
// 色弱模式
|
||||
weak: false,
|
||||
},
|
||||
}),
|
||||
getters: {},
|
||||
actions: {
|
||||
// 设置主题
|
||||
setThemeConfig({ key, val }) {
|
||||
this.themeConfig[key] = val;
|
||||
},
|
||||
// 切换 Collapse
|
||||
setCollapse(value) {
|
||||
this.isCollapse = value;
|
||||
this.withoutAnimation = false;
|
||||
},
|
||||
// 关闭侧边栏
|
||||
closeSideBar({ withoutAnimation }) {
|
||||
this.isCollapse = false;
|
||||
this.withoutAnimation = withoutAnimation;
|
||||
},
|
||||
toggleDevice(device) {
|
||||
this.device = device;
|
||||
},
|
||||
// 刷新
|
||||
setReload() {
|
||||
this.isReload = false;
|
||||
setTimeout(() => {
|
||||
this.isReload = true;
|
||||
}, 50);
|
||||
},
|
||||
},
|
||||
});
|
104
main/src/store/modules/tagsView.js
Normal file
@ -0,0 +1,104 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import router from '@/router';
|
||||
|
||||
export const useTagsViewStore = defineStore({
|
||||
id: 'tagsViewStore',
|
||||
state: () => ({
|
||||
activeTabsValue: '/home',
|
||||
visitedViews: [],
|
||||
cachedViews: [],
|
||||
}),
|
||||
getters: {},
|
||||
actions: {
|
||||
setTabsMenuValue(val) {
|
||||
this.activeTabsValue = val;
|
||||
},
|
||||
addView(view) {
|
||||
this.addVisitedView(view);
|
||||
},
|
||||
removeView(routes) {
|
||||
return new Promise((resolve) => {
|
||||
this.visitedViews = this.visitedViews.filter((item) => !routes.includes(item.path));
|
||||
resolve(null);
|
||||
});
|
||||
},
|
||||
addVisitedView(view) {
|
||||
this.setTabsMenuValue(view.path);
|
||||
if (this.visitedViews.some((v) => v.path === view.path)) return;
|
||||
|
||||
this.visitedViews.push(
|
||||
Object.assign({}, view, {
|
||||
title: view.meta.title || 'no-name',
|
||||
})
|
||||
);
|
||||
if (view.meta.keepAlive) {
|
||||
this.cachedViews.push(view.name);
|
||||
}
|
||||
},
|
||||
delView(activeTabPath) {
|
||||
return new Promise((resolve) => {
|
||||
this.delVisitedView(activeTabPath);
|
||||
this.delCachedView(activeTabPath);
|
||||
resolve({
|
||||
visitedViews: [...this.visitedViews],
|
||||
cachedViews: [...this.cachedViews],
|
||||
});
|
||||
});
|
||||
},
|
||||
toLastView(activeTabPath) {
|
||||
const index = this.visitedViews.findIndex((item) => item.path === activeTabPath);
|
||||
const nextTab = this.visitedViews[index + 1] || this.visitedViews[index - 1];
|
||||
if (!nextTab) return;
|
||||
router.push(nextTab.path);
|
||||
this.addVisitedView(nextTab);
|
||||
},
|
||||
delVisitedView(path) {
|
||||
return new Promise((resolve) => {
|
||||
this.visitedViews = this.visitedViews.filter((v) => {
|
||||
return v.path !== path || v.meta.affix;
|
||||
});
|
||||
this.cachedViews = this.cachedViews.filter((v) => {
|
||||
return v.path !== path || v.meta.affix;
|
||||
});
|
||||
resolve([...this.visitedViews]);
|
||||
});
|
||||
},
|
||||
delCachedView(view) {
|
||||
return new Promise((resolve) => {
|
||||
const index = this.cachedViews.indexOf(view.name);
|
||||
index > -1 && this.cachedViews.splice(index, 1);
|
||||
resolve([...this.cachedViews]);
|
||||
});
|
||||
},
|
||||
clearVisitedView() {
|
||||
this.delAllViews();
|
||||
},
|
||||
delAllViews() {
|
||||
return new Promise((resolve) => {
|
||||
this.visitedViews = this.visitedViews.filter((v) => v.meta.affix);
|
||||
this.cachedViews = this.visitedViews.filter((v) => v.meta.affix);
|
||||
resolve([...this.visitedViews]);
|
||||
});
|
||||
},
|
||||
delOtherViews(path) {
|
||||
this.visitedViews = this.visitedViews.filter((item) => {
|
||||
return item.path === path || item.meta.affix;
|
||||
});
|
||||
this.cachedViews = this.visitedViews.filter((item) => {
|
||||
return item.path === path || item.meta.affix;
|
||||
});
|
||||
},
|
||||
goHome() {
|
||||
this.activeTabsValue = '/home';
|
||||
router.push({ path: '/home' });
|
||||
},
|
||||
updateVisitedView(view) {
|
||||
for (let v of this.visitedViews) {
|
||||
if (v.path === view.path) {
|
||||
v = Object.assign(v, view);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
65
main/src/store/modules/user.js
Normal file
@ -0,0 +1,65 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { GenKey } from '@/config';
|
||||
import { isEmpty, encode, decode } from '@/utils';
|
||||
|
||||
export const useUserStore = defineStore({
|
||||
id: GenKey('USER_STATE'),
|
||||
state: () => ({
|
||||
token: null,
|
||||
userInfo: {},
|
||||
currentOrg: null,
|
||||
orgList: [],
|
||||
menus: [],
|
||||
}),
|
||||
getters: {},
|
||||
actions: {
|
||||
setToken(token) {
|
||||
this.token = token;
|
||||
},
|
||||
hasToken() {
|
||||
return !isEmpty(this.token);
|
||||
},
|
||||
setUserInfo(userInfo) {
|
||||
this.userInfo = encode(JSON.stringify(userInfo), true);
|
||||
},
|
||||
getUserInfo() {
|
||||
return !isEmpty(this.userInfo) ? JSON.parse(decode(this.userInfo, true)) : {};
|
||||
},
|
||||
setOrgList(orgList) {
|
||||
this.orgList = encode(JSON.stringify(orgList), true);
|
||||
},
|
||||
getOrgList() {
|
||||
return !isEmpty(this.orgList) ? JSON.parse(decode(this.orgList, true)) : [];
|
||||
},
|
||||
setCurrentOrg(org) {
|
||||
this.currentOrg = org;
|
||||
},
|
||||
getCurrentOrg() {
|
||||
const list = this.getOrgList().filter((item) => {
|
||||
return item.id === this.currentOrg;
|
||||
});
|
||||
return !isEmpty(list) ? list[0] : {};
|
||||
},
|
||||
setMenus(menus) {
|
||||
this.menus = encode(JSON.stringify(menus), true);
|
||||
},
|
||||
getMenus() {
|
||||
return !isEmpty(this.menus) ? JSON.parse(decode(this.menus, true)) : [];
|
||||
},
|
||||
logout() {
|
||||
this.token = null;
|
||||
this.userInfo = {};
|
||||
this.currentOrg = null;
|
||||
this.orgList = [];
|
||||
this.menus = [];
|
||||
localStorage.removeItem(GenKey('USER_STATE'));
|
||||
},
|
||||
clear() {
|
||||
localStorage.removeItem(GenKey('USER_STATE'));
|
||||
},
|
||||
},
|
||||
persist: {
|
||||
key: GenKey('USER_STATE'),
|
||||
storage: window.localStorage,
|
||||
},
|
||||
});
|
283
main/src/styles/common/base.scss
Normal file
@ -0,0 +1,283 @@
|
||||
html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
a,
|
||||
abbr,
|
||||
acronym,
|
||||
address,
|
||||
article,
|
||||
aside,
|
||||
blockquote,
|
||||
caption,
|
||||
code,
|
||||
del,
|
||||
dfn,
|
||||
dialog,
|
||||
header,
|
||||
footer,
|
||||
nav,
|
||||
object,
|
||||
section,
|
||||
body,
|
||||
dd,
|
||||
div,
|
||||
dl,
|
||||
dt,
|
||||
em,
|
||||
img,
|
||||
fieldset,
|
||||
figure,
|
||||
form,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
hgroup,
|
||||
iframe,
|
||||
legend,
|
||||
p,
|
||||
pre,
|
||||
q,
|
||||
span,
|
||||
tbody,
|
||||
tfoot,
|
||||
thead,
|
||||
ul,
|
||||
ol,
|
||||
li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
list-style: none;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
article,
|
||||
aside,
|
||||
details,
|
||||
dialog,
|
||||
figcaption,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
menu,
|
||||
nav,
|
||||
section {
|
||||
display: block;
|
||||
}
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 12px;
|
||||
font-family: 'Source Han Sans CN, Source Han Sans CN-Regular', 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'Heiti SC', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif;
|
||||
color: #323232;
|
||||
|
||||
// background: #000;
|
||||
}
|
||||
img {
|
||||
vertical-align: bottom;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
// ::input-placeholder {
|
||||
// color: #999999;
|
||||
// }
|
||||
::placeholder {
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
// :input-placeholder {
|
||||
// color: #cccccc;
|
||||
// }
|
||||
button::-moz-focus-inner,
|
||||
input::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
button:focus,
|
||||
input:focus,
|
||||
select:focus,
|
||||
textarea:focus {
|
||||
outline: 0;
|
||||
}
|
||||
input::-ms-clear {
|
||||
display: none;
|
||||
}
|
||||
article,
|
||||
aside,
|
||||
details,
|
||||
figcaption,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
main,
|
||||
nav,
|
||||
section,
|
||||
summary {
|
||||
display: block;
|
||||
}
|
||||
audio,
|
||||
canvas,
|
||||
progress,
|
||||
video {
|
||||
display: inline-block;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
[hidden],
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #323232;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
a:active,
|
||||
a:hover {
|
||||
outline: 0;
|
||||
}
|
||||
a:focus {
|
||||
outline: thin dotted;
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
abbr[title] {
|
||||
border-bottom: 1px dotted;
|
||||
}
|
||||
b,
|
||||
strong {
|
||||
font-weight: 700;
|
||||
}
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
mark {
|
||||
color: #000000;
|
||||
background: #ffff00;
|
||||
}
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
figure {
|
||||
margin: 1em 40px;
|
||||
}
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
}
|
||||
pre {
|
||||
overflow: auto;
|
||||
}
|
||||
code,
|
||||
kbd,
|
||||
pre,
|
||||
samp {
|
||||
font-size: 1em;
|
||||
font-family: monospace;
|
||||
}
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font: inherit;
|
||||
}
|
||||
button {
|
||||
overflow: visible;
|
||||
}
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
button,
|
||||
html input[type='button'],
|
||||
input[type='reset'],
|
||||
input[type='submit'] {
|
||||
appearance: button;
|
||||
cursor: pointer;
|
||||
}
|
||||
button[disabled],
|
||||
html input[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
button::-moz-focus-inner,
|
||||
input::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
input {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: normal;
|
||||
}
|
||||
input[type='checkbox'],
|
||||
input[type='radio'] {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
}
|
||||
input[type='number']::-webkit-inner-spin-button,
|
||||
input[type='number']::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
input[type='search'] {
|
||||
box-sizing: content-box;
|
||||
appearance: textfield;
|
||||
}
|
||||
input[type='search']::-webkit-search-cancel-button,
|
||||
input[type='search']::-webkit-search-decoration {
|
||||
appearance: none;
|
||||
}
|
||||
fieldset {
|
||||
margin: 0 2px;
|
||||
padding: 0.35em 0.625em 0.75em;
|
||||
border: 1px solid silver;
|
||||
}
|
||||
legend {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
optgroup {
|
||||
font-weight: 700;
|
||||
}
|
||||
table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
padding: 0;
|
||||
}
|
94
main/src/styles/common/define.scss
Normal file
@ -0,0 +1,94 @@
|
||||
@use "sass:list";
|
||||
|
||||
.flex {
|
||||
&-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
&-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
@each $type, $colors in $color-types {
|
||||
.text-#{$type} {
|
||||
color: list.nth($colors, 1);
|
||||
}
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.custom {
|
||||
&-page {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.el-pagination {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.el-pagination .btn-next.is-active,
|
||||
.el-pagination .btn-prev.is-active,
|
||||
.el-pagination .el-pager li.is-active {
|
||||
color: $color-primary !important;
|
||||
}
|
||||
|
||||
.el-pagination .btn-next,
|
||||
.el-pagination .btn-prev,
|
||||
.el-pagination .el-pager li {
|
||||
margin: 0 12px !important;
|
||||
font-size: 24px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.el-pagination .btn-next,
|
||||
.el-pagination .btn-prev {
|
||||
// border: 1px dashed #ddd;
|
||||
&:hover {
|
||||
color: #000 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-pagination .btn-next .el-icon,
|
||||
.el-pagination .btn-prev .el-icon {
|
||||
font-size: 32px !important;
|
||||
font-weight: 500 !important;
|
||||
}
|
||||
|
||||
.el-pagination .el-pager li {
|
||||
&:hover {
|
||||
font-weight: 500;
|
||||
color: $color-primary !important;
|
||||
}
|
||||
}
|
||||
|
||||
&-jumper {
|
||||
margin-left: 40px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
font-size: 24px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.el-input {
|
||||
width: 50px !important;
|
||||
margin: 0 20px;
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
56
main/src/styles/global.scss
Normal file
@ -0,0 +1,56 @@
|
||||
// color
|
||||
$legacy-ie: 10;
|
||||
$color-primary: #b10304;
|
||||
$color-success: #13ce66;
|
||||
$color-warning: #f7ba2a;
|
||||
$color-danger: #ff4949;
|
||||
$color-info: #50bfff;
|
||||
$color-secondary: #2e90fe;
|
||||
$color-white: #ffffff;
|
||||
$color-black: #1f2d3d;
|
||||
$color-black-light: #324057;
|
||||
$color-black-lighter: #475669;
|
||||
$color-blue-light: #5da9ff;
|
||||
$color-blue-lighter: #5da9ff;
|
||||
$color-black: #000000;
|
||||
$color-silver: #8492a6;
|
||||
$color-silver-light: #99a9bf;
|
||||
$color-silver-lighter: #c0ccda;
|
||||
$color-gray: #d3dce6;
|
||||
$color-gray-light: #e5e9f2;
|
||||
$color-gray-lighter: #eff2f7;
|
||||
$color-333: #333333;
|
||||
$color-666: #333333;
|
||||
$color-999: #999999;
|
||||
$color-border-gray: #d1dbe5;
|
||||
$color-input-border: #dcdfe6;
|
||||
$color-border: $color-border-gray;
|
||||
$color-types: (
|
||||
primary: (
|
||||
$color-primary,
|
||||
#4db3ff,
|
||||
#1d90e6
|
||||
),
|
||||
info: (
|
||||
$color-info,
|
||||
#73ccff,
|
||||
#48ace6
|
||||
),
|
||||
success: (
|
||||
$color-success,
|
||||
#42d885,
|
||||
#11b95c
|
||||
),
|
||||
warning: (
|
||||
$color-warning,
|
||||
#f9c855,
|
||||
#dea726
|
||||
),
|
||||
danger: (
|
||||
$color-danger,
|
||||
#ff6d6d,
|
||||
#e64242
|
||||
)
|
||||
);
|
||||
|
||||
@import "utils/utils";
|
13
main/src/styles/style.scss
Normal file
@ -0,0 +1,13 @@
|
||||
@import 'common/base.scss';
|
||||
@import 'common/define.scss';
|
||||
// @import "@/assets/fonts/iconfont.css";
|
||||
|
||||
#root,
|
||||
#app {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-family: Avenir, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
31
main/src/styles/utils/_bem.scss
Normal file
@ -0,0 +1,31 @@
|
||||
/// Block Element
|
||||
/// @access public
|
||||
/// @param {String} $element - Element's name
|
||||
@mixin element($element) {
|
||||
&__#{$element} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// @alias element
|
||||
@mixin e($element) {
|
||||
@include element($element) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// Block Modifier
|
||||
/// @access public
|
||||
/// @param {String} $modifier - Modifier's name
|
||||
@mixin modifier($modifier) {
|
||||
&_#{$modifier} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// @alias modifier
|
||||
@mixin m($modifier) {
|
||||
@include modifier($modifier) {
|
||||
@content;
|
||||
}
|
||||
}
|
30
main/src/styles/utils/_ellipsis.scss
Normal file
@ -0,0 +1,30 @@
|
||||
@mixin ellipsis($lines: 1, $line-height: 0) {
|
||||
overflow: hidden;
|
||||
|
||||
@if $lines == 1 {
|
||||
@if $legacy-ie <= 8 {
|
||||
word-wrap: normal; // for ie
|
||||
}
|
||||
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
} @else {
|
||||
display: flexbox;
|
||||
-webkit-line-clamp: $lines;
|
||||
-webkit-box-orient: vertical;
|
||||
|
||||
@if value-of($line-height) == 0 {
|
||||
@error 'line-height is required when clamp muti lines';
|
||||
}
|
||||
|
||||
@if unitless($line-height) or unit($line-height) == '%' {
|
||||
$line-height: value-of($line-height) * 1em;
|
||||
}
|
||||
|
||||
max-height: $line-height * $lines;
|
||||
|
||||
// &:after {
|
||||
// content: " ...";
|
||||
// }
|
||||
}
|
||||
}
|
5
main/src/styles/utils/_scrollable.scss
Normal file
@ -0,0 +1,5 @@
|
||||
@mixin scrollable() {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
34
main/src/styles/utils/_scrollbar.scss
Normal file
@ -0,0 +1,34 @@
|
||||
/// Mixin to customize scrollbars
|
||||
/// Beware, this does not work in all browsers
|
||||
/// @author Hugo Giraudel
|
||||
/// @param {Length} $size - Horizontal scrollbar's height and vertical scrollbar's width
|
||||
/// @param {Color} $foreground-color - Scrollbar's color
|
||||
/// @param {Color} $background-color [mix($foreground-color, white, 50%)] - Scrollbar's color
|
||||
/// @example scss - Scrollbar styling
|
||||
/// @include scrollbars(.5em, slategray);
|
||||
@mixin scrollbars($size, $foreground-color, $background-color: mix($foreground-color, white, 50%)) {
|
||||
// For Google Chrome
|
||||
::-webkit-scrollbar {
|
||||
width: $size;
|
||||
height: $size;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: $foreground-color;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: $background-color;
|
||||
}
|
||||
|
||||
// For Internet Explorer
|
||||
body {
|
||||
scrollbar-face-color: $foreground-color;
|
||||
scrollbar-track-color: $background-color;
|
||||
}
|
||||
}
|
||||
|
||||
/// alias
|
||||
@mixin scrollbar($size, $foreground-color, $background-color: mix($foreground-color, white, 50%)) {
|
||||
@include scrollbars($size, $foreground-color, $background-color: mix($foreground-color, white, 50%));
|
||||
}
|
11
main/src/styles/utils/_value-of.scss
Normal file
@ -0,0 +1,11 @@
|
||||
@function value-of($value) {
|
||||
@if type-of($value) == 'number' and not unitless($value) {
|
||||
@return $value / ($value * 0 + 1);
|
||||
}
|
||||
@return $value;
|
||||
}
|
||||
|
||||
// alias
|
||||
@function strip-unit($value) {
|
||||
@return value-of($value);
|
||||
}
|
21
main/src/styles/utils/utils.scss
Normal file
@ -0,0 +1,21 @@
|
||||
@import 'bem';
|
||||
@import 'ellipsis';
|
||||
@import 'scrollable';
|
||||
@import 'scrollbar';
|
||||
@import 'value-of';
|
||||
|
||||
@mixin flex-row() {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
@mixin flex-column() {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@mixin icon-space() {
|
||||
display: inline-block;
|
||||
content: '';
|
||||
background-size: 100%;
|
||||
}
|
99
main/src/utils/axios.js
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* @Descripttion:
|
||||
* @Author: zenghua.wang
|
||||
* @Date: 2022-02-23 21:12:37
|
||||
* @LastEditors: wzh 1048523306@qq.com
|
||||
* @LastEditTime: 2024-12-18 15:10:48
|
||||
*/
|
||||
import axios from 'axios';
|
||||
import { ElNotification } from 'element-plus';
|
||||
import router from '@/router';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
|
||||
const { VITE_APP_BASE_API, VITE_APP_UPLOAD_API } = import.meta.env;
|
||||
|
||||
/**
|
||||
* 创建axios实例
|
||||
*/
|
||||
const publicAxios = axios.create({
|
||||
baseURL: VITE_APP_BASE_API,
|
||||
timeout: 10000,
|
||||
});
|
||||
/**
|
||||
* 异常拦截处理器
|
||||
* @param error
|
||||
* @returns
|
||||
*/
|
||||
const errorHandler = async (error) => {
|
||||
const { response } = error;
|
||||
const UserStore = useUserStore();
|
||||
if (response && response.status) {
|
||||
switch (response.status) {
|
||||
case 401:
|
||||
case 403:
|
||||
UserStore.logout();
|
||||
router.push('/login');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Promise.reject(error?.response?.data);
|
||||
};
|
||||
/**
|
||||
* 请求拦截器
|
||||
*/
|
||||
publicAxios.interceptors.request.use(async (config) => {
|
||||
const UserStore = useUserStore();
|
||||
config.baseURL = config?.isUpload ? VITE_APP_UPLOAD_API : config?.isLocal ? '' : VITE_APP_BASE_API;
|
||||
if (UserStore.hasToken()) {
|
||||
config.headers['fairies-auth-token'] = UserStore.token;
|
||||
config.headers['cache-control'] = 'no-cache';
|
||||
config.headers.Pragma = 'no-cache';
|
||||
if (config?.isUpload) {
|
||||
config.headers['Content-Type'] = config.uploadType;
|
||||
}
|
||||
}
|
||||
if (config.method === 'POST' || config.method === 'DELETE') {
|
||||
config.headers.Accept = 'application/json';
|
||||
}
|
||||
return config;
|
||||
}, errorHandler);
|
||||
/**
|
||||
* 返回结果处理
|
||||
* @param res
|
||||
* @returns
|
||||
*/
|
||||
const formatResult = (res) => {
|
||||
const code = res.data.code || res.status;
|
||||
switch (code) {
|
||||
case 200:
|
||||
case 0:
|
||||
// code === 0 或 200 代表没有错误
|
||||
return res.data || res.data.data || res;
|
||||
case 500:
|
||||
case 1:
|
||||
// code === 1 或 500 代表存在错误
|
||||
// ElNotification.error(res.data.msg);
|
||||
break;
|
||||
default:
|
||||
ElNotification.error(res.data.msg);
|
||||
break;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 响应拦截器
|
||||
*/
|
||||
publicAxios.interceptors.response.use((response) => {
|
||||
const { config } = response;
|
||||
if (config?.responseType) {
|
||||
return response;
|
||||
}
|
||||
const result = formatResult(response);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
throw new Error(response.data.msg);
|
||||
}, errorHandler);
|
||||
|
||||
export default publicAxios;
|
490
main/src/utils/index.js
Normal file
@ -0,0 +1,490 @@
|
||||
/*
|
||||
* @Descripttion:
|
||||
* @Author: zenghua.wang
|
||||
* @Date: 2022-02-23 21:12:37
|
||||
* @LastEditors: wzh 1048523306@qq.com
|
||||
* @LastEditTime: 2024-12-17 11:55:31
|
||||
*/
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { Base64 } from 'js-base64';
|
||||
import JsZip from 'jszip';
|
||||
import JsZipUtils from 'jszip-utils';
|
||||
import { saveAs } from 'file-saver';
|
||||
|
||||
/**
|
||||
* @Title 防抖:指在一定时间内,多次触发同一个事件,只执行最后一次操作
|
||||
* @param {*} fn
|
||||
* @param {*} delay
|
||||
* @returns
|
||||
*/
|
||||
export function debounce(fn, delay) {
|
||||
let timer = null;
|
||||
return function (...args) {
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
fn.apply(this, args);
|
||||
}, delay);
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @Title 节流:指在一定时间内,多次触发同一个事件,只执行第一次操作
|
||||
* @param {*} fn
|
||||
* @param {*} delay
|
||||
* @returns
|
||||
*/
|
||||
export function throttle(fn, delay) {
|
||||
let timer = null;
|
||||
return function (...args) {
|
||||
if (!timer) {
|
||||
timer = setTimeout(() => {
|
||||
fn.apply(this, args);
|
||||
timer = null;
|
||||
}, delay);
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @Title 判断是否 empty,返回ture
|
||||
* @param {*} val:null 'null' undefined 'undefined' 0 '0' "" 返回true
|
||||
* @returns
|
||||
*/
|
||||
export const isEmpty = (val) => {
|
||||
if (val && parseInt(val) === 0) return false;
|
||||
if (typeof val === 'undefined' || val === 'null' || val == null || val === 'undefined' || val === undefined || val === '') {
|
||||
return true;
|
||||
} else if (typeof val === 'object' && Object.keys(val).length === 0) {
|
||||
return true;
|
||||
} else if (val instanceof Array && val.length === 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @Title 深度拷贝对象
|
||||
* @param {*} obj
|
||||
* @returns
|
||||
*/
|
||||
export const deepClone = (obj = {}) => {
|
||||
return cloneDeep(obj);
|
||||
};
|
||||
/**
|
||||
* @Title 将number转换为px
|
||||
* @param {*} val
|
||||
* @returns
|
||||
*/
|
||||
export const setPx = (val) => {
|
||||
if (isEmpty(val)) return '';
|
||||
return typeof val === 'number' ? `${val}px` : val;
|
||||
};
|
||||
/**
|
||||
* @Title 设置字典值
|
||||
* @param {*} columns
|
||||
* @param {*} key
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export const setDicData = (columns, key, data = []) => {
|
||||
if (isEmpty(data)) return;
|
||||
const len = columns.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
if (columns[i]?.prop === key) {
|
||||
columns[i]['dicData'] = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @Title 求字段lable
|
||||
* @param {*} tree
|
||||
* @returns
|
||||
*/
|
||||
export const setDicLabel = (dicData, value) => {
|
||||
let label = value;
|
||||
if (isEmpty(dicData)) return label;
|
||||
const len = dicData.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
if (dicData[i]?.value === value) {
|
||||
label = dicData[i].label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return label;
|
||||
};
|
||||
/**
|
||||
* @Title 数组交集
|
||||
* @param {*} arr1
|
||||
* @param {*} arr2
|
||||
* @returns
|
||||
*/
|
||||
export const intersectionArray = (arr1 = [], arr2 = []) => {
|
||||
return arr1.filter((item) => arr2.includes(item));
|
||||
};
|
||||
/**
|
||||
* @Title 数组并集
|
||||
* @param {*} arr1
|
||||
* @param {*} arr2
|
||||
* @returns
|
||||
*/
|
||||
export const unionArray = (arr1 = [], arr2 = []) => {
|
||||
return Array.from(new Set([...arr1, ...arr2]));
|
||||
};
|
||||
/**
|
||||
* @Title 数组差集
|
||||
* @param {*} arr1
|
||||
* @param {*} arr2
|
||||
* @returns
|
||||
*/
|
||||
export const differenceArray = (arr1 = [], arr2 = []) => {
|
||||
const s = new Set(arr2);
|
||||
return arr1.filter((x) => !s.has(x));
|
||||
};
|
||||
/**
|
||||
* @Title 加密
|
||||
* @param {*} n
|
||||
* @returns
|
||||
*/
|
||||
export const encode = (n, flag = false) => {
|
||||
if (flag) {
|
||||
return (
|
||||
((e) => {
|
||||
let t = e.length.toString();
|
||||
for (let n = 10 - t.length; n > 0; n--) t = '0' + t;
|
||||
return t;
|
||||
})(n) +
|
||||
((e) => {
|
||||
const t = Base64.encode(e).split('');
|
||||
for (let n = 0; n < Math.floor(e.length / 100 + 1); n++) t.splice(100 * n + 1, 0, 3);
|
||||
return t.join('');
|
||||
})(n)
|
||||
);
|
||||
}
|
||||
return n;
|
||||
};
|
||||
/**
|
||||
* @Title 解密
|
||||
* @param {*} e
|
||||
* @returns
|
||||
*/
|
||||
export const decode = (e, flag = false) => {
|
||||
if (flag) {
|
||||
try {
|
||||
const t = Number(e.substr(0, 10));
|
||||
const n = e.substr(10).split('');
|
||||
for (let i = 0, s = 0; s < Math.floor(t / 100) + 1; s++) {
|
||||
n.splice(100 * s + 1 - i, 1);
|
||||
i++;
|
||||
}
|
||||
const o = Base64.decode(n.join(''));
|
||||
return o;
|
||||
} catch (error) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return e;
|
||||
};
|
||||
/**
|
||||
* @Title 图片转base64
|
||||
* @param {*} file
|
||||
* @returns
|
||||
*/
|
||||
export const imageToBase64 = (file) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = () => {
|
||||
resolve(reader.result);
|
||||
};
|
||||
reader.onerror = reject;
|
||||
});
|
||||
};
|
||||
/**
|
||||
* @Title bufferToBase64
|
||||
* @param {*} buffer
|
||||
* @returns
|
||||
*/
|
||||
export const bufferToBase64 = (buffer) => {
|
||||
return 'data:image/jpeg;base64,' + window.btoa(new Uint8Array(buffer).reduce((data, byte) => data + String.fromCharCode(byte), ''));
|
||||
};
|
||||
/**
|
||||
* @Title blob转json
|
||||
* @param {*} file
|
||||
* @returns
|
||||
*/
|
||||
export const blobToJSON = (blob) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsText(blob, 'utf-8');
|
||||
reader.onload = () => {
|
||||
const res = !isEmpty(reader.result) ? JSON.parse(reader.result) : reader.result;
|
||||
resolve(res);
|
||||
};
|
||||
reader.onerror = reject;
|
||||
});
|
||||
};
|
||||
/**
|
||||
* @Title 将array转化为树
|
||||
* @param tree
|
||||
* @returns
|
||||
*/
|
||||
export const getTree = (tree = []) => {
|
||||
tree.forEach((item) => {
|
||||
delete item.children;
|
||||
});
|
||||
const map = {};
|
||||
tree.forEach((item) => {
|
||||
map[item.id] = item;
|
||||
});
|
||||
const arr = [];
|
||||
tree.forEach((item) => {
|
||||
const parent = map[item.parentId];
|
||||
if (parent) {
|
||||
(parent.children || (parent.children = [])).push(item);
|
||||
} else {
|
||||
arr.push(item);
|
||||
}
|
||||
});
|
||||
return arr;
|
||||
};
|
||||
/**
|
||||
* @Title 获取路由中的参数
|
||||
* @param name
|
||||
* @returns
|
||||
*/
|
||||
export const getUrlQuery = (name) => {
|
||||
const url = window.location.href;
|
||||
const hash = url.substring(url.indexOf('#') + 1);
|
||||
const searchIndex = hash.indexOf('?');
|
||||
const search = searchIndex !== -1 ? hash.substring(searchIndex + 1) : '';
|
||||
const usp = new URLSearchParams(search);
|
||||
return usp.get(name);
|
||||
};
|
||||
/**
|
||||
* @Title 将字符串url参数转换为Object
|
||||
* @param {*} url
|
||||
* @returns
|
||||
*/
|
||||
export const param2Obj = (url) => {
|
||||
return (url) => Object.fromEntries(new URLSearchParams(url));
|
||||
};
|
||||
/**
|
||||
* @Title 将Object参数转换为字符串
|
||||
* @param {*} json
|
||||
* @returns
|
||||
*/
|
||||
export const obj2Param = (json) => {
|
||||
if (!json) return '';
|
||||
return Object.keys(json)
|
||||
.map((key) => {
|
||||
if (isEmpty(json[key])) return '';
|
||||
return encodeURIComponent(key) + '=' + encodeURIComponent(json[key]);
|
||||
})
|
||||
.join('&');
|
||||
};
|
||||
/**
|
||||
* @Title 获取静态资源文件
|
||||
* @param {*} url
|
||||
* @returns
|
||||
*/
|
||||
export const getAssetsFile = (url) => {
|
||||
return new URL(`../assets/images/${url}`, import.meta.url);
|
||||
};
|
||||
/**
|
||||
* 文件下载
|
||||
* @param {*} url
|
||||
* @param {*} fileName
|
||||
* @returns
|
||||
*/
|
||||
export const dowloadFile = async (options = { url: '', files: null, fileName: '' }) => {
|
||||
const { url, files, fileName } = options;
|
||||
const chunkSize = 1 * 1024 * 1024;
|
||||
const jszip = new JsZip();
|
||||
|
||||
function chunkFile(file, chunkSize) {
|
||||
let chunks = [];
|
||||
let fileSize = file.size;
|
||||
let currentPos = 0;
|
||||
while (currentPos < fileSize) {
|
||||
let endPos = currentPos + chunkSize;
|
||||
if (endPos > fileSize) {
|
||||
endPos = fileSize;
|
||||
}
|
||||
chunks.push(file.slice(currentPos, endPos));
|
||||
currentPos = endPos;
|
||||
}
|
||||
return chunks;
|
||||
}
|
||||
|
||||
function dowloadLink(content, fileName) {
|
||||
const blob = new Blob([content]);
|
||||
if ('download' in document.createElement('a')) {
|
||||
const elink = document.createElement('a');
|
||||
elink.download = fileName;
|
||||
elink.style.display = 'none';
|
||||
elink.href = URL.createObjectURL(blob);
|
||||
document.body.appendChild(elink);
|
||||
elink.click();
|
||||
URL.revokeObjectURL(elink.href);
|
||||
document.body.removeChild(elink);
|
||||
} else {
|
||||
navigator.msSaveBlob(blob, fileName);
|
||||
}
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!isEmpty(options?.url)) {
|
||||
JsZipUtils.getBinaryContent(url, (err, file) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
jszip
|
||||
.loadAsync(file)
|
||||
.then((zip) => {
|
||||
return zip.generateAsync({ type: 'blob' });
|
||||
})
|
||||
.then((blob) => {
|
||||
saveAs(blob, `${fileName}.zip`);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// if (files.type === 'binary/octet-stream') {
|
||||
// dowloadLink(files, fileName);
|
||||
// return;
|
||||
// }
|
||||
let chunks = null;
|
||||
if (files.size > chunkSize) {
|
||||
chunks = chunkFile(files, chunkSize);
|
||||
}
|
||||
const fileType = files.type.split('/')[1];
|
||||
const newFile = files.type === 'binary/octet-stream' ? fileName : `${fileName}.${fileType}`;
|
||||
if (chunks) {
|
||||
let count = 1;
|
||||
chunks.forEach(function (chunk) {
|
||||
jszip.file(newFile, chunk, { binary: true });
|
||||
count++;
|
||||
});
|
||||
} else {
|
||||
jszip.file(`${fileName}.${fileType}`, files, { binary: true });
|
||||
}
|
||||
jszip.generateAsync({ type: 'blob' }).then((blob) => {
|
||||
saveAs(blob, `${fileName}.zip`);
|
||||
resolve(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
/**
|
||||
* @Title 模拟休眠
|
||||
* @param {*} duration
|
||||
* @returns
|
||||
*/
|
||||
export const sleep = (duration = 0) =>
|
||||
new Promise((resolve) => {
|
||||
setTimeout(resolve, duration);
|
||||
});
|
||||
/**
|
||||
* @Title 创建id
|
||||
* @param {*} prefix
|
||||
* @returns
|
||||
*/
|
||||
export const createId = (prefix) => {
|
||||
const val = Date.now() + Math.ceil(Math.random() * 99999);
|
||||
return isEmpty(prefix) ? val : prefix + '-' + val;
|
||||
};
|
||||
/**
|
||||
* @Title 生成数据
|
||||
* @param {*} duration
|
||||
* @returns
|
||||
*/
|
||||
export const mockData = (item = {}, len = 1) => {
|
||||
const list = [];
|
||||
for (let i = 0; i < len; i++) {
|
||||
let temp = { ...item, id: createId() };
|
||||
list.push(temp);
|
||||
}
|
||||
return list;
|
||||
};
|
||||
/**
|
||||
* @Title 日期格式化
|
||||
* @param {*} date
|
||||
* @param {*} format
|
||||
* @returns
|
||||
*/
|
||||
export const dateFormat = (datetime, formater = 'YYYY-MM-DD hh:mm:ss') => {
|
||||
if (datetime instanceof Date || datetime) {
|
||||
return dayjs(datetime).format(formater);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @Title 字符串转日期
|
||||
* @param {*} str
|
||||
* @returns
|
||||
*/
|
||||
export const toDate = (str) => {
|
||||
return !isEmpty(str) ? dayjs(str) : dayjs();
|
||||
};
|
||||
/**
|
||||
* @Title 字符串转日期
|
||||
* @param {*} str
|
||||
* @returns
|
||||
*/
|
||||
export const getDate = (num, type, formater = 'YYYY-MM-DD', start = true) => {
|
||||
const date = dayjs().subtract(num, type);
|
||||
return start ? date.startOf(type).format(formater) : date.endOf(type).format(formater);
|
||||
};
|
||||
/**
|
||||
* @Title: 获取时间差
|
||||
* @param start
|
||||
* @param end
|
||||
* @param type
|
||||
* @returns
|
||||
*/
|
||||
export const getDiffTime = (start, end, type) => {
|
||||
const startTime = dayjs(start);
|
||||
const endTime = dayjs(end);
|
||||
const duration = endTime.diff(startTime);
|
||||
let diff = 0;
|
||||
switch (type) {
|
||||
case 'DD': {
|
||||
diff = duration / (1000 * 60 * 60 * 24);
|
||||
break;
|
||||
}
|
||||
case 'HH': {
|
||||
diff = duration / (1000 * 60 * 60);
|
||||
break;
|
||||
}
|
||||
case 'mm': {
|
||||
diff = duration / (1000 * 60);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Math.round(diff);
|
||||
};
|
||||
/**
|
||||
* @Title: 开始日期
|
||||
* @param last
|
||||
* @param type
|
||||
* @param formater
|
||||
* @returns
|
||||
*/
|
||||
export const startDate = (num, type = 'month', formater = 'YYYY-MM-DD HH:mm:ss') => {
|
||||
if (num === 'now') return dayjs().format(formater);
|
||||
if (typeof num === 'string') return dayjs(num).startOf(type).format(formater);
|
||||
return num === 0 ? dayjs().startOf(type).format(formater) : dayjs().subtract(num, type).startOf(type).format(formater);
|
||||
};
|
||||
/**
|
||||
* @Title: 结束日期
|
||||
* @param num
|
||||
* @param type
|
||||
* @param formater
|
||||
* @returns
|
||||
*/
|
||||
export const endDate = (num = 0, type = 'month', formater = 'YYYY-MM-DD HH:mm:ss') => {
|
||||
if (num === 'now') return dayjs().format(formater);
|
||||
if (typeof num === 'string') return dayjs(num).endOf(type).format(formater);
|
||||
return num === 0 ? dayjs().endOf(type).format(formater) : dayjs().subtract(num, type).endOf(type).format(formater);
|
||||
};
|
84
main/src/utils/permission.js
Normal file
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @Description: 路由权限
|
||||
* @Author: zenghua.wang
|
||||
* @Date: 2022-01-26 22:04:31
|
||||
* @LastEditors: zenghua.wang
|
||||
* @LastEditTime: 2024-05-22 13:36:31
|
||||
*/
|
||||
import NProgress from 'nprogress';
|
||||
import 'nprogress/nprogress.css';
|
||||
import router from '@/router';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { usePermissionStore } from '@/store/modules/permission';
|
||||
|
||||
NProgress.configure({ showSpinner: false });
|
||||
|
||||
const { VITE_APP_NAME } = import.meta.env;
|
||||
const whiteList = ['/login'];
|
||||
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
// 解决三级菜单页面缓存问题
|
||||
// if (to.matched && to.matched.length > 1) {
|
||||
// for (let i = 0; i < to.matched.length; i++) {
|
||||
// const element = to.matched[i];
|
||||
// if (element.components.default.name === 'ViewBox') {
|
||||
// to.matched.splice(i, 1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
NProgress.start();
|
||||
if (typeof to.meta.title === 'string') {
|
||||
document.title = VITE_APP_NAME + ' | ' + to.meta.title;
|
||||
}
|
||||
|
||||
const userStore = useUserStore();
|
||||
const hasToken = true; //userStore.hasToken();
|
||||
|
||||
if (hasToken) {
|
||||
if (to.path === '/login') {
|
||||
next({ path: '/' });
|
||||
} else {
|
||||
try {
|
||||
const PermissionStore = usePermissionStore();
|
||||
if (!PermissionStore.routes.length) {
|
||||
const accessRoutes = await PermissionStore.generateRoutes(userStore.roles);
|
||||
accessRoutes.forEach((item) => router.addRoute(item));
|
||||
next({ ...to, replace: true });
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
} catch (error) {
|
||||
next(`/login?redirect=${to.path}`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (whiteList.indexOf(to.path) !== -1) {
|
||||
next();
|
||||
} else {
|
||||
next(`/login?redirect=${to.path}`);
|
||||
}
|
||||
}
|
||||
|
||||
// const PermissionStore = usePermissionStore();
|
||||
// console.log('===', PermissionStore.routes);
|
||||
// if (!PermissionStore.routes.length) {
|
||||
// const accessRoutes = await PermissionStore.getRoutes();
|
||||
// accessRoutes.forEach((item) => router.addRoute(item));
|
||||
// next({ ...to, replace: true });
|
||||
// } else {
|
||||
// next();
|
||||
// }
|
||||
});
|
||||
|
||||
router.afterEach((to) => {
|
||||
// qiankun子应用跳转回主应用时判断#app是否还有渲染的子应用,如若没有则重新渲染主应用
|
||||
// setTimeout(() => {
|
||||
// if (to.path === '/') {
|
||||
// if (window.wocwin_qiankun) {
|
||||
// window.wocwin_qiankun = null;
|
||||
// }
|
||||
// }
|
||||
// }, 300);
|
||||
NProgress.done();
|
||||
});
|
107
main/src/utils/router.js
Normal file
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* @Description: 路由方法
|
||||
* @Author: zenghua.wang
|
||||
* @Date: 2022-01-26 21:55:58
|
||||
* @LastEditors: zenghua.wang
|
||||
* @LastEditTime: 2024-04-14 11:03:08
|
||||
*/
|
||||
import path from 'path-browserify';
|
||||
import Views from '@/layouts/Views.vue';
|
||||
import { isEmpty } from './index';
|
||||
|
||||
const modules = import.meta.glob('../views/**/**.vue');
|
||||
|
||||
/**
|
||||
* 创建路由菜单
|
||||
* @param {*} menus
|
||||
*/
|
||||
export function createAsyncRoutes(menus = []) {
|
||||
if (isEmpty(menus)) return menus;
|
||||
const res = [];
|
||||
menus.forEach((menu) => {
|
||||
const tmp = {
|
||||
id: menu.id,
|
||||
parentId: menu.parentId,
|
||||
path: menu.path,
|
||||
component: isEmpty(menu.component) ? Views : modules[/* @vite-ignore */ `../views/${menu.component.replace('/views/', '')}`],
|
||||
redirect: menu.redirect ?? null,
|
||||
name: menu.name,
|
||||
meta: {
|
||||
title: menu.title ?? '',
|
||||
icon: menu.icon ?? '',
|
||||
keepAlive: menu.keepAlive ?? false,
|
||||
},
|
||||
children: menu.children,
|
||||
hidden: menu.hidden ?? false,
|
||||
};
|
||||
if (tmp.children) {
|
||||
tmp.children = createAsyncRoutes(tmp.children, false);
|
||||
}
|
||||
res.push(tmp);
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过递归过滤异步路由表
|
||||
* @param routes asyncRoutes
|
||||
* @param roles
|
||||
*/
|
||||
export function filterAsyncRoutes(routes, roles) {
|
||||
const res = [];
|
||||
routes.forEach((route) => {
|
||||
const tmp = { ...route };
|
||||
if (hasPermission(roles, tmp)) {
|
||||
if (tmp.children) {
|
||||
tmp.children = filterAsyncRoutes(tmp.children, roles);
|
||||
}
|
||||
res.push(tmp);
|
||||
}
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 meta.role 来确定当前用户是否具有权限
|
||||
* @param roles
|
||||
* @param route
|
||||
*/
|
||||
export function hasPermission(roles, route) {
|
||||
if (route.meta && route.meta.roles) {
|
||||
return roles.some((role) => route.meta.roles.includes(role));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用递归,过滤需要缓存的路由
|
||||
* @param {*} routers
|
||||
* @returns
|
||||
*/
|
||||
export function filterKeepAlive(routers) {
|
||||
const cacheRouter = [];
|
||||
const loop = (routers) => {
|
||||
routers.forEach((item) => {
|
||||
if (item.meta?.keepAlive && item.name) {
|
||||
cacheRouter.push(item.name);
|
||||
}
|
||||
if (item.children && item.children.length) {
|
||||
loop(item.children);
|
||||
}
|
||||
});
|
||||
};
|
||||
loop(routers);
|
||||
return cacheRouter;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} routers
|
||||
* @param {*} pathUrl
|
||||
*/
|
||||
export function handleRoutes(routers, pathUrl = '') {
|
||||
routers.forEach((item) => {
|
||||
item.path = path.resolve(pathUrl, item.path);
|
||||
});
|
||||
}
|
10
main/src/views/index.vue
Normal file
@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<div class="platform">
|
||||
<h2>平台首页</h2>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { reactive } from 'vue';
|
||||
|
||||
const state = reactive({});
|
||||
</script>
|
5
main/src/views/login/index.vue
Normal file
@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<div>登录</div>
|
||||
</template>
|
||||
|
||||
<script setup></script>
|
136
main/vite.config.js
Normal file
@ -0,0 +1,136 @@
|
||||
import { defineConfig, loadEnv } from 'vite';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import qiankun from 'vite-plugin-qiankun';
|
||||
import eslintPlugin from 'vite-plugin-eslint';
|
||||
import vueSetupExtend from 'vite-plugin-vue-setup-extend';
|
||||
import compression from 'vite-plugin-compression';
|
||||
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
|
||||
import { createHtmlPlugin } from 'vite-plugin-html';
|
||||
// import { viteMockServe } from 'vite-plugin-mock';
|
||||
import AutoImport from 'unplugin-auto-import/vite';
|
||||
import Components from 'unplugin-vue-components/vite';
|
||||
import postcssImport from 'postcss-import';
|
||||
import autoprefixer from 'autoprefixer';
|
||||
// import postCssPxToRem from 'postcss-pxtorem';
|
||||
import { resolve } from 'path';
|
||||
|
||||
export default defineConfig(({ command, mode }) => {
|
||||
const { VITE_PORT, VITE_APP_NAME } = loadEnv(mode, process.cwd());
|
||||
const config = {
|
||||
base: './',
|
||||
build: {
|
||||
target: 'ESNext',
|
||||
outDir: 'dist',
|
||||
minify: 'terser',
|
||||
},
|
||||
server: {
|
||||
host: '0.0.0.0',
|
||||
port: VITE_PORT,
|
||||
open: true,
|
||||
https: false,
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
},
|
||||
proxy: {
|
||||
// [VITE_APP_BASE_API]: {
|
||||
// target: VITE_APP_BASE_URL,
|
||||
// changeOrigin: true,
|
||||
// rewrite: (path) => path.replace(/^\/apis/, ''),
|
||||
// },
|
||||
'^/api': {
|
||||
target: process.env.VUE_APP_BASE_API, // 开发环境
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
'^/api': '',
|
||||
},
|
||||
'^/admin_api': {
|
||||
target: 'https://mock.mengxuegu.com/mock/65d00eb6351bbd02cf3398e3/api',
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
'^/admin_api': '',
|
||||
},
|
||||
},
|
||||
'^/v2api': {
|
||||
target: 'https://mock.mengxuegu.com/mock/663f2f7737199f49537c350f/api-v2',
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
'^/v2api': '',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': resolve(__dirname, 'src'),
|
||||
},
|
||||
extensions: ['.js', '.vue', '.json', '.ts'],
|
||||
},
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
scss: {
|
||||
additionalData: '@import "@/styles/global.scss";',
|
||||
api: 'modern-compiler',
|
||||
},
|
||||
},
|
||||
postcss: {
|
||||
plugins: [
|
||||
postcssImport,
|
||||
autoprefixer({
|
||||
overrideBrowserslist: ['> 1%', 'last 2 versions'],
|
||||
}),
|
||||
// postCssPxToRem({
|
||||
// rootValue: 192,
|
||||
// selectorBlackList: [],
|
||||
// propList: ['*'],
|
||||
// exclude: /node_modules/i,
|
||||
// }),
|
||||
],
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
vue(),
|
||||
qiankun(),
|
||||
vueSetupExtend(),
|
||||
createHtmlPlugin({
|
||||
inject: {
|
||||
data: {
|
||||
web_title: VITE_APP_NAME,
|
||||
},
|
||||
},
|
||||
}),
|
||||
eslintPlugin({
|
||||
include: ['src/**/*.ts', 'src/**/*.vue', 'src/*.ts', 'src/*.vue'],
|
||||
}),
|
||||
Components({
|
||||
dirs: ['../global/components', 'src/components'],
|
||||
extensions: ['vue', 'js', 'jsx', 'ts', 'tsx'],
|
||||
resolvers: [],
|
||||
}),
|
||||
compression(),
|
||||
AutoImport({
|
||||
include: [/\.[tj]s?$/, /\.vue$/],
|
||||
imports: ['vue', 'vue-router'],
|
||||
}),
|
||||
createSvgIconsPlugin({
|
||||
iconDirs: [resolve(process.cwd(), 'src/assets/svgs')],
|
||||
symbolId: 'icon-[name]',
|
||||
}),
|
||||
// viteMockServe({
|
||||
// mockPath: 'src/mock',
|
||||
// watchFiles: true,
|
||||
// localEnabled: command === 'dev',
|
||||
// prodEnabled: false,
|
||||
// }),
|
||||
],
|
||||
};
|
||||
if (mode === 'production') {
|
||||
config.build.terserOptions = {
|
||||
compress: {
|
||||
drop_console: true,
|
||||
drop_debugger: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
return config;
|
||||
});
|
7036
main/yarn.lock
Normal file
32
package.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "daimp-front",
|
||||
"version": "1.0.0",
|
||||
"description": "数字农业产业管理平台(Digital-Agriculture-Industry-Management-Platform)",
|
||||
"scripts": {
|
||||
"install:all": "npm-run-all install:* ",
|
||||
"install": "npm-run-all --serial install:*",
|
||||
"install:main": "cd main && yarn install",
|
||||
"install:sub-admin": "cd sub-admin && yarn install",
|
||||
"install:sub-vue": "cd sub-vue && yarn install",
|
||||
"dev": "npm-run-all --parallel dev:*",
|
||||
"dev:main": "cd main && yarn dev",
|
||||
"dev:sub-admin": "cd sub-app && yarn dev",
|
||||
"dev:sub-vue": "cd sub-vue && yarn dev",
|
||||
"build": "npm-run-all --serial build:*",
|
||||
"build:main": "cd main && yarn build",
|
||||
"build:sub-admin": "cd sub-admin && yarn build",
|
||||
"build:sub-vue": "cd sub-vue && yarn build",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [
|
||||
"vue3",
|
||||
"vite",
|
||||
"qiankun"
|
||||
],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"npm-run-all": "^4.1.5"
|
||||
}
|
||||
}
|
9
sub-admin/.editorconfig
Normal file
@ -0,0 +1,9 @@
|
||||
root = true
|
||||
|
||||
[*.{js,jsx,ts,tsx,vue}]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
end_of_line = auto
|
6
sub-admin/.env.development
Normal file
@ -0,0 +1,6 @@
|
||||
# 开发环境
|
||||
VITE_PORT = 9527
|
||||
VITE_MODE = 'DEV'
|
||||
VITE_APP_NAME = 'sub-admin'
|
||||
VITE_APP_BASE_API = '/apis'
|
||||
VITE_APP_BASE_URL = 'http://localhost:8080/'
|
5
sub-admin/.env.production
Normal file
@ -0,0 +1,5 @@
|
||||
# 生产环境
|
||||
VITE_MODE = 'PRO'
|
||||
VITE_APP_NAME = 'sub-vue'
|
||||
VITE_APP_BASE_API = 'https://www.localhost.com/8080/api/'
|
||||
VITE_APP_BASE_URL = 'https://www.localhost.com/8080/'
|
14
sub-admin/.eslintignore
Normal file
@ -0,0 +1,14 @@
|
||||
*.sh
|
||||
*.md
|
||||
*.woff
|
||||
*.ttf
|
||||
.vscode
|
||||
.idea
|
||||
.husky
|
||||
.local
|
||||
dist
|
||||
src/assets
|
||||
node_modules
|
||||
Dockerfile
|
||||
stats.html
|
||||
tailwind.config.js
|
62
sub-admin/.eslintrc.cjs
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* @Descripttion: .eslintrc.cjs
|
||||
* 在VSCode中安装ESLint插件,编写过程中检测代码质量
|
||||
* ESLint 代码质量校验相关配置
|
||||
* 这里使用prettier作为代码格式化工具,用ESLint做代码质检
|
||||
* 相关配置使用下面extends扩展先做默认设置
|
||||
* 在.prettierrc.cjs文件中配置好后,格式化规则会以.prettierrc.cjs作为最终格式,所以不建议在本文件中做代码格式化相关配置
|
||||
* 相关prettier配置ESLint会默认加载为代码质检 格式化以prettier为主
|
||||
* 在本配置文件中只做代码质量约束规范配置
|
||||
* @Author: zenghua.wang
|
||||
* @Date: 2022-09-22 15:53:58
|
||||
* @LastEditors: zenghua.wang
|
||||
* @LastEditTime: 2024-03-22 10:19:39
|
||||
*/
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
node: true,
|
||||
},
|
||||
extends: [
|
||||
'eslint-config-prettier',
|
||||
'eslint:recommended',
|
||||
// 'plugin:@typescript-eslint/recommended',
|
||||
'plugin:vue/vue3-recommended',
|
||||
'plugin:vue/vue3-essential',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
overrides: [
|
||||
{
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
files: ['.eslintrc.{js,cjs}'],
|
||||
parserOptions: {
|
||||
sourceType: 'script',
|
||||
},
|
||||
},
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
requireConfigFile: false,
|
||||
parser: '@babel/eslint-parser',
|
||||
// parser: '@typescript-eslint/parser',
|
||||
},
|
||||
plugins: ['vue', 'prettier'],
|
||||
globals: {
|
||||
defineProps: 'readonly',
|
||||
defineEmits: 'readonly',
|
||||
defineExpose: 'readonly',
|
||||
withDefaults: 'readonly',
|
||||
},
|
||||
// 这里时配置规则的,自己看情况配置
|
||||
rules: {
|
||||
'prettier/prettier': 'error',
|
||||
'no-debugger': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
'vue/no-unused-vars': 'off',
|
||||
'vue/multi-word-component-names': 'off',
|
||||
},
|
||||
};
|
116
sub-admin/.gitignore
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
20
sub-admin/.prettierignore
Normal file
@ -0,0 +1,20 @@
|
||||
## OS
|
||||
.DS_Store
|
||||
node_modules
|
||||
.idea
|
||||
.editorconfig
|
||||
package-lock.json
|
||||
.npmrc
|
||||
|
||||
# Ignored suffix
|
||||
*.log
|
||||
*.md
|
||||
*.svg
|
||||
*.png
|
||||
*ignore
|
||||
|
||||
## Local
|
||||
|
||||
## Built-files
|
||||
.cache
|
||||
dist
|
52
sub-admin/.prettierrc.cjs
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* @Descripttion: .prettierrc.cjs
|
||||
* 在VSCode中安装prettier插件 打开插件配置填写`.prettierrc.js` 将本文件作为其代码格式化规范
|
||||
* 在本文件中修改格式化规则,不会同时触发改变ESLint代码检查,所以每次修改本文件需要重启VSCode,ESLint检查才能同步代码格式化
|
||||
* 需要相应的代码格式化规范请自行查阅配置,下面为默认项目配置
|
||||
* @Author: zenghua.wang
|
||||
* @Date: 2022-09-22 15:53:58
|
||||
* @LastEditors: zenghua.wang
|
||||
* @LastEditTime: 2024-01-24 19:22:25
|
||||
*/
|
||||
module.exports = {
|
||||
// 一行最多多少个字符
|
||||
printWidth: 150,
|
||||
// 指定每个缩进级别的空格数
|
||||
tabWidth: 2,
|
||||
// 使用制表符而不是空格缩进行
|
||||
useTabs: false,
|
||||
// 在语句末尾是否需要分号
|
||||
semi: true,
|
||||
// 是否使用单引号
|
||||
singleQuote: true,
|
||||
// 更改引用对象属性的时间 可选值"<as-needed|consistent|preserve>"
|
||||
quoteProps: 'as-needed',
|
||||
// 在JSX中使用单引号而不是双引号
|
||||
jsxSingleQuote: false,
|
||||
// 多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>",默认none
|
||||
trailingComma: 'es5',
|
||||
// 在对象文字中的括号之间打印空格
|
||||
bracketSpacing: true,
|
||||
// jsx 标签的反尖括号需要换行
|
||||
jsxBracketSameLine: false,
|
||||
// 在单独的箭头函数参数周围包括括号 always:(x) => x \ avoid:x => x
|
||||
arrowParens: 'always',
|
||||
// 这两个选项可用于格式化以给定字符偏移量(分别包括和不包括)开始和结束的代码
|
||||
rangeStart: 0,
|
||||
rangeEnd: Infinity,
|
||||
// 指定要使用的解析器,不需要写文件开头的 @prettier
|
||||
requirePragma: false,
|
||||
// 不需要自动在文件开头插入 @prettier
|
||||
insertPragma: false,
|
||||
// 使用默认的折行标准 always\never\preserve
|
||||
proseWrap: 'preserve',
|
||||
// 指定HTML文件的全局空格敏感度 css\strict\ignore
|
||||
htmlWhitespaceSensitivity: 'css',
|
||||
// Vue文件脚本和样式标签缩进
|
||||
vueIndentScriptAndStyle: false,
|
||||
//在 windows 操作系统中换行符通常是回车 (CR) 加换行分隔符 (LF),也就是回车换行(CRLF),
|
||||
//然而在 Linux 和 Unix 中只使用简单的换行分隔符 (LF)。
|
||||
//对应的控制字符为 "\n" (LF) 和 "\r\n"(CRLF)。auto意为保持现有的行尾
|
||||
// 换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr>"
|
||||
endOfLine: 'auto',
|
||||
};
|
17
sub-admin/.stylelintignore
Normal file
@ -0,0 +1,17 @@
|
||||
# .stylelintignore
|
||||
# 旧的不需打包的样式库
|
||||
*.min.css
|
||||
|
||||
# 其他类型文件
|
||||
*.js
|
||||
*.jpg
|
||||
*.png
|
||||
*.eot
|
||||
*.ttf
|
||||
*.woff
|
||||
*.json
|
||||
|
||||
# 测试和打包目录
|
||||
/dist/*
|
||||
/node_modules/*
|
||||
/src/assets/*
|
131
sub-admin/.stylelintrc.cjs
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* @Descripttion: .stylelintrc.cjs
|
||||
* @Author: zenghua.wang
|
||||
* @Date: 2022-09-22 15:53:58
|
||||
* @LastEditors: zenghua.wang
|
||||
* @LastEditTime: 2024-01-24 18:49:26
|
||||
*/
|
||||
module.exports = {
|
||||
root: true,
|
||||
plugins: ['stylelint-order', 'stylelint-scss'],
|
||||
extends: [
|
||||
'stylelint-config-standard',
|
||||
'stylelint-config-standard-scss',
|
||||
'stylelint-config-prettier',
|
||||
'stylelint-config-html/vue',
|
||||
'stylelint-config-recommended-vue',
|
||||
'stylelint-config-recommended-scss'
|
||||
],
|
||||
overrides: [
|
||||
{
|
||||
files: ['**/*.{html,vue}'],
|
||||
customSyntax: 'postcss-html'
|
||||
}
|
||||
],
|
||||
rules: {
|
||||
indentation: 2,
|
||||
'selector-pseudo-element-no-unknown': [
|
||||
true,
|
||||
{
|
||||
ignorePseudoElements: ['v-deep', ':deep']
|
||||
}
|
||||
],
|
||||
'number-leading-zero': 'always',
|
||||
'no-descending-specificity': null,
|
||||
'function-url-quotes': 'always',
|
||||
'string-quotes': 'single',
|
||||
'unit-case': null,
|
||||
'color-hex-case': 'lower',
|
||||
'color-hex-length': 'long',
|
||||
'rule-empty-line-before': 'never',
|
||||
'font-family-no-missing-generic-family-keyword': null,
|
||||
'selector-type-no-unknown': null,
|
||||
'block-opening-brace-space-before': 'always',
|
||||
'at-rule-no-unknown': null,
|
||||
'no-duplicate-selectors': null,
|
||||
'property-no-unknown': null,
|
||||
'no-empty-source': null,
|
||||
'selector-class-pattern': null,
|
||||
'keyframes-name-pattern': null,
|
||||
'selector-pseudo-class-no-unknown': [true, { ignorePseudoClasses: ['global', 'deep'] }],
|
||||
'function-no-unknown': null,
|
||||
'order/properties-order': [
|
||||
'position',
|
||||
'top',
|
||||
'right',
|
||||
'bottom',
|
||||
'left',
|
||||
'z-index',
|
||||
'display',
|
||||
'justify-content',
|
||||
'align-items',
|
||||
'float',
|
||||
'clear',
|
||||
'overflow',
|
||||
'overflow-x',
|
||||
'overflow-y',
|
||||
'margin',
|
||||
'margin-top',
|
||||
'margin-right',
|
||||
'margin-bottom',
|
||||
'margin-left',
|
||||
'padding',
|
||||
'padding-top',
|
||||
'padding-right',
|
||||
'padding-bottom',
|
||||
'padding-left',
|
||||
'width',
|
||||
'min-width',
|
||||
'max-width',
|
||||
'height',
|
||||
'min-height',
|
||||
'max-height',
|
||||
'font-size',
|
||||
'font-family',
|
||||
'font-weight',
|
||||
'border',
|
||||
'border-style',
|
||||
'border-width',
|
||||
'border-color',
|
||||
'border-top',
|
||||
'border-top-style',
|
||||
'border-top-width',
|
||||
'border-top-color',
|
||||
'border-right',
|
||||
'border-right-style',
|
||||
'border-right-width',
|
||||
'border-right-color',
|
||||
'border-bottom',
|
||||
'border-bottom-style',
|
||||
'border-bottom-width',
|
||||
'border-bottom-color',
|
||||
'border-left',
|
||||
'border-left-style',
|
||||
'border-left-width',
|
||||
'border-left-color',
|
||||
'border-radius',
|
||||
'text-align',
|
||||
'text-justify',
|
||||
'text-indent',
|
||||
'text-overflow',
|
||||
'text-decoration',
|
||||
'white-space',
|
||||
'color',
|
||||
'background',
|
||||
'background-position',
|
||||
'background-repeat',
|
||||
'background-size',
|
||||
'background-color',
|
||||
'background-clip',
|
||||
'opacity',
|
||||
'filter',
|
||||
'list-style',
|
||||
'outline',
|
||||
'visibility',
|
||||
'box-shadow',
|
||||
'text-shadow',
|
||||
'resize',
|
||||
'transition'
|
||||
]
|
||||
}
|
||||
};
|
13
sub-admin/index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>EGGY TEAM</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
77
sub-admin/package.json
Normal file
@ -0,0 +1,77 @@
|
||||
{
|
||||
"name": "sub-admin",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --mode development",
|
||||
"build": "vite build --mode production",
|
||||
"build:dev": "vite build --mode dev",
|
||||
"build:qa": "vite build --mode qa",
|
||||
"preview": "vite preview",
|
||||
"format": "prettier --write 'src/**/*.{vue,ts,tsx,js,jsx,css,less,scss,json,md}'",
|
||||
"eslint": "npx eslint --init",
|
||||
"lint": "npm run lint:script && npm run lint:style",
|
||||
"lint:style": "stylelint 'src/**/*.{vue,scss,css,sass,less}' --fix",
|
||||
"lint:script": "eslint --ext .js,.ts,.tsx,.vue --fix --quiet ./src"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"@smallwei/avue": "^3.6.2",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||
"axios": "^1.6.5",
|
||||
"echarts": "^5.5.0",
|
||||
"element-plus": "^2.7.2",
|
||||
"js-base64": "^3.7.6",
|
||||
"lodash": "^4.17.21",
|
||||
"moment": "^2.30.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"pinia": "^2.1.7",
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
"screenfull": "^6.0.2",
|
||||
"vue": "^3.3.11",
|
||||
"vue-router": "^4.2.5",
|
||||
"vue3-custom-component": "1.1.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.23.7",
|
||||
"@babel/eslint-parser": "^7.23.3",
|
||||
"@types/path-browserify": "^1.0.2",
|
||||
"@vitejs/plugin-vue": "^4.5.2",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-vue": "^9.20.1",
|
||||
"mockjs": "^1.1.0",
|
||||
"postcss": "^8.4.33",
|
||||
"postcss-html": "^1.6.0",
|
||||
"postcss-import": "^16.0.0",
|
||||
"prettier": "^3.2.4",
|
||||
"sass": "^1.70.0",
|
||||
"stylelint": "^16.2.0",
|
||||
"stylelint-config-html": "^1.1.0",
|
||||
"stylelint-config-prettier": "^9.0.5",
|
||||
"stylelint-config-rational-order": "^0.1.2",
|
||||
"stylelint-config-recommended": "^14.0.0",
|
||||
"stylelint-config-recommended-scss": "^14.0.0",
|
||||
"stylelint-config-recommended-vue": "^1.5.0",
|
||||
"stylelint-config-standard": "^36.0.0",
|
||||
"stylelint-config-standard-scss": "^13.0.0",
|
||||
"stylelint-order": "^6.0.4",
|
||||
"stylelint-scss": "^6.1.0",
|
||||
"terser": "^5.27.0",
|
||||
"unplugin-auto-import": "^0.17.3",
|
||||
"unplugin-vue-components": "^0.26.0",
|
||||
"vite": "^5.0.8",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-eslint": "^1.8.1",
|
||||
"vite-plugin-mock": "^3.0.1",
|
||||
"vite-plugin-progress": "^0.0.7",
|
||||
"vite-plugin-qiankun": "^1.0.15",
|
||||
"vite-plugin-svg-icons": "^2.0.1",
|
||||
"vite-plugin-vue-setup-extend": "^0.4.0"
|
||||
}
|
||||
}
|
BIN
sub-admin/public/images/avatar.gif
Normal file
After Width: | Height: | Size: 6.2 KiB |
1
sub-admin/public/vite.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
27
sub-admin/src/App.vue
Normal file
@ -0,0 +1,27 @@
|
||||
<!--
|
||||
* @Description:
|
||||
* @Author: zenghua.wang
|
||||
* @Date: 2024-01-24 18:54:01
|
||||
* @LastEditors: zenghua.wang
|
||||
* @LastEditTime: 2024-01-26 22:57:34
|
||||
-->
|
||||
<template>
|
||||
<el-config-provider :size="size" :locale="zhCn">
|
||||
<router-view />
|
||||
</el-config-provider>
|
||||
</template>
|
||||
|
||||
<script setup name="app">
|
||||
import { computed } from 'vue';
|
||||
import { useSettingStore } from '@/store/modules/setting';
|
||||
// 配置element中文
|
||||
import zhCn from 'element-plus/es/locale/lang/zh-cn';
|
||||
|
||||
const SettingStore = useSettingStore();
|
||||
// 配置全局组件大小
|
||||
const size = computed(() => SettingStore.themeConfig.globalComSize);
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import './styles/style.scss';
|
||||
</style>
|
27
sub-admin/src/apis/common.js
Normal file
@ -0,0 +1,27 @@
|
||||
import request from '@/utils/axios';
|
||||
import { isEmpty } from '@/utils';
|
||||
|
||||
const { VITE_MODE, VITE_APP_UPLOAD_URL } = import.meta.env;
|
||||
|
||||
/**
|
||||
* @Title: 上传图片
|
||||
*/
|
||||
export function CommonUpload(data) {
|
||||
const url = !isEmpty(data?.url) ? (VITE_MODE === 'PRO' ? data?.url : data?.url.replace(VITE_APP_UPLOAD_URL, '')) : '/upload';
|
||||
return request(url, {
|
||||
method: 'PUT',
|
||||
isUpload: true,
|
||||
uploadType: data.file.type,
|
||||
data: data.file,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @Title: 上传编辑器图片
|
||||
*/
|
||||
export function UploadImageFromEditor(data) {
|
||||
return request('/store/rich-text/generate-pic-upload-url', {
|
||||
method: 'POST',
|
||||
data: data,
|
||||
});
|
||||
}
|