diff --git a/.docker-compose/nginx/conf.d/my.conf b/.docker-compose/nginx/conf.d/my.conf new file mode 100644 index 0000000..9a1685d --- /dev/null +++ b/.docker-compose/nginx/conf.d/my.conf @@ -0,0 +1,26 @@ +server { + listen 8080; + server_name localhost; + + #charset koi8-r; + #access_log logs/host.access.log main; + + location / { + root /usr/share/nginx/html; + add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; + try_files $uri $uri/ /index.html; + } + + location /api { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + rewrite ^/api/(.*)$ /$1 break; #重写 + proxy_pass http://177.7.0.12:8888; # 设置代理服务器的协议和地址 + } + + location /api/swagger/index.html { + proxy_pass http://127.0.0.1:8888/swagger/index.html; + } + } \ No newline at end of file diff --git a/.docker-compose/nginx/conf.d/nginx.conf b/.docker-compose/nginx/conf.d/nginx.conf new file mode 100644 index 0000000..29f68b8 --- /dev/null +++ b/.docker-compose/nginx/conf.d/nginx.conf @@ -0,0 +1,32 @@ +server { + listen 80; + server_name localhost; + + #charset koi8-r; + #access_log logs/host.access.log main; + + location / { + root /usr/share/nginx/html/dist; + add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; + try_files $uri $uri/ /index.html; + } + + location /api { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + rewrite ^/api/(.*)$ /$1 break; #重写 + proxy_pass http://127.0.0.1:8888; # 设置代理服务器的协议和地址 + } + location /form-generator { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_pass http://127.0.0.1:8888; + } + location /api/swagger/index.html { + proxy_pass http://127.0.0.1:8888/swagger/index.html; + } + } \ No newline at end of file diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..40b878d --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..ad07c38 --- /dev/null +++ b/.env.development @@ -0,0 +1,11 @@ +ENV = 'development' +VITE_CLI_PORT = 8080 +VITE_SERVER_PORT = 8888 +VITE_BASE_API = /api +VITE_FILE_API = /api +VITE_BASE_PATH = http://127.0.0.1 +VITE_POSITION = close +VITE_EDITOR = vscode +// VITE_EDITOR = webstorm 如果使用webstorm开发且要使用dom定位到代码行功能 请先自定添加 webstorm到环境变量 再将VITE_EDITOR值修改为webstorm +// 如果使用docker-compose开发模式,设置为下面的地址或本机主机IP +//VITE_BASE_PATH = http://177.7.0.12 diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..9345df2 --- /dev/null +++ b/.env.production @@ -0,0 +1,7 @@ +ENV = 'production' + +#下方为上线需要用到的程序代理前缀,一般用于nginx代理转发 +VITE_BASE_API = /api +VITE_FILE_API = /api +#下方修改为你的线上ip(如果需要在线使用表单构建工具时使用,其余情况无需使用以下环境变量) +VITE_BASE_PATH = https://demo.gin-vue-admin.com diff --git a/.gitignore b/.gitignore index a19f004..ea890fa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,6 @@ -# ---> Vue -# gitignore template for Vue.js projects -# -# Recommended template: Node.gitignore - -# TODO: where does this rule come from? -docs/_book - -# TODO: where does this rule come from? -test/ - +node_modules/* +package-lock.json +yarn.lock +bun.lockb +config.yaml +.idea diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..bc61a53 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,12 @@ +{ + "printWidth": 80, + "tabWidth": 2, + "useTabs": false, + "semi": false, + "singleQuote": true, + "trailingComma": "none", + "bracketSpacing": true, + "arrowParens": "always", + "vueIndentScriptAndStyle": true, + "endOfLine": "lf" +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..af4464e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +# 如果需要用 cicd ,请设置环境变量: +# variables: +# DOCKER_BUILDKIT: 1 + +FROM node:20-slim AS base +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +RUN corepack enable +COPY . /app +WORKDIR /app + + +FROM base AS prod-deps +RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod + +FROM base AS build +COPY --from=prod-deps /app/node_modules /app/node_modules +RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install && pnpm run build + + +FROM nginx:alpine +LABEL MAINTAINER="bypanghu@163.com" +COPY --from=base /app/.docker-compose/nginx/conf.d/my.conf /etc/nginx/conf.d/my.conf +COPY --from=build /app/dist /usr/share/nginx/html +RUN ls -al /usr/share/nginx/html diff --git a/README.md b/README.md index b724201..06f1a8c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,106 @@ -# lckt-admin +# gin-vue-admin web -老陈课堂-管理后台 \ No newline at end of file +## Project setup + +``` +npm install +``` + +### Compiles and hot-reloads for development + +``` +npm run serve +``` + +### Compiles and minifies for production + +``` +npm run build +``` + +### Run your tests + +``` +npm run test +``` + +### Lints and fixes files + +``` +npm run lint +``` + +整理代码结构 + +```lua +web + ├── babel.config.js + ├── Dockerfile + ├── favicon.ico + ├── index.html -- 主页面 + ├── limit.js -- 助手代码 + ├── package.json -- 包管理器代码 + ├── src -- 源代码 + │ ├── api -- api 组 + │ ├── App.vue -- 主页面 + │ ├── assets -- 静态资源 + │ ├── components -- 全局组件 + │ ├── core -- gva 组件包 + │ │ ├── config.js -- gva网站配置文件 + │ │ ├── gin-vue-admin.js -- 注册欢迎文件 + │ │ └── global.js -- 统一导入文件 + │ ├── directive -- v-auth 注册文件 + │ ├── main.js -- 主文件 + │ ├── permission.js -- 路由中间件 + │ ├── pinia -- pinia 状态管理器,取代vuex + │ │ ├── index.js -- 入口文件 + │ │ └── modules -- modules + │ │ ├── dictionary.js + │ │ ├── router.js + │ │ └── user.js + │ ├── router -- 路由声明文件 + │ │ └── index.js + │ ├── style -- 全局样式 + │ │ ├── base.scss + │ │ ├── basics.scss + │ │ ├── element_visiable.scss -- 此处可以全局覆盖 element-plus 样式 + │ │ ├── iconfont.css -- 顶部几个icon的样式文件 + │ │ ├── main.scss + │ │ ├── mobile.scss + │ │ └── newLogin.scss + │ ├── utils -- 方法包库 + │ │ ├── asyncRouter.js -- 动态路由相关 + │ │ ├── bus.js -- 全局mitt声明文件 + │ │ ├── date.js -- 日期相关 + │ │ ├── dictionary.js -- 获取字典方法 + │ │ ├── downloadImg.js -- 下载图片方法 + │ │ ├── format.js -- 格式整理相关 + │ │ ├── image.js -- 图片相关方法 + │ │ ├── page.js -- 设置页面标题 + │ │ ├── request.js -- 请求 + │ │ └── stringFun.js -- 字符串文件 + | ├── view -- 主要view代码 + | | ├── about -- 关于我们 + | | ├── dashboard -- 面板 + | | ├── error -- 错误 + | | ├── example --上传案例 + | | ├── iconList -- icon列表 + | | ├── init -- 初始化数据 + | | | ├── index -- 新版本 + | | | ├── init -- 旧版本 + | | ├── layout -- layout约束页面 + | | | ├── aside + | | | ├── bottomInfo -- bottomInfo + | | | ├── screenfull -- 全屏设置 + | | | ├── setting -- 系统设置 + | | | └── index.vue -- base 约束 + | | ├── login --登录 + | | ├── person --个人中心 + | | ├── superAdmin -- 超级管理员操作 + | | ├── system -- 系统检测页面 + | | ├── systemTools -- 系统配置相关页面 + | | └── routerHolder.vue -- page 入口页面 + ├── vite.config.js -- vite 配置文件 + └── yarn.lock + +``` diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..b1becff --- /dev/null +++ b/babel.config.js @@ -0,0 +1,4 @@ +module.exports = { + presets: [], + plugins: [] +} diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..3b443c5 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,29 @@ +import js from '@eslint/js' +import pluginVue from 'eslint-plugin-vue' +import globals from 'globals' + +export default [ + js.configs.recommended, + ...pluginVue.configs['flat/essential'], + { + name: 'app/files-to-lint', + files: ['**/*.{js,mjs,jsx,vue}'], + languageOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + globals: globals.node + }, + rules: { + 'vue/max-attributes-per-line': 0, + 'vue/no-v-model-argument': 0, + 'vue/multi-word-component-names': 'off', + 'no-lone-blocks': 'off', + 'no-extend-native': 'off', + 'no-unused-vars': ['error', { argsIgnorePattern: '^_' }] + } + }, + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/build/*.js', '**/src/assets/**', '**/public/**'] + } +] diff --git a/index.html b/index.html new file mode 100644 index 0000000..1d8d87a --- /dev/null +++ b/index.html @@ -0,0 +1,115 @@ + + + + + + + + + + + + + +
+
+
+
+
+
系统正在加载中,请稍候...
+
+
+ + + diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..ca45014 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "baseUrl": "./", + "paths": { + "@/*": ["src/*"] + } + }, + "exclude": ["node_modules", "dist"], + "include": ["src/**/*"] +} diff --git a/limit.js b/limit.js new file mode 100644 index 0000000..6ba9d46 --- /dev/null +++ b/limit.js @@ -0,0 +1,37 @@ +// 运行项目前通过node执行此脚本 (此脚本与 node_modules 目录同级) +const fs = require('fs') +const path = require('path') +const wfPath = path.resolve(__dirname, './node_modules/.bin') + +fs.readdir(wfPath, (err, files) => { + if (err) { + console.log(err) + } else { + if (files.length !== 0) { + files.forEach((item) => { + if (item.split('.')[1] === 'cmd') { + replaceStr(`${wfPath}/${item}`, /"%_prog%"/, '%_prog%') + } + }) + } + } +}) + +// 参数:[文件路径、 需要修改的字符串、修改后的字符串] (替换对应文件内字符串的公共函数) +function replaceStr(filePath, sourceRegx, targetSrt) { + fs.readFile(filePath, (err, data) => { + if (err) { + console.log(err) + } else { + let str = data.toString() + str = str.replace(sourceRegx, targetSrt) + fs.writeFile(filePath, str, (err) => { + if (err) { + console.log(err) + } else { + console.log('\x1B[42m%s\x1B[0m', '文件修改成功') + } + }) + } + }) +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..9bc5be3 --- /dev/null +++ b/package.json @@ -0,0 +1,75 @@ +{ + "name": "gin-vue-admin", + "version": "2.8.0", + "private": true, + "scripts": { + "serve": "vite --host --mode development", + "build": "vite build --mode production", + "limit-build": "npm install increase-memory-limit-fixbug cross-env -g && npm run fix-memory-limit && node ./limit && npm run build", + "preview": "vite preview", + "fix-memory-limit": "cross-env LIMIT=4096 increase-memory-limit" + }, + "dependencies": { + "@element-plus/icons-vue": "^2.3.1", + "@form-create/designer": "^3.2.6", + "@form-create/element-ui": "^3.2.10", + "@vue-office/docx": "^1.6.2", + "@vue-office/excel": "^1.7.11", + "@vue-office/pdf": "^2.0.2", + "@vueuse/core": "^11.0.3", + "@vueuse/integrations": "^12.0.0", + "@wangeditor/editor": "^5.1.23", + "@wangeditor/editor-for-vue": "^5.1.12", + "ace-builds": "^1.36.4", + "axios": "^1.7.7", + "chokidar": "^4.0.0", + "core-js": "^3.38.1", + "echarts": "5.5.1", + "element-plus": "^2.8.5", + "highlight.js": "^11.10.0", + "marked": "14.1.1", + "marked-highlight": "^2.1.4", + "mitt": "^3.0.1", + "nprogress": "^0.2.0", + "path": "^0.12.7", + "pinia": "^2.2.2", + "qs": "^6.13.0", + "screenfull": "^6.0.2", + "sortablejs": "^1.15.3", + "spark-md5": "^3.0.2", + "tailwindcss": "^3.4.10", + "universal-cookie": "^7", + "vform3-builds": "^3.0.10", + "vite-auto-import-svg": "^1.1.0", + "vue": "^3.5.7", + "vue-cropper": "^1.1.4", + "vue-echarts": "^7.0.3", + "vue-qr": "^4.0.9", + "vue-router": "^4.4.3", + "vue3-ace-editor": "^2.2.4", + "vuedraggable": "^4.1.0" + }, + "devDependencies": { + "@babel/eslint-parser": "^7.25.1", + "@eslint/js": "^9.14.0", + "@vitejs/plugin-legacy": "^5.4.2", + "@vitejs/plugin-vue": "^5.1.4", + "@vue/cli-plugin-babel": "~5.0.8", + "@vue/cli-plugin-eslint": "~5.0.8", + "@vue/cli-plugin-router": "~5.0.8", + "@vue/cli-plugin-vuex": "~5.0.8", + "@vue/cli-service": "~5.0.8", + "@vue/compiler-sfc": "^3.5.1", + "babel-plugin-import": "^1.13.8", + "chalk": "^5.3.0", + "dotenv": "^16.4.5", + "eslint": "^9.14.0", + "eslint-plugin-vue": "^9.30.0", + "sass": "^1.78.0", + "terser": "^5.31.6", + "vite": "^5.4.3", + "vite-plugin-banner": "^0.8.0", + "vite-plugin-importer": "^0.2.5", + "vite-plugin-vue-devtools": "^7.4.4" + } +} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..85f717c --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {} + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..ee520ce Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000..468cdab Binary files /dev/null and b/public/logo.png differ diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..6048a3f --- /dev/null +++ b/src/App.vue @@ -0,0 +1,41 @@ + + + + diff --git a/src/api/api.js b/src/api/api.js new file mode 100644 index 0000000..7eed8fc --- /dev/null +++ b/src/api/api.js @@ -0,0 +1,176 @@ +import service from '@/utils/request' + +// @Tags api +// @Summary 分页获取角色列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body modelInterface.PageInfo true "分页获取用户列表" +// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /api/getApiList [post] +// { +// page int +// pageSize int +// } +export const getApiList = (data) => { + return service({ + url: '/api/getApiList', + method: 'post', + data + }) +} + +// @Tags Api +// @Summary 创建基础api +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body api.CreateApiParams true "创建api" +// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /api/createApi [post] +export const createApi = (data) => { + return service({ + url: '/api/createApi', + method: 'post', + data + }) +} + +// @Tags menu +// @Summary 根据id获取菜单 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body api.GetById true "根据id获取菜单" +// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /menu/getApiById [post] +export const getApiById = (data) => { + return service({ + url: '/api/getApiById', + method: 'post', + data + }) +} + +// @Tags Api +// @Summary 更新api +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body api.CreateApiParams true "更新api" +// @Success 200 {string} json "{"success":true,"data":{},"msg":"更新成功"}" +// @Router /api/updateApi [post] +export const updateApi = (data) => { + return service({ + url: '/api/updateApi', + method: 'post', + data + }) +} + +// @Tags Api +// @Summary 更新api +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body api.CreateApiParams true "更新api" +// @Success 200 {string} json "{"success":true,"data":{},"msg":"更新成功"}" +// @Router /api/setAuthApi [post] +export const setAuthApi = (data) => { + return service({ + url: '/api/setAuthApi', + method: 'post', + data + }) +} + +// @Tags Api +// @Summary 获取所有的Api 不分页 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /api/getAllApis [post] +export const getAllApis = (data) => { + return service({ + url: '/api/getAllApis', + method: 'post', + data + }) +} + +// @Tags Api +// @Summary 删除指定api +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body dbModel.Api true "删除api" +// @Success 200 {string} json "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /api/deleteApi [post] +export const deleteApi = (data) => { + return service({ + url: '/api/deleteApi', + method: 'post', + data + }) +} + +// @Tags SysApi +// @Summary 删除选中Api +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.IdsReq true "ID" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /api/deleteApisByIds [delete] +export const deleteApisByIds = (data) => { + return service({ + url: '/api/deleteApisByIds', + method: 'delete', + data + }) +} + +// FreshCasbin +// @Tags SysApi +// @Summary 刷新casbin缓存 +// @accept application/json +// @Produce application/json +// @Success 200 {object} response.Response{msg=string} "刷新成功" +// @Router /api/freshCasbin [get] +export const freshCasbin = () => { + return service({ + url: '/api/freshCasbin', + method: 'get' + }) +} + +export const syncApi = () => { + return service({ + url: '/api/syncApi', + method: 'get' + }) +} + +export const getApiGroups = () => { + return service({ + url: '/api/getApiGroups', + method: 'get' + }) +} + +export const ignoreApi = (data) => { + return service({ + url: '/api/ignoreApi', + method: 'post', + data + }) +} + +export const enterSyncApi = (data) => { + return service({ + url: '/api/enterSyncApi', + method: 'post', + data + }) +} diff --git a/src/api/attachmentCategory.js b/src/api/attachmentCategory.js new file mode 100644 index 0000000..58980f6 --- /dev/null +++ b/src/api/attachmentCategory.js @@ -0,0 +1,26 @@ +import service from '@/utils/request' +// 分类列表 +export const getCategoryList = () => { + return service({ + url: '/attachmentCategory/getCategoryList', + method: 'get', + }) +} + +// 添加/编辑分类 +export const addCategory = (data) => { + return service({ + url: '/attachmentCategory/addCategory', + method: 'post', + data + }) +} + +// 删除分类 +export const deleteCategory = (data) => { + return service({ + url: '/attachmentCategory/deleteCategory', + method: 'post', + data + }) +} diff --git a/src/api/authority.js b/src/api/authority.js new file mode 100644 index 0000000..0401273 --- /dev/null +++ b/src/api/authority.js @@ -0,0 +1,85 @@ +import service from '@/utils/request' +// @Router /authority/getAuthorityList [post] +export const getAuthorityList = (data) => { + return service({ + url: '/authority/getAuthorityList', + method: 'post', + data + }) +} + +// @Summary 删除角色 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body {authorityId uint} true "删除角色" +// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /authority/deleteAuthority [post] +export const deleteAuthority = (data) => { + return service({ + url: '/authority/deleteAuthority', + method: 'post', + data + }) +} + +// @Summary 创建角色 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body api.CreateAuthorityPatams true "创建角色" +// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /authority/createAuthority [post] +export const createAuthority = (data) => { + return service({ + url: '/authority/createAuthority', + method: 'post', + data + }) +} + +// @Tags authority +// @Summary 拷贝角色 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body api.CreateAuthorityPatams true "拷贝角色" +// @Success 200 {string} json "{"success":true,"data":{},"msg":"拷贝成功"}" +// @Router /authority/copyAuthority [post] +export const copyAuthority = (data) => { + return service({ + url: '/authority/copyAuthority', + method: 'post', + data + }) +} + +// @Summary 设置角色资源权限 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body sysModel.SysAuthority true "设置角色资源权限" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"设置成功"}" +// @Router /authority/setDataAuthority [post] +export const setDataAuthority = (data) => { + return service({ + url: '/authority/setDataAuthority', + method: 'post', + data + }) +} + +// @Summary 修改角色 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysAuthority true "修改角色" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"设置成功"}" +// @Router /authority/setDataAuthority [post] +export const updateAuthority = (data) => { + return service({ + url: '/authority/updateAuthority', + method: 'put', + data + }) +} diff --git a/src/api/authorityBtn.js b/src/api/authorityBtn.js new file mode 100644 index 0000000..e12db47 --- /dev/null +++ b/src/api/authorityBtn.js @@ -0,0 +1,25 @@ +import service from '@/utils/request' + +export const getAuthorityBtnApi = (data) => { + return service({ + url: '/authorityBtn/getAuthorityBtn', + method: 'post', + data + }) +} + +export const setAuthorityBtnApi = (data) => { + return service({ + url: '/authorityBtn/setAuthorityBtn', + method: 'post', + data + }) +} + +export const canRemoveAuthorityBtnApi = (params) => { + return service({ + url: '/authorityBtn/canRemoveAuthorityBtn', + method: 'post', + params + }) +} diff --git a/src/api/autoCode.js b/src/api/autoCode.js new file mode 100644 index 0000000..8994b3c --- /dev/null +++ b/src/api/autoCode.js @@ -0,0 +1,198 @@ +import service from '@/utils/request' + +export const preview = (data) => { + return service({ + url: '/autoCode/preview', + method: 'post', + data + }) +} + +export const createTemp = (data) => { + return service({ + url: '/autoCode/createTemp', + method: 'post', + data + }) +} + +// @Tags SysApi +// @Summary 获取当前所有数据库 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}" +// @Router /autoCode/getDatabase [get] +export const getDB = (params) => { + return service({ + url: '/autoCode/getDB', + method: 'get', + params + }) +} + +// @Tags SysApi +// @Summary 获取当前数据库所有表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}" +// @Router /autoCode/getTables [get] +export const getTable = (params) => { + return service({ + url: '/autoCode/getTables', + method: 'get', + params + }) +} + +// @Tags SysApi +// @Summary 获取当前数据库所有表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}" +// @Router /autoCode/getColumn [get] +export const getColumn = (params) => { + return service({ + url: '/autoCode/getColumn', + method: 'get', + params + }) +} + +export const getSysHistory = (data) => { + return service({ + url: '/autoCode/getSysHistory', + method: 'post', + data + }) +} + +export const rollback = (data) => { + return service({ + url: '/autoCode/rollback', + method: 'post', + data + }) +} + +export const getMeta = (data) => { + return service({ + url: '/autoCode/getMeta', + method: 'post', + data + }) +} + +export const delSysHistory = (data) => { + return service({ + url: '/autoCode/delSysHistory', + method: 'post', + data + }) +} + +export const createPackageApi = (data) => { + return service({ + url: '/autoCode/createPackage', + method: 'post', + data + }) +} + +export const getPackageApi = () => { + return service({ + url: '/autoCode/getPackage', + method: 'post' + }) +} + +export const deletePackageApi = (data) => { + return service({ + url: '/autoCode/delPackage', + method: 'post', + data + }) +} + +export const getTemplatesApi = () => { + return service({ + url: '/autoCode/getTemplates', + method: 'get' + }) +} + +export const installPlug = (data) => { + return service({ + url: '/autoCode/installPlug', + method: 'post', + data + }) +} + +export const pubPlug = (params) => { + return service({ + url: '/autoCode/pubPlug', + method: 'post', + params + }) +} + +export const llmAuto = (data) => { + return service({ + url: '/autoCode/llmAuto', + method: 'post', + data: { ...data, mode: 'ai' }, + timeout: 1000 * 60 * 10, + loadingOption: { + lock: true, + fullscreen: true, + text: `小淼正在思考,请稍候...` + } + }) +} + +export const butler = (data) => { + return service({ + url: '/autoCode/llmAuto', + method: 'post', + data: { ...data, mode: 'butler' }, + timeout: 1000 * 60 * 10 + }) +} + + +export const eye = (data) => { + return service({ + url: '/autoCode/llmAuto', + method: 'post', + data: { ...data, mode: 'eye' }, + timeout: 1000 * 60 * 10 + }) +} + + +export const addFunc = (data) => { + return service({ + url: '/autoCode/addFunc', + method: 'post', + data + }) +} + +export const initMenu = (data) => { + return service({ + url: '/autoCode/initMenu', + method: 'post', + data + }) +} + +export const initAPI = (data) => { + return service({ + url: '/autoCode/initAPI', + method: 'post', + data + }) +} diff --git a/src/api/bot/bot.js b/src/api/bot/bot.js new file mode 100644 index 0000000..b159323 --- /dev/null +++ b/src/api/bot/bot.js @@ -0,0 +1,110 @@ +import service from '@/utils/request' +// @Tags Bot +// @Summary 创建机器人 +// @Security ApiKeyAuth +// @Accept application/json +// @Produce application/json +// @Param data body model.Bot true "创建机器人" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}" +// @Router /bt/createBot [post] +export const createBot = (data) => { + return service({ + url: '/bt/createBot', + method: 'post', + data + }) +} + +// @Tags Bot +// @Summary 删除机器人 +// @Security ApiKeyAuth +// @Accept application/json +// @Produce application/json +// @Param data body model.Bot true "删除机器人" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /bt/deleteBot [delete] +export const deleteBot = (params) => { + return service({ + url: '/bt/deleteBot', + method: 'delete', + params + }) +} + +// @Tags Bot +// @Summary 批量删除机器人 +// @Security ApiKeyAuth +// @Accept application/json +// @Produce application/json +// @Param data body request.IdsReq true "批量删除机器人" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /bt/deleteBot [delete] +export const deleteBotByIds = (params) => { + return service({ + url: '/bt/deleteBotByIds', + method: 'delete', + params + }) +} + +// @Tags Bot +// @Summary 更新机器人 +// @Security ApiKeyAuth +// @Accept application/json +// @Produce application/json +// @Param data body model.Bot true "更新机器人" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}" +// @Router /bt/updateBot [put] +export const updateBot = (data) => { + return service({ + url: '/bt/updateBot', + method: 'put', + data + }) +} + +// @Tags Bot +// @Summary 用id查询机器人 +// @Security ApiKeyAuth +// @Accept application/json +// @Produce application/json +// @Param data query model.Bot true "用id查询机器人" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}" +// @Router /bt/findBot [get] +export const findBot = (params) => { + return service({ + url: '/bt/findBot', + method: 'get', + params + }) +} + +// @Tags Bot +// @Summary 分页获取机器人列表 +// @Security ApiKeyAuth +// @Accept application/json +// @Produce application/json +// @Param data query request.PageInfo true "分页获取机器人列表" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /bt/getBotList [get] +export const getBotList = (params) => { + return service({ + url: '/bt/getBotList', + method: 'get', + params + }) +} + +// @Tags Bot +// @Summary 不需要鉴权的机器人接口 +// @Accept application/json +// @Produce application/json +// @Param data query botReq.BotSearch true "分页获取机器人列表" +// @Success 200 {object} response.Response{data=object,msg=string} "获取成功" +// @Router /bt/getBotPublic [get] +export const getBotPublic = () => { + return service({ + url: '/bt/getBotPublic', + method: 'get', + }) +} diff --git a/src/api/breakpoint.js b/src/api/breakpoint.js new file mode 100644 index 0000000..1dbfba2 --- /dev/null +++ b/src/api/breakpoint.js @@ -0,0 +1,43 @@ +import service from '@/utils/request' +// @Summary 设置角色资源权限 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body sysModel.SysAuthority true "设置角色资源权限" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"设置成功"}" +// @Router /authority/setDataAuthority [post] + +export const findFile = (params) => { + return service({ + url: '/fileUploadAndDownload/findFile', + method: 'get', + params + }) +} + +export const breakpointContinue = (data) => { + return service({ + url: '/fileUploadAndDownload/breakpointContinue', + method: 'post', + donNotShowLoading: true, + headers: { 'Content-Type': 'multipart/form-data' }, + data + }) +} + +export const breakpointContinueFinish = (params) => { + return service({ + url: '/fileUploadAndDownload/breakpointContinueFinish', + method: 'post', + params + }) +} + +export const removeChunk = (data, params) => { + return service({ + url: '/fileUploadAndDownload/removeChunk', + method: 'post', + data, + params + }) +} diff --git a/src/api/casbin.js b/src/api/casbin.js new file mode 100644 index 0000000..802e130 --- /dev/null +++ b/src/api/casbin.js @@ -0,0 +1,32 @@ +import service from '@/utils/request' +// @Tags authority +// @Summary 更改角色api权限 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body api.CreateAuthorityPatams true "更改角色api权限" +// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /casbin/UpdateCasbin [post] +export const UpdateCasbin = (data) => { + return service({ + url: '/casbin/updateCasbin', + method: 'post', + data + }) +} + +// @Tags casbin +// @Summary 获取权限列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body api.CreateAuthorityPatams true "获取权限列表" +// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /casbin/getPolicyPathByAuthorityId [post] +export const getPolicyPathByAuthorityId = (data) => { + return service({ + url: '/casbin/getPolicyPathByAuthorityId', + method: 'post', + data + }) +} diff --git a/src/api/category/category.js b/src/api/category/category.js new file mode 100644 index 0000000..701ec6d --- /dev/null +++ b/src/api/category/category.js @@ -0,0 +1,110 @@ +import service from '@/utils/request' +// @Tags Category +// @Summary 创建类别 +// @Security ApiKeyAuth +// @Accept application/json +// @Produce application/json +// @Param data body model.Category true "创建类别" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}" +// @Router /cat/createCategory [post] +export const createCategory = (data) => { + return service({ + url: '/cat/createCategory', + method: 'post', + data + }) +} + +// @Tags Category +// @Summary 删除类别 +// @Security ApiKeyAuth +// @Accept application/json +// @Produce application/json +// @Param data body model.Category true "删除类别" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /cat/deleteCategory [delete] +export const deleteCategory = (params) => { + return service({ + url: '/cat/deleteCategory', + method: 'delete', + params + }) +} + +// @Tags Category +// @Summary 批量删除类别 +// @Security ApiKeyAuth +// @Accept application/json +// @Produce application/json +// @Param data body request.IdsReq true "批量删除类别" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /cat/deleteCategory [delete] +export const deleteCategoryByIds = (params) => { + return service({ + url: '/cat/deleteCategoryByIds', + method: 'delete', + params + }) +} + +// @Tags Category +// @Summary 更新类别 +// @Security ApiKeyAuth +// @Accept application/json +// @Produce application/json +// @Param data body model.Category true "更新类别" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}" +// @Router /cat/updateCategory [put] +export const updateCategory = (data) => { + return service({ + url: '/cat/updateCategory', + method: 'put', + data + }) +} + +// @Tags Category +// @Summary 用id查询类别 +// @Security ApiKeyAuth +// @Accept application/json +// @Produce application/json +// @Param data query model.Category true "用id查询类别" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}" +// @Router /cat/findCategory [get] +export const findCategory = (params) => { + return service({ + url: '/cat/findCategory', + method: 'get', + params + }) +} + +// @Tags Category +// @Summary 分页获取类别列表 +// @Security ApiKeyAuth +// @Accept application/json +// @Produce application/json +// @Param data query request.PageInfo true "分页获取类别列表" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /cat/getCategoryList [get] +export const getCategoryList = (params) => { + return service({ + url: '/cat/getCategoryList', + method: 'get', + params + }) +} + +// @Tags Category +// @Summary 不需要鉴权的类别接口 +// @Accept application/json +// @Produce application/json +// @Param data query categoryReq.CategorySearch true "分页获取类别列表" +// @Success 200 {object} response.Response{data=object,msg=string} "获取成功" +// @Router /cat/getCategoryPublic [get] +export const getCategoryPublic = () => { + return service({ + url: '/cat/getCategoryPublic', + method: 'get', + }) +} diff --git a/src/api/customer.js b/src/api/customer.js new file mode 100644 index 0000000..4776f1c --- /dev/null +++ b/src/api/customer.js @@ -0,0 +1,80 @@ +import service from '@/utils/request' +// @Tags SysApi +// @Summary 删除客户 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body dbModel.ExaCustomer true "删除客户" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /customer/customer [post] +export const createExaCustomer = (data) => { + return service({ + url: '/customer/customer', + method: 'post', + data + }) +} + +// @Tags SysApi +// @Summary 更新客户信息 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body dbModel.ExaCustomer true "更新客户信息" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /customer/customer [put] +export const updateExaCustomer = (data) => { + return service({ + url: '/customer/customer', + method: 'put', + data + }) +} + +// @Tags SysApi +// @Summary 创建客户 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body dbModel.ExaCustomer true "创建客户" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /customer/customer [delete] +export const deleteExaCustomer = (data) => { + return service({ + url: '/customer/customer', + method: 'delete', + data + }) +} + +// @Tags SysApi +// @Summary 获取单一客户信息 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body dbModel.ExaCustomer true "获取单一客户信息" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /customer/customer [get] +export const getExaCustomer = (params) => { + return service({ + url: '/customer/customer', + method: 'get', + params + }) +} + +// @Tags SysApi +// @Summary 获取权限客户列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body modelInterface.PageInfo true "获取权限客户列表" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /customer/customerList [get] +export const getExaCustomerList = (params) => { + return service({ + url: '/customer/customerList', + method: 'get', + params + }) +} diff --git a/src/api/email.js b/src/api/email.js new file mode 100644 index 0000000..c2f16f4 --- /dev/null +++ b/src/api/email.js @@ -0,0 +1,14 @@ +import service from '@/utils/request' +// @Tags email +// @Summary 发送测试邮件 +// @Security ApiKeyAuth +// @Produce application/json +// @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}" +// @Router /email/emailTest [post] +export const emailTest = (data) => { + return service({ + url: '/email/emailTest', + method: 'post', + data + }) +} diff --git a/src/api/exportTemplate.js b/src/api/exportTemplate.js new file mode 100644 index 0000000..9f8729b --- /dev/null +++ b/src/api/exportTemplate.js @@ -0,0 +1,128 @@ +import service from '@/utils/request' + +// @Tags SysExportTemplate +// @Summary 创建导出模板 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysExportTemplate true "创建导出模板" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}" +// @Router /sysExportTemplate/createSysExportTemplate [post] +export const createSysExportTemplate = (data) => { + return service({ + url: '/sysExportTemplate/createSysExportTemplate', + method: 'post', + data + }) +} + +// @Tags SysExportTemplate +// @Summary 删除导出模板 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysExportTemplate true "删除导出模板" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /sysExportTemplate/deleteSysExportTemplate [delete] +export const deleteSysExportTemplate = (data) => { + return service({ + url: '/sysExportTemplate/deleteSysExportTemplate', + method: 'delete', + data + }) +} + +// @Tags SysExportTemplate +// @Summary 批量删除导出模板 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.IdsReq true "批量删除导出模板" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /sysExportTemplate/deleteSysExportTemplate [delete] +export const deleteSysExportTemplateByIds = (data) => { + return service({ + url: '/sysExportTemplate/deleteSysExportTemplateByIds', + method: 'delete', + data + }) +} + +// @Tags SysExportTemplate +// @Summary 更新导出模板 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysExportTemplate true "更新导出模板" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}" +// @Router /sysExportTemplate/updateSysExportTemplate [put] +export const updateSysExportTemplate = (data) => { + return service({ + url: '/sysExportTemplate/updateSysExportTemplate', + method: 'put', + data + }) +} + +// @Tags SysExportTemplate +// @Summary 用id查询导出模板 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data query model.SysExportTemplate true "用id查询导出模板" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}" +// @Router /sysExportTemplate/findSysExportTemplate [get] +export const findSysExportTemplate = (params) => { + return service({ + url: '/sysExportTemplate/findSysExportTemplate', + method: 'get', + params + }) +} + +// @Tags SysExportTemplate +// @Summary 分页获取导出模板列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data query request.PageInfo true "分页获取导出模板列表" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /sysExportTemplate/getSysExportTemplateList [get] +export const getSysExportTemplateList = (params) => { + return service({ + url: '/sysExportTemplate/getSysExportTemplateList', + method: 'get', + params + }) +} + + +// ExportExcel 导出表格token +// @Tags SysExportTemplate +// @Summary 导出表格 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Router /sysExportTemplate/exportExcel [get] +export const exportExcel = (params) => { + return service({ + url: '/sysExportTemplate/exportExcel', + method: 'get', + params + }) +} + +// ExportTemplate 导出表格模板 +// @Tags SysExportTemplate +// @Summary 导出表格模板 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Router /sysExportTemplate/exportTemplate [get] +export const exportTemplate = (params) => { + return service({ + url: '/sysExportTemplate/exportTemplate', + method: 'get', + params + }) +} diff --git a/src/api/fileUploadAndDownload.js b/src/api/fileUploadAndDownload.js new file mode 100644 index 0000000..0f260b6 --- /dev/null +++ b/src/api/fileUploadAndDownload.js @@ -0,0 +1,67 @@ +import service from '@/utils/request' +// @Tags FileUploadAndDownload +// @Summary 分页文件列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body modelInterface.PageInfo true "分页获取文件户列表" +// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /fileUploadAndDownload/getFileList [post] +export const getFileList = (data) => { + return service({ + url: '/fileUploadAndDownload/getFileList', + method: 'post', + data + }) +} + +// @Tags FileUploadAndDownload +// @Summary 删除文件 +// @Security ApiKeyAuth +// @Produce application/json +// @Param data body dbModel.FileUploadAndDownload true "传入文件里面id即可" +// @Success 200 {string} json "{"success":true,"data":{},"msg":"返回成功"}" +// @Router /fileUploadAndDownload/deleteFile [post] +export const deleteFile = (data) => { + return service({ + url: '/fileUploadAndDownload/deleteFile', + method: 'post', + data + }) +} + +/** + * 编辑文件名或者备注 + * @param data + * @returns {*} + */ +export const editFileName = (data) => { + return service({ + url: '/fileUploadAndDownload/editFileName', + method: 'post', + data + }) +} + +/** + * 导入URL + * @param data + * @returns {*} + */ +export const importURL = (data) => { + return service({ + url: '/fileUploadAndDownload/importURL', + method: 'post', + data + }) +} + + +// 上传文件 暂时用于头像上传 +export const uploadFile = (data) => { + return service({ + url: "/fileUploadAndDownload/upload", + method: "post", + data, + }); +}; \ No newline at end of file diff --git a/src/api/github.js b/src/api/github.js new file mode 100644 index 0000000..38e1067 --- /dev/null +++ b/src/api/github.js @@ -0,0 +1,19 @@ +import axios from 'axios' + +const service = axios.create() + +export function Commits(page) { + return service({ + url: + 'https://api.github.com/repos/flipped-aurora/gin-vue-admin/commits?page=' + + page, + method: 'get' + }) +} + +export function Members() { + return service({ + url: 'https://api.github.com/orgs/FLIPPED-AURORA/members', + method: 'get' + }) +} diff --git a/src/api/initdb.js b/src/api/initdb.js new file mode 100644 index 0000000..f1eb2f4 --- /dev/null +++ b/src/api/initdb.js @@ -0,0 +1,27 @@ +import service from '@/utils/request' +// @Tags InitDB +// @Summary 初始化用户数据库 +// @Produce application/json +// @Param data body request.InitDB true "初始化数据库参数" +// @Success 200 {string} string "{"code":0,"data":{},"msg":"自动创建数据库成功"}" +// @Router /init/initdb [post] +export const initDB = (data) => { + return service({ + url: '/init/initdb', + method: 'post', + data, + donNotShowLoading: true + }) +} + +// @Tags CheckDB +// @Summary 初始化用户数据库 +// @Produce application/json +// @Success 200 {string} string "{"code":0,"data":{},"msg":"探测完成"}" +// @Router /init/checkdb [post] +export const checkDB = () => { + return service({ + url: '/init/checkdb', + method: 'post' + }) +} diff --git a/src/api/jwt.js b/src/api/jwt.js new file mode 100644 index 0000000..811ffc4 --- /dev/null +++ b/src/api/jwt.js @@ -0,0 +1,14 @@ +import service from '@/utils/request' +// @Tags jwt +// @Summary jwt加入黑名单 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Success 200 {string} string "{"success":true,"data":{},"msg":"拉黑成功"}" +// @Router /jwt/jsonInBlacklist [post] +export const jsonInBlacklist = () => { + return service({ + url: '/jwt/jsonInBlacklist', + method: 'post' + }) +} diff --git a/src/api/menu.js b/src/api/menu.js new file mode 100644 index 0000000..163b5a6 --- /dev/null +++ b/src/api/menu.js @@ -0,0 +1,113 @@ +import service from '@/utils/request' +// @Summary 用户登录 获取动态路由 +// @Produce application/json +// @Param 可以什么都不填 调一下即可 +// @Router /menu/getMenu [post] +export const asyncMenu = () => { + return service({ + url: '/menu/getMenu', + method: 'post' + }) +} + +// @Summary 获取menu列表 +// @Produce application/json +// @Param { +// page int +// pageSize int +// } +// @Router /menu/getMenuList [post] +export const getMenuList = (data) => { + return service({ + url: '/menu/getMenuList', + method: 'post', + data + }) +} + +// @Summary 新增基础menu +// @Produce application/json +// @Param menu Object +// @Router /menu/getMenuList [post] +export const addBaseMenu = (data) => { + return service({ + url: '/menu/addBaseMenu', + method: 'post', + data + }) +} + +// @Summary 获取基础路由列表 +// @Produce application/json +// @Param 可以什么都不填 调一下即可 +// @Router /menu/getBaseMenuTree [post] +export const getBaseMenuTree = () => { + return service({ + url: '/menu/getBaseMenuTree', + method: 'post' + }) +} + +// @Summary 添加用户menu关联关系 +// @Produce application/json +// @Param menus Object authorityId string +// @Router /menu/getMenuList [post] +export const addMenuAuthority = (data) => { + return service({ + url: '/menu/addMenuAuthority', + method: 'post', + data + }) +} + +// @Summary 获取用户menu关联关系 +// @Produce application/json +// @Param authorityId string +// @Router /menu/getMenuAuthority [post] +export const getMenuAuthority = (data) => { + return service({ + url: '/menu/getMenuAuthority', + method: 'post', + data + }) +} + +// @Summary 删除menu +// @Produce application/json +// @Param ID float64 +// @Router /menu/deleteBaseMenu [post] +export const deleteBaseMenu = (data) => { + return service({ + url: '/menu/deleteBaseMenu', + method: 'post', + data + }) +} + +// @Summary 修改menu列表 +// @Produce application/json +// @Param menu Object +// @Router /menu/updateBaseMenu [post] +export const updateBaseMenu = (data) => { + return service({ + url: '/menu/updateBaseMenu', + method: 'post', + data + }) +} + +// @Tags menu +// @Summary 根据id获取菜单 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body api.GetById true "根据id获取菜单" +// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /menu/getBaseMenuById [post] +export const getBaseMenuById = (data) => { + return service({ + url: '/menu/getBaseMenuById', + method: 'post', + data + }) +} diff --git a/src/api/sysDictionary.js b/src/api/sysDictionary.js new file mode 100644 index 0000000..f5d6c86 --- /dev/null +++ b/src/api/sysDictionary.js @@ -0,0 +1,80 @@ +import service from '@/utils/request' +// @Tags SysDictionary +// @Summary 创建SysDictionary +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysDictionary true "创建SysDictionary" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /sysDictionary/createSysDictionary [post] +export const createSysDictionary = (data) => { + return service({ + url: '/sysDictionary/createSysDictionary', + method: 'post', + data + }) +} + +// @Tags SysDictionary +// @Summary 删除SysDictionary +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysDictionary true "删除SysDictionary" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /sysDictionary/deleteSysDictionary [delete] +export const deleteSysDictionary = (data) => { + return service({ + url: '/sysDictionary/deleteSysDictionary', + method: 'delete', + data + }) +} + +// @Tags SysDictionary +// @Summary 更新SysDictionary +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysDictionary true "更新SysDictionary" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}" +// @Router /sysDictionary/updateSysDictionary [put] +export const updateSysDictionary = (data) => { + return service({ + url: '/sysDictionary/updateSysDictionary', + method: 'put', + data + }) +} + +// @Tags SysDictionary +// @Summary 用id查询SysDictionary +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysDictionary true "用id查询SysDictionary" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}" +// @Router /sysDictionary/findSysDictionary [get] +export const findSysDictionary = (params) => { + return service({ + url: '/sysDictionary/findSysDictionary', + method: 'get', + params + }) +} + +// @Tags SysDictionary +// @Summary 分页获取SysDictionary列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.PageInfo true "分页获取SysDictionary列表" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /sysDictionary/getSysDictionaryList [get] +export const getSysDictionaryList = (params) => { + return service({ + url: '/sysDictionary/getSysDictionaryList', + method: 'get', + params + }) +} diff --git a/src/api/sysDictionaryDetail.js b/src/api/sysDictionaryDetail.js new file mode 100644 index 0000000..d4f8772 --- /dev/null +++ b/src/api/sysDictionaryDetail.js @@ -0,0 +1,80 @@ +import service from '@/utils/request' +// @Tags SysDictionaryDetail +// @Summary 创建SysDictionaryDetail +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysDictionaryDetail true "创建SysDictionaryDetail" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /sysDictionaryDetail/createSysDictionaryDetail [post] +export const createSysDictionaryDetail = (data) => { + return service({ + url: '/sysDictionaryDetail/createSysDictionaryDetail', + method: 'post', + data + }) +} + +// @Tags SysDictionaryDetail +// @Summary 删除SysDictionaryDetail +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysDictionaryDetail true "删除SysDictionaryDetail" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /sysDictionaryDetail/deleteSysDictionaryDetail [delete] +export const deleteSysDictionaryDetail = (data) => { + return service({ + url: '/sysDictionaryDetail/deleteSysDictionaryDetail', + method: 'delete', + data + }) +} + +// @Tags SysDictionaryDetail +// @Summary 更新SysDictionaryDetail +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysDictionaryDetail true "更新SysDictionaryDetail" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}" +// @Router /sysDictionaryDetail/updateSysDictionaryDetail [put] +export const updateSysDictionaryDetail = (data) => { + return service({ + url: '/sysDictionaryDetail/updateSysDictionaryDetail', + method: 'put', + data + }) +} + +// @Tags SysDictionaryDetail +// @Summary 用id查询SysDictionaryDetail +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysDictionaryDetail true "用id查询SysDictionaryDetail" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}" +// @Router /sysDictionaryDetail/findSysDictionaryDetail [get] +export const findSysDictionaryDetail = (params) => { + return service({ + url: '/sysDictionaryDetail/findSysDictionaryDetail', + method: 'get', + params + }) +} + +// @Tags SysDictionaryDetail +// @Summary 分页获取SysDictionaryDetail列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.PageInfo true "分页获取SysDictionaryDetail列表" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /sysDictionaryDetail/getSysDictionaryDetailList [get] +export const getSysDictionaryDetailList = (params) => { + return service({ + url: '/sysDictionaryDetail/getSysDictionaryDetailList', + method: 'get', + params + }) +} diff --git a/src/api/sysOperationRecord.js b/src/api/sysOperationRecord.js new file mode 100644 index 0000000..4428c03 --- /dev/null +++ b/src/api/sysOperationRecord.js @@ -0,0 +1,48 @@ +import service from '@/utils/request' +// @Tags SysOperationRecord +// @Summary 删除SysOperationRecord +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysOperationRecord true "删除SysOperationRecord" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /sysOperationRecord/deleteSysOperationRecord [delete] +export const deleteSysOperationRecord = (data) => { + return service({ + url: '/sysOperationRecord/deleteSysOperationRecord', + method: 'delete', + data + }) +} + +// @Tags SysOperationRecord +// @Summary 删除SysOperationRecord +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.IdsReq true "删除SysOperationRecord" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /sysOperationRecord/deleteSysOperationRecord [delete] +export const deleteSysOperationRecordByIds = (data) => { + return service({ + url: '/sysOperationRecord/deleteSysOperationRecordByIds', + method: 'delete', + data + }) +} + +// @Tags SysOperationRecord +// @Summary 分页获取SysOperationRecord列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.PageInfo true "分页获取SysOperationRecord列表" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /sysOperationRecord/getSysOperationRecordList [get] +export const getSysOperationRecordList = (params) => { + return service({ + url: '/sysOperationRecord/getSysOperationRecordList', + method: 'get', + params + }) +} diff --git a/src/api/sysParams.js b/src/api/sysParams.js new file mode 100644 index 0000000..348f1b5 --- /dev/null +++ b/src/api/sysParams.js @@ -0,0 +1,111 @@ +import service from '@/utils/request' +// @Tags SysParams +// @Summary 创建参数 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysParams true "创建参数" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}" +// @Router /sysParams/createSysParams [post] +export const createSysParams = (data) => { + return service({ + url: '/sysParams/createSysParams', + method: 'post', + data + }) +} + +// @Tags SysParams +// @Summary 删除参数 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysParams true "删除参数" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /sysParams/deleteSysParams [delete] +export const deleteSysParams = (params) => { + return service({ + url: '/sysParams/deleteSysParams', + method: 'delete', + params + }) +} + +// @Tags SysParams +// @Summary 批量删除参数 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.IdsReq true "批量删除参数" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /sysParams/deleteSysParams [delete] +export const deleteSysParamsByIds = (params) => { + return service({ + url: '/sysParams/deleteSysParamsByIds', + method: 'delete', + params + }) +} + +// @Tags SysParams +// @Summary 更新参数 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysParams true "更新参数" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}" +// @Router /sysParams/updateSysParams [put] +export const updateSysParams = (data) => { + return service({ + url: '/sysParams/updateSysParams', + method: 'put', + data + }) +} + +// @Tags SysParams +// @Summary 用id查询参数 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data query model.SysParams true "用id查询参数" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}" +// @Router /sysParams/findSysParams [get] +export const findSysParams = (params) => { + return service({ + url: '/sysParams/findSysParams', + method: 'get', + params + }) +} + +// @Tags SysParams +// @Summary 分页获取参数列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data query request.PageInfo true "分页获取参数列表" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /sysParams/getSysParamsList [get] +export const getSysParamsList = (params) => { + return service({ + url: '/sysParams/getSysParamsList', + method: 'get', + params + }) +} + +// @Tags SysParams +// @Summary 不需要鉴权的参数接口 +// @accept application/json +// @Produce application/json +// @Param data query systemReq.SysParamsSearch true "分页获取参数列表" +// @Success 200 {object} response.Response{data=object,msg=string} "获取成功" +// @Router /sysParams/getSysParam [get] +export const getSysParam = (params) => { + return service({ + url: '/sysParams/getSysParam', + method: 'get', + params + }) +} diff --git a/src/api/system.js b/src/api/system.js new file mode 100644 index 0000000..9395519 --- /dev/null +++ b/src/api/system.js @@ -0,0 +1,55 @@ +import service from '@/utils/request' +// @Tags systrm +// @Summary 获取配置文件内容 +// @Security ApiKeyAuth +// @Produce application/json +// @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}" +// @Router /system/getSystemConfig [post] +export const getSystemConfig = () => { + return service({ + url: '/system/getSystemConfig', + method: 'post' + }) +} + +// @Tags system +// @Summary 设置配置文件内容 +// @Security ApiKeyAuth +// @Produce application/json +// @Param data body sysModel.System true +// @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}" +// @Router /system/setSystemConfig [post] +export const setSystemConfig = (data) => { + return service({ + url: '/system/setSystemConfig', + method: 'post', + data + }) +} + +// @Tags system +// @Summary 获取服务器运行状态 +// @Security ApiKeyAuth +// @Produce application/json +// @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}" +// @Router /system/getServerInfo [post] +export const getSystemState = () => { + return service({ + url: '/system/getServerInfo', + method: 'post', + donNotShowLoading: true + }) +} + +/** + * 重启服务 + * @param data + * @returns {*} + */ +export const reloadSystem = (data) => { + return service({ + url: '/system/reloadSystem', + method: 'post', + data + }) +} diff --git a/src/api/user.js b/src/api/user.js new file mode 100644 index 0000000..2b357d0 --- /dev/null +++ b/src/api/user.js @@ -0,0 +1,181 @@ +import service from '@/utils/request' +// @Summary 用户登录 +// @Produce application/json +// @Param data body {username:"string",password:"string"} +// @Router /base/login [post] +export const login = (data) => { + return service({ + url: '/base/login', + method: 'post', + data: data + }) +} + +// @Summary 获取验证码 +// @Produce application/json +// @Param data body {username:"string",password:"string"} +// @Router /base/captcha [post] +export const captcha = () => { + return service({ + url: '/base/captcha', + method: 'post' + }) +} + +// @Summary 用户注册 +// @Produce application/json +// @Param data body {username:"string",password:"string"} +// @Router /base/resige [post] +export const register = (data) => { + return service({ + url: '/user/admin_register', + method: 'post', + data: data + }) +} + +// @Summary 修改密码 +// @Produce application/json +// @Param data body {username:"string",password:"string",newPassword:"string"} +// @Router /user/changePassword [post] +export const changePassword = (data) => { + return service({ + url: '/user/changePassword', + method: 'post', + data: data + }) +} + +// @Tags User +// @Summary 分页获取用户列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body modelInterface.PageInfo true "分页获取用户列表" +// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /user/getUserList [post] +export const getUserList = (data) => { + return service({ + url: '/user/getUserList', + method: 'post', + data: data + }) +} + +// @Tags User +// @Summary 设置用户权限 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body api.SetUserAuth true "设置用户权限" +// @Success 200 {string} json "{"success":true,"data":{},"msg":"修改成功"}" +// @Router /user/setUserAuthority [post] +export const setUserAuthority = (data) => { + return service({ + url: '/user/setUserAuthority', + method: 'post', + data: data + }) +} + +// @Tags SysUser +// @Summary 删除用户 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.SetUserAuth true "删除用户" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}" +// @Router /user/deleteUser [delete] +export const deleteUser = (data) => { + return service({ + url: '/user/deleteUser', + method: 'delete', + data: data + }) +} + +// @Tags SysUser +// @Summary 设置用户信息 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysUser true "设置用户信息" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}" +// @Router /user/setUserInfo [put] +export const setUserInfo = (data) => { + return service({ + url: '/user/setUserInfo', + method: 'put', + data: data + }) +} + +// @Tags SysUser +// @Summary 设置用户信息 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysUser true "设置用户信息" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}" +// @Router /user/setSelfInfo [put] +export const setSelfInfo = (data) => { + return service({ + url: '/user/setSelfInfo', + method: 'put', + data: data + }) +} + +// @Tags SysUser +// @Summary 设置自身界面配置 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysUser true "设置自身界面配置" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}" +// @Router /user/setSelfSetting [put] +export const setSelfSetting = (data) => { + return service({ + url: '/user/setSelfSetting', + method: 'put', + data: data + }) +} + +// @Tags User +// @Summary 设置用户权限 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body api.setUserAuthorities true "设置用户权限" +// @Success 200 {string} json "{"success":true,"data":{},"msg":"修改成功"}" +// @Router /user/setUserAuthorities [post] +export const setUserAuthorities = (data) => { + return service({ + url: '/user/setUserAuthorities', + method: 'post', + data: data + }) +} + +// @Tags User +// @Summary 获取用户信息 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /user/getUserInfo [get] +export const getUserInfo = () => { + return service({ + url: '/user/getUserInfo', + method: 'get' + }) +} + +export const resetPassword = (data) => { + return service({ + url: '/user/resetPassword', + method: 'post', + data: data + }) +} diff --git a/src/assets/404.png b/src/assets/404.png new file mode 100644 index 0000000..f803724 Binary files /dev/null and b/src/assets/404.png differ diff --git a/src/assets/background.svg b/src/assets/background.svg new file mode 100644 index 0000000..7375bb5 --- /dev/null +++ b/src/assets/background.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/banner.jpg b/src/assets/banner.jpg new file mode 100644 index 0000000..675411e Binary files /dev/null and b/src/assets/banner.jpg differ diff --git a/src/assets/banner2.jpg b/src/assets/banner2.jpg new file mode 100644 index 0000000..62e08a4 Binary files /dev/null and b/src/assets/banner2.jpg differ diff --git a/src/assets/dashboard.png b/src/assets/dashboard.png new file mode 100644 index 0000000..64981d0 Binary files /dev/null and b/src/assets/dashboard.png differ diff --git a/src/assets/docs.png b/src/assets/docs.png new file mode 100644 index 0000000..bb98d6e Binary files /dev/null and b/src/assets/docs.png differ diff --git a/src/assets/flipped-aurora.png b/src/assets/flipped-aurora.png new file mode 100644 index 0000000..c94033b Binary files /dev/null and b/src/assets/flipped-aurora.png differ diff --git a/src/assets/github.png b/src/assets/github.png new file mode 100644 index 0000000..d1d200e Binary files /dev/null and b/src/assets/github.png differ diff --git a/src/assets/icons/ai-gva.svg b/src/assets/icons/ai-gva.svg new file mode 100644 index 0000000..fcbea93 --- /dev/null +++ b/src/assets/icons/ai-gva.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/customer-gva.svg b/src/assets/icons/customer-gva.svg new file mode 100644 index 0000000..1e72201 --- /dev/null +++ b/src/assets/icons/customer-gva.svg @@ -0,0 +1 @@ + diff --git a/src/assets/kefu.png b/src/assets/kefu.png new file mode 100644 index 0000000..47cab15 Binary files /dev/null and b/src/assets/kefu.png differ diff --git a/src/assets/login_background.jpg b/src/assets/login_background.jpg new file mode 100644 index 0000000..e601f24 Binary files /dev/null and b/src/assets/login_background.jpg differ diff --git a/src/assets/login_background.svg b/src/assets/login_background.svg new file mode 100644 index 0000000..0a9514b --- /dev/null +++ b/src/assets/login_background.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/login_left.svg b/src/assets/login_left.svg new file mode 100644 index 0000000..9c48b0b --- /dev/null +++ b/src/assets/login_left.svg @@ -0,0 +1,123 @@ + + + 搭建网站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/login_right_banner.jpg b/src/assets/login_right_banner.jpg new file mode 100644 index 0000000..0a597c1 Binary files /dev/null and b/src/assets/login_right_banner.jpg differ diff --git a/src/assets/logo.jpg b/src/assets/logo.jpg new file mode 100644 index 0000000..09502d5 Binary files /dev/null and b/src/assets/logo.jpg differ diff --git a/src/assets/logo.png b/src/assets/logo.png new file mode 100644 index 0000000..b497ee0 Binary files /dev/null and b/src/assets/logo.png differ diff --git a/src/assets/logo_login.png b/src/assets/logo_login.png new file mode 100644 index 0000000..e330458 Binary files /dev/null and b/src/assets/logo_login.png differ diff --git a/src/assets/nav_logo.png b/src/assets/nav_logo.png new file mode 100644 index 0000000..468cdab Binary files /dev/null and b/src/assets/nav_logo.png differ diff --git a/src/assets/noBody.png b/src/assets/noBody.png new file mode 100644 index 0000000..e16488e Binary files /dev/null and b/src/assets/noBody.png differ diff --git a/src/assets/notFound.png b/src/assets/notFound.png new file mode 100644 index 0000000..59ca9f0 Binary files /dev/null and b/src/assets/notFound.png differ diff --git a/src/assets/qm.png b/src/assets/qm.png new file mode 100644 index 0000000..9f598ca Binary files /dev/null and b/src/assets/qm.png differ diff --git a/src/assets/video.png b/src/assets/video.png new file mode 100644 index 0000000..af4d35f Binary files /dev/null and b/src/assets/video.png differ diff --git a/src/components/arrayCtrl/arrayCtrl.vue b/src/components/arrayCtrl/arrayCtrl.vue new file mode 100644 index 0000000..1296cf7 --- /dev/null +++ b/src/components/arrayCtrl/arrayCtrl.vue @@ -0,0 +1,67 @@ + + + diff --git a/src/components/bottomInfo/bottomInfo.vue b/src/components/bottomInfo/bottomInfo.vue new file mode 100644 index 0000000..376de05 --- /dev/null +++ b/src/components/bottomInfo/bottomInfo.vue @@ -0,0 +1,44 @@ + + + + diff --git a/src/components/charts/index.vue b/src/components/charts/index.vue new file mode 100644 index 0000000..0895434 --- /dev/null +++ b/src/components/charts/index.vue @@ -0,0 +1,54 @@ + + + + + + + diff --git a/src/components/commandMenu/index.vue b/src/components/commandMenu/index.vue new file mode 100644 index 0000000..27ef93f --- /dev/null +++ b/src/components/commandMenu/index.vue @@ -0,0 +1,196 @@ + + + + + diff --git a/src/components/customPic/index.vue b/src/components/customPic/index.vue new file mode 100644 index 0000000..6a265de --- /dev/null +++ b/src/components/customPic/index.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/src/components/exportExcel/exportExcel.vue b/src/components/exportExcel/exportExcel.vue new file mode 100644 index 0000000..6c1189e --- /dev/null +++ b/src/components/exportExcel/exportExcel.vue @@ -0,0 +1,75 @@ + + + diff --git a/src/components/exportExcel/exportTemplate.vue b/src/components/exportExcel/exportTemplate.vue new file mode 100644 index 0000000..dd77f95 --- /dev/null +++ b/src/components/exportExcel/exportTemplate.vue @@ -0,0 +1,40 @@ + + + diff --git a/src/components/exportExcel/importExcel.vue b/src/components/exportExcel/importExcel.vue new file mode 100644 index 0000000..cd3a7d9 --- /dev/null +++ b/src/components/exportExcel/importExcel.vue @@ -0,0 +1,45 @@ + + + diff --git a/src/components/office/docx.vue b/src/components/office/docx.vue new file mode 100644 index 0000000..e607d0b --- /dev/null +++ b/src/components/office/docx.vue @@ -0,0 +1,31 @@ + + + + diff --git a/src/components/office/excel.vue b/src/components/office/excel.vue new file mode 100644 index 0000000..5b22f91 --- /dev/null +++ b/src/components/office/excel.vue @@ -0,0 +1,36 @@ + + + + diff --git a/src/components/office/index.vue b/src/components/office/index.vue new file mode 100644 index 0000000..d22d6da --- /dev/null +++ b/src/components/office/index.vue @@ -0,0 +1,49 @@ + + + diff --git a/src/components/office/pdf.vue b/src/components/office/pdf.vue new file mode 100644 index 0000000..2ca4363 --- /dev/null +++ b/src/components/office/pdf.vue @@ -0,0 +1,39 @@ + + + diff --git a/src/components/richtext/rich-edit.vue b/src/components/richtext/rich-edit.vue new file mode 100644 index 0000000..151b7df --- /dev/null +++ b/src/components/richtext/rich-edit.vue @@ -0,0 +1,86 @@ + + + + + diff --git a/src/components/richtext/rich-view.vue b/src/components/richtext/rich-view.vue new file mode 100644 index 0000000..b1de744 --- /dev/null +++ b/src/components/richtext/rich-view.vue @@ -0,0 +1,58 @@ + + + + diff --git a/src/components/selectFile/selectFile.vue b/src/components/selectFile/selectFile.vue new file mode 100644 index 0000000..61bad6f --- /dev/null +++ b/src/components/selectFile/selectFile.vue @@ -0,0 +1,87 @@ + + + diff --git a/src/components/selectImage/selectComponent.vue b/src/components/selectImage/selectComponent.vue new file mode 100644 index 0000000..18cc64a --- /dev/null +++ b/src/components/selectImage/selectComponent.vue @@ -0,0 +1,86 @@ + + diff --git a/src/components/selectImage/selectImage.vue b/src/components/selectImage/selectImage.vue new file mode 100644 index 0000000..b517601 --- /dev/null +++ b/src/components/selectImage/selectImage.vue @@ -0,0 +1,453 @@ + + + + diff --git a/src/components/svgIcon/svgIcon.vue b/src/components/svgIcon/svgIcon.vue new file mode 100644 index 0000000..a72a421 --- /dev/null +++ b/src/components/svgIcon/svgIcon.vue @@ -0,0 +1,32 @@ + + + diff --git a/src/components/upload/QR-code.vue b/src/components/upload/QR-code.vue new file mode 100644 index 0000000..2a166c2 --- /dev/null +++ b/src/components/upload/QR-code.vue @@ -0,0 +1,65 @@ + + + diff --git a/src/components/upload/common.vue b/src/components/upload/common.vue new file mode 100644 index 0000000..f3d1fa1 --- /dev/null +++ b/src/components/upload/common.vue @@ -0,0 +1,90 @@ + + + diff --git a/src/components/upload/cropper.vue b/src/components/upload/cropper.vue new file mode 100644 index 0000000..1506a8f --- /dev/null +++ b/src/components/upload/cropper.vue @@ -0,0 +1,237 @@ + + + + + diff --git a/src/components/upload/image.vue b/src/components/upload/image.vue new file mode 100644 index 0000000..0b0ae5e --- /dev/null +++ b/src/components/upload/image.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/src/components/warningBar/warningBar.vue b/src/components/warningBar/warningBar.vue new file mode 100644 index 0000000..9d01881 --- /dev/null +++ b/src/components/warningBar/warningBar.vue @@ -0,0 +1,33 @@ + + diff --git a/src/core/config.js b/src/core/config.js new file mode 100644 index 0000000..4cb3892 --- /dev/null +++ b/src/core/config.js @@ -0,0 +1,53 @@ +/** + * 网站配置文件 + */ +const greenText = (text) => `\x1b[32m${text}\x1b[0m` + +const config = { + appName: 'Lckt-Admin', + appLogo: 'logo.png', + showViteLogo: true, + logs: [] +} + +export const viteLogo = (env) => { + if (config.showViteLogo) { + console.log( + greenText( + `> 欢迎使用Gin-Vue-Admin,开源地址:https://github.com/flipped-aurora/gin-vue-admin` + ) + ) + console.log(greenText(`> 当前版本:v2.8.0`)) + console.log(greenText(`> 加群方式:微信:shouzi_1994 QQ群:470239250`)) + console.log( + greenText(`> 项目地址:https://github.com/flipped-aurora/gin-vue-admin`) + ) + console.log(greenText(`> 插件市场:https://plugin.gin-vue-admin.com`)) + console.log( + greenText(`> GVA讨论社区:https://support.qq.com/products/371961`) + ) + console.log( + greenText( + `> 默认自动化文档地址:http://127.0.0.1:${env.VITE_SERVER_PORT}/swagger/index.html` + ) + ) + console.log( + greenText(`> 默认前端文件运行地址:http://127.0.0.1:${env.VITE_CLI_PORT}`) + ) + console.log( + greenText( + `--------------------------------------版权声明--------------------------------------` + ) + ) + console.log(greenText(`** 版权所有方:flipped-aurora开源团队 **`)) + console.log(greenText(`** 版权持有公司:北京翻转极光科技有限责任公司 **`)) + console.log( + greenText( + `** 剔除授权标识需购买商用授权:https://gin-vue-admin.com/empower/index.html **` + ) + ) + console.log('\n') + } +} + +export default config diff --git a/src/core/gin-vue-admin.js b/src/core/gin-vue-admin.js new file mode 100644 index 0000000..764da3f --- /dev/null +++ b/src/core/gin-vue-admin.js @@ -0,0 +1,27 @@ +/* + * gin-vue-admin web框架组 + * + * */ +// 加载网站配置文件夹 +import { register } from './global' + +export default { + install: (app) => { + register(app) + console.log(` + 欢迎使用 Gin-Vue-Admin + 当前版本:v2.8.0 + 加群方式:微信:shouzi_1994 QQ群:622360840 + 项目地址:https://github.com/flipped-aurora/gin-vue-admin + 插件市场:https://plugin.gin-vue-admin.com + GVA讨论社区:https://support.qq.com/products/371961 + 默认自动化文档地址:http://127.0.0.1:${import.meta.env.VITE_SERVER_PORT}/swagger/index.html + 默认前端文件运行地址:http://127.0.0.1:${import.meta.env.VITE_CLI_PORT} + 如果项目让您获得了收益,希望您能请团队喝杯可乐:https://www.gin-vue-admin.com/coffee/index.html + --------------------------------------版权声明-------------------------------------- + ** 版权所有方:flipped-aurora开源团队 ** + ** 版权持有公司:北京翻转极光科技有限责任公司 ** + ** 剔除授权标识需购买商用授权:https://gin-vue-admin.com/empower/index.html ** + `) + } +} diff --git a/src/core/global.js b/src/core/global.js new file mode 100644 index 0000000..b402b70 --- /dev/null +++ b/src/core/global.js @@ -0,0 +1,59 @@ +import config from './config' +import { h } from 'vue' + +// 统一导入el-icon图标 +import * as ElIconModules from '@element-plus/icons-vue' +import svgIcon from '@/components/svgIcon/svgIcon.vue' +// 导入转换图标名称的函数 + +const createIconComponent = (name) => ({ + name: 'SvgIcon', + render() { + return h(svgIcon, { + name: name + }) + } +}) + +const registerIcons = async (app) => { + const iconModules = import.meta.glob('@/assets/icons/**/*.svg') // 系统目录 svg 图标 + const pluginIconModules = import.meta.glob( + '@/plugin/**/assets/icons/**/*.svg' + ) // 插件目录 svg 图标 + const mergedIconModules = Object.assign({}, iconModules, pluginIconModules) // 合并所有 svg 图标 + for (const path in mergedIconModules) { + let pluginName = '' + if (path.startsWith('/src/plugin/')) { + pluginName = `${path.split('/')[3]}-` + } + const iconName = path + .split('/') + .pop() + .replace(/\.svg$/, '') + // 如果iconName带空格则不加入到图标库中并且提示名称不合法 + if (iconName.indexOf(' ') !== -1) { + console.error(`icon ${iconName}.svg includes whitespace in ${path}`) + continue + } + const key = `${pluginName}${iconName}` + // 开发模式下列出所有 svg 图标,方便开发者直接查找复制使用 + import.meta.env.MODE == 'development' && + console.log(`svg-icon-component: <${key} />`) + const iconComponent = createIconComponent(key) + config.logs.push({ + key: key, + label: key + }) + app.component(key, iconComponent) + } +} + +export const register = (app) => { + // 统一注册el-icon图标 + for (const iconName in ElIconModules) { + app.component(iconName, ElIconModules[iconName]) + } + app.component('SvgIcon', svgIcon) + registerIcons(app) + app.config.globalProperties.$GIN_VUE_ADMIN = config +} diff --git a/src/directive/auth.js b/src/directive/auth.js new file mode 100644 index 0000000..d2b9b6a --- /dev/null +++ b/src/directive/auth.js @@ -0,0 +1,40 @@ +// 权限按钮展示指令 +import { useUserStore } from '@/pinia/modules/user' +export default { + install: (app) => { + const userStore = useUserStore() + app.directive('auth', { + // 当被绑定的元素插入到 DOM 中时…… + mounted: function (el, binding) { + const userInfo = userStore.userInfo + let type = '' + switch (Object.prototype.toString.call(binding.value)) { + case '[object Array]': + type = 'Array' + break + case '[object String]': + type = 'String' + break + case '[object Number]': + type = 'Number' + break + default: + type = '' + break + } + if (type === '') { + el.parentNode.removeChild(el) + return + } + const waitUse = binding.value.toString().split(',') + let flag = waitUse.some((item) => Number(item) === userInfo.authorityId) + if (binding.modifiers.not) { + flag = !flag + } + if (!flag) { + el.parentNode.removeChild(el) + } + } + }) + } +} diff --git a/src/hooks/charts.js b/src/hooks/charts.js new file mode 100644 index 0000000..b7f7bb3 --- /dev/null +++ b/src/hooks/charts.js @@ -0,0 +1,18 @@ +// 本组件参考 arco-pro 的实现 +// https://github.com/arco-design/arco-design-pro-vue/blob/main/arco-design-pro-vite/src/hooks/chart-option.ts + +import { computed } from 'vue' +import { useAppStore } from '@/pinia' + +export default function useChartOption(sourceOption) { + const appStore = useAppStore() + const isDark = computed(() => { + return appStore.isDark + }) + const chartOption = computed(() => { + return sourceOption(isDark.value) + }) + return { + chartOption + } +} diff --git a/src/hooks/responsive.js b/src/hooks/responsive.js new file mode 100644 index 0000000..e324c16 --- /dev/null +++ b/src/hooks/responsive.js @@ -0,0 +1,35 @@ +// 本组件参考 arco-pro 的实现 +// https://github.com/arco-design/arco-design-pro-vue/blob/main/arco-design-pro-vite/src/hooks/responsive.ts + +import { onMounted, onBeforeMount, onBeforeUnmount } from 'vue' +import { useDebounceFn } from '@vueuse/core' +import { useAppStore } from '@/pinia' +import { addEventListen, removeEventListen } from '@/utils/event' + +const WIDTH = 992 + +function queryDevice() { + const rect = document.body.getBoundingClientRect() + return rect.width - 1 < WIDTH +} + +export default function useResponsive(immediate) { + const appStore = useAppStore() + function resizeHandler() { + if (!document.hidden) { + const isMobile = queryDevice() + appStore.toggleDevice(isMobile ? 'mobile' : 'desktop') + // appStore.toggleDevice(isMobile); + } + } + const debounceFn = useDebounceFn(resizeHandler, 100) + onMounted(() => { + if (immediate) debounceFn() + }) + onBeforeMount(() => { + addEventListen(window, 'resize', debounceFn) + }) + onBeforeUnmount(() => { + removeEventListen(window, 'resize', debounceFn) + }) +} diff --git a/src/hooks/use-windows-resize.js b/src/hooks/use-windows-resize.js new file mode 100644 index 0000000..a3e1490 --- /dev/null +++ b/src/hooks/use-windows-resize.js @@ -0,0 +1,23 @@ +// 监听 window 的 resize 事件,返回当前窗口的宽高 +import { shallowRef } from 'vue' +import { tryOnMounted, useEventListener } from '@vueuse/core' + +const width = shallowRef(0) +const height = shallowRef(0) + +export const useWindowResize = (cb) => { + const onResize = () => { + width.value = window.innerWidth + height.value = window.innerHeight + if (cb && typeof cb === 'function') { + cb(width.value, height.value) + } + } + + tryOnMounted(onResize) + useEventListener('resize', onResize, { passive: true }) + return { + width, + height + } +} diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..372b491 --- /dev/null +++ b/src/main.js @@ -0,0 +1,21 @@ +import './style/element_visiable.scss' +import 'element-plus/theme-chalk/dark/css-vars.css' +import { createApp } from 'vue' +import ElementPlus from 'element-plus' + +import 'element-plus/dist/index.css' +// 引入gin-vue-admin前端初始化相关内容 +import './core/gin-vue-admin' +// 引入封装的router +import router from '@/router/index' +import '@/permission' +import run from '@/core/gin-vue-admin.js' +import auth from '@/directive/auth' +import { store } from '@/pinia' +import App from './App.vue' + +const app = createApp(App) +app.config.productionTip = false + +app.use(run).use(ElementPlus).use(store).use(auth).use(router).mount('#app') +export default app diff --git a/src/pathInfo.json b/src/pathInfo.json new file mode 100644 index 0000000..8205a95 --- /dev/null +++ b/src/pathInfo.json @@ -0,0 +1,74 @@ +{ + "/src/view/about/index.vue": "About", + "/src/view/bot/bot/bot.vue": "Bot", + "/src/view/bot/bot/botForm.vue": "BotForm", + "/src/view/category/category/category.vue": "Category", + "/src/view/category/category/categoryForm.vue": "CategoryForm", + "/src/view/dashboard/components/banner.vue": "Banner", + "/src/view/dashboard/components/card.vue": "Card", + "/src/view/dashboard/components/charts-content-numbers.vue": "ChartsContentNumbers", + "/src/view/dashboard/components/charts-people-numbers.vue": "ChartsPeopleNumbers", + "/src/view/dashboard/components/charts.vue": "Charts", + "/src/view/dashboard/components/notice.vue": "Notice", + "/src/view/dashboard/components/pluginTable.vue": "PluginTable", + "/src/view/dashboard/components/quickLinks.vue": "QuickLinks", + "/src/view/dashboard/components/table.vue": "Table", + "/src/view/dashboard/components/wiki.vue": "Wiki", + "/src/view/dashboard/index.vue": "Dashboard", + "/src/view/error/index.vue": "Error", + "/src/view/error/reload.vue": "Reload", + "/src/view/example/breakpoint/breakpoint.vue": "BreakPoint", + "/src/view/example/customer/customer.vue": "Customer", + "/src/view/example/index.vue": "Example", + "/src/view/example/upload/scanUpload.vue": "scanUpload", + "/src/view/example/upload/upload.vue": "Upload", + "/src/view/init/index.vue": "Init", + "/src/view/layout/aside/asideComponent/asyncSubmenu.vue": "AsyncSubmenu", + "/src/view/layout/aside/asideComponent/index.vue": "AsideComponent", + "/src/view/layout/aside/asideComponent/menuItem.vue": "MenuItem", + "/src/view/layout/aside/combinationMode.vue": "GvaAside", + "/src/view/layout/aside/headMode.vue": "GvaAside", + "/src/view/layout/aside/index.vue": "Index", + "/src/view/layout/aside/normalMode.vue": "GvaAside", + "/src/view/layout/header/index.vue": "Index", + "/src/view/layout/header/tools.vue": "Tools", + "/src/view/layout/iframe.vue": "GvaLayoutIframe", + "/src/view/layout/index.vue": "GvaLayout", + "/src/view/layout/screenfull/index.vue": "Screenfull", + "/src/view/layout/search/search.vue": "BtnBox", + "/src/view/layout/setting/index.vue": "GvaSetting", + "/src/view/layout/setting/title.vue": "layoutSettingTitle", + "/src/view/layout/tabs/index.vue": "HistoryComponent", + "/src/view/login/index.vue": "Login", + "/src/view/person/person.vue": "Person", + "/src/view/routerHolder.vue": "RouterHolder", + "/src/view/superAdmin/api/api.vue": "Api", + "/src/view/superAdmin/authority/authority.vue": "Authority", + "/src/view/superAdmin/authority/components/apis.vue": "Apis", + "/src/view/superAdmin/authority/components/datas.vue": "Datas", + "/src/view/superAdmin/authority/components/menus.vue": "Menus", + "/src/view/superAdmin/dictionary/sysDictionary.vue": "SysDictionary", + "/src/view/superAdmin/dictionary/sysDictionaryDetail.vue": "SysDictionaryDetail", + "/src/view/superAdmin/index.vue": "SuperAdmin", + "/src/view/superAdmin/menu/components/components-cascader.vue": "ComponentsCascader", + "/src/view/superAdmin/menu/icon.vue": "Icon", + "/src/view/superAdmin/menu/menu.vue": "Menus", + "/src/view/superAdmin/operation/sysOperationRecord.vue": "SysOperationRecord", + "/src/view/superAdmin/params/sysParams.vue": "SysParams", + "/src/view/superAdmin/user/user.vue": "User", + "/src/view/system/state.vue": "State", + "/src/view/systemTools/autoCode/component/fieldDialog.vue": "FieldDialog", + "/src/view/systemTools/autoCode/component/previewCodeDialog.vue": "PreviewCodeDialog", + "/src/view/systemTools/autoCode/index.vue": "AutoCode", + "/src/view/systemTools/autoCodeAdmin/index.vue": "AutoCodeAdmin", + "/src/view/systemTools/autoPkg/autoPkg.vue": "AutoPkg", + "/src/view/systemTools/exportTemplate/exportTemplate.vue": "ExportTemplate", + "/src/view/systemTools/formCreate/index.vue": "FormGenerator", + "/src/view/systemTools/index.vue": "System", + "/src/view/systemTools/installPlugin/index.vue": "Index", + "/src/view/systemTools/pubPlug/pubPlug.vue": "PubPlug", + "/src/view/systemTools/system/system.vue": "Config", + "/src/plugin/announcement/form/info.vue": "InfoForm", + "/src/plugin/announcement/view/info.vue": "Info", + "/src/plugin/email/view/index.vue": "Email" +} \ No newline at end of file diff --git a/src/permission.js b/src/permission.js new file mode 100644 index 0000000..3b48995 --- /dev/null +++ b/src/permission.js @@ -0,0 +1,147 @@ +import { useUserStore } from '@/pinia/modules/user' +import { useRouterStore } from '@/pinia/modules/router' +import getPageTitle from '@/utils/page' +import router from '@/router' +import Nprogress from 'nprogress' +import 'nprogress/nprogress.css' + +// 配置 NProgress +Nprogress.configure({ + showSpinner: false, + ease: 'ease', + speed: 500 +}) + +// 白名单路由 +const WHITE_LIST = ['Login', 'Init'] + +// 处理路由加载 +const setupRouter = async (userStore) => { + try { + const routerStore = useRouterStore() + await Promise.all([routerStore.SetAsyncRouter(), userStore.GetUserInfo()]) + + routerStore.asyncRouters.forEach((route) => router.addRoute(route)) + return true + } catch (error) { + console.error('Setup router failed:', error) + return false + } +} + +// 移除加载动画 +const removeLoading = () => { + const element = document.getElementById('gva-loading-box') + element?.remove() +} + +// 处理组件缓存 +const handleKeepAlive = async (to) => { + if (!to.matched.some((item) => item.meta.keepAlive)) return + + if (to.matched?.length > 2) { + for (let i = 1; i < to.matched.length; i++) { + const element = to.matched[i - 1] + + if (element.name === 'layout') { + to.matched.splice(i, 1) + await handleKeepAlive(to) + continue + } + + if (typeof element.components.default === 'function') { + await element.components.default() + await handleKeepAlive(to) + } + } + } +} + +// 处理路由重定向 +const handleRedirect = (to, userStore) => { + if (router.hasRoute(userStore.userInfo.authority.defaultRouter)) { + return { ...to, replace: true } + } + return { path: '/layout/404' } +} + +// 路由守卫 +router.beforeEach(async (to, from) => { + const userStore = useUserStore() + const routerStore = useRouterStore() + const token = userStore.token + + Nprogress.start() + + // 处理元数据和缓存 + to.meta.matched = [...to.matched] + await handleKeepAlive(to) + + // 设置页面标题 + document.title = getPageTitle(to.meta.title, to) + + if (to.meta.client) { + return true + } + + // 白名单路由处理 + if (WHITE_LIST.includes(to.name)) { + if (token) { + if(!routerStore.asyncRouterFlag){ + await setupRouter(userStore) + } + if(userStore.userInfo.authority.defaultRouter){ + return { name: userStore.userInfo.authority.defaultRouter } + } + } + return true + } + + // 需要登录的路由处理 + if (token) { + // 处理需要跳转到首页的情况 + if (sessionStorage.getItem('needToHome') === 'true') { + sessionStorage.removeItem('needToHome') + return { path: '/' } + } + + // 处理异步路由 + if (!routerStore.asyncRouterFlag && !WHITE_LIST.includes(from.name)) { + const setupSuccess = await setupRouter(userStore) + + if (setupSuccess && userStore.token) { + return handleRedirect(to, userStore) + } + + return { + name: 'Login', + query: { redirect: to.href } + } + } + + return to.matched.length ? true : { path: '/layout/404' } + } + + // 未登录跳转登录页 + return { + name: 'Login', + query: { + redirect: document.location.hash + } + } +}) + +// 路由加载完成 +router.afterEach(() => { + document.querySelector('.main-cont.main-right')?.scrollTo(0, 0) + Nprogress.done() +}) + +// 路由错误处理 +router.onError((error) => { + console.error('Router error:', error) + Nprogress.remove() +}) + +// 移除初始加载动画 +removeLoading() diff --git a/src/pinia/index.js b/src/pinia/index.js new file mode 100644 index 0000000..85e45e8 --- /dev/null +++ b/src/pinia/index.js @@ -0,0 +1,8 @@ +import { createPinia } from 'pinia' +import { useAppStore } from '@/pinia/modules/app' +import { useUserStore } from '@/pinia/modules/user' +import { useDictionaryStore } from '@/pinia/modules/dictionary' + +const store = createPinia() + +export { store, useAppStore, useUserStore, useDictionaryStore } diff --git a/src/pinia/modules/app.js b/src/pinia/modules/app.js new file mode 100644 index 0000000..8b32235 --- /dev/null +++ b/src/pinia/modules/app.js @@ -0,0 +1,133 @@ +import { defineStore } from 'pinia' +import { ref, watchEffect, reactive } from 'vue' +import { setBodyPrimaryColor } from '@/utils/format' +import { useDark, usePreferredDark } from '@vueuse/core' + +export const useAppStore = defineStore('app', () => { + const device = ref('') + const drawerSize = ref('') + const operateMinWith = ref('240') + const config = reactive({ + weakness: false, + grey: false, + primaryColor: '#3b82f6', + showTabs: true, + darkMode: 'auto', + layout_side_width: 256, + layout_side_collapsed_width: 80, + layout_side_item_height: 48, + show_watermark: true, + side_mode: 'normal', + // 页面过渡动画配置 + transition_type: 'slide' + }) + + const isDark = useDark({ + selector: 'html', + attribute: 'class', + valueDark: 'dark', + valueLight: 'light' + }) + + const preferredDark = usePreferredDark() + + const toggleTheme = (darkMode) => { + isDark.value = darkMode + } + + const toggleWeakness = (e) => { + config.weakness = e + } + + const toggleGrey = (e) => { + config.grey = e + } + + const togglePrimaryColor = (e) => { + config.primaryColor = e + } + + const toggleTabs = (e) => { + config.showTabs = e + } + + const toggleDevice = (e) => { + if (e === 'mobile') { + drawerSize.value = '100%' + operateMinWith.value = '80' + } else { + drawerSize.value = '800' + operateMinWith.value = '240' + } + device.value = e + } + + const toggleDarkMode = (e) => { + config.darkMode = e + } + + // 监听系统主题变化 + watchEffect(() => { + if (config.darkMode === 'auto') { + isDark.value = preferredDark.value + return + } + isDark.value = config.darkMode === 'dark' + }) + + const toggleConfigSideWidth = (e) => { + config.layout_side_width = e + } + + const toggleConfigSideCollapsedWidth = (e) => { + config.layout_side_collapsed_width = e + } + + const toggleConfigSideItemHeight = (e) => { + config.layout_side_item_height = e + } + + const toggleConfigWatermark = (e) => { + config.show_watermark = e + } + + const toggleSideMode = (e) => { + config.side_mode = e + } + + const toggleTransition = (e) => { + config.transition_type = e + } + + // 监听色弱模式和灰色模式 + watchEffect(() => { + document.documentElement.classList.toggle('html-weakenss', config.weakness) + document.documentElement.classList.toggle('html-grey', config.grey) + }) + + // 监听主题色 + watchEffect(() => { + setBodyPrimaryColor(config.primaryColor, isDark.value ? 'dark' : 'light') + }) + + return { + isDark, + device, + drawerSize, + operateMinWith, + config, + toggleTheme, + toggleDevice, + toggleWeakness, + toggleGrey, + togglePrimaryColor, + toggleTabs, + toggleDarkMode, + toggleConfigSideWidth, + toggleConfigSideCollapsedWidth, + toggleConfigSideItemHeight, + toggleConfigWatermark, + toggleSideMode, + toggleTransition + } +}) diff --git a/src/pinia/modules/dictionary.js b/src/pinia/modules/dictionary.js new file mode 100644 index 0000000..57a2844 --- /dev/null +++ b/src/pinia/modules/dictionary.js @@ -0,0 +1,41 @@ +import { findSysDictionary } from '@/api/sysDictionary' + +import { defineStore } from 'pinia' +import { ref } from 'vue' + +export const useDictionaryStore = defineStore('dictionary', () => { + const dictionaryMap = ref({}) + + const setDictionaryMap = (dictionaryRes) => { + dictionaryMap.value = { ...dictionaryMap.value, ...dictionaryRes } + } + + const getDictionary = async (type) => { + if (dictionaryMap.value[type] && dictionaryMap.value[type].length) { + return dictionaryMap.value[type] + } else { + const res = await findSysDictionary({ type }) + if (res.code === 0) { + const dictionaryRes = {} + const dict = [] + res.data.resysDictionary.sysDictionaryDetails && + res.data.resysDictionary.sysDictionaryDetails.forEach((item) => { + dict.push({ + label: item.label, + value: item.value, + extend: item.extend + }) + }) + dictionaryRes[res.data.resysDictionary.type] = dict + setDictionaryMap(dictionaryRes) + return dictionaryMap.value[type] + } + } + } + + return { + dictionaryMap, + setDictionaryMap, + getDictionary + } +}) diff --git a/src/pinia/modules/params.js b/src/pinia/modules/params.js new file mode 100644 index 0000000..54cdbf9 --- /dev/null +++ b/src/pinia/modules/params.js @@ -0,0 +1,31 @@ +import { getSysParam } from '@/api/sysParams' +import { defineStore } from 'pinia' +import { ref } from 'vue' + +export const useParamsStore = defineStore('params', () => { + const paramsMap = ref({}) + + const setParamsMap = (paramsRes) => { + paramsMap.value = { ...paramsMap.value, ...paramsRes } + } + + const getParams = async(key) => { + if (paramsMap.value[key] && paramsMap.value[key].length) { + return paramsMap.value[key] + } else { + const res = await getSysParam({ key }) + if (res.code === 0) { + const paramsRes = {} + paramsRes[key] = res.data.value + setParamsMap(paramsRes) + return paramsMap.value[key] + } + } + } + + return { + paramsMap, + setParamsMap, + getParams + } +}) diff --git a/src/pinia/modules/router.js b/src/pinia/modules/router.js new file mode 100644 index 0000000..33ebbc9 --- /dev/null +++ b/src/pinia/modules/router.js @@ -0,0 +1,144 @@ +import { asyncRouterHandle } from '@/utils/asyncRouter' +import { emitter } from '@/utils/bus.js' +import { asyncMenu } from '@/api/menu' +import { defineStore } from 'pinia' +import { ref, watchEffect } from 'vue' +import pathInfo from '@/pathInfo.json' + +const notLayoutRouterArr = [] +const keepAliveRoutersArr = [] +const nameMap = {} + +const formatRouter = (routes, routeMap, parent) => { + routes && + routes.forEach((item) => { + item.parent = parent + item.meta.btns = item.btns + item.meta.hidden = item.hidden + if (item.meta.defaultMenu === true) { + if (!parent) { + item = { ...item, path: `/${item.path}` } + notLayoutRouterArr.push(item) + } + } + routeMap[item.name] = item + if (item.children && item.children.length > 0) { + formatRouter(item.children, routeMap, item) + } + }) +} + +const KeepAliveFilter = (routes) => { + routes && + routes.forEach((item) => { + // 子菜单中有 keep-alive 的,父菜单也必须 keep-alive,否则无效。这里将子菜单中有 keep-alive 的父菜单也加入。 + if ( + (item.children && item.children.some((ch) => ch.meta.keepAlive)) || + item.meta.keepAlive + ) { + const path = item.meta.path + keepAliveRoutersArr.push(pathInfo[path]) + nameMap[item.name] = pathInfo[path] + } + if (item.children && item.children.length > 0) { + KeepAliveFilter(item.children) + } + }) +} + +export const useRouterStore = defineStore('router', () => { + const keepAliveRouters = ref([]) + const asyncRouterFlag = ref(0) + const setKeepAliveRouters = (history) => { + const keepArrTemp = [] + history.forEach((item) => { + if (nameMap[item.name]) { + keepArrTemp.push(nameMap[item.name]) + } + }) + keepAliveRouters.value = Array.from(new Set(keepArrTemp)) + } + emitter.on('setKeepAlive', setKeepAliveRouters) + + const asyncRouters = ref([]) + + const topMenu = ref([]) + + const leftMenu = ref([]) + + const menuMap = {} + + const topActive = ref('') + + const setLeftMenu = (name) => { + sessionStorage.setItem('topActive', name) + topActive.value = name + leftMenu.value = [] + if (menuMap[name]?.children) { + leftMenu.value = menuMap[name].children + } + return menuMap[name]?.children + } + + watchEffect(() => { + let topActive = sessionStorage.getItem('topActive') + asyncRouters.value[0]?.children.forEach((item) => { + if (item.hidden) return + menuMap[item.name] = item + topMenu.value.push({ ...item, children: [] }) + }) + + setLeftMenu(topActive) + }) + + const routeMap = {} + // 从后台获取动态路由 + const SetAsyncRouter = async () => { + asyncRouterFlag.value++ + const baseRouter = [ + { + path: '/layout', + name: 'layout', + component: 'view/layout/index.vue', + meta: { + title: '底层layout' + }, + children: [] + } + ] + const asyncRouterRes = await asyncMenu() + const asyncRouter = asyncRouterRes.data.menus + asyncRouter && + asyncRouter.push({ + path: 'reload', + name: 'Reload', + hidden: true, + meta: { + title: '', + closeTab: true + }, + component: 'view/error/reload.vue' + }) + formatRouter(asyncRouter, routeMap) + baseRouter[0].children = asyncRouter + if (notLayoutRouterArr.length !== 0) { + baseRouter.push(...notLayoutRouterArr) + } + asyncRouterHandle(baseRouter) + KeepAliveFilter(asyncRouter) + asyncRouters.value = baseRouter + return true + } + + return { + topActive, + setLeftMenu, + topMenu, + leftMenu, + asyncRouters, + keepAliveRouters, + asyncRouterFlag, + SetAsyncRouter, + routeMap + } +}) diff --git a/src/pinia/modules/user.js b/src/pinia/modules/user.js new file mode 100644 index 0000000..b103ec7 --- /dev/null +++ b/src/pinia/modules/user.js @@ -0,0 +1,144 @@ +import { login, getUserInfo } from '@/api/user' +import { jsonInBlacklist } from '@/api/jwt' +import router from '@/router/index' +import { ElLoading, ElMessage } from 'element-plus' +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import { useRouterStore } from './router' +import { useCookies } from '@vueuse/integrations/useCookies' +import { useStorage } from '@vueuse/core' + +import { useAppStore } from '@/pinia' + +export const useUserStore = defineStore('user', () => { + const appStore = useAppStore() + const loadingInstance = ref(null) + + const userInfo = ref({ + uuid: '', + nickName: '', + headerImg: '', + authority: {} + }) + const token = useStorage('token', '') + const xToken = useCookies('x-token') + const currentToken = computed(() => token.value || xToken.value || '') + + const setUserInfo = (val) => { + userInfo.value = val + if (val.originSetting) { + Object.keys(appStore.config).forEach((key) => { + if (val.originSetting[key] !== undefined) { + appStore.config[key] = val.originSetting[key] + } + }) + } + console.log(appStore.config) + } + + const setToken = (val) => { + token.value = val + xToken.value = val + } + + const NeedInit = async () => { + await ClearStorage() + await router.push({ name: 'Init', replace: true }) + } + + const ResetUserInfo = (value = {}) => { + userInfo.value = { + ...userInfo.value, + ...value + } + } + /* 获取用户信息*/ + const GetUserInfo = async () => { + const res = await getUserInfo() + if (res.code === 0) { + setUserInfo(res.data.userInfo) + } + return res + } + /* 登录*/ + const LoginIn = async (loginInfo) => { + try { + loadingInstance.value = ElLoading.service({ + fullscreen: true, + text: '登录中,请稍候...' + }) + + const res = await login(loginInfo) + + if (res.code !== 0) { + ElMessage.error(res.message || '登录失败') + return false + } + // 登陆成功,设置用户信息和权限相关信息 + setUserInfo(res.data.user) + setToken(res.data.token) + + // 初始化路由信息 + const routerStore = useRouterStore() + await routerStore.SetAsyncRouter() + const asyncRouters = routerStore.asyncRouters + + // 注册到路由表里 + asyncRouters.forEach((asyncRouter) => { + router.addRoute(asyncRouter) + }) + + if (!router.hasRoute(userInfo.value.authority.defaultRouter)) { + ElMessage.error('请联系管理员进行授权') + } else { + await router.replace({ name: userInfo.value.authority.defaultRouter }) + } + + const isWindows = /windows/i.test(navigator.userAgent) + window.localStorage.setItem('osType', isWindows ? 'WIN' : 'MAC') + + // 全部操作均结束,关闭loading并返回 + return true + } catch (error) { + console.error('LoginIn error:', error) + return false + } finally { + loadingInstance.value?.close() + } + } + /* 登出*/ + const LoginOut = async () => { + const res = await jsonInBlacklist() + + // 登出失败 + if (res.code !== 0) { + return + } + + await ClearStorage() + + // 把路由定向到登录页,无需等待直接reload + router.push({ name: 'Login', replace: true }) + window.location.reload() + } + /* 清理数据 */ + const ClearStorage = async () => { + token.value = '' + xToken.value = '' + sessionStorage.clear() + localStorage.removeItem('originSetting') + } + + return { + userInfo, + token: currentToken, + NeedInit, + ResetUserInfo, + GetUserInfo, + LoginIn, + LoginOut, + setToken, + loadingInstance, + ClearStorage + } +}) diff --git a/src/plugin/announcement/api/info.js b/src/plugin/announcement/api/info.js new file mode 100644 index 0000000..e19770b --- /dev/null +++ b/src/plugin/announcement/api/info.js @@ -0,0 +1,110 @@ +import service from '@/utils/request' + +// @Tags Info +// @Summary 创建公告 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.Info true "创建公告" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}" +// @Router /info/createInfo [post] +export const createInfo = (data) => { + return service({ + url: '/info/createInfo', + method: 'post', + data + }) +} + +// @Tags Info +// @Summary 删除公告 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.Info true "删除公告" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /info/deleteInfo [delete] +export const deleteInfo = (params) => { + return service({ + url: '/info/deleteInfo', + method: 'delete', + params + }) +} + +// @Tags Info +// @Summary 批量删除公告 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.IdsReq true "批量删除公告" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /info/deleteInfo [delete] +export const deleteInfoByIds = (params) => { + return service({ + url: '/info/deleteInfoByIds', + method: 'delete', + params + }) +} + +// @Tags Info +// @Summary 更新公告 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.Info true "更新公告" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}" +// @Router /info/updateInfo [put] +export const updateInfo = (data) => { + return service({ + url: '/info/updateInfo', + method: 'put', + data + }) +} + +// @Tags Info +// @Summary 用id查询公告 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data query model.Info true "用id查询公告" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}" +// @Router /info/findInfo [get] +export const findInfo = (params) => { + return service({ + url: '/info/findInfo', + method: 'get', + params + }) +} + +// @Tags Info +// @Summary 分页获取公告列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data query request.PageInfo true "分页获取公告列表" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /info/getInfoList [get] +export const getInfoList = (params) => { + return service({ + url: '/info/getInfoList', + method: 'get', + params + }) +} +// @Tags Info +// @Summary 获取数据源 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}" +// @Router /info/findInfoDataSource [get] +export const getInfoDataSource = () => { + return service({ + url: '/info/getInfoDataSource', + method: 'get' + }) +} diff --git a/src/plugin/announcement/form/info.vue b/src/plugin/announcement/form/info.vue new file mode 100644 index 0000000..9824048 --- /dev/null +++ b/src/plugin/announcement/form/info.vue @@ -0,0 +1,137 @@ + + + + + diff --git a/src/plugin/announcement/view/info.vue b/src/plugin/announcement/view/info.vue new file mode 100644 index 0000000..a684e97 --- /dev/null +++ b/src/plugin/announcement/view/info.vue @@ -0,0 +1,510 @@ + + + + + diff --git a/src/plugin/email/api/email.js b/src/plugin/email/api/email.js new file mode 100644 index 0000000..c3f6c7b --- /dev/null +++ b/src/plugin/email/api/email.js @@ -0,0 +1,29 @@ +import service from '@/utils/request' +// @Tags System +// @Summary 发送测试邮件 +// @Security ApiKeyAuth +// @Produce application/json +// @Success 200 {string} string "{"success":true,"data":{},"msg":"发送成功"}" +// @Router /email/emailTest [post] +export const emailTest = (data) => { + return service({ + url: '/email/emailTest', + method: 'post', + data + }) +} + +// @Tags System +// @Summary 发送邮件 +// @Security ApiKeyAuth +// @Produce application/json +// @Param data body email_response.Email true "发送邮件必须的参数" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"发送成功"}" +// @Router /email/sendEmail [post] +export const sendEmail = (data) => { + return service({ + url: '/email/sendEmail', + method: 'post', + data + }) +} diff --git a/src/plugin/email/view/index.vue b/src/plugin/email/view/index.vue new file mode 100644 index 0000000..188c45b --- /dev/null +++ b/src/plugin/email/view/index.vue @@ -0,0 +1,60 @@ + + + diff --git a/src/router/index.js b/src/router/index.js new file mode 100644 index 0000000..4181603 --- /dev/null +++ b/src/router/index.js @@ -0,0 +1,41 @@ +import { createRouter, createWebHashHistory } from 'vue-router' + +const routes = [ + { + path: '/', + redirect: '/login' + }, + { + path: '/init', + name: 'Init', + component: () => import('@/view/init/index.vue') + }, + { + path: '/login', + name: 'Login', + component: () => import('@/view/login/index.vue') + }, + { + path: '/scanUpload', + name: 'ScanUpload', + meta: { + title: '扫码上传', + client: true + }, + component: () => import('@/view/example/upload/scanUpload.vue') + }, + { + path: '/:catchAll(.*)', + meta: { + closeTab: true + }, + component: () => import('@/view/error/index.vue') + }, +] + +const router = createRouter({ + history: createWebHashHistory(), + routes +}) + +export default router diff --git a/src/style/element/index.scss b/src/style/element/index.scss new file mode 100644 index 0000000..0c2de8d --- /dev/null +++ b/src/style/element/index.scss @@ -0,0 +1,24 @@ +@forward 'element-plus/theme-chalk/src/common/var.scss' with ( + $colors: ( + 'white': #ffffff, + 'black': #000000, + 'primary': ( + 'base': #4d70ff + ), + 'success': ( + 'base': #67c23a + ), + 'warning': ( + 'base': #e6a23c + ), + 'danger': ( + 'base': #f56c6c + ), + 'error': ( + 'base': #f56c6c + ), + 'info': ( + 'base': #909399 + ) + ) +); diff --git a/src/style/element_visiable.scss b/src/style/element_visiable.scss new file mode 100644 index 0000000..4d33aef --- /dev/null +++ b/src/style/element_visiable.scss @@ -0,0 +1,136 @@ +@use '@/style/main.scss'; +@use '@/style/reset'; + +@tailwind base; +@tailwind components; +@tailwind utilities; + +.el-button { + font-weight: 400; + border-radius: 2px; +} + +.gva-pagination { + @apply flex justify-end; + .el-pagination__editor { + .el-input__inner { + @apply h-8; + } + } + + .is-active { + @apply rounded text-white; + background: var(--el-color-primary); + color: #ffffff !important; + } +} + +.el-drawer__header { + margin-bottom: 0 !important; + padding-top: 16px !important; + padding-bottom: 16px !important; + @apply border-0 border-b border-solid border-gray-200; +} + +.el-form--inline { + .el-form-item { + & > .el-input, + .el-cascader, + .el-select, + .el-date-editor, + .el-autocomplete { + @apply w-52; + } + } +} + +.el-dropdown { + @apply overflow-hidden; +} + +.el-table { + tr { + th { + @apply dark:bg-slate-900; + .cell { + @apply leading-[36px] text-gray-700 dark:text-gray-200; + } + } + } + .el-table__row { + td { + @apply dark:bg-slate-900; + .cell { + @apply leading-[32px] text-gray-600 dark:text-gray-300; + } + } + } + tr { + th { + &.is-leaf { + @apply dark:bg-slate-900; + } + } + } +} + +// layout + +// table +.el-pagination { + @apply mt-8; + .btn-prev, + .btn-next { + @apply border border-solid border-gray-300 dark:border-gray-700 rounded; + } + .el-pager { + li { + @apply border border-solid border-gray-300 dark:border-gray-600 rounded text-gray-600 text-sm mx-1; + } + } +} +.el-menu { + li { + @apply my-1; + } +} +.el-menu--vertical { + .el-menu-item { + border-radius: 2px; + &.is-active { + background-color: var(--el-color-primary) !important; + color: #fff !important; + } + } +} + +.el-sub-menu.el-sub-menu__hide-arrow { + height: 44px; +} + +.el-tabs__header { + margin: 0 0 1px !important; +} + +.el-sub-menu.is-active { + > .el-sub-menu__title { + color: var(--el-color-primary) !important; + } +} + +.el-sub-menu__title.el-tooltip__trigger, +.el-menu-item .el-menu-tooltip__trigger { + justify-content: center; +} + +.el-menu--horizontal .el-menu .el-sub-menu__title { + justify-content: flex-start; +} + +html.dark { + /* 自定义深色背景颜色 */ + --el-bg-color: rgb(30, 41, 59); + --el-bg-color-overlay: rgb(40, 51, 69); + --el-fill-color-light: rgb(15, 23, 42); + --el-fill-color: rgb(15, 23, 42); +} diff --git a/src/style/iconfont.css b/src/style/iconfont.css new file mode 100644 index 0000000..623bf13 --- /dev/null +++ b/src/style/iconfont.css @@ -0,0 +1,47 @@ +@font-face { + font-family: 'gvaIcon'; + src: url('data:font/ttf;charset=utf-8;base64,AAEAAAANAIAAAwBQRkZUTZJUyU8AAA14AAAAHEdERUYAKQARAAANWAAAAB5PUy8yPJpJTAAAAVgAAABgY21hcM0T0L4AAAHYAAABWmdhc3D//wADAAANUAAAAAhnbHlmRk3UvwAAA0wAAAbYaGVhZB/a5jgAAADcAAAANmhoZWEHngOFAAABFAAAACRobXR4DaoBrAAAAbgAAAAebG9jYQbMCGgAAAM0AAAAGG1heHABGgB+AAABOAAAACBuYW1lXoIBAgAACiQAAAKCcG9zdN15OnUAAAyoAAAAqAABAAAAAQAA+a916l8PPPUACwQAAAAAAN5YUSMAAAAA3lhRIwBL/8ADwAM1AAAACAACAAAAAAAAAAEAAAOA/4AAXAQAAAAAAAPAAAEAAAAAAAAAAAAAAAAAAAAEAAEAAAALAHIABQAAAAAAAgAAAAoACgAAAP8AAAAAAAAABAQAAZAABQAAAokCzAAAAI8CiQLMAAAB6wAyAQgAAAIABQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUGZFZADA5mXmfQOA/4AAAAPcAIAAAAABAAAAAAAAAAAAAAAgAAEEAAAAAAAAAAQAAAAEAACLAIoAYAB1AHYASwBLAGAAAAAAAAMAAAADAAAAHAABAAAAAABUAAMAAQAAABwABAA4AAAACgAIAAIAAuZm5mrmduZ9//8AAOZl5mrmdeZ7//8ZnhmbGZEZjQABAAAAAAAAAAAAAAAAAQYAAAEAAAAAAAAAAQIAAAACAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEYAigEcAbgCUAK6AxoDbAACAIsAIANsAswAEQAjAAAlIicBJjQ3ATYeAQYHCQEeAQYhIicBJjQ3ATYeAQYHCQEeAQYDSw0J/qsLCwFVChsSAgr+xAE8CgIV/qkNCP6qCgoBVgkbEgIK/sUBOwoCFCAJATULGQsBNQoCExwI/uL+4ggbFAkBNQsZCwE1CgITHAj+4v7iCRoUAAAAAAIAigAgA2sCzAARACIAAAE0JwEmDgEWFwkBDgEWMjcBNiUBJg4BFhcJAQ4BFjI3ATY0AiAL/qsJHBECCQE8/sQJAhQZCQFVCwFA/qsKGxICCgE8/sQKAhUZCQFVCwF1DQsBNQoCExwI/uL+4gkaFAkBNQskATUKAhMcCP7i/uIJGhQJATULGQADAGD/wAOgAzUATABcAGwAAAE1NCcmJyYiBwYHBh0BDgEdARQWOwEyNj0BNCYrATU0NzY3NjIXFhcWHQEjIgYdARQWOwEGBwYHLgEjIgYUFjMyNjc2NzY3PgE9ATQmBRUUBisBIiY9ATQ2OwEyFgUUBisBIiY9ATQ2OwEyFhUDYDAvT1O+U08vMBslLB9VHi0tHiAoJkFDnENBJiggHi0tHhUPJC5SChwRHCQkHBEeCHJAMxAfKiX9kAYFVQUGBgVVBQYCVQYFVQUGBgVVBQYByQxgUlAuMDAuUFJgDAQqG6seLCweqx4tCk5DQScnJydBQ04KLR6rHiwrGiAGDxElNiUSEAc1KkUBKx6rGyhFqwQGBgSrBQYGsAQGBgSrBQYGBQAABAB1//UDjQMLABsANwBSAHEAABMyNj0BFxYyNjQvATMyNjQmKwEiBwYHBh0BFBYFIgYdAScmIgYUHwEjIgYUFjsBMjc2NzY9ATYmJQc1NCYiBh0BFBcWFxY7ATI2NCYrATc2NCYGATQ1FSYnJisBIgYUFjsBBwYUFjI/ARUUFjI2PQEnJpUNE7wJHRMKvIcMFBQM1ggCDAgCFALiDRPJCRoTCcmJDBQUDNYIAg8CAwES/gbJExkUAggKBAbWDBQUDInJCRMXAgEHCwQG2AwUFAyJvAkSHgi8ExoTAgEB9RQMibwIEhkKvBMZFAIGDAQI1gwU6hQMickJExoJyRMZFAIICgQG2AwUIsmHDBQUDNYIAg8CAxQZE8kKGRMBAcABAQIOAwMUGRO8ChkTCbyHDBQUDNYFBAAABAB2//cDjgMMABoANQBRAG0AAAEjIgYUFjsBMjc2NzY9ATQmIgYdAScmIgYUFwEzMjY0JisBIgcGBwYdARQWMjY9ARcWMjY0JyUmJyYrASIGFBY7AQcGFBYyPwEVFBYyNj0BLgE3FhcWOwEyNjQmKwE3NjQmIg8BNTQmIgYdAR4BATqJDRMTDdUJAg8CAhMaE7cKGRQKAjeJDRMTDdUJAg8CAhMaE8gJHhIK/i8HCgQH1w0TEw2JyQoTHQnIFBkTAQKoBwoEBtYNExMNibwKFBkKvBMZFAICAhoUGRMCBwoEBtYNExMNib4KExoK/iAUGRMCBwoEB9UNExMNickIEhkK8w8CAhMZFMgKGRMJyYkNExMN1QIJzQ8CAhMZFLsKGhMKvIkNExMN1QMIAAAAAAUAS//LA7UDNQAUACkAKgA3AEQAAAEiBwYHBhQXFhcWMjc2NzY0JyYnJgMiJyYnJjQ3Njc2MhcWFxYUBwYHBgMjFB4BMj4BNC4BIg4BFyIGHQEUFjI2PQE0JgIAd2ZiOzs7O2Jm7mZiOzs7O2Jmd2VXVDIzMzJUV8pXVDIzMzJUV2UrDBQWFAwMFBYUDCsNExMaExMDNTs7YmbuZmI7Ozs7YmbuZmI7O/zWMzJUV8pXVDIzMzJUV8pXVDIzAjULFAwMFBYUDAwUgBQM6w0TEw3rDBQAAQBL/+ADwAMgAD0AAAEmBg8BLgEjIgcGBwYUFxYXFjMyPgE3Ni4BBgcOAiMiJyYnJjQ3Njc2MzIeARcnJg4BFh8BMj8BNj8BNCYDpgwXAxc5yXZyY184Ojo4X2NyWaB4HgULGhcFGWaJS2FUUTAwMTBRU2FIhGQbgA0WBw4NwgUIBAwDMQ0CsQMODFhmeDk3XmHiYV43OUV9UQ0XCQsMRWo6MC9PUr9TTy8wNmNBJQMOGhYDMwMBCAu6DRYAAAAAAgBg/8YDugMiAB4AMwAABSc+ATU0JyYnJiIHBgcGFBcWFxYzMjc2NxcWMjc2JiUiJyYnJjQ3Njc2MhcWFxYUBwYHBgOxviouNDFVV8lXVTIzMzJVV2RDPzwzvgkeCAcB/hxUSEYpKiopRkioSEYpKyspRkgCvjB9RGRYVDIzNDJVWMlXVTE0GBYqvgkJChuBKylGSKhIRikqKilGSKhIRikrAAAAABIA3gABAAAAAAAAABMAKAABAAAAAAABAAgATgABAAAAAAACAAcAZwABAAAAAAADAAgAgQABAAAAAAAEAAgAnAABAAAAAAAFAAsAvQABAAAAAAAGAAgA2wABAAAAAAAKACsBPAABAAAAAAALABMBkAADAAEECQAAACYAAAADAAEECQABABAAPAADAAEECQACAA4AVwADAAEECQADABAAbwADAAEECQAEABAAigADAAEECQAFABYApQADAAEECQAGABAAyQADAAEECQAKAFYA5AADAAEECQALACYBaABDAHIAZQBhAHQAZQBkACAAYgB5ACAAaQBjAG8AbgBmAG8AbgB0AABDcmVhdGVkIGJ5IGljb25mb250AABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABSAGUAZwB1AGwAYQByAABSZWd1bGFyAABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABWAGUAcgBzAGkAbwBuACAAMQAuADAAAFZlcnNpb24gMS4wAABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABHAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAHMAdgBnADIAdAB0AGYAIABmAHIAbwBtACAARgBvAG4AdABlAGwAbABvACAAcAByAG8AagBlAGMAdAAuAABHZW5lcmF0ZWQgYnkgc3ZnMnR0ZiBmcm9tIEZvbnRlbGxvIHByb2plY3QuAABoAHQAdABwADoALwAvAGYAbwBuAHQAZQBsAGwAbwAuAGMAbwBtAABodHRwOi8vZm9udGVsbG8uY29tAAAAAAIAAAAAAAAACgAAAAAAAQAAAAAAAAAAAAAAAAAAAAAACwAAAAEAAgECAQMBBAEFAQYBBwEIAQkRYXJyb3ctZG91YmxlLWxlZnQSYXJyb3ctZG91YmxlLXJpZ2h0EGN1c3RvbWVyLXNlcnZpY2URZnVsbHNjcmVlbi1leHBhbmQRZnVsbHNjcmVlbi1zaHJpbmsGcHJvbXB0B3JlZnJlc2gGc2VhcmNoAAAAAf//AAIAAQAAAAwAAAAWAAAAAgABAAMACgABAAQAAAACAAAAAAAAAAEAAAAA1aQnCAAAAADeWFEjAAAAAN5YUSM=') + format('truetype'); + font-weight: 600; + font-style: normal; + font-display: swap; +} +.gvaIcon { + font-family: 'gvaIcon' !important; + font-size: 16px; + font-style: normal; + font-weight: 800; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.gvaIcon-arrow-double-left:before { + content: '\e665'; +} + +.gvaIcon-arrow-double-right:before { + content: '\e666'; +} + +.gvaIcon-fullscreen-shrink:before { + content: '\e676'; +} +.gvaIcon-customer-service:before { + content: '\e66a'; +} + +.gvaIcon-fullscreen-expand:before { + content: '\e675'; +} + +.gvaIcon-prompt:before { + content: '\e67b'; +} + +.gvaIcon-refresh:before { + content: '\e67c'; +} + +.gvaIcon-search:before { + content: '\e67d'; +} diff --git a/src/style/main.scss b/src/style/main.scss new file mode 100644 index 0000000..a213d48 --- /dev/null +++ b/src/style/main.scss @@ -0,0 +1,51 @@ +@use '@/style/iconfont.css'; +@use "./transition.scss"; + +.html-grey { + filter: grayscale(100%); +} + +.html-weakenss { + filter: invert(80%); +} + +.gva-table-box { + @apply p-4 bg-white text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded my-2; + .el-table { + @apply border-x border-t border-b-0 rounded border-table-border border-solid -mx-[1px]; + } +} + +.gva-btn-list { + @apply mb-3 flex items-center; +} + +#nprogress .bar { + background: #29d !important; +} +.gva-customer-icon { + @apply w-4 h-4; +} + +::-webkit-scrollbar { + @apply hidden; +} + +.gva-search-box { + @apply p-4 bg-white text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded my-2; +} + +.gva-form-box { + @apply p-4 bg-white text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded my-2; +} + +.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content { + background: var(--el-color-primary-bg) !important; +} + +.el-dropdown { + outline: none; + * { + outline: none; + } +} diff --git a/src/style/reset.scss b/src/style/reset.scss new file mode 100644 index 0000000..2cd44c7 --- /dev/null +++ b/src/style/reset.scss @@ -0,0 +1,469 @@ +/* Document + ========================================================================== */ + +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in iOS. + */ + +html { + line-height: 1.15; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers. + */ + +body { + margin: 0; +} + +/** + * Render the `main` element consistently in IE. + */ + +main { + display: block; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; + /* 1 */ + height: 0; + /* 1 */ + overflow: visible; + /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +pre { + font-family: monospace, monospace; + /* 1 */ + font-size: 1em; + /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Remove the gray background on active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * 1. Remove the bottom border in Chrome 57- + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; + /* 1 */ + text-decoration: underline; + /* 2 */ + text-decoration: underline dotted; + /* 2 */ +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +samp { + font-family: monospace, monospace; + /* 1 */ + font-size: 1em; + /* 2 */ +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove the border on images inside links in IE 10. + */ + +img { + border-style: none; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers. + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + line-height: 1.15; + /* 1 */ + margin: 0; + /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { + /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { + /* 1 */ + text-transform: none; +} + +/** + * Correct the inability to style clickable types in iOS and Safari. + */ + +button, +[type='button'], +[type='reset'], +[type='submit'] { + -webkit-appearance: button; +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type='button']::-moz-focus-inner, +[type='reset']::-moz-focus-inner, +[type='submit']::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type='button']:-moz-focusring, +[type='reset']:-moz-focusring, +[type='submit']:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Correct the padding in Firefox. + */ + +fieldset { + padding: 0.35em 0.75em 0.625em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; + /* 1 */ + color: inherit; + /* 2 */ + display: table; + /* 1 */ + max-width: 100%; + /* 1 */ + padding: 0; + /* 3 */ + white-space: normal; + /* 1 */ +} + +/** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + vertical-align: baseline; +} + +/** + * Remove the default vertical scrollbar in IE 10+. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10. + * 2. Remove the padding in IE 10. + */ + +[type='checkbox'], +[type='radio'] { + box-sizing: border-box; + /* 1 */ + padding: 0; + /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type='number']::-webkit-inner-spin-button, +[type='number']::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type='search'] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/** + * Remove the inner padding in Chrome and Safari on macOS. + */ + +[type='search']::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in Edge, IE 10+, and Firefox. + */ + +details { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; +} + +/* Misc + ========================================================================== */ + +/** + * Add the correct display in IE 10+. + */ + +template { + display: none; +} + +/** + * Add the correct display in IE 10. + */ + +[hidden] { + display: none; +} + +HTML, +body, +div, +ul, +ol, +dl, +li, +dt, +dd, +p, +blockquote, +pre, +form, +fieldset, +table, +th, +td { + border: none; + font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', + 'Microsoft YaHei', '微软雅黑', Arial, sans-serif; + font-size: 14px; + margin: 0px; + padding: 0px; +} + +html, +body { + height: 100%; + width: 100%; +} + +address, +caption, +cite, +code, +th, +var { + font-style: normal; + font-weight: normal; +} + +a { + text-decoration: none; +} + +input::-ms-clear { + display: none; +} + +input::-ms-reveal { + display: none; +} + +input { + -webkit-appearance: none; + margin: 0; + outline: none; + padding: 0; +} + +input::-webkit-input-placeholder { + color: #ccc; +} + +input::-ms-input-placeholder { + color: #ccc; +} + +input::-moz-placeholder { + color: #ccc; +} + +input[type='submit'], +input[type='button'] { + cursor: pointer; +} + +button[disabled], +input[disabled] { + cursor: default; +} + +img { + border: none; +} + +ul, +ol, +li { + list-style-type: none; +} diff --git a/src/style/transition.scss b/src/style/transition.scss new file mode 100644 index 0000000..09a2543 --- /dev/null +++ b/src/style/transition.scss @@ -0,0 +1,68 @@ + +// 淡入淡出动画 +.fade-enter-active, +.fade-leave-active { + transition: all 0.3s ease; +} + +.fade-enter-from, +.fade-leave-to { + opacity: 0; + transform: translateY(10px); +} + +.header { + border-radius: 0 0 10px 10px; +} + +.body { + height: calc(100% - 6rem); +} + +@keyframes slideDown { + from { + transform: translateY(-20px); + opacity: 0; + } + + to { + transform: translateY(0); + opacity: 1; + } +} + +@keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} +// 缩放动画 +.zoom-enter-active, +.zoom-leave-active { + transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1); +} + +.zoom-enter-from, +.zoom-leave-to { + opacity: 0; + transform: scale(0.95); +} + + +/* fade-slide */ +.slide-leave-active, +.slide-enter-active { + transition: all 0.3s; +} +.slide-enter-from { + opacity: 0; + transform: translateX(-30px); +} +.slide-leave-to { + opacity: 0; + transform: translateX(30px); +} diff --git a/src/utils/asyncRouter.js b/src/utils/asyncRouter.js new file mode 100644 index 0000000..9e7a5ca --- /dev/null +++ b/src/utils/asyncRouter.js @@ -0,0 +1,29 @@ +const viewModules = import.meta.glob('../view/**/*.vue') +const pluginModules = import.meta.glob('../plugin/**/*.vue') + +export const asyncRouterHandle = (asyncRouter) => { + asyncRouter.forEach((item) => { + if (item.component && typeof item.component === 'string') { + item.meta.path = '/src/' + item.component + if (item.component.split('/')[0] === 'view') { + item.component = dynamicImport(viewModules, item.component) + } else if (item.component.split('/')[0] === 'plugin') { + item.component = dynamicImport(pluginModules, item.component) + } + } + if (item.children) { + asyncRouterHandle(item.children) + } + }) +} + +function dynamicImport(dynamicViewsModules, component) { + const keys = Object.keys(dynamicViewsModules) + const matchKeys = keys.filter((key) => { + const k = key.replace('../', '') + return k === component + }) + const matchKey = matchKeys[0] + + return dynamicViewsModules[matchKey] +} diff --git a/src/utils/btnAuth.js b/src/utils/btnAuth.js new file mode 100644 index 0000000..f94fa9b --- /dev/null +++ b/src/utils/btnAuth.js @@ -0,0 +1,6 @@ +import { useRoute } from 'vue-router' +import { reactive } from 'vue' +export const useBtnAuth = () => { + const route = useRoute() + return route.meta.btns || reactive({}) +} diff --git a/src/utils/bus.js b/src/utils/bus.js new file mode 100644 index 0000000..f2a3b92 --- /dev/null +++ b/src/utils/bus.js @@ -0,0 +1,4 @@ +// using ES6 modules +import mitt from 'mitt' + +export const emitter = mitt() diff --git a/src/utils/closeThisPage.js b/src/utils/closeThisPage.js new file mode 100644 index 0000000..b2a0c05 --- /dev/null +++ b/src/utils/closeThisPage.js @@ -0,0 +1,5 @@ +import { emitter } from '@/utils/bus.js' + +export const closeThisPage = () => { + emitter.emit('closeThisPage') +} diff --git a/src/utils/date.js b/src/utils/date.js new file mode 100644 index 0000000..987a40d --- /dev/null +++ b/src/utils/date.js @@ -0,0 +1,44 @@ +// 对Date的扩展,将 Date 转化为指定格式的String +// 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符, +// 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字) +// (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423 +// (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18 +// eslint-disable-next-line no-extend-native +Date.prototype.Format = function(fmt) { + const o = { + 'M+': this.getMonth() + 1, // 月份 + 'd+': this.getDate(), // 日 + 'h+': this.getHours(), // 小时 + 'm+': this.getMinutes(), // 分 + 's+': this.getSeconds(), // 秒 + 'q+': Math.floor((this.getMonth() + 3) / 3), // 季度 + 'S': this.getMilliseconds() // 毫秒 + } + const reg = /(y+)/ + if (reg.test(fmt)) { + const t = reg.exec(fmt)[1] + fmt = fmt.replace( + t, + (this.getFullYear() + '').substring(4 - t.length) + ) + } + for (let k in o) { + const regx = new RegExp('(' + k + ')') + if (regx.test(fmt)) { + const t = regx.exec(fmt)[1] + fmt = fmt.replace( + t, + t.length === 1 ? o[k] : ('00' + o[k]).substring(('' + o[k]).length) + ) + } + } + return fmt +} + +export function formatTimeToStr(times, pattern) { + let d = new Date(times).Format('yyyy-MM-dd hh:mm:ss') + if (pattern) { + d = new Date(times).Format(pattern) + } + return d.toLocaleString() +} diff --git a/src/utils/dictionary.js b/src/utils/dictionary.js new file mode 100644 index 0000000..89ec656 --- /dev/null +++ b/src/utils/dictionary.js @@ -0,0 +1,26 @@ +import { useDictionaryStore } from '@/pinia/modules/dictionary' +// 获取字典方法 使用示例 getDict('sex').then(res) 或者 async函数下 const res = await getDict('sex') +export const getDict = async (type) => { + const dictionaryStore = useDictionaryStore() + await dictionaryStore.getDictionary(type) + return dictionaryStore.dictionaryMap[type] +} + +// 字典文字展示方法 +export const showDictLabel = ( + dict, + code, + keyCode = 'value', + valueCode = 'label' +) => { + if (!dict) { + return '' + } + const dictMap = {} + dict.forEach((item) => { + if (Reflect.has(item, keyCode) && Reflect.has(item, valueCode)) { + dictMap[item[keyCode]] = item[valueCode] + } + }) + return Reflect.has(dictMap, code) ? dictMap[code] : '' +} diff --git a/src/utils/doc.js b/src/utils/doc.js new file mode 100644 index 0000000..55a3949 --- /dev/null +++ b/src/utils/doc.js @@ -0,0 +1,3 @@ +export const toDoc = (url) => { + window.open(url, '_blank') +} diff --git a/src/utils/downloadImg.js b/src/utils/downloadImg.js new file mode 100644 index 0000000..10506c7 --- /dev/null +++ b/src/utils/downloadImg.js @@ -0,0 +1,20 @@ +export const downloadImage = (imgsrc, name) => { + // 下载图片地址和图片名 + var image = new Image() + image.setAttribute('crossOrigin', 'anonymous') + image.onload = function () { + var canvas = document.createElement('canvas') + canvas.width = image.width + canvas.height = image.height + var context = canvas.getContext('2d') + context.drawImage(image, 0, 0, image.width, image.height) + var url = canvas.toDataURL('image/png') // 得到图片的base64编码数据 + + var a = document.createElement('a') // 生成一个a元素 + var event = new MouseEvent('click') // 创建一个单击事件 + a.download = name || 'photo' // 设置图片名称 + a.href = url // 将生成的URL设置为a.href属性 + a.dispatchEvent(event) // 触发a的单击事件 + } + image.src = imgsrc +} diff --git a/src/utils/event.js b/src/utils/event.js new file mode 100644 index 0000000..4861bf7 --- /dev/null +++ b/src/utils/event.js @@ -0,0 +1,17 @@ +export function addEventListen(target, event, handler, capture = false) { + if ( + target.addEventListener && + typeof target.addEventListener === 'function' + ) { + target.addEventListener(event, handler, capture) + } +} + +export function removeEventListen(target, event, handler, capture = false) { + if ( + target.removeEventListener && + typeof target.removeEventListener === 'function' + ) { + target.removeEventListener(event, handler, capture) + } +} diff --git a/src/utils/fmtRouterTitle.js b/src/utils/fmtRouterTitle.js new file mode 100644 index 0000000..bcaeb67 --- /dev/null +++ b/src/utils/fmtRouterTitle.js @@ -0,0 +1,13 @@ +export const fmtTitle = (title, now) => { + const reg = /\$\{(.+?)\}/ + const reg_g = /\$\{(.+?)\}/g + const result = title.match(reg_g) + if (result) { + result.forEach((item) => { + const key = item.match(reg)[1] + const value = now.params[key] || now.query[key] + title = title.replace(item, value) + }) + } + return title +} diff --git a/src/utils/format.js b/src/utils/format.js new file mode 100644 index 0000000..f5062e7 --- /dev/null +++ b/src/utils/format.js @@ -0,0 +1,146 @@ +import { formatTimeToStr } from '@/utils/date' +import { getDict } from '@/utils/dictionary' +import { ref } from 'vue' + +export const formatBoolean = (bool) => { + if (bool !== null) { + return bool ? '是' : '否' + } else { + return '' + } +} +export const formatDate = (time) => { + if (time !== null && time !== '') { + var date = new Date(time) + return formatTimeToStr(date, 'yyyy-MM-dd hh:mm:ss') + } else { + return '' + } +} + +export const filterDict = (value, options) => { + const rowLabel = options && options.filter((item) => item.value === value) + return rowLabel && rowLabel[0] && rowLabel[0].label +} + +export const filterDataSource = (dataSource, value) => { + if (Array.isArray(value)) { + return value.map((item) => { + const rowLabel = dataSource && dataSource.find((i) => i.value === item) + return rowLabel?.label + }) + } + const rowLabel = dataSource && dataSource.find((item) => item.value === value) + return rowLabel?.label +} + +export const getDictFunc = async (type) => { + const dicts = await getDict(type) + return dicts +} + +const path = + import.meta.env.VITE_BASE_PATH + ':' + import.meta.env.VITE_SERVER_PORT + '/' +export const ReturnArrImg = (arr) => { + const imgArr = [] + if (arr instanceof Array) { + // 如果是数组类型 + for (const arrKey in arr) { + if (arr[arrKey].slice(0, 4) !== 'http') { + imgArr.push(path + arr[arrKey]) + } else { + imgArr.push(arr[arrKey]) + } + } + } else { + // 如果不是数组类型 + if (arr?.slice(0, 4) !== 'http') { + imgArr.push(path + arr) + } else { + imgArr.push(arr) + } + } + return imgArr +} + +export const returnArrImg = ReturnArrImg + +export const onDownloadFile = (url) => { + window.open(path + url) +} +const colorToHex = (u) => { + let e = u.replace('#', '').match(/../g) + for (let t = 0; t < 3; t++) e[t] = parseInt(e[t], 16) + return e +} + +const hexToColor = (u, e, t) => { + let a = [u.toString(16), e.toString(16), t.toString(16)] + for (let n = 0; n < 3; n++) a[n].length === 1 && (a[n] = `0${a[n]}`) + return `#${a.join('')}` +} +const generateAllColors = (u, e) => { + let t = colorToHex(u) + const target = [10, 10, 30] + for (let a = 0; a < 3; a++) t[a] = Math.floor(t[a] * (1 - e) + target[a] * e) + return hexToColor(t[0], t[1], t[2]) +} + +const generateAllLightColors = (u, e) => { + let t = colorToHex(u) + const target = [240, 248, 255] // RGB for blue white color + for (let a = 0; a < 3; a++) t[a] = Math.floor(t[a] * (1 - e) + target[a] * e) + return hexToColor(t[0], t[1], t[2]) +} + +function addOpacityToColor(u, opacity) { + let t = colorToHex(u) + return `rgba(${t[0]}, ${t[1]}, ${t[2]}, ${opacity})` +} + +export const setBodyPrimaryColor = (primaryColor, darkMode) => { + let fmtColorFunc = generateAllColors + if (darkMode === 'light') { + fmtColorFunc = generateAllLightColors + } + + document.documentElement.style.setProperty('--el-color-primary', primaryColor) + document.documentElement.style.setProperty( + '--el-color-primary-bg', + addOpacityToColor(primaryColor, 0.4) + ) + for (let times = 1; times <= 2; times++) { + document.documentElement.style.setProperty( + `--el-color-primary-dark-${times}`, + fmtColorFunc(primaryColor, times / 10) + ) + } + for (let times = 1; times <= 10; times++) { + document.documentElement.style.setProperty( + `--el-color-primary-light-${times}`, + fmtColorFunc(primaryColor, times / 10) + ) + } + document.documentElement.style.setProperty( + `--el-menu-hover-bg-color`, + addOpacityToColor(primaryColor, 0.2) + ) +} + +const baseUrl = ref(import.meta.env.VITE_BASE_API) + +export const getBaseUrl = () => { + return baseUrl.value === '/' ? '' : baseUrl.value +} + +export const CreateUUID = () => { + let d = new Date().getTime() + if (window.performance && typeof window.performance.now === 'function') { + d += performance.now() + } + return '00000000-0000-0000-0000-000000000000'.replace(/0/g, (c) => { + const r = (d + Math.random() * 16) % 16 | 0 // d是随机种子 + d = Math.floor(d / 16) + return (c === '0' ? r : (r & 0x3) | 0x8).toString(16) + }) +} diff --git a/src/utils/image.js b/src/utils/image.js new file mode 100644 index 0000000..8b65232 --- /dev/null +++ b/src/utils/image.js @@ -0,0 +1,126 @@ +export default class ImageCompress { + constructor(file, fileSize, maxWH = 1920) { + this.file = file + this.fileSize = fileSize + this.maxWH = maxWH // 最大长宽 + } + + compress() { + // 压缩 + const fileType = this.file.type + const fileSize = this.file.size / 1024 + return new Promise((resolve) => { + const reader = new FileReader() + reader.readAsDataURL(this.file) + reader.onload = () => { + const canvas = document.createElement('canvas') + const img = document.createElement('img') + img.src = reader.result + img.onload = () => { + const ctx = canvas.getContext('2d') + const _dWH = this.dWH(img.width, img.height, this.maxWH) + canvas.width = _dWH.width + canvas.height = _dWH.height + + // 清空后, 重写画布 + ctx.clearRect(0, 0, canvas.width, canvas.height) + ctx.drawImage(img, 0, 0, canvas.width, canvas.height) + + const newImgData = canvas.toDataURL(fileType, 0.9) + + // 压缩宽高后的图像大小 + const newImgSize = this.fileSizeKB(newImgData) + + if (newImgSize > this.fileSize) { + console.log('图片尺寸太大!' + fileSize + ' >> ' + newImgSize) + } + + const blob = this.dataURLtoBlob(newImgData, fileType) + const nfile = new File([blob], this.file.name) + resolve(nfile) + } + } + }) + } + + /** + * 长宽等比缩小 + * 图像的一边(长或宽)为最大目标值 + */ + dWH(srcW, srcH, dMax) { + const defaults = { + width: srcW, + height: srcH + } + if (Math.max(srcW, srcH) > dMax) { + if (srcW > srcH) { + defaults.width = dMax + defaults.height = Math.round(srcH * (dMax / srcW)) + return defaults + } else { + defaults.height = dMax + defaults.width = Math.round(srcW * (dMax / srcH)) + return defaults + } + } else { + return defaults + } + } + + fileSizeKB(dataURL) { + let sizeKB = 0 + sizeKB = Math.round((dataURL.split(',')[1].length * 3) / 4 / 1024) + return sizeKB + } + + /** + * 转为Blob + */ + dataURLtoBlob(dataURL, fileType) { + const byteString = atob(dataURL.split(',')[1]) + let mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0] + const ab = new ArrayBuffer(byteString.length) + const ia = new Uint8Array(ab) + for (let i = 0; i < byteString.length; i++) { + ia[i] = byteString.charCodeAt(i) + } + if (fileType) { + mimeString = fileType + } + return new Blob([ab], { type: mimeString, lastModifiedDate: new Date() }) + } +} + +const path = import.meta.env.VITE_FILE_API +export const getUrl = (url) => { + if (url && url.slice(0, 4) !== 'http') { + if (path === '/') { + return url + } + if (url.slice(0, 1) === '/') { + return path + url + } + return path + '/' + url + } else { + return url + } +} + +const VIDEO_EXTENSIONS = ['.mp4', '.mov', '.webm', '.ogg'] +const VIDEO_MIME_TYPES = ['video/mp4', 'video/webm', 'video/ogg'] +const IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/webp', 'image/svg+xml'] + +export const isVideoExt = (url) => { + const urlLower = url?.toLowerCase() || '' + return urlLower !== '' && VIDEO_EXTENSIONS.some(ext => urlLower.endsWith(ext)) +} + +export const isVideoMime = (type) => { + const typeLower = type?.toLowerCase() || '' + return typeLower !== '' && VIDEO_MIME_TYPES.includes(typeLower) +} + +export const isImageMime = (type) => { + const typeLower = type?.toLowerCase() || '' + return typeLower !== '' && IMAGE_MIME_TYPES.includes(typeLower) +} diff --git a/src/utils/page.js b/src/utils/page.js new file mode 100644 index 0000000..6a3c6d8 --- /dev/null +++ b/src/utils/page.js @@ -0,0 +1,9 @@ +import { fmtTitle } from '@/utils/fmtRouterTitle' +import config from '@/core/config' +export default function getPageTitle(pageTitle, route) { + if (pageTitle) { + const title = fmtTitle(pageTitle, route) + return `${title} - ${config.appName}` + } + return `${config.appName}` +} diff --git a/src/utils/params.js b/src/utils/params.js new file mode 100644 index 0000000..b03d539 --- /dev/null +++ b/src/utils/params.js @@ -0,0 +1,14 @@ +import { useParamsStore } from '@/pinia/modules/params' +/* + * 获取参数方法 使用示例 getParams('key').then(res) 或者 async函数下 const res = await getParams('key') + * const res = ref('') + * const fun = async () => { + * res.value = await getParams('test') + * } + * fun() + */ +export const getParams = async(key) => { + const paramsStore = useParamsStore() + await paramsStore.getParams(key) + return paramsStore.paramsMap[key] +} diff --git a/src/utils/request.js b/src/utils/request.js new file mode 100644 index 0000000..342ce8f --- /dev/null +++ b/src/utils/request.js @@ -0,0 +1,172 @@ +import axios from 'axios' // 引入axios +import { ElMessage, ElMessageBox } from 'element-plus' +import { useUserStore } from '@/pinia/modules/user' +import router from '@/router/index' +import { ElLoading } from 'element-plus' + +const service = axios.create({ + baseURL: import.meta.env.VITE_BASE_API, + timeout: 99999 +}) +let activeAxios = 0 +let timer +let loadingInstance +const showLoading = ( + option = { + target: null + } +) => { + const loadDom = document.getElementById('gva-base-load-dom') + activeAxios++ + if (timer) { + clearTimeout(timer) + } + timer = setTimeout(() => { + if (activeAxios > 0) { + if (!option.target) option.target = loadDom + loadingInstance = ElLoading.service(option) + } + }, 400) +} + +const closeLoading = () => { + activeAxios-- + if (activeAxios <= 0) { + clearTimeout(timer) + loadingInstance && loadingInstance.close() + } +} +// http request 拦截器 +service.interceptors.request.use( + (config) => { + if (!config.donNotShowLoading) { + showLoading(config.loadingOption) + } + const userStore = useUserStore() + config.headers = { + 'Content-Type': 'application/json', + 'x-token': userStore.token, + 'x-user-id': userStore.userInfo.ID, + ...config.headers + } + return config + }, + (error) => { + if (!error.config.donNotShowLoading) { + closeLoading() + } + ElMessage({ + showClose: true, + message: error, + type: 'error' + }) + return error + } +) + +// http response 拦截器 +service.interceptors.response.use( + (response) => { + const userStore = useUserStore() + if (!response.config.donNotShowLoading) { + closeLoading() + } + if (response.headers['new-token']) { + userStore.setToken(response.headers['new-token']) + } + if (response.data.code === 0 || response.headers.success === 'true') { + if (response.headers.msg) { + response.data.msg = decodeURI(response.headers.msg) + } + return response.data + } else { + ElMessage({ + showClose: true, + message: response.data.msg || decodeURI(response.headers.msg), + type: 'error' + }) + return response.data.msg ? response.data : response + } + }, + (error) => { + if (!error.config.donNotShowLoading) { + closeLoading() + } + + if (!error.response) { + ElMessageBox.confirm( + ` +

检测到请求错误

+

${error}

+ `, + '请求报错', + { + dangerouslyUseHTMLString: true, + distinguishCancelAndClose: true, + confirmButtonText: '稍后重试', + cancelButtonText: '取消' + } + ) + return + } + + switch (error.response.status) { + case 500: + ElMessageBox.confirm( + ` +

检测到接口错误${error}

+

错误码 500 :此类错误内容常见于后台panic,请先查看后台日志,如果影响您正常使用可强制登出清理缓存

+ `, + '接口报错', + { + dangerouslyUseHTMLString: true, + distinguishCancelAndClose: true, + confirmButtonText: '清理缓存', + cancelButtonText: '取消' + } + ).then(() => { + const userStore = useUserStore() + userStore.ClearStorage() + router.push({ name: 'Login', replace: true }) + }) + break + case 404: + ElMessageBox.confirm( + ` +

检测到接口错误${error}

+

错误码 404 :此类错误多为接口未注册(或未重启)或者请求路径(方法)与api路径(方法)不符--如果为自动化代码请检查是否存在空格

+ `, + '接口报错', + { + dangerouslyUseHTMLString: true, + distinguishCancelAndClose: true, + confirmButtonText: '我知道了', + cancelButtonText: '取消' + } + ) + break + case 401: + ElMessageBox.confirm( + ` +

无效的令牌

+

错误码: 401 错误信息:${error}

+ `, + '身份信息', + { + dangerouslyUseHTMLString: true, + distinguishCancelAndClose: true, + confirmButtonText: '重新登录', + cancelButtonText: '取消' + } + ).then(() => { + const userStore = useUserStore() + userStore.ClearStorage() + router.push({ name: 'Login', replace: true }) + }) + break + } + + return error + } +) +export default service diff --git a/src/utils/stringFun.js b/src/utils/stringFun.js new file mode 100644 index 0000000..baec83d --- /dev/null +++ b/src/utils/stringFun.js @@ -0,0 +1,29 @@ +/* eslint-disable */ +export const toUpperCase = (str) => { + if (str[0]) { + return str.replace(str[0], str[0].toUpperCase()) + } else { + return '' + } +} + +export const toLowerCase = (str) => { + if (str[0]) { + return str.replace(str[0], str[0].toLowerCase()) + } else { + return '' + } +} + +// 驼峰转换下划线 +export const toSQLLine = (str) => { + if (str === 'ID') return 'ID' + return str.replace(/([A-Z])/g, '_$1').toLowerCase() +} + +// 下划线转换驼峰 +export const toHump = (name) => { + return name.replace(/\_(\w)/g, function (all, letter) { + return letter.toUpperCase() + }) +} diff --git a/src/view/about/index.vue b/src/view/about/index.vue new file mode 100644 index 0000000..bf02bec --- /dev/null +++ b/src/view/about/index.vue @@ -0,0 +1,166 @@ + + + + + diff --git a/src/view/bot/bot/bot.vue b/src/view/bot/bot/bot.vue new file mode 100644 index 0000000..cb278d8 --- /dev/null +++ b/src/view/bot/bot/bot.vue @@ -0,0 +1,411 @@ + + + + + + diff --git a/src/view/bot/bot/botForm.vue b/src/view/bot/bot/botForm.vue new file mode 100644 index 0000000..3afe384 --- /dev/null +++ b/src/view/bot/bot/botForm.vue @@ -0,0 +1,118 @@ + + + + + + diff --git a/src/view/category/category/category.vue b/src/view/category/category/category.vue new file mode 100644 index 0000000..9209f81 --- /dev/null +++ b/src/view/category/category/category.vue @@ -0,0 +1,438 @@ + + + + + + diff --git a/src/view/category/category/categoryForm.vue b/src/view/category/category/categoryForm.vue new file mode 100644 index 0000000..48a71ba --- /dev/null +++ b/src/view/category/category/categoryForm.vue @@ -0,0 +1,119 @@ + + + + + + diff --git a/src/view/dashboard/components/banner.vue b/src/view/dashboard/components/banner.vue new file mode 100644 index 0000000..226dda9 --- /dev/null +++ b/src/view/dashboard/components/banner.vue @@ -0,0 +1,43 @@ + + + + + + + diff --git a/src/view/dashboard/components/card.vue b/src/view/dashboard/components/card.vue new file mode 100644 index 0000000..2a50b28 --- /dev/null +++ b/src/view/dashboard/components/card.vue @@ -0,0 +1,46 @@ + + + + + + + diff --git a/src/view/dashboard/components/charts-content-numbers.vue b/src/view/dashboard/components/charts-content-numbers.vue new file mode 100644 index 0000000..4d7fb9e --- /dev/null +++ b/src/view/dashboard/components/charts-content-numbers.vue @@ -0,0 +1,189 @@ + + + + + + + diff --git a/src/view/dashboard/components/charts-people-numbers.vue b/src/view/dashboard/components/charts-people-numbers.vue new file mode 100644 index 0000000..3d10b3f --- /dev/null +++ b/src/view/dashboard/components/charts-people-numbers.vue @@ -0,0 +1,138 @@ + + + + + + + diff --git a/src/view/dashboard/components/charts.vue b/src/view/dashboard/components/charts.vue new file mode 100644 index 0000000..650b5f1 --- /dev/null +++ b/src/view/dashboard/components/charts.vue @@ -0,0 +1,54 @@ + + + + + + + diff --git a/src/view/dashboard/components/index.js b/src/view/dashboard/components/index.js new file mode 100644 index 0000000..a59985b --- /dev/null +++ b/src/view/dashboard/components/index.js @@ -0,0 +1,19 @@ +import GvaBanner from './banner.vue' +import GvaCard from './card.vue' +import GvaChart from './charts.vue' +import GvaTable from './table.vue' +import GvaNotice from './notice.vue' +import GvaQuickLink from './quickLinks.vue' +import GvaWiki from './wiki.vue' +import GvaPluginTable from './pluginTable.vue' + +export { + GvaBanner, + GvaCard, + GvaChart, + GvaTable, + GvaNotice, + GvaQuickLink, + GvaWiki, + GvaPluginTable +} diff --git a/src/view/dashboard/components/notice.vue b/src/view/dashboard/components/notice.vue new file mode 100644 index 0000000..6e81261 --- /dev/null +++ b/src/view/dashboard/components/notice.vue @@ -0,0 +1,80 @@ + + + + + + + diff --git a/src/view/dashboard/components/pluginTable.vue b/src/view/dashboard/components/pluginTable.vue new file mode 100644 index 0000000..e131cb9 --- /dev/null +++ b/src/view/dashboard/components/pluginTable.vue @@ -0,0 +1,66 @@ + + + + + + + diff --git a/src/view/dashboard/components/quickLinks.vue b/src/view/dashboard/components/quickLinks.vue new file mode 100644 index 0000000..5619b88 --- /dev/null +++ b/src/view/dashboard/components/quickLinks.vue @@ -0,0 +1,111 @@ + + + + + diff --git a/src/view/dashboard/components/table.vue b/src/view/dashboard/components/table.vue new file mode 100644 index 0000000..47c8dde --- /dev/null +++ b/src/view/dashboard/components/table.vue @@ -0,0 +1,52 @@ + + + + + + + diff --git a/src/view/dashboard/components/wiki.vue b/src/view/dashboard/components/wiki.vue new file mode 100644 index 0000000..eea7240 --- /dev/null +++ b/src/view/dashboard/components/wiki.vue @@ -0,0 +1,45 @@ + + + + + + + diff --git a/src/view/dashboard/index.vue b/src/view/dashboard/index.vue new file mode 100644 index 0000000..353bca6 --- /dev/null +++ b/src/view/dashboard/index.vue @@ -0,0 +1,77 @@ + + + + + diff --git a/src/view/error/index.vue b/src/view/error/index.vue new file mode 100644 index 0000000..1f0079f --- /dev/null +++ b/src/view/error/index.vue @@ -0,0 +1,37 @@ + + + diff --git a/src/view/error/reload.vue b/src/view/error/reload.vue new file mode 100644 index 0000000..1fd027e --- /dev/null +++ b/src/view/error/reload.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/view/example/breakpoint/breakpoint.vue b/src/view/example/breakpoint/breakpoint.vue new file mode 100644 index 0000000..dbda33d --- /dev/null +++ b/src/view/example/breakpoint/breakpoint.vue @@ -0,0 +1,340 @@ + + + + + \ No newline at end of file diff --git a/src/view/example/customer/customer.vue b/src/view/example/customer/customer.vue new file mode 100644 index 0000000..f4a3104 --- /dev/null +++ b/src/view/example/customer/customer.vue @@ -0,0 +1,215 @@ + + + + + diff --git a/src/view/example/index.vue b/src/view/example/index.vue new file mode 100644 index 0000000..0c3b58d --- /dev/null +++ b/src/view/example/index.vue @@ -0,0 +1,19 @@ + + + diff --git a/src/view/example/upload/scanUpload.vue b/src/view/example/upload/scanUpload.vue new file mode 100644 index 0000000..59845d7 --- /dev/null +++ b/src/view/example/upload/scanUpload.vue @@ -0,0 +1,245 @@ + + + + + + + diff --git a/src/view/example/upload/upload.vue b/src/view/example/upload/upload.vue new file mode 100644 index 0000000..eae676a --- /dev/null +++ b/src/view/example/upload/upload.vue @@ -0,0 +1,448 @@ + + + diff --git a/src/view/init/index.vue b/src/view/init/index.vue new file mode 100644 index 0000000..211ec4a --- /dev/null +++ b/src/view/init/index.vue @@ -0,0 +1,368 @@ + + + + + diff --git a/src/view/layout/aside/asideComponent/asyncSubmenu.vue b/src/view/layout/aside/asideComponent/asyncSubmenu.vue new file mode 100644 index 0000000..b9c4bf4 --- /dev/null +++ b/src/view/layout/aside/asideComponent/asyncSubmenu.vue @@ -0,0 +1,66 @@ + + + + + diff --git a/src/view/layout/aside/asideComponent/index.vue b/src/view/layout/aside/asideComponent/index.vue new file mode 100644 index 0000000..32e7d41 --- /dev/null +++ b/src/view/layout/aside/asideComponent/index.vue @@ -0,0 +1,47 @@ + + + diff --git a/src/view/layout/aside/asideComponent/menuItem.vue b/src/view/layout/aside/asideComponent/menuItem.vue new file mode 100644 index 0000000..b6b4ff7 --- /dev/null +++ b/src/view/layout/aside/asideComponent/menuItem.vue @@ -0,0 +1,43 @@ + + + + + diff --git a/src/view/layout/aside/combinationMode.vue b/src/view/layout/aside/combinationMode.vue new file mode 100644 index 0000000..3e588ce --- /dev/null +++ b/src/view/layout/aside/combinationMode.vue @@ -0,0 +1,146 @@ + + diff --git a/src/view/layout/aside/headMode.vue b/src/view/layout/aside/headMode.vue new file mode 100644 index 0000000..dd8295f --- /dev/null +++ b/src/view/layout/aside/headMode.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/src/view/layout/aside/index.vue b/src/view/layout/aside/index.vue new file mode 100644 index 0000000..c5e010a --- /dev/null +++ b/src/view/layout/aside/index.vue @@ -0,0 +1,34 @@ + + + diff --git a/src/view/layout/aside/normalMode.vue b/src/view/layout/aside/normalMode.vue new file mode 100644 index 0000000..8c0fae1 --- /dev/null +++ b/src/view/layout/aside/normalMode.vue @@ -0,0 +1,120 @@ + + + + + diff --git a/src/view/layout/header/index.vue b/src/view/layout/header/index.vue new file mode 100644 index 0000000..bf7b5be --- /dev/null +++ b/src/view/layout/header/index.vue @@ -0,0 +1,140 @@ + + + + + + + diff --git a/src/view/layout/header/tools.vue b/src/view/layout/header/tools.vue new file mode 100644 index 0000000..deba8d8 --- /dev/null +++ b/src/view/layout/header/tools.vue @@ -0,0 +1,192 @@ + + + + + + + diff --git a/src/view/layout/iframe.vue b/src/view/layout/iframe.vue new file mode 100644 index 0000000..137b520 --- /dev/null +++ b/src/view/layout/iframe.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/src/view/layout/index.vue b/src/view/layout/index.vue new file mode 100644 index 0000000..8ce52a2 --- /dev/null +++ b/src/view/layout/index.vue @@ -0,0 +1,114 @@ + + + + + diff --git a/src/view/layout/screenfull/index.vue b/src/view/layout/screenfull/index.vue new file mode 100644 index 0000000..da91a50 --- /dev/null +++ b/src/view/layout/screenfull/index.vue @@ -0,0 +1,62 @@ + + + + + diff --git a/src/view/layout/search/search.vue b/src/view/layout/search/search.vue new file mode 100644 index 0000000..5375d70 --- /dev/null +++ b/src/view/layout/search/search.vue @@ -0,0 +1,98 @@ + + + + diff --git a/src/view/layout/setting/index.vue b/src/view/layout/setting/index.vue new file mode 100644 index 0000000..12a7f2a --- /dev/null +++ b/src/view/layout/setting/index.vue @@ -0,0 +1,212 @@ + + + + + diff --git a/src/view/layout/setting/title.vue b/src/view/layout/setting/title.vue new file mode 100644 index 0000000..ea536ad --- /dev/null +++ b/src/view/layout/setting/title.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/src/view/layout/tabs/index.vue b/src/view/layout/tabs/index.vue new file mode 100644 index 0000000..4ad54f3 --- /dev/null +++ b/src/view/layout/tabs/index.vue @@ -0,0 +1,425 @@ + + + + + + diff --git a/src/view/login/index.vue b/src/view/login/index.vue new file mode 100644 index 0000000..4870b8a --- /dev/null +++ b/src/view/login/index.vue @@ -0,0 +1,238 @@ + + + diff --git a/src/view/person/person.vue b/src/view/person/person.vue new file mode 100644 index 0000000..9920aae --- /dev/null +++ b/src/view/person/person.vue @@ -0,0 +1,631 @@ + + + + + diff --git a/src/view/routerHolder.vue b/src/view/routerHolder.vue new file mode 100644 index 0000000..1b671ab --- /dev/null +++ b/src/view/routerHolder.vue @@ -0,0 +1,22 @@ + + + + diff --git a/src/view/superAdmin/api/api.vue b/src/view/superAdmin/api/api.vue new file mode 100644 index 0000000..21e971c --- /dev/null +++ b/src/view/superAdmin/api/api.vue @@ -0,0 +1,832 @@ + + + + + diff --git a/src/view/superAdmin/authority/authority.vue b/src/view/superAdmin/authority/authority.vue new file mode 100644 index 0000000..0774141 --- /dev/null +++ b/src/view/superAdmin/authority/authority.vue @@ -0,0 +1,422 @@ + + + + + diff --git a/src/view/superAdmin/authority/components/apis.vue b/src/view/superAdmin/authority/components/apis.vue new file mode 100644 index 0000000..ea17645 --- /dev/null +++ b/src/view/superAdmin/authority/components/apis.vue @@ -0,0 +1,174 @@ + + + diff --git a/src/view/superAdmin/authority/components/datas.vue b/src/view/superAdmin/authority/components/datas.vue new file mode 100644 index 0000000..71e4d5b --- /dev/null +++ b/src/view/superAdmin/authority/components/datas.vue @@ -0,0 +1,145 @@ + + + diff --git a/src/view/superAdmin/authority/components/menus.vue b/src/view/superAdmin/authority/components/menus.vue new file mode 100644 index 0000000..8e2d1c6 --- /dev/null +++ b/src/view/superAdmin/authority/components/menus.vue @@ -0,0 +1,233 @@ + + + + + diff --git a/src/view/superAdmin/dictionary/sysDictionary.vue b/src/view/superAdmin/dictionary/sysDictionary.vue new file mode 100644 index 0000000..dcb273d --- /dev/null +++ b/src/view/superAdmin/dictionary/sysDictionary.vue @@ -0,0 +1,255 @@ + + + + + diff --git a/src/view/superAdmin/dictionary/sysDictionaryDetail.vue b/src/view/superAdmin/dictionary/sysDictionaryDetail.vue new file mode 100644 index 0000000..a03229f --- /dev/null +++ b/src/view/superAdmin/dictionary/sysDictionaryDetail.vue @@ -0,0 +1,321 @@ + + + + + diff --git a/src/view/superAdmin/index.vue b/src/view/superAdmin/index.vue new file mode 100644 index 0000000..4e148d1 --- /dev/null +++ b/src/view/superAdmin/index.vue @@ -0,0 +1,20 @@ + + + diff --git a/src/view/superAdmin/menu/components/components-cascader.vue b/src/view/superAdmin/menu/components/components-cascader.vue new file mode 100644 index 0000000..e7de000 --- /dev/null +++ b/src/view/superAdmin/menu/components/components-cascader.vue @@ -0,0 +1,131 @@ + + + + + diff --git a/src/view/superAdmin/menu/icon.vue b/src/view/superAdmin/menu/icon.vue new file mode 100644 index 0000000..d67124e --- /dev/null +++ b/src/view/superAdmin/menu/icon.vue @@ -0,0 +1,1179 @@ + + + + + diff --git a/src/view/superAdmin/menu/menu.vue b/src/view/superAdmin/menu/menu.vue new file mode 100644 index 0000000..ec4a7e0 --- /dev/null +++ b/src/view/superAdmin/menu/menu.vue @@ -0,0 +1,680 @@ + + + + + diff --git a/src/view/superAdmin/operation/sysOperationRecord.vue b/src/view/superAdmin/operation/sysOperationRecord.vue new file mode 100644 index 0000000..27764c1 --- /dev/null +++ b/src/view/superAdmin/operation/sysOperationRecord.vue @@ -0,0 +1,277 @@ + + + + + diff --git a/src/view/superAdmin/params/sysParams.vue b/src/view/superAdmin/params/sysParams.vue new file mode 100644 index 0000000..89fe6f9 --- /dev/null +++ b/src/view/superAdmin/params/sysParams.vue @@ -0,0 +1,604 @@ + + + + + diff --git a/src/view/superAdmin/user/user.vue b/src/view/superAdmin/user/user.vue new file mode 100644 index 0000000..1561ef1 --- /dev/null +++ b/src/view/superAdmin/user/user.vue @@ -0,0 +1,524 @@ + + + + + diff --git a/src/view/system/state.vue b/src/view/system/state.vue new file mode 100644 index 0000000..e54eeb9 --- /dev/null +++ b/src/view/system/state.vue @@ -0,0 +1,192 @@ + + + + diff --git a/src/view/systemTools/autoCode/component/fieldDialog.vue b/src/view/systemTools/autoCode/component/fieldDialog.vue new file mode 100644 index 0000000..8f130e7 --- /dev/null +++ b/src/view/systemTools/autoCode/component/fieldDialog.vue @@ -0,0 +1,502 @@ + + + diff --git a/src/view/systemTools/autoCode/component/previewCodeDialog.vue b/src/view/systemTools/autoCode/component/previewCodeDialog.vue new file mode 100644 index 0000000..aa9c030 --- /dev/null +++ b/src/view/systemTools/autoCode/component/previewCodeDialog.vue @@ -0,0 +1,119 @@ + + + diff --git a/src/view/systemTools/autoCode/index.vue b/src/view/systemTools/autoCode/index.vue new file mode 100644 index 0000000..a1a9cff --- /dev/null +++ b/src/view/systemTools/autoCode/index.vue @@ -0,0 +1,1685 @@ + + + + + diff --git a/src/view/systemTools/autoCodeAdmin/index.vue b/src/view/systemTools/autoCodeAdmin/index.vue new file mode 100644 index 0000000..18bb089 --- /dev/null +++ b/src/view/systemTools/autoCodeAdmin/index.vue @@ -0,0 +1,620 @@ + + + diff --git a/src/view/systemTools/autoPkg/autoPkg.vue b/src/view/systemTools/autoPkg/autoPkg.vue new file mode 100644 index 0000000..4ef2c5a --- /dev/null +++ b/src/view/systemTools/autoPkg/autoPkg.vue @@ -0,0 +1,205 @@ + + + diff --git a/src/view/systemTools/exportTemplate/code.js b/src/view/systemTools/exportTemplate/code.js new file mode 100644 index 0000000..98823ee --- /dev/null +++ b/src/view/systemTools/exportTemplate/code.js @@ -0,0 +1,32 @@ +export const getCode = (templateID) => { + return ` + +` +} diff --git a/src/view/systemTools/exportTemplate/exportTemplate.vue b/src/view/systemTools/exportTemplate/exportTemplate.vue new file mode 100644 index 0000000..9136556 --- /dev/null +++ b/src/view/systemTools/exportTemplate/exportTemplate.vue @@ -0,0 +1,996 @@ + + + + + diff --git a/src/view/systemTools/formCreate/index.vue b/src/view/systemTools/formCreate/index.vue new file mode 100644 index 0000000..7e266f9 --- /dev/null +++ b/src/view/systemTools/formCreate/index.vue @@ -0,0 +1,18 @@ + + + diff --git a/src/view/systemTools/index.vue b/src/view/systemTools/index.vue new file mode 100644 index 0000000..697d431 --- /dev/null +++ b/src/view/systemTools/index.vue @@ -0,0 +1,20 @@ + + + diff --git a/src/view/systemTools/installPlugin/index.vue b/src/view/systemTools/installPlugin/index.vue new file mode 100644 index 0000000..ce88c5c --- /dev/null +++ b/src/view/systemTools/installPlugin/index.vue @@ -0,0 +1,42 @@ + + + diff --git a/src/view/systemTools/pubPlug/pubPlug.vue b/src/view/systemTools/pubPlug/pubPlug.vue new file mode 100644 index 0000000..b16eaf2 --- /dev/null +++ b/src/view/systemTools/pubPlug/pubPlug.vue @@ -0,0 +1,225 @@ + + + + + diff --git a/src/view/systemTools/system/system.vue b/src/view/systemTools/system/system.vue new file mode 100644 index 0000000..dfbc913 --- /dev/null +++ b/src/view/systemTools/system/system.vue @@ -0,0 +1,1085 @@ + + + + + diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..35531e0 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,23 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'], + important: true, + theme: { + extend: { + backgroundColor: { + main: '#F5F5F5' + }, + textColor: { + active: 'var(--el-color-primary)' + }, + boxShadowColor: { + active: 'var(--el-color-primary)' + }, + borderColor: { + 'table-border': 'var(--el-border-color-lighter)' + } + } + }, + darkMode: 'class', + plugins: [] +} diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..b35c7e9 --- /dev/null +++ b/vite.config.js @@ -0,0 +1,113 @@ +import legacyPlugin from '@vitejs/plugin-legacy' +import Banner from 'vite-plugin-banner' +import * as path from 'path' +import * as dotenv from 'dotenv' +import * as fs from 'fs' +import vuePlugin from '@vitejs/plugin-vue' +import vueDevTools from 'vite-plugin-vue-devtools' +import VueFilePathPlugin from './vitePlugin/componentName/index.js' +import { svgBuilder } from 'vite-auto-import-svg' +import { AddSecret } from './vitePlugin/secret' +// @see https://cn.vitejs.dev/config/ +export default ({ mode }) => { + AddSecret('') + const NODE_ENV = mode || 'development' + const envFiles = [`.env.${NODE_ENV}`] + for (const file of envFiles) { + const envConfig = dotenv.parse(fs.readFileSync(file)) + for (const k in envConfig) { + process.env[k] = envConfig[k] + } + } + + const timestamp = Date.parse(new Date()) + + const optimizeDeps = {} + + const alias = { + '@': path.resolve(__dirname, './src'), + vue$: 'vue/dist/vue.runtime.esm-bundler.js' + } + + const esbuild = {} + + const rollupOptions = { + output: { + entryFileNames: 'assets/087AC4D233B64EB0[name].[hash].js', + chunkFileNames: 'assets/087AC4D233B64EB0[name].[hash].js', + assetFileNames: 'assets/087AC4D233B64EB0[name].[hash].[ext]' + } + } + + const config = { + base: '/', // 编译后js导入的资源路径 + root: './', // index.html文件所在位置 + publicDir: 'public', // 静态资源文件夹 + resolve: { + alias + }, + define: { + 'process.env': {} + }, + css: { + preprocessorOptions: { + scss: { + api: 'modern-compiler' // or "modern" + } + } + }, + server: { + // 如果使用docker-compose开发模式,设置为false + open: true, + port: process.env.VITE_CLI_PORT, + proxy: { + // 把key的路径代理到target位置 + // detail: https://cli.vuejs.org/config/#devserver-proxy + [process.env.VITE_BASE_API]: { + // 需要代理的路径 例如 '/api' + target: `${process.env.VITE_BASE_PATH}:${process.env.VITE_SERVER_PORT}/`, // 代理到 目标路径 + changeOrigin: true, + rewrite: (path) => + path.replace(new RegExp('^' + process.env.VITE_BASE_API), '') + } + }, + allowedHosts: ['all','lckt.echol.top'], + }, + build: { + minify: 'terser', // 是否进行压缩,boolean | 'terser' | 'esbuild',默认使用terser + manifest: false, // 是否产出manifest.json + sourcemap: false, // 是否产出sourcemap.json + outDir: 'dist', // 产出目录 + terserOptions: { + compress: { + //生产环境时移除console + drop_console: true, + drop_debugger: true + } + }, + rollupOptions + }, + esbuild, + optimizeDeps, + plugins: [ + process.env.VITE_POSITION === 'open' && + vueDevTools({ launchEditor: process.env.VITE_EDITOR }), + legacyPlugin({ + targets: [ + 'Android > 39', + 'Chrome >= 60', + 'Safari >= 10.1', + 'iOS >= 10.3', + 'Firefox >= 54', + 'Edge >= 15' + ] + }), + vuePlugin(), + svgBuilder('./src/assets/icons/'), + svgBuilder('./src/plugin/'), + [Banner(`\n Build based on gin-vue-admin \n Time : ${timestamp}`)], + VueFilePathPlugin('./src/pathInfo.json') + ] + } + return config +} diff --git a/vitePlugin/componentName/index.js b/vitePlugin/componentName/index.js new file mode 100644 index 0000000..bae9f0f --- /dev/null +++ b/vitePlugin/componentName/index.js @@ -0,0 +1,85 @@ +import fs from 'fs' +import path from 'path' +import chokidar from 'chokidar' + +const toPascalCase = (str) => { + return str.replace(/(^\w|-\w)/g, clearAndUpper) +} + +const clearAndUpper = (text) => { + return text.replace(/-/, '').toUpperCase() +} + +// 递归获取目录下所有的 .vue 文件 +const getAllVueFiles = (dir, fileList = []) => { + const files = fs.readdirSync(dir) + files.forEach((file) => { + const filePath = path.join(dir, file) + if (fs.statSync(filePath).isDirectory()) { + getAllVueFiles(filePath, fileList) + } else if (filePath.endsWith('.vue')) { + fileList.push(filePath) + } + }) + return fileList +} + +// 从 .vue 文件内容中提取组件名称 +const extractComponentName = (fileContent) => { + const regex = /defineOptions\(\s*{\s*name:\s*["']([^"']+)["']/ + const match = fileContent.match(regex) + return match ? match[1] : null +} + +// Vite 插件定义 +const vueFilePathPlugin = (outputFilePath) => { + let root + + const generatePathNameMap = () => { + const vueFiles = [ + ...getAllVueFiles(path.join(root, 'src/view')), + ...getAllVueFiles(path.join(root, 'src/plugin')) + ] + const pathNameMap = vueFiles.reduce((acc, filePath) => { + const content = fs.readFileSync(filePath, 'utf-8') + const componentName = extractComponentName(content) + let relativePath = '/' + path.relative(root, filePath).replace(/\\/g, '/') + acc[relativePath] = + componentName || toPascalCase(path.basename(filePath, '.vue')) + return acc + }, {}) + const outputContent = JSON.stringify(pathNameMap, null, 2) + fs.writeFileSync(outputFilePath, outputContent) + } + + const watchDirectoryChanges = () => { + const watchDirectories = [ + path.join(root, 'src/view'), + path.join(root, 'src/plugin') + ] + const watcher = chokidar.watch(watchDirectories, { + persistent: true, + ignoreInitial: true + }) + watcher.on('all', () => { + generatePathNameMap() + }) + } + + return { + name: 'vue-file-path-plugin', + configResolved(resolvedConfig) { + root = resolvedConfig.root + }, + buildStart() { + generatePathNameMap() + }, + buildEnd() { + if (process.env.NODE_ENV === 'development') { + watchDirectoryChanges() + } + } + } +} + +export default vueFilePathPlugin diff --git a/vitePlugin/secret/index.js b/vitePlugin/secret/index.js new file mode 100644 index 0000000..93a8464 --- /dev/null +++ b/vitePlugin/secret/index.js @@ -0,0 +1,6 @@ +export function AddSecret(secret) { + if (!secret) { + secret = '' + } + global['gva-secret'] = secret +}