@ -0,0 +1,19 @@ |
|||
root = true |
|||
|
|||
[*] |
|||
charset=utf-8 |
|||
end_of_line=lf |
|||
insert_final_newline=true |
|||
indent_style=space |
|||
indent_size=2 |
|||
max_line_length = 100 |
|||
|
|||
[*.{yml,yaml,json}] |
|||
indent_style = space |
|||
indent_size = 2 |
|||
|
|||
[*.md] |
|||
trim_trailing_whitespace = false |
|||
|
|||
[Makefile] |
|||
indent_style = tab |
@ -0,0 +1,23 @@ |
|||
# port |
|||
VITE_PORT = 3200 |
|||
|
|||
# 网站标题 |
|||
# VITE_GLOB_APP_TITLE = 企业级低代码平台 |
|||
VITE_GLOB_APP_TITLE=边海防智能监控站 |
|||
|
|||
# 简称,用于配置文件名字 不要出现空格、数字开头等特殊字符 |
|||
VITE_GLOB_APP_SHORT_NAME = JeecgBootAdmin |
|||
|
|||
# 单点登录服务端地址 |
|||
VITE_GLOB_APP_CAS_BASE_URL=http://cas.test.com:8443/cas |
|||
|
|||
# 是否开启单点登录 |
|||
VITE_GLOB_APP_OPEN_SSO = false |
|||
|
|||
# 开启微前端模式 |
|||
VITE_GLOB_APP_OPEN_QIANKUN=true |
|||
|
|||
# 文件预览地址 |
|||
VITE_GLOB_ONLINE_VIEW_URL=http://fileview.jeecg.com/onlinePreview |
|||
|
|||
|
@ -0,0 +1,46 @@ |
|||
### |
|||
# @Author: Fuyuu 1805498209@qq.com |
|||
# @Date: 2023-11-24 10:15:22 |
|||
# @LastEditors: Fuyuu 1805498209@qq.com |
|||
# @LastEditTime: 2023-11-24 18:10:19 |
|||
# @FilePath: \dt-admin-pc\.env.development |
|||
# @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE |
|||
### |
|||
# 是否打开mock |
|||
VITE_USE_MOCK = true |
|||
|
|||
# 发布路径 |
|||
VITE_PUBLIC_PATH = / |
|||
|
|||
# 跨域代理,您可以配置多个 ,请注意,没有换行符 |
|||
# VITE_PROXY = [["/jeecgboot","http://localhost:8088/military"],["/upload","http://localhost:3300/upload"]] |
|||
VITE_PROXY = [["/dt","http://192.168.1.174:8088/dt"],["/upload","http://localhost:3300/upload"]] |
|||
|
|||
# 控制台不输出 |
|||
VITE_DROP_CONSOLE = false |
|||
|
|||
#后台接口父地址(必填) |
|||
VITE_GLOB_API_URL=/dt |
|||
|
|||
#后台接口全路径地址(必填) |
|||
# VITE_GLOB_DOMAIN_URL=http://localhost:8088/jmilitary |
|||
VITE_GLOB_DOMAIN_URL=http://192.168.1.174:8088/dt |
|||
|
|||
# 接口前缀 |
|||
VITE_GLOB_API_URL_PREFIX= |
|||
|
|||
#微前端qiankun应用,命名必须以VITE_APP_SUB_开头,jeecg-app-1为子应用的项目名称,也是子应用的路由父路径 |
|||
VITE_APP_SUB_jeecg-app-1 = '//localhost:8092' |
|||
|
|||
#地图地址 |
|||
VITE_GLOB_EARTHMAP_URL=/dt |
|||
#地图地址-卫星 |
|||
VITE_GLOB_SATELLITE_URL=/mapTile/satellite_ny/ |
|||
#地图地址-矢量 |
|||
VITE_GLOB_VECTOR_URL=/mapTile/vector_ny/ |
|||
#地图地址-地形 |
|||
VITE_GLOB_TERRAIN_URL=/mapTile/terrain_ny/ |
|||
#静态资源 |
|||
#VITE_GLOB_STATICDOMAIN_URL=VITE_GLOB_DOMAIN_URL + '/sys/common/static' |
|||
|
|||
|
@ -0,0 +1,42 @@ |
|||
### |
|||
# @Author: Fuyuu 1805498209@qq.com |
|||
# @Date: 2023-11-24 10:15:22 |
|||
# @LastEditors: Fuyuu 1805498209@qq.com |
|||
# @LastEditTime: 2023-11-28 14:15:57 |
|||
# @FilePath: \dt-admin-pc\.env.production |
|||
# @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE |
|||
### |
|||
# 是否启用mock |
|||
VITE_USE_MOCK = true |
|||
|
|||
# 发布路径 |
|||
VITE_PUBLIC_PATH = / |
|||
|
|||
# 控制台不输出 |
|||
VITE_DROP_CONSOLE = true |
|||
|
|||
# 是否启用gzip或brotli压缩 |
|||
# 选项值: gzip | brotli | none |
|||
# 如果需要多个可以使用“,”分隔 |
|||
VITE_BUILD_COMPRESS = 'gzip' |
|||
|
|||
# 使用压缩时是否删除原始文件,默认为false |
|||
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false |
|||
|
|||
#后台接口父地址(必填) |
|||
VITE_GLOB_API_URL=http://192.168.1.174:8088/dt/ |
|||
|
|||
#后台接口全路径地址(必填) |
|||
VITE_GLOB_DOMAIN_URL=http://192.168.1.174:8088/dt/ |
|||
|
|||
# 接口父路径前缀 |
|||
VITE_GLOB_API_URL_PREFIX= |
|||
|
|||
# 是否启用图像压缩 |
|||
VITE_USE_IMAGEMIN= true |
|||
|
|||
# 使用pwa |
|||
VITE_USE_PWA = false |
|||
|
|||
# 是否兼容旧浏览器 |
|||
VITE_LEGACY = false |
@ -0,0 +1,34 @@ |
|||
# 是否启用mock |
|||
VITE_USE_MOCK = true |
|||
|
|||
# 发布路径 |
|||
VITE_PUBLIC_PATH = / |
|||
|
|||
# 控制台不输出 |
|||
VITE_DROP_CONSOLE = true |
|||
|
|||
# 是否启用gzip或brotli压缩 |
|||
# 选项值: gzip | brotli | none |
|||
# 如果需要多个可以使用“,”分隔 |
|||
VITE_BUILD_COMPRESS = 'gzip' |
|||
|
|||
# 使用压缩时是否删除原始文件,默认为false |
|||
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false |
|||
|
|||
#后台接口父地址(必填) |
|||
VITE_GLOB_API_URL=/jeecgboot |
|||
|
|||
#后台接口全路径地址(必填) |
|||
VITE_GLOB_DOMAIN_URL=http://localhost:8080/jeecg-boot |
|||
|
|||
# 接口父路径前缀 |
|||
VITE_GLOB_API_URL_PREFIX= |
|||
|
|||
# 是否启用图像压缩 |
|||
VITE_USE_IMAGEMIN= true |
|||
|
|||
# 使用pwa |
|||
VITE_USE_PWA = false |
|||
|
|||
# 是否兼容旧浏览器 |
|||
VITE_LEGACY = false |
@ -0,0 +1,15 @@ |
|||
|
|||
*.sh |
|||
node_modules |
|||
*.md |
|||
*.woff |
|||
*.ttf |
|||
.vscode |
|||
.idea |
|||
dist |
|||
/public |
|||
/docs |
|||
.husky |
|||
.local |
|||
/bin |
|||
Dockerfile |
@ -0,0 +1,81 @@ |
|||
// @ts-check
|
|||
const { defineConfig } = require('eslint-define-config'); |
|||
module.exports = defineConfig({ |
|||
root: true, |
|||
env: { |
|||
browser: true, |
|||
node: true, |
|||
es6: true, |
|||
}, |
|||
globals:{ |
|||
"Cesium": true |
|||
}, |
|||
parser: 'vue-eslint-parser', |
|||
parserOptions: { |
|||
parser: '@typescript-eslint/parser', |
|||
ecmaVersion: 2020, |
|||
sourceType: 'module', |
|||
jsxPragma: 'React', |
|||
ecmaFeatures: { |
|||
jsx: true, |
|||
}, |
|||
}, |
|||
extends: [ |
|||
'plugin:vue/vue3-recommended', |
|||
'plugin:@typescript-eslint/recommended', |
|||
'prettier', |
|||
'plugin:prettier/recommended', |
|||
'plugin:jest/recommended', |
|||
], |
|||
rules: { |
|||
'vue/script-setup-uses-vars': 'error', |
|||
'@typescript-eslint/ban-ts-ignore': 'off', |
|||
'@typescript-eslint/explicit-function-return-type': 'off', |
|||
'@typescript-eslint/no-explicit-any': 'off', |
|||
'@typescript-eslint/no-var-requires': 'off', |
|||
'@typescript-eslint/no-empty-function': 'off', |
|||
'vue/custom-event-name-casing': 'off', |
|||
'no-use-before-define': 'off', |
|||
'@typescript-eslint/no-use-before-define': 'off', |
|||
'@typescript-eslint/ban-ts-comment': 'off', |
|||
'@typescript-eslint/ban-types': 'off', |
|||
'@typescript-eslint/no-non-null-assertion': 'off', |
|||
'@typescript-eslint/explicit-module-boundary-types': 'off', |
|||
'@typescript-eslint/no-unused-vars': [ |
|||
'error', |
|||
{ |
|||
argsIgnorePattern: '^_', |
|||
varsIgnorePattern: '^_', |
|||
}, |
|||
], |
|||
'no-unused-vars': [ |
|||
'error', |
|||
{ |
|||
argsIgnorePattern: '^_', |
|||
varsIgnorePattern: '^_', |
|||
}, |
|||
], |
|||
'space-before-function-paren': 'off', |
|||
|
|||
'vue/attributes-order': 'off', |
|||
'vue/one-component-per-file': 'off', |
|||
'vue/html-closing-bracket-newline': 'off', |
|||
'vue/max-attributes-per-line': 'off', |
|||
'vue/multiline-html-element-content-newline': 'off', |
|||
'vue/singleline-html-element-content-newline': 'off', |
|||
'vue/attribute-hyphenation': 'off', |
|||
'vue/require-default-prop': 'off', |
|||
'vue/html-self-closing': [ |
|||
'error', |
|||
{ |
|||
html: { |
|||
void: 'always', |
|||
normal: 'never', |
|||
component: 'always', |
|||
}, |
|||
svg: 'always', |
|||
math: 'always', |
|||
}, |
|||
], |
|||
}, |
|||
}); |
@ -0,0 +1,35 @@ |
|||
node_modules |
|||
.DS_Store |
|||
.github |
|||
dist |
|||
dist_electron |
|||
.npmrc |
|||
.cache |
|||
|
|||
tests/server/static |
|||
tests/server/static/upload |
|||
|
|||
.local |
|||
# local env files |
|||
.env.local |
|||
.env.*.local |
|||
.eslintcache |
|||
|
|||
# Log files |
|||
npm-debug.log* |
|||
yarn-debug.log* |
|||
yarn-error.log* |
|||
pnpm-debug.log* |
|||
|
|||
# Editor directories and files |
|||
.idea |
|||
# .vscode |
|||
*.suo |
|||
*.ntvs* |
|||
*.njsproj |
|||
*.sln |
|||
*.sw? |
|||
/os_del.cmd |
|||
/.vscode/ |
|||
/.history/ |
|||
/svn clear.bat |
@ -0,0 +1,6 @@ |
|||
ports: |
|||
- port: 3344 |
|||
onOpen: open-preview |
|||
tasks: |
|||
- init: yarn |
|||
command: yarn dev |
@ -0,0 +1,9 @@ |
|||
/dist/* |
|||
.local |
|||
.output.js |
|||
/node_modules/** |
|||
|
|||
**/*.svg |
|||
**/*.sh |
|||
|
|||
/public/* |
@ -0,0 +1,3 @@ |
|||
/dist/* |
|||
/public/* |
|||
public/* |
@ -0,0 +1,48 @@ |
|||
# test directories |
|||
__tests__ |
|||
test |
|||
tests |
|||
powered-test |
|||
|
|||
# asset directories |
|||
docs |
|||
doc |
|||
website |
|||
images |
|||
assets |
|||
|
|||
# examples |
|||
example |
|||
examples |
|||
|
|||
# code coverage directories |
|||
coverage |
|||
.nyc_output |
|||
|
|||
# build scripts |
|||
Makefile |
|||
Gulpfile.js |
|||
Gruntfile.js |
|||
|
|||
# configs |
|||
appveyor.yml |
|||
circle.yml |
|||
codeship-services.yml |
|||
codeship-steps.yml |
|||
wercker.yml |
|||
.tern-project |
|||
.gitattributes |
|||
.editorconfig |
|||
.*ignore |
|||
.eslintrc |
|||
.jshintrc |
|||
.flowconfig |
|||
.documentup.json |
|||
.yarn-metadata.json |
|||
.travis.yml |
|||
|
|||
# misc |
|||
*.md |
|||
|
|||
!istanbul-reports/lib/html/assets |
|||
!istanbul-api/node_modules/istanbul-reports/lib/html/assets |
@ -0,0 +1,30 @@ |
|||
FROM nginx |
|||
MAINTAINER jeecgos@163.com |
|||
VOLUME /tmp |
|||
ENV LANG en_US.UTF-8 |
|||
RUN echo "server { \ |
|||
listen 80; \ |
|||
location /jeecgboot/ { \ |
|||
proxy_pass http://jeecg-boot-system:8080/jeecg-boot/; \ |
|||
proxy_redirect off; \ |
|||
proxy_set_header Host jeecg-boot-system; \ |
|||
proxy_set_header X-Real-IP \$remote_addr; \ |
|||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; \ |
|||
} \ |
|||
#解决Router(mode: 'history')模式下,刷新路由地址不能找到页面的问题 \ |
|||
location / { \ |
|||
root /var/www/html/; \ |
|||
index index.html index.htm; \ |
|||
if (!-e \$request_filename) { \ |
|||
rewrite ^(.*)\$ /index.html?s=\$1 last; \ |
|||
break; \ |
|||
} \ |
|||
} \ |
|||
access_log /var/log/nginx/access.log ; \ |
|||
} " > /etc/nginx/conf.d/default.conf \ |
|||
&& mkdir -p /var/www \ |
|||
&& mkdir -p /var/www/html |
|||
|
|||
ADD dist/ /var/www/html/ |
|||
EXPOSE 80 |
|||
EXPOSE 443 |
@ -1,9 +1,32 @@ |
|||
MIT License |
|||
|
|||
Copyright (c) <year> <copyright holders> |
|||
Copyright (c) 2020-present, Jeecg |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is |
|||
furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. |
|||
The above copyright notice and this permission notice shall be included in all |
|||
copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|||
SOFTWARE. |
|||
|
|||
|
|||
|
|||
开源协议补充 |
|||
JeecgBoot 是由 北京敲敲云科技有限公司 发行的软件。 总部位于北京,地址:中国·北京·朝阳区科荟前街1号院奥林佳泰大厦。邮箱:jeecgos@163.com |
|||
本软件受适用的国家软件著作权法(包括国际条约)和双重保护许可。 |
|||
|
|||
1.允许基于本平台软件开展业务系统开发。 |
|||
2.不得基于该平台软件的基础,修改包装成一个与JeecgBoot平台软件功能类似的产品进行发布、销售,或与JeecgBoot参与同类软件产品市场的竞争。 |
|||
违反此条款属于侵权行为,须赔偿侵权经济损失,同时立即停止著作权侵权行为。 |
|||
解释权归:http://www.jeecg.com |
@ -1,4 +1,418 @@ |
|||
# dt-admin-pc-v2 |
|||
|
|||
数字孪生Web 后台dt( digital twin)2.0版本 |
|||
统一命名格式 |
|||
|
|||
|
|||
## 源码下载 |
|||
|
|||
- 后台源码 :http://192.168.1.200/lxc/dt-java.git |
|||
- 前端源码 :http://192.168.1.200/lxc/dt-admin.git |
|||
- 地图3D展示:http://192.168.1.200/lxc/dt-map-web.git |
|||
|
|||
##### 项目说明 |
|||
|
|||
| 项目名 | 说明 | |
|||
|--------------------|------------------------| |
|||
| `dt-admin` | Vue3版前端代码 | |
|||
| `dt-java` | SpringBoot后台项目(支持微服务) | |
|||
| `dt-map-web` |Cesium 项目 | |
|||
|
|||
## 技术文档 |
|||
|
|||
- 官方文档:[http://help.jeecg.com](http://help.jeecg.com) |
|||
- 官方网站: [http://www.jeecg.com](http://www.jeecg.com) |
|||
- 在线演示:[低代码演示](http://boot3.jeecg.com) | [敲敲云零代码](https://www.qiaoqiaoyun.com) |
|||
- 快速入门:[常见问题](http://help.jeecg.com/qa.html) | [入门视频](https://www.bilibili.com/video/BV1V34y187Y9 "入门视频") | [ 代码生成](http://help.jeecg.com/vue3/codegen/online.html) |
|||
|
|||
|
|||
## 安装与使用 |
|||
|
|||
|
|||
> 环境要求: 版本要求Node 14.18+ / 16+ 版本以上,不再支持 Node 12 / 13 / 15。 |
|||
> 建议使用pnpm,如果使用yarn,请用Yarn1.x版本,否则依赖可能安装不上。 |
|||
|
|||
|
|||
- Get the project code |
|||
|
|||
```bash |
|||
git clone https://github.com/jeecgboot/jeecgboot-vue3.git |
|||
``` |
|||
|
|||
- Installation dependencies |
|||
|
|||
```bash |
|||
cd jeecgboot-vue3 |
|||
|
|||
pnpm install |
|||
``` |
|||
|
|||
- 配置接口地址 `.env.development` |
|||
|
|||
```bash |
|||
VITE_PROXY = [["/jeecgboot","http://localhost:8080/jeecg-boot"],["/upload","http://localhost:3300/upload"]] |
|||
VITE_GLOB_DOMAIN_URL=http://localhost:8080/jeecg-boot |
|||
``` |
|||
|
|||
> 说明:把`http://localhost:8080/jeecg-boot` 换成自己地址,其他不用改。 |
|||
|
|||
|
|||
- run |
|||
|
|||
```bash |
|||
pnpm serve |
|||
``` |
|||
|
|||
|
|||
- build |
|||
|
|||
```bash |
|||
pnpm build |
|||
``` |
|||
|
|||
|
|||
## Docker镜像启动前端(单体模式) |
|||
|
|||
- host设置 |
|||
|
|||
>注意: 需要把`127.0.0.1`替换成真实IP 比如`192.`开头,不然后端不通。 |
|||
|
|||
```bash |
|||
127.0.0.1 jeecg-boot-system |
|||
127.0.0.1 jeecg-boot-gateway |
|||
``` |
|||
|
|||
|
|||
- 下载项目 |
|||
|
|||
```bash |
|||
git clone https://github.com/jeecgboot/jeecgboot-vue3.git |
|||
|
|||
cd jeecgboot-vue3 |
|||
``` |
|||
|
|||
- 配置接口域名 `.env.production` |
|||
|
|||
```bash |
|||
VITE_GLOB_API_URL=/jeecgboot |
|||
VITE_GLOB_DOMAIN_URL=http://jeecg-boot-system:8080/jeecg-boot |
|||
``` |
|||
后台单体启动 [见此文档](https://help.jeecg.com/java/setup/docker/up.html) |
|||
|
|||
- 编译项目 |
|||
|
|||
```bash |
|||
pnpm install |
|||
|
|||
pnpm build |
|||
``` |
|||
|
|||
- 启动容器 |
|||
```bash |
|||
docker build -t jeecgboot-vue3 . |
|||
docker run --name jeecgboot-vue3-nginx -p 80:80 -d jeecgboot-vue3 |
|||
``` |
|||
|
|||
- 访问前台 |
|||
|
|||
http://localhost |
|||
|
|||
## Docker镜像启动前端(微服务模式) |
|||
> 这里只写与单体的区别步骤 |
|||
|
|||
- 区别1. 修改后台域名 |
|||
.env.production |
|||
|
|||
```bash |
|||
VITE_GLOB_API_URL=/jeecgboot |
|||
VITE_GLOB_DOMAIN_URL=http://jeecg-boot-gateway:9999 |
|||
``` |
|||
|
|||
后台微服务启动 [见此文档](https://help.jeecg.com/java/springcloud/docker.html) |
|||
|
|||
- 区别2. 修改Dockerfile文件 |
|||
|
|||
```bash |
|||
- 把`http://jeecg-boot-system:8080/jeecg-boot`替换成 `http://jeecg-boot-gateway:9999` |
|||
- 把`jeecg-boot-system`替换成 `jeecg-boot-gateway` |
|||
``` |
|||
|
|||
- 其他与单体模式一样 |
|||
|
|||
```bash |
|||
镜像需要重现构建,最好把单体的镜像删掉,重新构建docker镜像。 |
|||
``` |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
## 入门必备 |
|||
|
|||
本项目需要一定前端基础知识,请确保掌握 Vue 的基础知识,以便能处理一些常见的问题。 建议在开发前先学一下以下内容,提前了解和学习这些知识,会对项目理解非常有帮助: |
|||
|
|||
* [JeecgBoot-Vue3文档](http://help.jeecg.com) |
|||
* [Vue3 文档](https://cn.vuejs.org/) |
|||
* [Vben文档](https://doc.vvbin.cn) |
|||
* [Ant-Design-Vue](https://www.antdv.com/docs/vue/introduce-cn/) |
|||
* [TypeScript](https://www.typescriptlang.org/) |
|||
* [Vue-router](https://router.vuejs.org/zh) |
|||
* [Es6](https://es6.ruanyifeng.com/) |
|||
* [Vitejs](https://cn.vitejs.dev/guide/) |
|||
* [Pinia(vuex替代方案)](https://pinia.esm.dev/introduction.html) |
|||
* [Vue-RFCS](https://github.com/vuejs/rfcs) |
|||
* [Vue2 迁移到 3](https://v3.vuejs.org/guide/migration/introduction.html) |
|||
* [vxetable文档](https://vxetable.cn) |
|||
* [~~WindiCss~~](https://windicss.netlify.app/) |
|||
|
|||
|
|||
## 浏览器支持 |
|||
|
|||
**本地开发**推荐使用`Chrome 最新版`浏览器,**不支持**`Chrome 90`以下版本。 |
|||
|
|||
**生产环境**支持现代浏览器,不支持 IE。 |
|||
|
|||
| [![IE](https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png)](http://godban.github.io/browsers-support-badges/)IE | [![ Edge](https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png)](http://godban.github.io/browsers-support-badges/)Edge | [![Firefox](https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png)](http://godban.github.io/browsers-support-badges/)Firefox | [![Chrome](https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png)](http://godban.github.io/browsers-support-badges/)Chrome | [![Safari](https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png)](http://godban.github.io/browsers-support-badges/)Safari | |
|||
| --- | --- | --- | --- | --- | |
|||
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions | |
|||
|
|||
|
|||
|
|||
## 功能模块 |
|||
> vue3版本已经实现了系统管理、系统监控、报表、各种组件、前端权限、GUI代码生成、Online表单、Online报表等平台功能,完全可以用于生产环境。 |
|||
|
|||
``` |
|||
├─首页 |
|||
│ ├─首页(四套首页满足不同场景需求) |
|||
│ ├─工作台 |
|||
├─系统管理 |
|||
│ ├─用户管理 |
|||
│ ├─角色管理 |
|||
│ ├─菜单管理 |
|||
│ ├─权限设置(支持按钮权限、数据权限) |
|||
│ ├─表单权限(控制字段禁用、隐藏) |
|||
│ ├─部门管理 |
|||
│ ├─我的部门(二级管理员) |
|||
│ └─字典管理 |
|||
│ └─分类字典 |
|||
│ └─系统公告 |
|||
│ └─职务管理 |
|||
│ └─通讯录 |
|||
│ └─对象存储 |
|||
│ └─多租户管理 |
|||
├─系统监控 |
|||
│ ├─网关路由配置(gateway) |
|||
│ ├─定时任务 |
|||
│ ├─数据源管理 |
|||
│ ├─系统日志 |
|||
│ ├─消息中心(支持短信、邮件、微信推送等等) |
|||
│ ├─数据日志(记录数据快照,可对比快照,查看数据变更情况) |
|||
│ ├─系统通知 |
|||
│ ├─SQL监控 |
|||
│ ├─性能监控 |
|||
│ │ ├─监控 Redis |
|||
│ │ ├─Tomcat |
|||
│ │ ├─jvm |
|||
│ │ ├─服务器信息 |
|||
│ │ ├─请求追踪 |
|||
│ │ ├─磁盘监控 |
|||
├─消息中心 |
|||
│ ├─我的消息 |
|||
│ ├─消息管理 |
|||
│ ├─模板管理 |
|||
├─积木报表设计器 |
|||
│─报表示例 |
|||
│ ├─曲线图 |
|||
│ └─饼状图 |
|||
│ └─柱状图 |
|||
│ └─折线图 |
|||
│ └─面积图 |
|||
│ └─雷达图 |
|||
│ └─仪表图 |
|||
│ └─进度条 |
|||
│ └─排名列表 |
|||
│ └─等等 |
|||
│─大屏模板 |
|||
│ ├─作战指挥中心大屏 |
|||
│ └─物流服务中心大屏 |
|||
├─代码生成器(GUI) |
|||
│ ├─代码生成器功能(一键生成前后端代码,生成后无需修改直接用,绝对是后端开发福音) |
|||
│ ├─代码生成器模板(提供4套模板,分别支持单表和一对多模型,不同风格选择) |
|||
│ ├─代码生成器模板(生成代码,自带excel导入导出) |
|||
│ ├─查询过滤器(查询逻辑无需编码,系统根据页面配置自动生成) |
|||
│ ├─高级查询器(弹窗自动组合查询条件) |
|||
│ ├─Excel导入导出工具集成(支持单表,一对多 导入导出) |
|||
│ ├─平台移动自适应支持 |
|||
│─常用示例 |
|||
│ ├─自定义组件示例 |
|||
│ ├─JVxeTable示例(ERP行业复杂排版效果) |
|||
│ ├─单表模型例子 |
|||
│ └─一对多模型例子 |
|||
│ └─打印例子 |
|||
│ └─一对多内嵌示例 |
|||
│ └─异步树Table |
|||
│ └─图片拖拽排序 |
|||
│ └─图片翻页 |
|||
│ └─图片预览 |
|||
│ └─PDF预览 |
|||
│─封装通用组件 |
|||
│ ├─行编辑表格JVxeTable |
|||
│ └─省略显示组件 |
|||
│ └─时间控件 |
|||
│ └─高级查询 (未实现) |
|||
│ └─用户选择组件 |
|||
│ └─报表组件封装 |
|||
│ └─字典组件 |
|||
│ └─下拉多选组件 |
|||
│ └─选人组件 |
|||
│ └─选部门组件 |
|||
│ └─通过部门选人组件 |
|||
│ └─封装曲线、柱状图、饼状图、折线图等等报表的组件(经过封装,使用简单) |
|||
│ └─在线code编辑器 |
|||
│ └─上传文件组件 |
|||
│ └─树列表组件 |
|||
│ └─表单禁用组件 |
|||
│ └─等等 |
|||
│─更多页面模板 |
|||
│ └─Mock示例(子菜单很多) |
|||
│ └─页面&导航(子菜单很多) |
|||
│ └─组件&功能(子菜单很多) |
|||
├─高级功能 |
|||
│ ├─支持微前端 |
|||
│ ├─提供CAS单点登录 |
|||
│ ├─集成Websocket消息通知机制 |
|||
│ ├─支持第三方登录(QQ、钉钉、微信等) |
|||
│ ├─系统编码规则 |
|||
├─Online在线开发(低代码) |
|||
│ ├─Online在线表单 - 功能已开放 |
|||
│ ├─Online代码生成器 - 功能已开放 |
|||
│ ├─Online在线报表 - 功能已开放 |
|||
│ ├─Online在线图表(暂未开源) |
|||
│ ├─多数据源管理 |
|||
│─流程模块功能 (暂未开源) |
|||
│ ├─流程设计器 |
|||
│ ├─表单设计器 |
|||
│ ├─大屏设计器 |
|||
│ ├─门户设计/仪表盘设计器 |
|||
│ └─我的任务 |
|||
│ └─历史流程 |
|||
│ └─历史流程 |
|||
│ └─流程实例管理 |
|||
│ └─流程监听管理 |
|||
│ └─流程表达式 |
|||
│ └─我发起的流程 |
|||
│ └─我的抄送 |
|||
│ └─流程委派、抄送、跳转 |
|||
│ └─OA办公组件 |
|||
└─其他模块 |
|||
└─更多功能开发中。。 |
|||
|
|||
``` |
|||
|
|||
|
|||
## 系统效果 |
|||
系统后台 |
|||
|
|||
![](https://oscimg.oschina.net/oscnet/up-000530d95df337b43089ac77e562494f454.png) |
|||
|
|||
![输入图片说明](https://jeecgos.oss-cn-beijing.aliyuncs.com/files/site/vue3_20220310142354.png "在这里输入图片标题") |
|||
|
|||
|
|||
![输入图片说明](https://jeecgos.oss-cn-beijing.aliyuncs.com/files/site/vue3_20220310142409.png "在这里输入图片标题") |
|||
|
|||
![输入图片说明](https://jeecgos.oss-cn-beijing.aliyuncs.com/files/site/vue3_20220310142401.png "在这里输入图片标题") |
|||
|
|||
![输入图片说明](https://jeecgos.oss-cn-beijing.aliyuncs.com/files/site/vue3_11.png "在这里输入图片标题") |
|||
|
|||
Online开发&代码生成 |
|||
![](https://oscimg.oschina.net/oscnet/up-e8862f2c3c14eace9090c20a8fb928234a4.png) |
|||
|
|||
![](https://oscimg.oschina.net/oscnet/up-e3b3a736236bc66f255a9a32ab3f9b7196b.png) |
|||
|
|||
![](https://oscimg.oschina.net/oscnet/up-221b8cbdea3c17d31a1365023a73d3d439f.png) |
|||
|
|||
![](https://oscimg.oschina.net/oscnet/up-14092f6f213b26ab145cf70b2dc6dec5635.png) |
|||
|
|||
|
|||
|
|||
|
|||
系统交互 |
|||
![](https://oscimg.oschina.net/oscnet/up-78b151fc888d4319377bf1cc311fe826871.png) |
|||
|
|||
![](https://oscimg.oschina.net/oscnet/up-16c07e000278329b69b228ae3189814b8e9.png) |
|||
|
|||
|
|||
流程设计 |
|||
![](https://oscimg.oschina.net/oscnet/up-981ce174e4fbb48c8a2ce4ccfd7372e2994.png) |
|||
|
|||
![输入图片说明](https://static.oschina.net/uploads/img/201907/05165142_yyQ7.png "在这里输入图片标题") |
|||
|
|||
![输入图片说明](https://static.oschina.net/uploads/img/201904/14160917_9Ftz.png "在这里输入图片标题") |
|||
|
|||
![输入图片说明](https://static.oschina.net/uploads/img/201904/14160633_u59G.png "在这里输入图片标题") |
|||
|
|||
简版流程设计 |
|||
|
|||
![](https://oscimg.oschina.net/oscnet/up-1dc0d052149ec675f3e4fad632b82b48add.png) |
|||
|
|||
![](https://oscimg.oschina.net/oscnet/up-de31bc2f9d9b8332c554b0954cc73d79593.png) |
|||
|
|||
![](https://oscimg.oschina.net/oscnet/up-7f83b25159663686d67ed080eb16068c3b4.png) |
|||
|
|||
仪表盘设计器 |
|||
![](https://oscimg.oschina.net/oscnet/up-9c9d41288c31398d76b390bdd400f13a582.png) |
|||
|
|||
![](https://oscimg.oschina.net/oscnet/up-fad98d42b2cf92f92a903c9cff7579f18ec.png) |
|||
|
|||
报表设计器 |
|||
![](https://oscimg.oschina.net/oscnet/up-64648de000851f15f6c7b9573d107ebb5f8.png) |
|||
|
|||
![](https://oscimg.oschina.net/oscnet/up-fa52b44445db281c51d3f267dce7450d21b.gif) |
|||
|
|||
![](https://oscimg.oschina.net/oscnet/up-68a19149d640f1646c8ed89ed4375e3326c.png) |
|||
|
|||
![](https://oscimg.oschina.net/oscnet/up-f7e9cb2e3740f2d19ff63b40ec2dd554f96.png) |
|||
|
|||
表单设计器 |
|||
![](https://oscimg.oschina.net/oscnet/up-5f8cb657615714b02190b355e59f60c5937.png) |
|||
|
|||
![](https://oscimg.oschina.net/oscnet/up-d9659b2f324e33218476ec98c9b400e6508.png) |
|||
|
|||
![](https://oscimg.oschina.net/oscnet/up-4868615395272d3206dbb960ade02dbc291.png) |
|||
|
|||
大屏设计器 |
|||
![](https://oscimg.oschina.net/oscnet/up-402a6034124474bfef8dfc5b4b2bac1ce5c.png) |
|||
|
|||
![](https://oscimg.oschina.net/oscnet/up-6f7ba2e2ebbeea0d203db8d69fd87644c9f.png) |
|||
|
|||
![](https://oscimg.oschina.net/oscnet/up-ee8d34f318da466b8a6070a6e3111d12ce7.png) |
|||
|
|||
![](https://oscimg.oschina.net/oscnet/up-6b81781b43086819049c4421206810667c5.png) |
|||
|
|||
|
|||
报表效果 |
|||
|
|||
![](https://static.oschina.net/uploads/img/201904/14160828_pkFr.png "") |
|||
|
|||
![](https://static.oschina.net/uploads/img/201904/14160834_Lo23.png "") |
|||
|
|||
![](https://static.oschina.net/uploads/img/201904/14160842_QK7B.png "") |
|||
|
|||
![](https://static.oschina.net/uploads/img/201904/14160849_GBm5.png "") |
|||
|
|||
![](https://static.oschina.net/uploads/img/201904/14160858_6RAM.png "") |
|||
|
|||
接口文档 |
|||
|
|||
![](https://oscimg.oschina.net/oscnet/up-e6ea09dbaa01b8458c2e23614077ba9507f.png) |
|||
|
|||
|
|||
手机端 |
|||
![](https://oscimg.oschina.net/oscnet/da543c5d0d57baab0cecaa4670c8b68c521.jpg) |
|||
![](https://oscimg.oschina.net/oscnet/fda4bd82cab9d682de1c1fbf2060bf14fa6.jpg) |
|||
|
|||
PAD端 |
|||
![](https://oscimg.oschina.net/oscnet/e90fef970a8c33790ab03ffd6c4c7cec225.jpg) |
|||
![](https://oscimg.oschina.net/oscnet/d78218803a9e856a0aa82b45efc49849a0c.jpg) |
|||
![](https://oscimg.oschina.net/oscnet/59c23b230f52384e588ee16309b44fa20de.jpg) |
|||
|
|||
|
|||
|
|||
|
@ -0,0 +1,80 @@ |
|||
import { generate } from '@ant-design/colors'; |
|||
|
|||
// export const primaryColor = '#1890FF';
|
|||
export const primaryColor = '#009688'; |
|||
|
|||
export const darkMode = 'light'; |
|||
|
|||
type Fn = (...arg: any) => any; |
|||
|
|||
type GenerateTheme = 'default' | 'dark'; |
|||
|
|||
export interface GenerateColorsParams { |
|||
mixLighten: Fn; |
|||
mixDarken: Fn; |
|||
tinycolor: any; |
|||
color?: string; |
|||
} |
|||
|
|||
export function generateAntColors(color: string, theme: GenerateTheme = 'default') { |
|||
return generate(color, { |
|||
theme, |
|||
}); |
|||
} |
|||
|
|||
export function getThemeColors(color?: string) { |
|||
const tc = color || primaryColor; |
|||
const lightColors = generateAntColors(tc); |
|||
const primary = lightColors[5]; |
|||
const modeColors = generateAntColors(primary, 'dark'); |
|||
|
|||
return [...lightColors, ...modeColors]; |
|||
} |
|||
|
|||
export function generateColors({ |
|||
color = primaryColor, |
|||
mixLighten, |
|||
mixDarken, |
|||
tinycolor, |
|||
}: GenerateColorsParams) { |
|||
const arr = new Array(19).fill(0); |
|||
const lightens = arr.map((_t, i) => { |
|||
return mixLighten(color, i / 5); |
|||
}); |
|||
|
|||
const darkens = arr.map((_t, i) => { |
|||
return mixDarken(color, i / 5); |
|||
}); |
|||
|
|||
const alphaColors = arr.map((_t, i) => { |
|||
return tinycolor(color) |
|||
.setAlpha(i / 20) |
|||
.toRgbString(); |
|||
}); |
|||
|
|||
const shortAlphaColors = alphaColors.map((item) => item.replace(/\s/g, '').replace(/0\./g, '.')); |
|||
|
|||
const tinycolorLightens = arr |
|||
.map((_t, i) => { |
|||
return tinycolor(color) |
|||
.lighten(i * 5) |
|||
.toHexString(); |
|||
}) |
|||
.filter((item) => item !== '#ffffff'); |
|||
|
|||
const tinycolorDarkens = arr |
|||
.map((_t, i) => { |
|||
return tinycolor(color) |
|||
.darken(i * 5) |
|||
.toHexString(); |
|||
}) |
|||
.filter((item) => item !== '#000000'); |
|||
return [ |
|||
...lightens, |
|||
...darkens, |
|||
...alphaColors, |
|||
...shortAlphaColors, |
|||
...tinycolorDarkens, |
|||
...tinycolorLightens, |
|||
].filter((item) => !item.includes('-')); |
|||
} |
@ -0,0 +1,8 @@ |
|||
/** |
|||
* The name of the configuration file entered in the production environment |
|||
*/ |
|||
const path = require('path'); |
|||
export const GLOB_CONFIG_FILE_NAME = '_app.config.js'; |
|||
|
|||
export const OUTPUT_DIR = 'dist'; |
|||
|
@ -0,0 +1,37 @@ |
|||
import { generateAntColors, primaryColor } from '../config/themeConfig'; |
|||
import { getThemeVariables } from 'ant-design-vue/dist/theme'; |
|||
import { resolve } from 'path'; |
|||
|
|||
/** |
|||
* less global variable |
|||
*/ |
|||
export function generateModifyVars(dark = false) { |
|||
const palettes = generateAntColors(primaryColor); |
|||
const primary = palettes[5]; |
|||
|
|||
const primaryColorObj: Record<string, string> = {}; |
|||
|
|||
for (let index = 0; index < 10; index++) { |
|||
primaryColorObj[`primary-${index + 1}`] = palettes[index]; |
|||
} |
|||
|
|||
const modifyVars = getThemeVariables({ dark }); |
|||
return { |
|||
...modifyVars, |
|||
// Used for global import to avoid the need to import each style file separately
|
|||
// reference: Avoid repeated references
|
|||
hack: `${modifyVars.hack} @import (reference) "${resolve('src/design/config.less')}";`, |
|||
'primary-color': primary, |
|||
...primaryColorObj, |
|||
'info-color': primary, |
|||
'processing-color': primary, |
|||
'success-color': '#55D187', // Success color
|
|||
'error-color': '#ED6F6F', // False color
|
|||
'warning-color': '#EFBD47', // Warning color
|
|||
//'border-color-base': '#EEEEEE',
|
|||
'font-size-base': '14px', // Main font size
|
|||
'border-radius-base': '2px', // Component/float fillet
|
|||
'link-color': primary, // Link color
|
|||
'app-content-background': '#fafafa', // Link color
|
|||
}; |
|||
} |
@ -0,0 +1,68 @@ |
|||
import path from 'path'; |
|||
import fs from 'fs-extra'; |
|||
import inquirer from 'inquirer'; |
|||
import colors from 'picocolors'; |
|||
import pkg from '../../../package.json'; |
|||
|
|||
async function generateIcon() { |
|||
const dir = path.resolve(process.cwd(), 'node_modules/@iconify/json'); |
|||
|
|||
const raw = await fs.readJSON(path.join(dir, 'collections.json')); |
|||
|
|||
const collections = Object.entries(raw).map(([id, v]) => ({ |
|||
...(v as any), |
|||
id, |
|||
})); |
|||
|
|||
const choices = collections.map((item) => ({ key: item.id, value: item.id, name: item.name })); |
|||
|
|||
inquirer |
|||
.prompt([ |
|||
{ |
|||
type: 'list', |
|||
name: 'useType', |
|||
choices: [ |
|||
{ key: 'local', value: 'local', name: 'Local' }, |
|||
{ key: 'onLine', value: 'onLine', name: 'OnLine' }, |
|||
], |
|||
message: 'How to use icons?', |
|||
}, |
|||
{ |
|||
type: 'list', |
|||
name: 'iconSet', |
|||
choices: choices, |
|||
message: 'Select the icon set that needs to be generated?', |
|||
}, |
|||
{ |
|||
type: 'input', |
|||
name: 'output', |
|||
message: 'Select the icon set that needs to be generated?', |
|||
default: 'src/components/Icon/data', |
|||
}, |
|||
]) |
|||
.then(async (answers) => { |
|||
const { iconSet, output, useType } = answers; |
|||
const outputDir = path.resolve(process.cwd(), output); |
|||
fs.ensureDir(outputDir); |
|||
const genCollections = collections.filter((item) => [iconSet].includes(item.id)); |
|||
const prefixSet: string[] = []; |
|||
for (const info of genCollections) { |
|||
const data = await fs.readJSON(path.join(dir, 'json', `${info.id}.json`)); |
|||
if (data) { |
|||
const { prefix } = data; |
|||
const isLocal = useType === 'local'; |
|||
const icons = Object.keys(data.icons).map((item) => `${isLocal ? prefix + ':' : ''}${item}`); |
|||
|
|||
await fs.writeFileSync( |
|||
path.join(output, `icons.data.ts`), |
|||
`export default ${isLocal ? JSON.stringify(icons) : JSON.stringify({ prefix, icons })}` |
|||
); |
|||
prefixSet.push(prefix); |
|||
} |
|||
} |
|||
fs.emptyDir(path.join(process.cwd(), 'node_modules/.vite')); |
|||
console.log(`✨ ${colors.cyan(`[${pkg.name}]`)}` + ' - Icon generated successfully:' + `[${prefixSet}]`); |
|||
}); |
|||
} |
|||
|
|||
generateIcon(); |
@ -0,0 +1,7 @@ |
|||
/** |
|||
* Get the configuration file variable name |
|||
* @param env |
|||
*/ |
|||
export const getConfigFileName = (env: Record<string, any>) => { |
|||
return `__PRODUCTION__${env.VITE_GLOB_APP_SHORT_NAME || '__APP'}__CONF__`.toUpperCase().replace(/\s/g, ''); |
|||
}; |
@ -0,0 +1,47 @@ |
|||
/** |
|||
* Generate additional configuration files when used for packaging. The file can be configured with some global variables, so that it can be changed directly externally without repackaging |
|||
*/ |
|||
import { GLOB_CONFIG_FILE_NAME, OUTPUT_DIR } from '../constant'; |
|||
import fs, { writeFileSync } from 'fs-extra'; |
|||
import colors from 'picocolors'; |
|||
|
|||
import { getEnvConfig, getRootPath } from '../utils'; |
|||
import { getConfigFileName } from '../getConfigFileName'; |
|||
|
|||
import pkg from '../../package.json'; |
|||
|
|||
interface CreateConfigParams { |
|||
configName: string; |
|||
config: any; |
|||
configFileName?: string; |
|||
} |
|||
|
|||
function createConfig(params: CreateConfigParams) { |
|||
const { configName, config, configFileName } = params; |
|||
try { |
|||
const windowConf = `window.${configName}`; |
|||
// Ensure that the variable will not be modified
|
|||
let configStr = `${windowConf}=${JSON.stringify(config)};`; |
|||
configStr += ` |
|||
Object.freeze(${windowConf}); |
|||
Object.defineProperty(window, "${configName}", { |
|||
configurable: false, |
|||
writable: false, |
|||
}); |
|||
`.replace(/\s/g, '');
|
|||
|
|||
fs.mkdirp(getRootPath(OUTPUT_DIR)); |
|||
writeFileSync(getRootPath(`${OUTPUT_DIR}/${configFileName}`), configStr); |
|||
|
|||
console.log(colors.cyan(`✨ [${pkg.name}]`) + ` - configuration file is build successfully:`); |
|||
console.log(colors.gray(OUTPUT_DIR + '/' + colors.green(configFileName)) + '\n'); |
|||
} catch (error) { |
|||
console.log(colors.red('configuration file configuration file failed to package:\n' + error)); |
|||
} |
|||
} |
|||
|
|||
export function runBuildConfig() { |
|||
const config = getEnvConfig(); |
|||
const configFileName = getConfigFileName(config); |
|||
createConfig({ config, configName: configFileName, configFileName: GLOB_CONFIG_FILE_NAME }); |
|||
} |
@ -0,0 +1,23 @@ |
|||
// #!/usr/bin/env node
|
|||
|
|||
import { runBuildConfig } from './buildConf'; |
|||
import colors from 'picocolors'; |
|||
|
|||
import pkg from '../../package.json'; |
|||
|
|||
export const runBuild = async () => { |
|||
try { |
|||
const argvList = process.argv.splice(2); |
|||
|
|||
// Generate configuration file
|
|||
if (!argvList.includes('disabled-config')) { |
|||
runBuildConfig(); |
|||
} |
|||
|
|||
console.log(`✨ ${colors.cyan(`[${pkg.name}]`)}` + ' - build successfully!'); |
|||
} catch (error) { |
|||
console.log(colors.red('vite build error:\n' + error)); |
|||
process.exit(1); |
|||
} |
|||
}; |
|||
runBuild(); |
@ -0,0 +1,92 @@ |
|||
import fs from 'fs'; |
|||
import path from 'path'; |
|||
import dotenv from 'dotenv'; |
|||
|
|||
export function isDevFn(mode: string): boolean { |
|||
return mode === 'development'; |
|||
} |
|||
|
|||
export function isProdFn(mode: string): boolean { |
|||
return mode === 'production'; |
|||
} |
|||
|
|||
/** |
|||
* Whether to generate package preview |
|||
*/ |
|||
export function isReportMode(): boolean { |
|||
return process.env.REPORT === 'true'; |
|||
} |
|||
|
|||
// Read all environment variable configuration files to process.env
|
|||
export function wrapperEnv(envConf: Recordable): ViteEnv { |
|||
const ret: any = {}; |
|||
|
|||
for (const envName of Object.keys(envConf)) { |
|||
let realName = envConf[envName].replace(/\\n/g, '\n'); |
|||
realName = realName === 'true' ? true : realName === 'false' ? false : realName; |
|||
|
|||
if (envName === 'VITE_PORT') { |
|||
realName = Number(realName); |
|||
} |
|||
if (envName === 'VITE_PROXY' && realName) { |
|||
try { |
|||
realName = JSON.parse(realName.replace(/'/g, '"')); |
|||
} catch (error) { |
|||
realName = ''; |
|||
} |
|||
} |
|||
ret[envName] = realName; |
|||
if (typeof realName === 'string') { |
|||
process.env[envName] = realName; |
|||
} else if (typeof realName === 'object') { |
|||
process.env[envName] = JSON.stringify(realName); |
|||
} |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
/** |
|||
* 获取当前环境下生效的配置文件名 |
|||
*/ |
|||
function getConfFiles() { |
|||
const script = process.env.npm_lifecycle_script; |
|||
const reg = new RegExp('--mode ([a-z_\\d]+)'); |
|||
const result = reg.exec(script as string) as any; |
|||
if (result) { |
|||
const mode = result[1] as string; |
|||
return ['.env', `.env.${mode}`]; |
|||
} |
|||
return ['.env', '.env.production']; |
|||
} |
|||
|
|||
/** |
|||
* Get the environment variables starting with the specified prefix |
|||
* @param match prefix |
|||
* @param confFiles ext |
|||
*/ |
|||
export function getEnvConfig(match = 'VITE_GLOB_', confFiles = getConfFiles()) { |
|||
let envConfig = {}; |
|||
confFiles.forEach((item) => { |
|||
try { |
|||
const env = dotenv.parse(fs.readFileSync(path.resolve(process.cwd(), item))); |
|||
envConfig = { ...envConfig, ...env }; |
|||
} catch (e) { |
|||
console.error(`Error in parsing ${item}`, e); |
|||
} |
|||
}); |
|||
const reg = new RegExp(`^(${match})`); |
|||
Object.keys(envConfig).forEach((key) => { |
|||
if (!reg.test(key)) { |
|||
Reflect.deleteProperty(envConfig, key); |
|||
} |
|||
}); |
|||
return envConfig; |
|||
} |
|||
|
|||
/** |
|||
* Get user root directory |
|||
* @param dir file path |
|||
*/ |
|||
export function getRootPath(...dir: string[]) { |
|||
return path.resolve(process.cwd(), ...dir); |
|||
} |
@ -0,0 +1,32 @@ |
|||
/** |
|||
* Used to package and output gzip. Note that this does not work properly in Vite, the specific reason is still being investigated |
|||
* https://github.com/anncwb/vite-plugin-compression
|
|||
*/ |
|||
import type { PluginOption } from 'vite'; |
|||
import compressPlugin from 'vite-plugin-compression'; |
|||
|
|||
export function configCompressPlugin(compress: 'gzip' | 'brotli' | 'none', deleteOriginFile = false): PluginOption | PluginOption[] { |
|||
const compressList = compress.split(','); |
|||
|
|||
const plugins: PluginOption[] = []; |
|||
|
|||
if (compressList.includes('gzip')) { |
|||
plugins.push( |
|||
compressPlugin({ |
|||
ext: '.gz', |
|||
deleteOriginFile, |
|||
}) |
|||
); |
|||
} |
|||
|
|||
if (compressList.includes('brotli')) { |
|||
plugins.push( |
|||
compressPlugin({ |
|||
ext: '.br', |
|||
algorithm: 'brotliCompress', |
|||
deleteOriginFile, |
|||
}) |
|||
); |
|||
} |
|||
return plugins; |
|||
} |
@ -0,0 +1,40 @@ |
|||
/** |
|||
* Plugin to minimize and use ejs template syntax in index.html. |
|||
* https://github.com/anncwb/vite-plugin-html
|
|||
*/ |
|||
import type { PluginOption } from 'vite'; |
|||
import { createHtmlPlugin } from 'vite-plugin-html'; |
|||
import pkg from '../../../package.json'; |
|||
import { GLOB_CONFIG_FILE_NAME } from '../../constant'; |
|||
|
|||
export function configHtmlPlugin(env: ViteEnv, isBuild: boolean) { |
|||
const { VITE_GLOB_APP_TITLE, VITE_PUBLIC_PATH } = env; |
|||
|
|||
const path = VITE_PUBLIC_PATH.endsWith('/') ? VITE_PUBLIC_PATH : `${VITE_PUBLIC_PATH}/`; |
|||
|
|||
const getAppConfigSrc = () => { |
|||
return `${path || '/'}${GLOB_CONFIG_FILE_NAME}?v=${pkg.version}-${new Date().getTime()}`; |
|||
}; |
|||
|
|||
const htmlPlugin: PluginOption[] = createHtmlPlugin({ |
|||
minify: isBuild, |
|||
inject: { |
|||
// Inject data into ejs template
|
|||
data: { |
|||
title: VITE_GLOB_APP_TITLE, |
|||
}, |
|||
// Embed the generated app.config.js file
|
|||
tags: isBuild |
|||
? [ |
|||
{ |
|||
tag: 'script', |
|||
attrs: { |
|||
src: getAppConfigSrc(), |
|||
}, |
|||
}, |
|||
] |
|||
: [], |
|||
}, |
|||
}); |
|||
return htmlPlugin; |
|||
} |
@ -0,0 +1,34 @@ |
|||
// Image resource files used to compress the output of the production environment
|
|||
// https://github.com/anncwb/vite-plugin-imagemin
|
|||
import viteImagemin from 'vite-plugin-imagemin'; |
|||
|
|||
export function configImageminPlugin() { |
|||
const plugin = viteImagemin({ |
|||
gifsicle: { |
|||
optimizationLevel: 7, |
|||
interlaced: false, |
|||
}, |
|||
optipng: { |
|||
optimizationLevel: 7, |
|||
}, |
|||
mozjpeg: { |
|||
quality: 20, |
|||
}, |
|||
pngquant: { |
|||
quality: [0.8, 0.9], |
|||
speed: 4, |
|||
}, |
|||
svgo: { |
|||
plugins: [ |
|||
{ |
|||
name: 'removeViewBox', |
|||
}, |
|||
{ |
|||
name: 'removeEmptyAttrs', |
|||
active: false, |
|||
}, |
|||
], |
|||
}, |
|||
}); |
|||
return plugin; |
|||
} |
@ -0,0 +1,80 @@ |
|||
import { PluginOption } from 'vite'; |
|||
import vue from '@vitejs/plugin-vue'; |
|||
import vueJsx from '@vitejs/plugin-vue-jsx'; |
|||
import legacy from '@vitejs/plugin-legacy'; |
|||
import purgeIcons from 'vite-plugin-purge-icons'; |
|||
import windiCSS from 'vite-plugin-windicss'; |
|||
import VitePluginCertificate from 'vite-plugin-mkcert'; |
|||
import vueSetupExtend from 'vite-plugin-vue-setup-extend'; |
|||
import { configHtmlPlugin } from './html'; |
|||
import { configPwaConfig } from './pwa'; |
|||
import { configMockPlugin } from './mock'; |
|||
import { configCompressPlugin } from './compress'; |
|||
import { configStyleImportPlugin } from './styleImport'; |
|||
import { configVisualizerConfig } from './visualizer'; |
|||
import { configThemePlugin } from './theme'; |
|||
import { configImageminPlugin } from './imagemin'; |
|||
import { configSvgIconsPlugin } from './svgSprite'; |
|||
import OptimizationPersist from 'vite-plugin-optimize-persist' |
|||
import PkgConfig from 'vite-plugin-package-config' |
|||
|
|||
export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) { |
|||
const { VITE_USE_IMAGEMIN, VITE_USE_MOCK, VITE_LEGACY, VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE } = viteEnv; |
|||
|
|||
const vitePlugins: (PluginOption | PluginOption[])[] = [ |
|||
// have to
|
|||
vue(), |
|||
// have to
|
|||
vueJsx(), |
|||
// support name
|
|||
vueSetupExtend(), |
|||
// @ts-ignore
|
|||
VitePluginCertificate({ |
|||
source: 'coding', |
|||
}), |
|||
]; |
|||
|
|||
// vite-plugin-windicss
|
|||
vitePlugins.push(windiCSS()); |
|||
|
|||
// @vitejs/plugin-legacy
|
|||
VITE_LEGACY && isBuild && vitePlugins.push(legacy()); |
|||
|
|||
// vite-plugin-html
|
|||
vitePlugins.push(configHtmlPlugin(viteEnv, isBuild)); |
|||
|
|||
// vite-plugin-svg-icons
|
|||
vitePlugins.push(configSvgIconsPlugin(isBuild)); |
|||
|
|||
// vite-plugin-mock
|
|||
VITE_USE_MOCK && vitePlugins.push(configMockPlugin(isBuild)); |
|||
|
|||
// vite-plugin-purge-icons
|
|||
vitePlugins.push(purgeIcons()); |
|||
|
|||
// vite-plugin-style-import
|
|||
vitePlugins.push(configStyleImportPlugin(isBuild)); |
|||
|
|||
// rollup-plugin-visualizer
|
|||
vitePlugins.push(configVisualizerConfig()); |
|||
|
|||
// vite-plugin-theme
|
|||
vitePlugins.push(configThemePlugin(isBuild)); |
|||
|
|||
// The following plugins only work in the production environment
|
|||
if (isBuild) { |
|||
// vite-plugin-imagemin
|
|||
VITE_USE_IMAGEMIN && vitePlugins.push(configImageminPlugin()); |
|||
|
|||
// rollup-plugin-gzip
|
|||
vitePlugins.push(configCompressPlugin(VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE)); |
|||
|
|||
// vite-plugin-pwa
|
|||
vitePlugins.push(configPwaConfig(viteEnv)); |
|||
} |
|||
|
|||
//vite-plugin-theme【解决vite首次打开界面加载慢问题】
|
|||
vitePlugins.push(PkgConfig()); |
|||
vitePlugins.push(OptimizationPersist()); |
|||
return vitePlugins; |
|||
} |
@ -0,0 +1,19 @@ |
|||
/** |
|||
* Mock plugin for development and production. |
|||
* https://github.com/anncwb/vite-plugin-mock
|
|||
*/ |
|||
import { viteMockServe } from 'vite-plugin-mock'; |
|||
|
|||
export function configMockPlugin(isBuild: boolean) { |
|||
return viteMockServe({ |
|||
ignore: /^\_/, |
|||
mockPath: 'mock', |
|||
localEnabled: !isBuild, |
|||
prodEnabled: isBuild, |
|||
injectCode: ` |
|||
import { setupProdMockServer } from '../mock/_createProductionServer'; |
|||
|
|||
setupProdMockServer(); |
|||
`,
|
|||
}); |
|||
} |
@ -0,0 +1,33 @@ |
|||
/** |
|||
* Zero-config PWA for Vite |
|||
* https://github.com/antfu/vite-plugin-pwa
|
|||
*/ |
|||
import { VitePWA } from 'vite-plugin-pwa'; |
|||
|
|||
export function configPwaConfig(env: ViteEnv) { |
|||
const { VITE_USE_PWA, VITE_GLOB_APP_TITLE, VITE_GLOB_APP_SHORT_NAME } = env; |
|||
|
|||
if (VITE_USE_PWA) { |
|||
// vite-plugin-pwa
|
|||
const pwaPlugin = VitePWA({ |
|||
manifest: { |
|||
name: VITE_GLOB_APP_TITLE, |
|||
short_name: VITE_GLOB_APP_SHORT_NAME, |
|||
icons: [ |
|||
{ |
|||
src: './resource/img/pwa-192x192.png', |
|||
sizes: '192x192', |
|||
type: 'image/png', |
|||
}, |
|||
{ |
|||
src: './resource/img/pwa-512x512.png', |
|||
sizes: '512x512', |
|||
type: 'image/png', |
|||
}, |
|||
], |
|||
}, |
|||
}); |
|||
return pwaPlugin; |
|||
} |
|||
return []; |
|||
} |
@ -0,0 +1,81 @@ |
|||
/** |
|||
* Introduces component library styles on demand. |
|||
* https://github.com/anncwb/vite-plugin-style-import
|
|||
*/ |
|||
import { createStyleImportPlugin } from 'vite-plugin-style-import'; |
|||
|
|||
export function configStyleImportPlugin(_isBuild: boolean) { |
|||
if (!_isBuild) { |
|||
return []; |
|||
} |
|||
const styleImportPlugin = createStyleImportPlugin({ |
|||
libs: [ |
|||
{ |
|||
libraryName: 'ant-design-vue', |
|||
esModule: true, |
|||
resolveStyle: (name) => { |
|||
// 这里是无需额外引入样式文件的“子组件”列表
|
|||
const ignoreList = [ |
|||
'anchor-link', |
|||
'sub-menu', |
|||
'menu-item', |
|||
'menu-divider', |
|||
'menu-item-group', |
|||
'breadcrumb-item', |
|||
'breadcrumb-separator', |
|||
'form-item', |
|||
'step', |
|||
'select-option', |
|||
'select-opt-group', |
|||
'card-grid', |
|||
'card-meta', |
|||
'collapse-panel', |
|||
'descriptions-item', |
|||
'list-item', |
|||
'list-item-meta', |
|||
'table-column', |
|||
'table-column-group', |
|||
'tab-pane', |
|||
'tab-content', |
|||
'timeline-item', |
|||
'tree-node', |
|||
'skeleton-input', |
|||
'skeleton-avatar', |
|||
'skeleton-title', |
|||
'skeleton-paragraph', |
|||
'skeleton-image', |
|||
'skeleton-button', |
|||
]; |
|||
// 这里是需要额外引入样式的子组件列表
|
|||
// 单独引入子组件时需引入组件样式,否则会在打包后导致子组件样式丢失
|
|||
const replaceList = { |
|||
'typography-text': 'typography', |
|||
'typography-title': 'typography', |
|||
'typography-paragraph': 'typography', |
|||
'typography-link': 'typography', |
|||
'dropdown-button': 'dropdown', |
|||
'input-password': 'input', |
|||
'input-search': 'input', |
|||
'input-group': 'input', |
|||
'radio-group': 'radio', |
|||
'checkbox-group': 'checkbox', |
|||
'layout-sider': 'layout', |
|||
'layout-content': 'layout', |
|||
'layout-footer': 'layout', |
|||
'layout-header': 'layout', |
|||
'month-picker': 'date-picker', |
|||
'range-picker': 'date-picker', |
|||
'image-preview-group': 'image', |
|||
}; |
|||
|
|||
return ignoreList.includes(name) |
|||
? '' |
|||
: replaceList.hasOwnProperty(name) |
|||
? `ant-design-vue/es/${replaceList[name]}/style/index` |
|||
: `ant-design-vue/es/${name}/style/index`; |
|||
}, |
|||
}, |
|||
], |
|||
}); |
|||
return styleImportPlugin; |
|||
} |
@ -0,0 +1,17 @@ |
|||
/** |
|||
* Vite Plugin for fast creating SVG sprites. |
|||
* https://github.com/anncwb/vite-plugin-svg-icons
|
|||
*/ |
|||
|
|||
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'; |
|||
import path from 'path'; |
|||
|
|||
export function configSvgIconsPlugin(isBuild: boolean) { |
|||
const svgIconsPlugin = createSvgIconsPlugin({ |
|||
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')], |
|||
svgoOptions: isBuild, |
|||
// default
|
|||
symbolId: 'icon-[dir]-[name]', |
|||
}); |
|||
return svgIconsPlugin; |
|||
} |
@ -0,0 +1,100 @@ |
|||
/** |
|||
* Vite plugin for website theme color switching |
|||
* https://github.com/anncwb/vite-plugin-theme
|
|||
*/ |
|||
import type { PluginOption } from 'vite'; |
|||
import path from 'path'; |
|||
import { viteThemePlugin, antdDarkThemePlugin, mixLighten, mixDarken, tinycolor } from '@rys-fe/vite-plugin-theme'; |
|||
import { getThemeColors, generateColors } from '../../config/themeConfig'; |
|||
import { generateModifyVars } from '../../generate/generateModifyVars'; |
|||
|
|||
export function configThemePlugin(isBuild: boolean): PluginOption[] { |
|||
const colors = generateColors({ |
|||
mixDarken, |
|||
mixLighten, |
|||
tinycolor, |
|||
}); |
|||
|
|||
// update-begin-修复编译后主题色切换不生效黑屏的问题-----------------------
|
|||
// https://github.com/vbenjs/vue-vben-admin/issues/1445
|
|||
// 抽取出viteThemePlugin插件,下方会根据不同环境设置enforce
|
|||
const vite_theme_plugin = viteThemePlugin({ |
|||
resolveSelector: (s) => { |
|||
s = s.trim(); |
|||
switch (s) { |
|||
case '.ant-steps-item-process .ant-steps-item-icon > .ant-steps-icon': |
|||
return '.ant-steps-item-icon > .ant-steps-icon'; |
|||
case '.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled)': |
|||
case '.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover': |
|||
case '.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):active': |
|||
return s; |
|||
case '.ant-steps-item-icon > .ant-steps-icon': |
|||
return s; |
|||
case '.ant-select-item-option-selected:not(.ant-select-item-option-disabled)': |
|||
return s; |
|||
default: |
|||
if (s.indexOf('.ant-btn') >= -1) { |
|||
// 按钮被重新定制过,需要过滤掉class防止覆盖
|
|||
return s; |
|||
} |
|||
} |
|||
return s.startsWith('[data-theme') ? s : `[data-theme] ${s}`; |
|||
}, |
|||
colorVariables: [...getThemeColors(), ...colors], |
|||
}); |
|||
vite_theme_plugin.forEach(function (item) { |
|||
//对vite:theme插件特殊配置
|
|||
if ('vite:theme' === item.name) { |
|||
// 打包时去除enforce: "post",vite 2.6.x适配,否则生成app-theme-style为空,因为async transform(code, id) {的code没有正确获取
|
|||
if (isBuild) { |
|||
delete item.enforce; |
|||
} |
|||
} |
|||
}); |
|||
// update-end-修复编译后主题色切换不生效黑屏的问题-----------------------
|
|||
|
|||
const plugin = [ |
|||
vite_theme_plugin, |
|||
antdDarkThemePlugin({ |
|||
preloadFiles: [ |
|||
path.resolve(process.cwd(), 'node_modules/ant-design-vue/dist/antd.less'), |
|||
//path.resolve(process.cwd(), 'node_modules/ant-design-vue/dist/antd.dark.less'),
|
|||
path.resolve(process.cwd(), 'src/design/index.less'), |
|||
], |
|||
filter: (id) => (isBuild ? !id.endsWith('antd.less') : true), |
|||
// extractCss: false,
|
|||
darkModifyVars: { |
|||
...generateModifyVars(true), |
|||
'text-color': '#c9d1d9', |
|||
'primary-1': 'rgb(255 255 255 / 8%)', |
|||
'text-color-base': '#c9d1d9', |
|||
'component-background': '#151515', |
|||
'heading-color': 'rgb(255 255 255 / 65%)', |
|||
// black: '#0e1117',
|
|||
// #8b949e
|
|||
'text-color-secondary': '#8b949e', |
|||
'border-color-base': '#303030', |
|||
'header-light-bottom-border-color': '#303030', |
|||
// 'border-color-split': '#30363d',
|
|||
'item-active-bg': '#111b26', |
|||
'app-content-background': '#1e1e1e', |
|||
'tree-node-selected-bg': '#11263c', |
|||
|
|||
'alert-success-border-color': '#274916', |
|||
'alert-success-bg-color': '#162312', |
|||
'alert-success-icon-color': '#49aa19', |
|||
'alert-info-border-color': '#153450', |
|||
'alert-info-bg-color': '#111b26', |
|||
'alert-info-icon-color': '#177ddc', |
|||
'alert-warning-border-color': '#594214', |
|||
'alert-warning-bg-color': '#2b2111', |
|||
'alert-warning-icon-color': '#d89614', |
|||
'alert-error-border-color': '#58181c', |
|||
'alert-error-bg-color': '#2a1215', |
|||
'alert-error-icon-color': '#a61d24', |
|||
}, |
|||
}), |
|||
]; |
|||
|
|||
return plugin as unknown as PluginOption[]; |
|||
} |
@ -0,0 +1,17 @@ |
|||
/** |
|||
* Package file volume analysis |
|||
*/ |
|||
import visualizer from 'rollup-plugin-visualizer'; |
|||
import { isReportMode } from '../../utils'; |
|||
|
|||
export function configVisualizerConfig() { |
|||
if (isReportMode()) { |
|||
return visualizer({ |
|||
filename: './node_modules/.cache/visualizer/stats.html', |
|||
open: true, |
|||
gzipSize: true, |
|||
brotliSize: true, |
|||
}) as Plugin; |
|||
} |
|||
return []; |
|||
} |
@ -0,0 +1,34 @@ |
|||
/** |
|||
* Used to parse the .env.development proxy configuration |
|||
*/ |
|||
import type { ProxyOptions } from 'vite'; |
|||
|
|||
type ProxyItem = [string, string]; |
|||
|
|||
type ProxyList = ProxyItem[]; |
|||
|
|||
type ProxyTargetList = Record<string, ProxyOptions>; |
|||
|
|||
const httpsRE = /^https:\/\//; |
|||
|
|||
/** |
|||
* Generate proxy |
|||
* @param list |
|||
*/ |
|||
export function createProxy(list: ProxyList = []) { |
|||
const ret: ProxyTargetList = {}; |
|||
for (const [prefix, target] of list) { |
|||
const isHttps = httpsRE.test(target); |
|||
|
|||
// https://github.com/http-party/node-http-proxy#options
|
|||
ret[prefix] = { |
|||
target: target, |
|||
changeOrigin: true, |
|||
ws: true, |
|||
rewrite: (path) => path.replace(new RegExp(`^${prefix}`), ''), |
|||
// https is require secure=false
|
|||
...(isHttps ? { secure: false } : {}), |
|||
}; |
|||
} |
|||
return ret; |
|||
} |
@ -0,0 +1,32 @@ |
|||
module.exports = { |
|||
ignores: [(commit) => commit.includes('init')], |
|||
extends: ['@commitlint/config-conventional'], |
|||
rules: { |
|||
'body-leading-blank': [2, 'always'], |
|||
'footer-leading-blank': [1, 'always'], |
|||
'header-max-length': [2, 'always', 108], |
|||
'subject-empty': [2, 'never'], |
|||
'type-empty': [2, 'never'], |
|||
'type-enum': [ |
|||
2, |
|||
'always', |
|||
[ |
|||
'feat', |
|||
'fix', |
|||
'perf', |
|||
'style', |
|||
'docs', |
|||
'test', |
|||
'refactor', |
|||
'build', |
|||
'ci', |
|||
'chore', |
|||
'revert', |
|||
'wip', |
|||
'workflow', |
|||
'types', |
|||
'release', |
|||
], |
|||
], |
|||
}, |
|||
}; |
@ -0,0 +1,56 @@ |
|||
// electron/electron.js
|
|||
const path = require('path'); |
|||
const { app, BrowserWindow } = require('electron'); |
|||
|
|||
const isDev = process.env.IS_DEV == "true" ? true : false; |
|||
|
|||
function createWindow() { |
|||
// Create the browser window.
|
|||
const mainWindow = new BrowserWindow({ |
|||
width: 800, |
|||
height: 600, |
|||
webPreferences: { |
|||
//preload: path.join(__dirname, 'preload.js'),
|
|||
javascript: true, |
|||
plugins: true, |
|||
allowRunningInsecureContent: true, |
|||
nodeIntegration: true, |
|||
}, |
|||
}); |
|||
|
|||
// and load the index.html of the app.
|
|||
// win.loadFile("index.html");
|
|||
|
|||
mainWindow.loadURL( |
|||
isDev |
|||
? 'http://localhost:3200' |
|||
: `file://${path.join(__dirname, '../dist/index.html')}` |
|||
); |
|||
|
|||
// mainWindow.loadURL('http://127.0.0.1:5500');
|
|||
// Open the DevTools.
|
|||
// if (isDev) {
|
|||
mainWindow.webContents.openDevTools(); |
|||
// }
|
|||
} |
|||
|
|||
// This method will be called when Electron has finished
|
|||
// initialization and is ready to create browser windows.
|
|||
// Some APIs can only be used after this event occurs.
|
|||
app.whenReady().then(() => { |
|||
createWindow() |
|||
app.on('activate', function () { |
|||
// On macOS it's common to re-create a window in the app when the
|
|||
// dock icon is clicked and there are no other windows open.
|
|||
if (BrowserWindow.getAllWindows().length === 0) createWindow() |
|||
}) |
|||
}); |
|||
|
|||
// Quit when all windows are closed, except on macOS. There, it's common
|
|||
// for applications and their menu bar to stay active until the user quits
|
|||
// explicitly with Cmd + Q.
|
|||
app.on('window-all-closed', () => { |
|||
if (process.platform !== 'darwin') { |
|||
app.quit(); |
|||
} |
|||
}); |
@ -0,0 +1,175 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="zh_CN" id="htmlRoot"> |
|||
<head> |
|||
<meta charset="UTF-8" /> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> |
|||
<meta name="renderer" content="webkit" /> |
|||
<meta |
|||
name="viewport" |
|||
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0" |
|||
/> |
|||
<script src="<%= BASE_URL %>earthsdk/XbsjEarth/XbsjEarth.js"></script> |
|||
<script src="<%= BASE_URL %>earthsdk/XbsjEarthUI/xbsj.js"></script> |
|||
<script src="<%= BASE_URL %>earthsdk/XbsjCesium/Cesium.js"></script> |
|||
<script type="text/javascript" src="<%= BASE_URL %>military/third/api/getImosSdkJs"></script> |
|||
<link rel="stylesheet" href="<%= BASE_URL %>earthsdk/XbsjCesium/Widgets/widgets.css"> |
|||
<script src="<%= BASE_URL %>js/d3kit/libs/cesium-d3kit.js"></script> |
|||
<title><%= title %></title> |
|||
<link rel="icon" href="/zgxlogo.png" /> |
|||
<!-- 全局配置 --> |
|||
<script> |
|||
window._CONFIG = {}; |
|||
</script> |
|||
</head> |
|||
<body> |
|||
<script> |
|||
(() => { |
|||
var htmlRoot = document.getElementById('htmlRoot'); |
|||
var theme = window.localStorage.getItem('__APP__DARK__MODE__'); |
|||
if (htmlRoot && theme) { |
|||
htmlRoot.setAttribute('data-theme', theme); |
|||
theme = htmlRoot = null; |
|||
} |
|||
})(); |
|||
</script> |
|||
<div id="app"> |
|||
<style> |
|||
html[data-theme='dark'] .app-loading { |
|||
background-color: #2c344a; |
|||
} |
|||
|
|||
html[data-theme='dark'] .app-loading .app-loading-title { |
|||
color: rgba(255, 255, 255, 0.85); |
|||
} |
|||
|
|||
.app-loading { |
|||
display: flex; |
|||
width: 100%; |
|||
height: 100%; |
|||
justify-content: center; |
|||
align-items: center; |
|||
flex-direction: column; |
|||
background-color: #f4f7f9; |
|||
} |
|||
|
|||
.app-loading .app-loading-wrap { |
|||
position: absolute; |
|||
top: 50%; |
|||
left: 50%; |
|||
display: flex; |
|||
-webkit-transform: translate3d(-50%, -50%, 0); |
|||
transform: translate3d(-50%, -50%, 0); |
|||
justify-content: center; |
|||
align-items: center; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.app-loading .dots { |
|||
display: flex; |
|||
padding: 98px; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
.app-loading .app-loading-title { |
|||
display: flex; |
|||
margin-top: 30px; |
|||
font-size: 30px; |
|||
color: rgba(0, 0, 0, 0.85); |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
.app-loading .app-loading-logo { |
|||
display: block; |
|||
width: 90px; |
|||
margin: 0 auto; |
|||
margin-bottom: 20px; |
|||
} |
|||
|
|||
.dot { |
|||
position: relative; |
|||
display: inline-block; |
|||
width: 48px; |
|||
height: 48px; |
|||
margin-top: 30px; |
|||
font-size: 32px; |
|||
transform: rotate(45deg); |
|||
box-sizing: border-box; |
|||
animation: antRotate 1.2s infinite linear; |
|||
} |
|||
|
|||
.dot i { |
|||
position: absolute; |
|||
display: block; |
|||
width: 20px; |
|||
height: 20px; |
|||
background-color: #0065cc; |
|||
border-radius: 100%; |
|||
opacity: 0.3; |
|||
transform: scale(0.75); |
|||
animation: antSpinMove 1s infinite linear alternate; |
|||
transform-origin: 50% 50%; |
|||
} |
|||
|
|||
.dot i:nth-child(1) { |
|||
top: 0; |
|||
left: 0; |
|||
} |
|||
|
|||
.dot i:nth-child(2) { |
|||
top: 0; |
|||
right: 0; |
|||
-webkit-animation-delay: 0.4s; |
|||
animation-delay: 0.4s; |
|||
} |
|||
|
|||
.dot i:nth-child(3) { |
|||
right: 0; |
|||
bottom: 0; |
|||
-webkit-animation-delay: 0.8s; |
|||
animation-delay: 0.8s; |
|||
} |
|||
|
|||
.dot i:nth-child(4) { |
|||
bottom: 0; |
|||
left: 0; |
|||
-webkit-animation-delay: 1.2s; |
|||
animation-delay: 1.2s; |
|||
} |
|||
@keyframes antRotate { |
|||
to { |
|||
-webkit-transform: rotate(405deg); |
|||
transform: rotate(405deg); |
|||
} |
|||
} |
|||
@-webkit-keyframes antRotate { |
|||
to { |
|||
-webkit-transform: rotate(405deg); |
|||
transform: rotate(405deg); |
|||
} |
|||
} |
|||
@keyframes antSpinMove { |
|||
to { |
|||
opacity: 1; |
|||
} |
|||
} |
|||
@-webkit-keyframes antSpinMove { |
|||
to { |
|||
opacity: 1; |
|||
} |
|||
} |
|||
</style> |
|||
<div class="app-loading"> |
|||
<div class="app-loading-wrap"> |
|||
<!-- <img src="/resource/img/zgxlogo.png" class="app-loading-logo" alt="Logo" /> --> |
|||
<div class="app-loading-dots"> |
|||
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span> |
|||
</div> |
|||
<div class="app-loading-title"><%= title %></div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<script type="module" src="/src/main.ts"></script> |
|||
</body> |
|||
</html> |
@ -0,0 +1,36 @@ |
|||
export default { |
|||
preset: 'ts-jest', |
|||
roots: ['<rootDir>/tests/'], |
|||
clearMocks: true, |
|||
moduleDirectories: ['node_modules', 'src'], |
|||
moduleFileExtensions: ['js', 'ts', 'vue', 'tsx', 'jsx', 'json', 'node'], |
|||
modulePaths: ['<rootDir>/src', '<rootDir>/node_modules'], |
|||
testMatch: [ |
|||
'**/tests/**/*.[jt]s?(x)', |
|||
'**/?(*.)+(spec|test).[tj]s?(x)', |
|||
'(/__tests__/.*|(\\.|/)(test|spec))\\.(js|ts)$', |
|||
], |
|||
testPathIgnorePatterns: [ |
|||
'<rootDir>/tests/server/', |
|||
'<rootDir>/tests/__mocks__/', |
|||
'/node_modules/', |
|||
], |
|||
transform: { |
|||
'^.+\\.tsx?$': 'ts-jest', |
|||
}, |
|||
transformIgnorePatterns: ['<rootDir>/tests/__mocks__/', '/node_modules/'], |
|||
// A map from regular expressions to module names that allow to stub out resources with a single module
|
|||
moduleNameMapper: { |
|||
'\\.(vs|fs|vert|frag|glsl|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': |
|||
'<rootDir>/tests/__mocks__/fileMock.ts', |
|||
'\\.(sass|s?css|less)$': '<rootDir>/tests/__mocks__/styleMock.ts', |
|||
'\\?worker$': '<rootDir>/tests/__mocks__/workerMock.ts', |
|||
'^/@/(.*)$': '<rootDir>/src/$1', |
|||
}, |
|||
testEnvironment: 'jsdom', |
|||
verbose: true, |
|||
collectCoverage: false, |
|||
coverageDirectory: 'coverage', |
|||
collectCoverageFrom: ['src/**/*.{js,ts,vue}'], |
|||
coveragePathIgnorePatterns: ['^.+\\.d\\.ts$'], |
|||
}; |
@ -0,0 +1,18 @@ |
|||
import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'; |
|||
|
|||
const modules = import.meta.glob('./**/*.ts', { eager: true }); |
|||
|
|||
const mockModules: any[] = []; |
|||
Object.keys(modules).forEach((key) => { |
|||
if (key.includes('/_')) { |
|||
return; |
|||
} |
|||
mockModules.push(...(modules as Recordable)[key].default); |
|||
}); |
|||
|
|||
/** |
|||
* Used in a production environment. Need to manually import all modules |
|||
*/ |
|||
export function setupProdMockServer() { |
|||
createProdMockServer(mockModules); |
|||
} |
@ -0,0 +1,63 @@ |
|||
// Interface data format used to return a unified format
|
|||
|
|||
export function resultSuccess<T = Recordable>(result: T, { message = 'ok' } = {}) { |
|||
return { |
|||
code: 0, |
|||
result, |
|||
message, |
|||
type: 'success', |
|||
}; |
|||
} |
|||
|
|||
export function resultPageSuccess<T = any>( |
|||
pageNo: number, |
|||
pageSize: number, |
|||
list: T[], |
|||
{ message = 'ok' } = {} |
|||
) { |
|||
const pageData = pagination(pageNo, pageSize, list); |
|||
|
|||
return { |
|||
...resultSuccess({ |
|||
records: pageData, |
|||
total: list.length, |
|||
}), |
|||
message, |
|||
}; |
|||
} |
|||
|
|||
export function resultError(message = 'Request failed', { code = -1, result = null } = {}) { |
|||
return { |
|||
code, |
|||
result, |
|||
message, |
|||
type: 'error', |
|||
}; |
|||
} |
|||
|
|||
export function pagination<T = any>(pageNo: number, pageSize: number, array: T[]): T[] { |
|||
const offset = (pageNo - 1) * Number(pageSize); |
|||
const ret = |
|||
offset + Number(pageSize) >= array.length |
|||
? array.slice(offset, array.length) |
|||
: array.slice(offset, offset + Number(pageSize)); |
|||
return ret; |
|||
} |
|||
|
|||
export interface requestParams { |
|||
method: string; |
|||
body: any; |
|||
headers?: { authorization?: string }; |
|||
query: any; |
|||
} |
|||
|
|||
/** |
|||
* @description 本函数用于从request数据中获取token,请根据项目的实际情况修改 |
|||
* |
|||
*/ |
|||
export function getRequestToken({ headers }: requestParams): string | undefined { |
|||
return headers?.authorization; |
|||
} |
|||
|
|||
//TODO 接口父路径(写死不够灵活)
|
|||
export const baseUrl = '/jeecgboot/mock'; |
@ -0,0 +1,70 @@ |
|||
import { MockMethod } from 'vite-plugin-mock'; |
|||
import { resultSuccess, resultError, baseUrl } from '../_util'; |
|||
import { ResultEnum } from '../../src/enums/httpEnum'; |
|||
const userInfo = { |
|||
name: 'Jeecg', |
|||
userid: '00000001', |
|||
email: 'test@gmail.com', |
|||
signature: '海纳百川,有容乃大', |
|||
introduction: '微笑着,努力着,欣赏着', |
|||
title: '交互专家', |
|||
group: '某某某事业群-某某平台部-某某技术部-UED', |
|||
tags: [ |
|||
{ |
|||
key: '0', |
|||
label: '很有想法的', |
|||
}, |
|||
{ |
|||
key: '1', |
|||
label: '专注设计', |
|||
}, |
|||
{ |
|||
key: '2', |
|||
label: '辣~', |
|||
}, |
|||
{ |
|||
key: '3', |
|||
label: '大长腿', |
|||
}, |
|||
{ |
|||
key: '4', |
|||
label: '川妹子', |
|||
}, |
|||
{ |
|||
key: '5', |
|||
label: '海纳百川', |
|||
}, |
|||
], |
|||
notifyCount: 12, |
|||
unreadCount: 11, |
|||
country: 'China', |
|||
address: 'Xiamen City 77', |
|||
phone: '0592-268888888', |
|||
}; |
|||
|
|||
export default [ |
|||
{ |
|||
url: `${baseUrl}/account/getAccountInfo`, |
|||
timeout: 1000, |
|||
method: 'get', |
|||
response: () => { |
|||
return resultSuccess(userInfo); |
|||
}, |
|||
}, |
|||
{ |
|||
url: `${baseUrl}/user/sessionTimeout`, |
|||
method: 'post', |
|||
statusCode: 401, |
|||
response: () => { |
|||
return resultError(); |
|||
}, |
|||
}, |
|||
{ |
|||
url: '/basic-api/user/tokenExpired', |
|||
method: 'post', |
|||
statusCode: 200, |
|||
response: () => { |
|||
return resultError('Token Expired!', { code: ResultEnum.TIMEOUT as number }); |
|||
}, |
|||
}, |
|||
] as MockMethod[]; |
@ -0,0 +1,28 @@ |
|||
import { MockMethod } from 'vite-plugin-mock'; |
|||
import { resultSuccess, baseUrl } from '../_util'; |
|||
|
|||
const demoList = (keyword, count = 20) => { |
|||
const result = { |
|||
list: [] as any[], |
|||
}; |
|||
for (let index = 0; index < count; index++) { |
|||
result.list.push({ |
|||
name: `${keyword ?? ''}选项${index}`, |
|||
id: `${index}`, |
|||
}); |
|||
} |
|||
return result; |
|||
}; |
|||
|
|||
export default [ |
|||
{ |
|||
url: `${baseUrl}/select/getDemoOptions`, |
|||
timeout: 1000, |
|||
method: 'get', |
|||
response: ({ query }) => { |
|||
const { keyword,count} = query; |
|||
console.log(keyword); |
|||
return resultSuccess(demoList(keyword,count)); |
|||
}, |
|||
}, |
|||
] as MockMethod[]; |
@ -0,0 +1,298 @@ |
|||
import { MockMethod } from 'vite-plugin-mock'; |
|||
import { resultError, resultPageSuccess, resultSuccess, baseUrl } from '../_util'; |
|||
|
|||
const accountList = (() => { |
|||
const result: any[] = []; |
|||
for (let index = 0; index < 20; index++) { |
|||
result.push({ |
|||
id: `${index}`, |
|||
account: '@first', |
|||
email: '@email', |
|||
nickname: '@cname()', |
|||
role: '@first', |
|||
createTime: '@datetime', |
|||
remark: '@cword(10,20)', |
|||
'status|1': ['0', '1'], |
|||
}); |
|||
} |
|||
return result; |
|||
})(); |
|||
|
|||
const userList = (() => { |
|||
const result: any[] = []; |
|||
for (let index = 0; index < 20; index++) { |
|||
result.push({ |
|||
id: `${index}`, |
|||
username: '@first', |
|||
email: '@email', |
|||
realname: '@cname()', |
|||
createTime: '@datetime', |
|||
remark: '@cword(10,20)', |
|||
avatar: 'https://q1.qlogo.cn/g?b=qq&nk=190848757&s=640' |
|||
}); |
|||
} |
|||
return result; |
|||
})(); |
|||
|
|||
const roleList = (() => { |
|||
const result: any[] = []; |
|||
for (let index = 0; index < 4; index++) { |
|||
result.push({ |
|||
id: index + 1, |
|||
orderNo: `${index + 1}`, |
|||
roleName: ['超级管理员', '管理员', '文章管理员', '普通用户'][index], |
|||
roleValue: '@first', |
|||
createTime: '@datetime', |
|||
remark: '@cword(10,20)', |
|||
menu: [['0', '1', '2'], ['0', '1'], ['0', '2'], ['2']][index], |
|||
'status|1': ['0', '1'], |
|||
}); |
|||
} |
|||
return result; |
|||
})(); |
|||
|
|||
const newRoleList = (() => { |
|||
const result: any[] = []; |
|||
for (let index = 0; index < 4; index++) { |
|||
result.push({ |
|||
id: index + 1, |
|||
orderNo: `${index + 1}`, |
|||
roleName: ['超级管理员', '管理员', '文章管理员', '普通用户'][index], |
|||
roleCode: '@first', |
|||
createTime: '@datetime', |
|||
remark: '@cword(10,20)' |
|||
}); |
|||
} |
|||
return result; |
|||
})(); |
|||
|
|||
const testList = (() => { |
|||
const result: any[] = []; |
|||
for (let index = 0; index < 4; index++) { |
|||
result.push({ |
|||
id: index + 1, |
|||
orderNo: `${index + 1}`, |
|||
testName: ['数据1', '数据2', '数据3', '数据4'][index], |
|||
testValue: '@first', |
|||
createTime: '@datetime' |
|||
}); |
|||
} |
|||
return result; |
|||
})(); |
|||
|
|||
const tableDemoList = (() => { |
|||
const result: any[] = []; |
|||
for (let index = 0; index < 4; index++) { |
|||
result.push({ |
|||
id: index + 1, |
|||
orderCode: '2008200' + `${index + 1}`, |
|||
orderMoney: '@natural(1000,3000)', |
|||
ctype: '@natural(1,2)', |
|||
content: '@cword(10,20)', |
|||
orderDate: '@datetime' |
|||
}); |
|||
} |
|||
return result; |
|||
})(); |
|||
|
|||
const deptList = (() => { |
|||
const result: any[] = []; |
|||
for (let index = 0; index < 3; index++) { |
|||
result.push({ |
|||
id: `${index}`, |
|||
deptName: ['华东分部', '华南分部', '西北分部'][index], |
|||
orderNo: index + 1, |
|||
createTime: '@datetime', |
|||
remark: '@cword(10,20)', |
|||
'status|1': ['0', '0', '1'], |
|||
children: (() => { |
|||
const children: any[] = []; |
|||
for (let j = 0; j < 4; j++) { |
|||
children.push({ |
|||
id: `${index}-${j}`, |
|||
deptName: ['研发部', '市场部', '商务部', '财务部'][j], |
|||
orderNo: j + 1, |
|||
createTime: '@datetime', |
|||
remark: '@cword(10,20)', |
|||
'status|1': ['0', '1'], |
|||
parentDept: `${index}`, |
|||
children: undefined, |
|||
}); |
|||
} |
|||
return children; |
|||
})(), |
|||
}); |
|||
} |
|||
return result; |
|||
})(); |
|||
|
|||
const menuList = (() => { |
|||
const result: any[] = []; |
|||
for (let index = 0; index < 3; index++) { |
|||
result.push({ |
|||
id: `${index}`, |
|||
icon: ['ion:layers-outline', 'ion:git-compare-outline', 'ion:tv-outline'][index], |
|||
component: 'LAYOUT', |
|||
type: '0', |
|||
menuName: ['Dashboard', '权限管理', '功能'][index], |
|||
permission: '', |
|||
orderNo: index + 1, |
|||
createTime: '@datetime', |
|||
'status|1': ['0', '0', '1'], |
|||
children: (() => { |
|||
const children: any[] = []; |
|||
for (let j = 0; j < 4; j++) { |
|||
children.push({ |
|||
id: `${index}-${j}`, |
|||
type: '1', |
|||
menuName: ['菜单1', '菜单2', '菜单3', '菜单4'][j], |
|||
icon: 'ion:document', |
|||
permission: ['menu1:view', 'menu2:add', 'menu3:update', 'menu4:del'][index], |
|||
component: [ |
|||
'/dashboard/welcome/index', |
|||
'/dashboard/Analysis/index', |
|||
'/dashboard/workbench/index', |
|||
'/dashboard/test/index', |
|||
][j], |
|||
orderNo: j + 1, |
|||
createTime: '@datetime', |
|||
'status|1': ['0', '1'], |
|||
parentMenu: `${index}`, |
|||
children: (() => { |
|||
const children: any[] = []; |
|||
for (let k = 0; k < 4; k++) { |
|||
children.push({ |
|||
id: `${index}-${j}-${k}`, |
|||
type: '2', |
|||
menuName: '按钮' + (j + 1) + '-' + (k + 1), |
|||
icon: '', |
|||
permission: |
|||
['menu1:view', 'menu2:add', 'menu3:update', 'menu4:del'][index] + |
|||
':btn' + |
|||
(k + 1), |
|||
component: [ |
|||
'/dashboard/welcome/index', |
|||
'/dashboard/Analysis/index', |
|||
'/dashboard/workbench/index', |
|||
'/dashboard/test/index', |
|||
][j], |
|||
orderNo: j + 1, |
|||
createTime: '@datetime', |
|||
'status|1': ['0', '1'], |
|||
parentMenu: `${index}-${j}`, |
|||
children: undefined, |
|||
}); |
|||
} |
|||
return children; |
|||
})(), |
|||
}); |
|||
} |
|||
return children; |
|||
})(), |
|||
}); |
|||
} |
|||
return result; |
|||
})(); |
|||
|
|||
export default [ |
|||
{ |
|||
url: `${baseUrl}/system/getAccountList`, |
|||
timeout: 100, |
|||
method: 'get', |
|||
response: ({ query }) => { |
|||
const { page = 1, pageSize = 20 } = query; |
|||
return resultPageSuccess(page, pageSize, accountList); |
|||
}, |
|||
}, |
|||
{ |
|||
url: `${baseUrl}/sys/user/list`, |
|||
timeout: 100, |
|||
method: 'get', |
|||
response: ({ query }) => { |
|||
const { page = 1, pageSize = 20 } = query; |
|||
return resultPageSuccess(page, pageSize, userList); |
|||
}, |
|||
}, |
|||
{ |
|||
url: `${baseUrl}/system/getRoleListByPage`, |
|||
timeout: 100, |
|||
method: 'get', |
|||
response: ({ query }) => { |
|||
const { page = 1, pageSize = 20 } = query; |
|||
return resultPageSuccess(page, pageSize, roleList); |
|||
}, |
|||
}, |
|||
{ |
|||
url: `${baseUrl}/sys/role/list`, |
|||
timeout: 100, |
|||
method: 'get', |
|||
response: ({ query }) => { |
|||
const { page = 1, pageSize = 20 } = query; |
|||
return resultPageSuccess(page, pageSize, newRoleList); |
|||
}, |
|||
}, |
|||
{ |
|||
url: `${baseUrl}/system/getTestListByPage`, |
|||
timeout: 100, |
|||
method: 'get', |
|||
response: ({ query }) => { |
|||
const { page = 1, pageSize = 20 } = query; |
|||
return resultPageSuccess(page, pageSize, testList); |
|||
}, |
|||
}, |
|||
{ |
|||
url: `${baseUrl}/system/getDemoTableListByPage`, |
|||
timeout: 100, |
|||
method: 'get', |
|||
response: ({ query }) => { |
|||
const { page = 1, pageSize = 20 } = query; |
|||
return resultPageSuccess(page, pageSize, tableDemoList); |
|||
}, |
|||
}, |
|||
{ |
|||
url: `${baseUrl}/system/setRoleStatus`, |
|||
timeout: 500, |
|||
method: 'post', |
|||
response: ({ query }) => { |
|||
const { id, status } = query; |
|||
return resultSuccess({ id, status }); |
|||
}, |
|||
}, |
|||
{ |
|||
url: `${baseUrl}/system/getAllRoleList`, |
|||
timeout: 100, |
|||
method: 'get', |
|||
response: () => { |
|||
return resultSuccess(roleList); |
|||
}, |
|||
}, |
|||
{ |
|||
url: `${baseUrl}/system/getDeptList`, |
|||
timeout: 100, |
|||
method: 'get', |
|||
response: () => { |
|||
return resultSuccess(deptList); |
|||
}, |
|||
}, |
|||
{ |
|||
url: `${baseUrl}/system/getMenuList`, |
|||
timeout: 100, |
|||
method: 'get', |
|||
response: () => { |
|||
return resultSuccess(menuList); |
|||
}, |
|||
}, |
|||
{ |
|||
url: `${baseUrl}/system/accountExist`, |
|||
timeout: 500, |
|||
method: 'post', |
|||
response: ({ body }) => { |
|||
const { account } = body || {}; |
|||
if (account && account.indexOf('admin') !== -1) { |
|||
return resultError('该字段不能包含admin'); |
|||
} else { |
|||
return resultSuccess(`${account} can use`); |
|||
} |
|||
}, |
|||
}, |
|||
] as MockMethod[]; |
@ -0,0 +1,52 @@ |
|||
import { MockMethod } from 'vite-plugin-mock'; |
|||
import { Random } from 'mockjs'; |
|||
import { resultPageSuccess, baseUrl } from '../_util'; |
|||
|
|||
function getRandomPics(count = 10): string[] { |
|||
const arr: string[] = []; |
|||
for (let i = 0; i < count; i++) { |
|||
arr.push(Random.image('800x600', Random.color(), Random.color(), Random.title())); |
|||
} |
|||
return arr; |
|||
} |
|||
|
|||
const demoList = (() => { |
|||
const result: any[] = []; |
|||
for (let index = 0; index < 200; index++) { |
|||
result.push({ |
|||
id: `${index}`, |
|||
beginTime: '@datetime', |
|||
endTime: '@datetime', |
|||
address: '@city()', |
|||
name: '@cname()', |
|||
name1: '@cname()', |
|||
name2: '@cname()', |
|||
name3: '@cname()', |
|||
name4: '@cname()', |
|||
name5: '@cname()', |
|||
name6: '@cname()', |
|||
name7: '@cname()', |
|||
name8: '@cname()', |
|||
avatar: Random.image('400x400', Random.color(), Random.color(), Random.first()), |
|||
imgArr: getRandomPics(Math.ceil(Math.random() * 3) + 1), |
|||
imgs: getRandomPics(Math.ceil(Math.random() * 3) + 1), |
|||
date: `@date('yyyy-MM-dd')`, |
|||
time: `@time('HH:mm')`, |
|||
'no|100000-10000000': 100000, |
|||
'status|1': ['normal', 'enable', 'disable'], |
|||
}); |
|||
} |
|||
return result; |
|||
})(); |
|||
|
|||
export default [ |
|||
{ |
|||
url: `${baseUrl}/table/getDemoList`, |
|||
timeout: 100, |
|||
method: 'get', |
|||
response: ({ query }) => { |
|||
const { page = 1, pageSize = 20 } = query; |
|||
return resultPageSuccess(page, pageSize, demoList); |
|||
}, |
|||
}, |
|||
] as MockMethod[]; |
@ -0,0 +1,38 @@ |
|||
import { MockMethod } from 'vite-plugin-mock'; |
|||
import { resultSuccess, baseUrl } from '../_util'; |
|||
|
|||
const demoTreeList = (keyword) => { |
|||
const result = { |
|||
list: [] as Recordable[], |
|||
}; |
|||
for (let index = 0; index < 5; index++) { |
|||
const children: Recordable[] = []; |
|||
for (let j = 0; j < 3; j++) { |
|||
children.push({ |
|||
title: `${keyword ?? ''}选项${index}-${j}`, |
|||
value: `${index}-${j}`, |
|||
key: `${index}-${j}`, |
|||
}); |
|||
} |
|||
result.list.push({ |
|||
title: `${keyword ?? ''}选项${index}`, |
|||
value: `${index}`, |
|||
key: `${index}`, |
|||
children, |
|||
}); |
|||
} |
|||
return result; |
|||
}; |
|||
|
|||
export default [ |
|||
{ |
|||
url: `${baseUrl}/tree/getDemoOptions`, |
|||
timeout: 1000, |
|||
method: 'get', |
|||
response: ({ query }) => { |
|||
const { keyword } = query; |
|||
console.log(keyword); |
|||
return resultSuccess(demoTreeList(keyword)); |
|||
}, |
|||
}, |
|||
] as MockMethod[]; |
@ -0,0 +1,270 @@ |
|||
import { resultSuccess, resultError, getRequestToken, requestParams,baseUrl} from '../_util'; |
|||
import { MockMethod } from 'vite-plugin-mock'; |
|||
import { createFakeUserList } from './user'; |
|||
|
|||
// single
|
|||
const dashboardRoute = { |
|||
path: '/dashboard', |
|||
name: 'Dashboard', |
|||
component: 'LAYOUT', |
|||
redirect: '/dashboard/analysis', |
|||
meta: { |
|||
title: 'routes.dashboard.dashboard', |
|||
hideChildrenInMenu: true, |
|||
icon: 'bx:bx-home', |
|||
}, |
|||
children: [ |
|||
{ |
|||
path: 'analysis', |
|||
name: 'Analysis', |
|||
component: '/dashboard/Analysis/index', |
|||
meta: { |
|||
hideMenu: true, |
|||
hideBreadcrumb: true, |
|||
title: 'routes.dashboard.analysis', |
|||
currentActiveMenu: '/dashboard', |
|||
icon: 'bx:bx-home', |
|||
}, |
|||
}, |
|||
{ |
|||
path: 'workbench', |
|||
name: 'Workbench', |
|||
component: '/dashboard/workbench/index', |
|||
meta: { |
|||
hideMenu: true, |
|||
hideBreadcrumb: true, |
|||
title: 'routes.dashboard.workbench', |
|||
currentActiveMenu: '/dashboard', |
|||
icon: 'bx:bx-home', |
|||
}, |
|||
}, |
|||
], |
|||
}; |
|||
|
|||
const backRoute = { |
|||
path: 'back', |
|||
name: 'PermissionBackDemo', |
|||
meta: { |
|||
title: 'routes.demo.permission.back', |
|||
}, |
|||
|
|||
children: [ |
|||
{ |
|||
path: 'page', |
|||
name: 'BackAuthPage', |
|||
component: '/demo/permission/back/index', |
|||
meta: { |
|||
title: 'routes.demo.permission.backPage', |
|||
}, |
|||
}, |
|||
{ |
|||
path: 'btn', |
|||
name: 'BackAuthBtn', |
|||
component: '/demo/permission/back/Btn', |
|||
meta: { |
|||
title: 'routes.demo.permission.backBtn', |
|||
}, |
|||
}, |
|||
], |
|||
}; |
|||
|
|||
const authRoute = { |
|||
path: '/permission', |
|||
name: 'Permission', |
|||
component: 'LAYOUT', |
|||
redirect: '/permission/front/page', |
|||
meta: { |
|||
icon: 'carbon:user-role', |
|||
title: 'routes.demo.permission.permission', |
|||
}, |
|||
children: [backRoute], |
|||
}; |
|||
|
|||
const levelRoute = { |
|||
path: '/level', |
|||
name: 'Level', |
|||
component: 'LAYOUT', |
|||
redirect: '/level/menu1/menu1-1', |
|||
meta: { |
|||
icon: 'carbon:user-role', |
|||
title: 'routes.demo.level.level', |
|||
}, |
|||
|
|||
children: [ |
|||
{ |
|||
path: 'menu1', |
|||
name: 'Menu1Demo', |
|||
meta: { |
|||
title: 'Menu1', |
|||
}, |
|||
children: [ |
|||
{ |
|||
path: 'menu1-1', |
|||
name: 'Menu11Demo', |
|||
meta: { |
|||
title: 'Menu1-1', |
|||
}, |
|||
children: [ |
|||
{ |
|||
path: 'menu1-1-1', |
|||
name: 'Menu111Demo', |
|||
component: '/demo/level/Menu111', |
|||
meta: { |
|||
title: 'Menu111', |
|||
}, |
|||
}, |
|||
], |
|||
}, |
|||
{ |
|||
path: 'menu1-2', |
|||
name: 'Menu12Demo', |
|||
component: '/demo/level/Menu12', |
|||
meta: { |
|||
title: 'Menu1-2', |
|||
}, |
|||
}, |
|||
], |
|||
}, |
|||
{ |
|||
path: 'menu2', |
|||
name: 'Menu2Demo', |
|||
component: '/demo/level/Menu2', |
|||
meta: { |
|||
title: 'Menu2', |
|||
}, |
|||
}, |
|||
], |
|||
}; |
|||
|
|||
const sysRoute = { |
|||
path: '/system', |
|||
name: 'System', |
|||
component: 'LAYOUT', |
|||
redirect: '/system/account', |
|||
meta: { |
|||
icon: 'ion:settings-outline', |
|||
title: 'routes.demo.system.moduleName', |
|||
}, |
|||
children: [ |
|||
{ |
|||
path: 'account', |
|||
name: 'AccountManagement', |
|||
meta: { |
|||
title: 'routes.demo.system.account', |
|||
ignoreKeepAlive: true, |
|||
}, |
|||
component: '/demo/system/account/index', |
|||
}, |
|||
{ |
|||
path: 'account_detail/:id', |
|||
name: 'AccountDetail', |
|||
meta: { |
|||
hideMenu: true, |
|||
title: 'routes.demo.system.account_detail', |
|||
ignoreKeepAlive: true, |
|||
showMenu: false, |
|||
currentActiveMenu: '/system/account', |
|||
}, |
|||
component: '/demo/system/account/AccountDetail', |
|||
}, |
|||
{ |
|||
path: 'role', |
|||
name: 'RoleManagement', |
|||
meta: { |
|||
title: 'routes.demo.system.role', |
|||
ignoreKeepAlive: true, |
|||
}, |
|||
component: '/demo/system/role/index', |
|||
}, |
|||
|
|||
{ |
|||
path: 'menu', |
|||
name: 'MenuManagement', |
|||
meta: { |
|||
title: 'routes.demo.system.menu', |
|||
ignoreKeepAlive: true, |
|||
}, |
|||
component: '/demo/system/menu/index', |
|||
}, |
|||
{ |
|||
path: 'dept', |
|||
name: 'DeptManagement', |
|||
meta: { |
|||
title: 'routes.demo.system.dept', |
|||
ignoreKeepAlive: true, |
|||
}, |
|||
component: '/demo/system/dept/index', |
|||
}, |
|||
{ |
|||
path: 'changePassword', |
|||
name: 'ChangePassword', |
|||
meta: { |
|||
title: 'routes.demo.system.password', |
|||
ignoreKeepAlive: true, |
|||
}, |
|||
component: '/demo/system/password/index', |
|||
}, |
|||
], |
|||
}; |
|||
|
|||
const linkRoute = { |
|||
path: '/link', |
|||
name: 'Link', |
|||
component: 'LAYOUT', |
|||
meta: { |
|||
icon: 'ion:tv-outline', |
|||
title: 'routes.demo.iframe.frame', |
|||
}, |
|||
children: [ |
|||
{ |
|||
path: 'doc', |
|||
name: 'Doc', |
|||
meta: { |
|||
title: 'routes.demo.iframe.doc', |
|||
frameSrc: 'https://vvbin.cn/doc-next/', |
|||
}, |
|||
}, |
|||
{ |
|||
path: 'https://vvbin.cn/doc-next/', |
|||
name: 'DocExternal', |
|||
component: 'LAYOUT', |
|||
meta: { |
|||
title: 'routes.demo.iframe.docExternal', |
|||
}, |
|||
}, |
|||
], |
|||
}; |
|||
|
|||
export default [ |
|||
{ |
|||
url: `${baseUrl}/sys/permission/getUserPermissionByToken`, |
|||
timeout: 1000, |
|||
method: 'get', |
|||
response: (request: requestParams) => { |
|||
const token = getRequestToken(request); |
|||
if (!token) { |
|||
return resultError('Invalid token!'); |
|||
} |
|||
const checkUser = createFakeUserList().find((item) => item.token === token); |
|||
if (!checkUser) { |
|||
return resultError('Invalid user token!'); |
|||
} |
|||
const id = checkUser.userId; |
|||
let menu: Object[]; |
|||
switch (id) { |
|||
case '1': |
|||
dashboardRoute.redirect = dashboardRoute.path + '/' + dashboardRoute.children[0].path; |
|||
menu = [dashboardRoute, authRoute, levelRoute, sysRoute, linkRoute]; |
|||
break; |
|||
case '2': |
|||
dashboardRoute.redirect = dashboardRoute.path + '/' + dashboardRoute.children[1].path; |
|||
menu = [dashboardRoute, authRoute, levelRoute, linkRoute]; |
|||
break; |
|||
default: |
|||
menu = []; |
|||
} |
|||
|
|||
return resultSuccess(menu); |
|||
}, |
|||
}, |
|||
] as MockMethod[]; |
@ -0,0 +1,124 @@ |
|||
import { MockMethod } from 'vite-plugin-mock'; |
|||
import { resultError, resultSuccess, getRequestToken, requestParams, baseUrl } from '../_util'; |
|||
export function createFakeUserList() { |
|||
return [ |
|||
{ |
|||
userId: '1', |
|||
username: 'admin', |
|||
realname: '管理员', |
|||
avatar: 'https://q1.qlogo.cn/g?b=qq&nk=190848757&s=640', |
|||
desc: 'manager', |
|||
password: '123456', |
|||
token: 'fakeToken1', |
|||
homePath: '/dashboard/analysis', |
|||
roles: [ |
|||
{ |
|||
roleName: 'Super Admin', |
|||
value: 'super', |
|||
}, |
|||
], |
|||
}, |
|||
{ |
|||
userId: '2', |
|||
username: 'jeecg', |
|||
password: '123456', |
|||
realname: '测试用户', |
|||
avatar: 'https://q1.qlogo.cn/g?b=qq&nk=339449197&s=640', |
|||
desc: 'tester', |
|||
token: 'fakeToken2', |
|||
homePath: '/dashboard/workbench', |
|||
roles: [ |
|||
{ |
|||
roleName: 'Tester', |
|||
value: 'test', |
|||
}, |
|||
], |
|||
}, |
|||
]; |
|||
} |
|||
|
|||
const fakeCodeList: any = { |
|||
'1': ['1000', '3000', '5000'], |
|||
|
|||
'2': ['2000', '4000', '6000'], |
|||
}; |
|||
|
|||
export default [ |
|||
// mock user login
|
|||
{ |
|||
url: `${baseUrl}/sys/login`, |
|||
timeout: 200, |
|||
method: 'post', |
|||
response: ({ body }) => { |
|||
const { username, password } = body; |
|||
const checkUser = createFakeUserList().find( |
|||
(item) => item.username === username && password === item.password |
|||
); |
|||
if (!checkUser) { |
|||
return resultError('Incorrect account or password!'); |
|||
} |
|||
const { userId, username: _username, token, realname, desc, roles } = checkUser; |
|||
return resultSuccess({ |
|||
roles, |
|||
userId, |
|||
username: _username, |
|||
token, |
|||
realname, |
|||
desc, |
|||
}); |
|||
}, |
|||
}, |
|||
{ |
|||
url: `${baseUrl}/sys/user/getUserInfo`, |
|||
method: 'get', |
|||
response: (request: requestParams) => { |
|||
const token = getRequestToken(request); |
|||
if (!token) return resultError('Invalid token'); |
|||
const checkUser = createFakeUserList().find((item) => item.token === token); |
|||
if (!checkUser) { |
|||
return resultError('The corresponding user information was not obtained!'); |
|||
} |
|||
return resultSuccess(checkUser); |
|||
}, |
|||
}, |
|||
{ |
|||
url: `${baseUrl}/sys/permission/getPermCode`, |
|||
timeout: 200, |
|||
method: 'get', |
|||
response: (request: requestParams) => { |
|||
const token = getRequestToken(request); |
|||
if (!token) return resultError('Invalid token'); |
|||
const checkUser = createFakeUserList().find((item) => item.token === token); |
|||
if (!checkUser) { |
|||
return resultError('Invalid token!'); |
|||
} |
|||
const codeList = fakeCodeList[checkUser.userId]; |
|||
|
|||
return resultSuccess(codeList); |
|||
}, |
|||
}, |
|||
{ |
|||
url: `${baseUrl}/sys/logout`, |
|||
timeout: 200, |
|||
method: 'get', |
|||
response: (request: requestParams) => { |
|||
const token = getRequestToken(request); |
|||
if (!token) return resultError('Invalid token'); |
|||
const checkUser = createFakeUserList().find((item) => item.token === token); |
|||
if (!checkUser) { |
|||
return resultError('Invalid token!'); |
|||
} |
|||
return resultSuccess(undefined, { message: 'Token has been destroyed' }); |
|||
}, |
|||
}, |
|||
{ |
|||
url: `${baseUrl}/sys/randomImage/1629428467008`, |
|||
timeout: 200, |
|||
method: 'get', |
|||
response: (request: requestParams) => { |
|||
const result = |
|||
'data:image/jpg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAjAGkDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3h/ME5lErCKNSHi8rO44yCp65/P060gmdbbIaKecxl0VDsEmOmMk8cgZ96dcypFGpkEm0uOUzxznJI6DjnPH54ryTWNW1+P436T4ftNev4LTU7Brhw9tbCSHiZxGrNCcKCijkMeuSSOAD1KJ7hrTZNK0d1Iz7egGVPRSV6HGRkE4z1xV5SWQEqVJGSpxke3FeYL4n1PSfi5pXhK7vxrFlf27XVveyQRrcQHa4KFo1CMhMLdFUjfy2F59NjZm3Bl2kMRxnGO3JA7Y/HI7UAVrjfbWt3NJLNKmCwVAoaNcc4PHTk8+n5rKs1tDGtsdw5X94GkOT90ls5xnr14PYDNeUfDzxvq3xCuNZvG8SNp1zBKHtdFgtYpFjhAADuWXfKpJwwRkIwcFd6geg+Dm12Tw9bN4hkX+0Y5bmKcLGVV9s7KjLkA7dijBPLAgnJ5oWgGrb36zBtqyPh9oKwuvG4DncByCeeexPsLHm7jH5amSNxnzFI2gY479/bNVrxYZpRD57Q3JRkikRFLxlgfmUspGQEbrkccg8V5l8PfEOt6h4p8YW+r+JJf7M8OXZhjWWC2jjMQaZSZWWNSMLGDkFQD1BHFAHq7usMcksjnYoLHI+6AOen0pqllZfNkUMWZVUdG5yOvOcD+dcclt4j1/XlvtM8T3dn4cIc7kgt2a4PGwwBoTiLqfMZm34+VQpVz0Ou2t/eWfk2GrXGmTNxHcW9ukxV8EAOrqwKZIJ+6fl+8M0AXjHcb5GWdcN9xWjyF6ehGe/5j05jmdri3cxPJGI3YOAOXABGARnGTjkcjpwenmvwt8Y61czeIdM8b6g0esaW3mTR3SwQJFAB99dijcOpZySoBjI+8TXR+EtK16SNdR1rWL64WUNPaWtxbxQGBXbKCVY0VjKq/f525dgBxuKA6i4ZfsSEyq0R275Wm8v5f7wZe/TjgHNWqiiSWNEV5vNwp3MygFj68cAdeMen4y0wKk6Mtysp3yQsvktEoyPmI+YgnGB9O57dPIfGML3H7SnhaGO+msXfS2C3EIjLqcXPTzFZeenIPXjnFeyiIJIzx4XzH3SZBO75ccc8dF/L3zXHah4D0K58US+ILuLUPtcMeI5l1G5WT5i+VjYSDYCW2hVIHLDaMg0AX9K8FaVZ+IJPEVxPc6rrTAxLf3rqzRJgKURUVUToeQoPzNk8mt0qRJF5uTMVdBNGuAucHoScdByeOPcAxRw3MdzOpuC3nZkQiEBY8EcMf4sggfRT0qYQSJBJGJWlGwKodirZxjlxzzxzjIOfYAA8Tn+HehfErRoPGvhDUP7J1uQCaWK3YmJLpQWZT0aN95X5xxgBgp3ZPb/AAi8U6r4q8BRajriv9qW5khFy6hBcrkEOoCqAAW2cZ5Q85yBdtPAfhSTSv7Og0mWxiWH7PcQ288lq86Y2/vjEy+cCM8sW6t6mukt9PttNsobLTbC0gtY34gjURIgzuJVVGM55xxz3oAnZf8ASI38vcQrLu3fdBwenccfy96+abbwjqHiu8+K1lpt/NFJBqYlW1MwSO5KzzECRmBJwA2ASBuKljxkfSF9ai7jeESzRtJGy5R3UAdCcoVIOGOCCD36qMc9oHgHw/oGrSalpMd1a3DuWnRb6Z1lYr/y2VnYOw3sQT03Z96AMn4W+PP+Et0xrLVZmi8TaerRX9pJH5Rba2BIE9egbGMMSCACtdxOHuYmXy3CCVRjIHmLkbs5HTrx3A9DXJN8LvCraj/adpa3SajtZBqC6rdGaMhdgw3mZOB8uMjgY9q39X0Sx1myuLLUknWwbLSLDdyQrKGUhgxRlOPvZUnac5OT0AseQfEHT7u71CP4keHrbTZJtFSGWQ/Zmk+3gMytMByDGm0BXwrbVdwwVYmPqXhvxDZeKdEj1bRL6AWM42NvT9/DLtVQkmWOXBx16jbjIINGl+GdPs9I/seG6nSAfIY7e/n3qqEBVSQuZI1A25RWABOOhO7P8NeA/DejRveaBpb2IuW2k/bJmDxjIDlJNyk4LYyOjHBGaAOwjeQogYxtIuBNtbhTjPH6cHsalqlbWMFrcSNuVnkkeZAwG5c/eI79wOO2O+SbtABSMiuMMoYZBwRnkHIP50UUALRRRQAUUUUAFFFFACBVUsVUAscsQOpxjn8AKWiigBFVUQIihVUYAAwAKY8EUkqSOgZ0BCk9uQf5qD+FFFAElFFFAH//2Q=='; |
|||
return resultSuccess(result); |
|||
}, |
|||
}, |
|||
] as MockMethod[]; |
@ -0,0 +1,357 @@ |
|||
{ |
|||
"name": "jeecgboot-vue3", |
|||
"version": "3.5.1", |
|||
"author": { |
|||
"name": "jeecg", |
|||
"email": "jeecgos@163.com", |
|||
"url": "https://github.com/jeecgboot/jeecgboot-vue3" |
|||
}, |
|||
"main": "electron/electron.js", |
|||
"build": { |
|||
"appId": "com.my-website.my-app", |
|||
"productName": "MyApp", |
|||
"copyright": "Copyright © 2022 ${author}", |
|||
"mac": { |
|||
"category": "public.app-category.utilities" |
|||
}, |
|||
"nsis": { |
|||
"oneClick": false, |
|||
"allowToChangeInstallationDirectory": true |
|||
}, |
|||
"files": [ |
|||
"dist/**/*", |
|||
"electron/**/*" |
|||
], |
|||
"extraResources": [ |
|||
"./_app.config.js" |
|||
], |
|||
"directories": { |
|||
"buildResources": "assets", |
|||
"output": "dist_electron" |
|||
}, |
|||
"electronDownload": { |
|||
"mirror": "https://npm.taobao.org/mirrors/electron/" |
|||
} |
|||
}, |
|||
"scripts": { |
|||
"electron:serve": "cross-env IS_DEV=true electron .", |
|||
"electron:start": "npm run dev & npm run electron:serve", |
|||
"electron:dev": "concurrently \"npm run dev\" \"npm run electron:serve\" ", |
|||
"electron:build.win": "npm run build && electron-builder --win --dir", |
|||
"electron:builder": "electron-builder --win --dir", |
|||
"bootstrap": "pnpm install", |
|||
"serve": "npm run dev", |
|||
"dev": "vite", |
|||
"clean:cache": "rimraf node_modules/.cache/ && rimraf node_modules/.vite", |
|||
"clean:lib": "rimraf node_modules", |
|||
"build": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=8192 vite build && esno ./build/script/postBuild.ts", |
|||
"build:test": "cross-env NODE_OPTIONS=--max-old-space-size=8192 vite build --mode test && esno ./build/script/postBuild.ts", |
|||
"build:no-cache": "pnpm clean:cache && npm run build", |
|||
"report": "cross-env REPORT=true npm run build", |
|||
"type:check": "vue-tsc --noEmit --skipLibCheck", |
|||
"preview": "npm run build && vite preview", |
|||
"preview:dist": "vite preview", |
|||
"log": "conventional-changelog -p angular -i CHANGELOG.md -s", |
|||
"lint:eslint": "eslint --cache --max-warnings 0 \"{src,mock}/**/*.{vue,ts,tsx}\" --fix", |
|||
"lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"", |
|||
"lint:stylelint": "stylelint --cache --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/", |
|||
"lint:lint-staged": "lint-staged -c ./.husky/lintstagedrc.js", |
|||
"lint:pretty": "pretty-quick --staged", |
|||
"test:unit": "jest", |
|||
"test:unit-coverage": "jest --coverage", |
|||
"test:gzip": "http-server dist --cors --gzip -c-1", |
|||
"test:br": "http-server dist --cors --brotli -c-1", |
|||
"reinstall": "rimraf pnpm-lock.yaml && yarn.lock && rimraf package.lock.json && rimraf node_modules && npm run bootstrap", |
|||
"prepare": "husky install", |
|||
"gen:icon": "esno ./build/generate/icon/index.ts" |
|||
}, |
|||
"dependencies": { |
|||
"@ant-design/colors": "^6.0.0", |
|||
"@ant-design/icons-vue": "^6.1.0", |
|||
"@easydarwin/easyplayer": "^5.0.7", |
|||
"@iconify/iconify": "^2.2.1", |
|||
"@jeecg/online": "3.4.4-RC", |
|||
"@logicflow/core": "^1.1.13", |
|||
"@logicflow/extension": "^1.1.13", |
|||
"@vue/compiler-ssr": "^3.3.4", |
|||
"@vue/runtime-core": "^3.2.33", |
|||
"@vue/server-renderer": "^3.3.4", |
|||
"@vue/shared": "^3.2.33", |
|||
"@vueuse/core": "^8.3.0", |
|||
"@vueuse/shared": "^8.3.0", |
|||
"@zxcvbn-ts/core": "^2.0.1", |
|||
"ant-design-vue": "^3.2.12", |
|||
"autofit.js": "^3.0.4", |
|||
"axios": "^0.26.1", |
|||
"china-area-data": "^5.0.1", |
|||
"clipboard": "^2.0.8", |
|||
"codemirror": "^5.65.3", |
|||
"concurrently": "^8.2.2", |
|||
"cron-parser": "^3.5.0", |
|||
"cropperjs": "^1.5.12", |
|||
"crypto-js": "^4.1.1", |
|||
"dayjs": "^1.11.1", |
|||
"dom-align": "^1.12.2", |
|||
"earthsdk": "^1.7.16", |
|||
"echarts": "^5.3.2", |
|||
"electron-packager": "^17.1.2", |
|||
"emoji-mart-vue-fast": "^11.1.1", |
|||
"enquire.js": "^2.1.6", |
|||
"intro.js": "^5.1.0", |
|||
"jquery": "^3.7.0", |
|||
"lodash": "^4.17.21", |
|||
"lodash-es": "^4.17.21", |
|||
"lodash.get": "^4.4.2", |
|||
"md5": "^2.3.0", |
|||
"mitt": "^3.0.1", |
|||
"mockjs": "^1.1.0", |
|||
"moment": "^2.29.4", |
|||
"nprogress": "^0.2.0", |
|||
"particles.vue3": "^2.11.0", |
|||
"path-to-regexp": "^6.2.0", |
|||
"pinia": "2.0.12", |
|||
"pinyin-pro": "^3.11.0", |
|||
"print-js": "^1.6.0", |
|||
"qrcode": "^1.5.0", |
|||
"qrcodejs2": "0.0.2", |
|||
"qs": "^6.10.3", |
|||
"resize-observer-polyfill": "^1.5.1", |
|||
"serve": "^14.2.1", |
|||
"showdown": "^2.1.0", |
|||
"sortablejs": "^1.15.0", |
|||
"tinymce": "^5.10.3", |
|||
"tsparticles": "^2.11.0", |
|||
"v-scale-screen": "^2.2.0", |
|||
"vditor": "^3.8.13", |
|||
"vue": "^3.2.33", |
|||
"vue-cesium": "^3.2.2", |
|||
"vue-class-component": "^8.0.0-0", |
|||
"vue-cropper": "^0.5.6", |
|||
"vue-cropperjs": "^5.0.0", |
|||
"vue-i18n": "^9.1.9", |
|||
"vue-infinite-scroll": "^2.0.2", |
|||
"vue-json-pretty": "^2.0.6", |
|||
"vue-print-nb-jeecg": "^1.0.12", |
|||
"vue-router": "^4.0.14", |
|||
"vue-types": "^4.1.1", |
|||
"vue3-colorpicker": "^2.2.2", |
|||
"vue3-seamless-scroll": "^2.0.1", |
|||
"vuedraggable": "^4.1.0", |
|||
"vxe-table": "4.1.0", |
|||
"vxe-table-plugin-antd": "3.0.5", |
|||
"wait-on": "^7.0.1", |
|||
"xe-utils": "^3.3.1", |
|||
"xss": "^1.0.13" |
|||
}, |
|||
"devDependencies": { |
|||
"@commitlint/cli": "^16.2.3", |
|||
"@commitlint/config-conventional": "^16.2.1", |
|||
"@iconify/json": "^2.1.30", |
|||
"@purge-icons/generated": "^0.8.1", |
|||
"@rys-fe/vite-plugin-theme": "^0.8.6", |
|||
"@types/codemirror": "^5.60.5", |
|||
"@types/crypto-js": "^4.1.1", |
|||
"@types/fs-extra": "^9.0.13", |
|||
"@types/inquirer": "^8.2.1", |
|||
"@types/intro.js": "^3.0.2", |
|||
"@types/jest": "^27.0.2", |
|||
"@types/lodash-es": "^4.17.6", |
|||
"@types/mockjs": "^1.0.6", |
|||
"@types/node": "^17.0.25", |
|||
"@types/nprogress": "^0.2.0", |
|||
"@types/pinyin": "^2.10.0", |
|||
"@types/qrcode": "^1.4.2", |
|||
"@types/qs": "^6.9.7", |
|||
"@types/showdown": "^1.9.4", |
|||
"@types/sortablejs": "^1.10.7", |
|||
"@typescript-eslint/eslint-plugin": "^5.20.0", |
|||
"@typescript-eslint/parser": "^5.20.0", |
|||
"@vitejs/plugin-legacy": "^2.0.0", |
|||
"@vitejs/plugin-vue": "^3.0.1", |
|||
"@vitejs/plugin-vue-jsx": "^1.3.10", |
|||
"@vue/compiler-sfc": "^3.2.33", |
|||
"@vue/test-utils": "^2.0.0-rc.21", |
|||
"autoprefixer": "^10.4.4", |
|||
"commitizen": "^4.2.4", |
|||
"conventional-changelog-cli": "^2.2.2", |
|||
"cross-env": "^7.0.3", |
|||
"cz-git": "^1.3.9", |
|||
"czg": "^1.3.9", |
|||
"dotenv": "^16.0.0", |
|||
"electron": "^27.0.2", |
|||
"electron-builder": "^24.6.4", |
|||
"eslint": "^8.22.0", |
|||
"eslint-config-prettier": "^8.6.0", |
|||
"eslint-define-config": "^1.14.0", |
|||
"eslint-plugin-jest": "^27.2.1", |
|||
"eslint-plugin-prettier": "^4.2.1", |
|||
"eslint-plugin-vue": "^9.9.0", |
|||
"esno": "^0.14.1", |
|||
"fs-extra": "^10.1.0", |
|||
"http-server": "^14.0.0", |
|||
"husky": "^7.0.4", |
|||
"inquirer": "^8.2.2", |
|||
"is-ci": "^3.0.0", |
|||
"jest": "^27.3.1", |
|||
"less": "^4.1.2", |
|||
"lint-staged": "12.3.7", |
|||
"npm-run-all": "^4.1.5", |
|||
"picocolors": "^1.0.0", |
|||
"postcss": "^8.4.12", |
|||
"postcss-html": "^1.4.1", |
|||
"postcss-less": "^6.0.0", |
|||
"prettier": "^2.6.2", |
|||
"pretty-quick": "^3.1.1", |
|||
"rimraf": "^3.0.2", |
|||
"rollup": "^2.70.2", |
|||
"rollup-plugin-visualizer": "^5.6.0", |
|||
"stylelint": "^14.7.1", |
|||
"stylelint-config-prettier": "^9.0.3", |
|||
"stylelint-config-recommended": "^7.0.0", |
|||
"stylelint-config-recommended-vue": "^1.4.0", |
|||
"stylelint-config-standard": "^25.0.0", |
|||
"stylelint-order": "^5.0.0", |
|||
"ts-jest": "^27.0.7", |
|||
"ts-node": "^10.7.0", |
|||
"typescript": "^4.6.3", |
|||
"vite": "^3.0.2", |
|||
"vite-plugin-compression": "^0.5.1", |
|||
"vite-plugin-html": "^3.2.0", |
|||
"vite-plugin-imagemin": "^0.6.1", |
|||
"vite-plugin-mkcert": "^1.10.1", |
|||
"vite-plugin-mock": "^2.9.6", |
|||
"vite-plugin-optimize-persist": "^0.1.2", |
|||
"vite-plugin-package-config": "^0.1.1", |
|||
"vite-plugin-purge-icons": "^0.8.2", |
|||
"vite-plugin-pwa": "^0.12.3", |
|||
"vite-plugin-style-import": "^2.0.0", |
|||
"vite-plugin-svg-icons": "^2.0.1", |
|||
"vite-plugin-vue-setup-extend": "^0.4.0", |
|||
"vite-plugin-windicss": "^1.8.7", |
|||
"vue-eslint-parser": "^8.3.0", |
|||
"vue-tsc": "^0.33.9" |
|||
}, |
|||
"resolutions": { |
|||
"bin-wrapper": "npm:bin-wrapper-china", |
|||
"rollup": "^2.72.0" |
|||
}, |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "git+https://github.com/jeecgboot/jeecgboot-vue3.git" |
|||
}, |
|||
"license": "MIT", |
|||
"bugs": { |
|||
"url": "https://github.com/jeecgboot/jeecgboot-vue3/issues" |
|||
}, |
|||
"homepage": "https://github.com/jeecgboot/jeecgboot-vue3", |
|||
"engines": { |
|||
"node": "^12 || >=14" |
|||
}, |
|||
"vite": { |
|||
"optimizeDeps": { |
|||
"include": [ |
|||
"@ant-design/colors", |
|||
"@ant-design/icons-vue", |
|||
"@vueuse/core", |
|||
"@vueuse/shared", |
|||
"@zxcvbn-ts/core", |
|||
"ant-design-vue", |
|||
"axios", |
|||
"china-area-data", |
|||
"clipboard", |
|||
"codemirror", |
|||
"codemirror/addon/fold/brace-fold.js", |
|||
"codemirror/addon/fold/comment-fold.js", |
|||
"codemirror/addon/fold/foldcode.js", |
|||
"codemirror/addon/fold/foldgutter.js", |
|||
"codemirror/addon/fold/indent-fold.js", |
|||
"codemirror/addon/hint/anyword-hint.js", |
|||
"codemirror/addon/hint/show-hint.js", |
|||
"codemirror/addon/selection/active-line.js", |
|||
"codemirror/mode/clike/clike.js", |
|||
"codemirror/mode/css/css.js", |
|||
"codemirror/mode/javascript/javascript.js", |
|||
"codemirror/mode/markdown/markdown.js", |
|||
"codemirror/mode/python/python.js", |
|||
"codemirror/mode/r/r.js", |
|||
"codemirror/mode/shell/shell.js", |
|||
"codemirror/mode/sql/sql.js", |
|||
"codemirror/mode/swift/swift.js", |
|||
"codemirror/mode/vue/vue.js", |
|||
"codemirror/mode/xml/xml.js", |
|||
"cron-parser", |
|||
"cropperjs", |
|||
"crypto-js/aes", |
|||
"crypto-js/enc-base64", |
|||
"crypto-js/enc-utf8", |
|||
"crypto-js/md5", |
|||
"crypto-js/mode-ecb", |
|||
"crypto-js/pad-pkcs7", |
|||
"dom-align", |
|||
"echarts", |
|||
"echarts/charts", |
|||
"echarts/components", |
|||
"echarts/core", |
|||
"echarts/renderers", |
|||
"emoji-mart-vue-fast/src", |
|||
"intro.js", |
|||
"lodash-es", |
|||
"md5", |
|||
"nprogress", |
|||
"path-to-regexp", |
|||
"pinia", |
|||
"print-js", |
|||
"qrcode", |
|||
"qs", |
|||
"resize-observer-polyfill", |
|||
"showdown", |
|||
"sortablejs", |
|||
"tinymce/icons/default/icons", |
|||
"tinymce/plugins/advlist", |
|||
"tinymce/plugins/anchor", |
|||
"tinymce/plugins/autolink", |
|||
"tinymce/plugins/autosave", |
|||
"tinymce/plugins/code", |
|||
"tinymce/plugins/codesample", |
|||
"tinymce/plugins/contextmenu", |
|||
"tinymce/plugins/directionality", |
|||
"tinymce/plugins/fullscreen", |
|||
"tinymce/plugins/hr", |
|||
"tinymce/plugins/image", |
|||
"tinymce/plugins/insertdatetime", |
|||
"tinymce/plugins/link", |
|||
"tinymce/plugins/lists", |
|||
"tinymce/plugins/media", |
|||
"tinymce/plugins/nonbreaking", |
|||
"tinymce/plugins/noneditable", |
|||
"tinymce/plugins/pagebreak", |
|||
"tinymce/plugins/paste", |
|||
"tinymce/plugins/preview", |
|||
"tinymce/plugins/print", |
|||
"tinymce/plugins/save", |
|||
"tinymce/plugins/searchreplace", |
|||
"tinymce/plugins/spellchecker", |
|||
"tinymce/plugins/tabfocus", |
|||
"tinymce/plugins/table", |
|||
"tinymce/plugins/template", |
|||
"tinymce/plugins/textcolor", |
|||
"tinymce/plugins/textpattern", |
|||
"tinymce/plugins/visualblocks", |
|||
"tinymce/plugins/visualchars", |
|||
"tinymce/plugins/wordcount", |
|||
"tinymce/themes/silver", |
|||
"tinymce/tinymce", |
|||
"vditor", |
|||
"vue", |
|||
"vue-i18n", |
|||
"vue-print-nb-jeecg/src/printarea", |
|||
"vue-router", |
|||
"vue-types", |
|||
"vxe-table", |
|||
"vxe-table-plugin-antd", |
|||
"xe-utils", |
|||
"xss" |
|||
] |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,5 @@ |
|||
module.exports = { |
|||
plugins: { |
|||
autoprefixer: {}, |
|||
}, |
|||
}; |
@ -0,0 +1,20 @@ |
|||
module.exports = { |
|||
printWidth: 150, |
|||
tabWidth: 2, |
|||
useTabs: false, |
|||
semi: true, //语句末尾使用分号
|
|||
vueIndentScriptAndStyle: true, |
|||
singleQuote: true, // 使用单引号
|
|||
quoteProps: 'as-needed', |
|||
bracketSpacing: true, |
|||
trailingComma: 'es5', |
|||
jsxBracketSameLine: false, |
|||
jsxSingleQuote: false, |
|||
arrowParens: 'always', |
|||
insertPragma: false, |
|||
requirePragma: false, |
|||
proseWrap: 'never', |
|||
htmlWhitespaceSensitivity: 'strict', |
|||
endOfLine: 'auto', |
|||
rangeStart: 0, |
|||
}; |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 111 KiB |
After Width: | Height: | Size: 191 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 7.1 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 9.4 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 8.0 KiB |
After Width: | Height: | Size: 9.1 KiB |
After Width: | Height: | Size: 7.7 KiB |