初始代码
19
.editorconfig
Normal file
@@ -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
|
||||
8
.env
Normal file
@@ -0,0 +1,8 @@
|
||||
# 端口号
|
||||
VITE_PORT = 3100
|
||||
|
||||
# 网站标题
|
||||
VITE_GLOB_APP_TITLE = 加载中...
|
||||
|
||||
# 简称,用于配置文件名字 不要出现空格、数字开头等特殊字符
|
||||
VITE_GLOB_APP_SHORT_NAME = yunzhu
|
||||
23
.env.development
Normal file
@@ -0,0 +1,23 @@
|
||||
# 资源公共路径,需要以 /开头和结尾
|
||||
VITE_PUBLIC_PATH = /
|
||||
|
||||
# 本地开发代理,可以解决跨域及多地址代理
|
||||
# 如果接口地址匹配到,则会转发到http://localhost:30000,防止本地出现跨域问题
|
||||
# 可以有多个,注意多个不能换行,否则代理将会失效
|
||||
VITE_PROXY = [["/dev","http://localhost:30000"], ["/reportDev","http://localhost:32000"]]
|
||||
|
||||
# 是否删除Console.log
|
||||
VITE_DROP_CONSOLE = false
|
||||
|
||||
# 接口地址
|
||||
# 如果没有跨域问题,直接在这里配置即可
|
||||
VITE_GLOB_API_URL=/dev
|
||||
|
||||
# 报表接口
|
||||
VITE_GLOB_REPORT_API_URL=/reportDev
|
||||
|
||||
# WebSocket基础地址
|
||||
VITE_GLOB_WEBSOCKET_URL='ws://localhost:30000'
|
||||
|
||||
# 接口地址前缀,有些系统所有接口地址都有前缀,可以在这里统一加,方便切换
|
||||
VITE_GLOB_API_URL_PREFIX=
|
||||
31
.env.production
Normal file
@@ -0,0 +1,31 @@
|
||||
# 资源公共路径,需要以 / 开头和结尾
|
||||
VITE_PUBLIC_PATH = /
|
||||
|
||||
# 是否删除Console.log
|
||||
VITE_DROP_CONSOLE = true
|
||||
|
||||
# 打包是否输出gz|br文件
|
||||
# 可选: gzip | brotli | none
|
||||
# 也可以有多个, 例如 'gzip'|'brotli',这样会同时生成.gz和.br文件
|
||||
VITE_BUILD_COMPRESS = 'gzip'
|
||||
|
||||
# 使用压缩时是否删除原始文件,默认为false
|
||||
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
|
||||
|
||||
# 是否在打包时使用cdn替换本地库,内网环境请设置为false
|
||||
VITE_CDN = false
|
||||
|
||||
# 接口地址 可以由nginx做转发或者直接写实际地址
|
||||
VITE_GLOB_API_URL=
|
||||
|
||||
# 报表接口地址 可以由nginx做转发或者直接写实际地址
|
||||
VITE_GLOB_REPORT_API_URL=
|
||||
|
||||
# WebSocket基础地址 (为空时默认取当前url路径,若需要自定义,请输入)
|
||||
VITE_GLOB_WEBSOCKET_URL=
|
||||
|
||||
# 接口地址前缀
|
||||
VITE_GLOB_API_URL_PREFIX=
|
||||
|
||||
# 打包是否开启pwa功能
|
||||
VITE_USE_PWA = false
|
||||
34
.env.test
Normal file
@@ -0,0 +1,34 @@
|
||||
NODE_ENV=production
|
||||
|
||||
# 资源公共路径,需要以 / 开头和结尾
|
||||
VITE_PUBLIC_PATH = /
|
||||
|
||||
# 是否删除Console.log
|
||||
VITE_DROP_CONSOLE = true
|
||||
|
||||
# 打包是否输出gz|br文件
|
||||
# 可选: gzip | brotli | none
|
||||
# 也可以有多个, 例如 'gzip'|'brotli',这样会同时生成.gz和.br文件
|
||||
VITE_BUILD_COMPRESS = 'gzip'
|
||||
|
||||
# 使用压缩时是否删除原始文件,默认为false
|
||||
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
|
||||
|
||||
# 是否在打包时使用cdn替换本地库,内网环境请设置为false
|
||||
VITE_CDN = false
|
||||
|
||||
# 接口地址 可以由nginx做转发或者直接写实际地址
|
||||
VITE_GLOB_API_URL=
|
||||
|
||||
# 报表接口地址 可以由nginx做转发或者直接写实际地址
|
||||
VITE_GLOB_REPORT_API_URL=
|
||||
|
||||
# WebSocket基础地址 (为空时默认取当前url路径,若需要自定义,请输入)
|
||||
VITE_GLOB_WEBSOCKET_URL=
|
||||
|
||||
# 接口地址前缀
|
||||
VITE_GLOB_API_URL_PREFIX=
|
||||
|
||||
# 打包是否开启pwa功能
|
||||
VITE_USE_PWA = false
|
||||
|
||||
16
.eslintignore
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
*.sh
|
||||
node_modules
|
||||
*.md
|
||||
*.woff
|
||||
*.ttf
|
||||
.vscode
|
||||
.idea
|
||||
dist
|
||||
/public
|
||||
/docs
|
||||
.husky
|
||||
.local
|
||||
/bin
|
||||
Dockerfile
|
||||
/src
|
||||
76
.eslintrc.js
Normal file
@@ -0,0 +1,76 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
es6: 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',
|
||||
'plugin:prettier/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/require-explicit-emits': 'off',
|
||||
'vue/html-self-closing': [
|
||||
'error',
|
||||
{
|
||||
html: {
|
||||
void: 'always',
|
||||
normal: 'never',
|
||||
component: 'always',
|
||||
},
|
||||
svg: 'always',
|
||||
math: 'always',
|
||||
},
|
||||
],
|
||||
'vue/multi-word-component-names': 'off',
|
||||
},
|
||||
};
|
||||
30
.gitignore
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
.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?
|
||||
|
||||
.vscode
|
||||
6
.gitpod.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
ports:
|
||||
- port: 3344
|
||||
onOpen: open-preview
|
||||
tasks:
|
||||
- init: pnpm install
|
||||
command: pnpm run dev
|
||||
9
.prettierignore
Normal file
@@ -0,0 +1,9 @@
|
||||
/dist/*
|
||||
.local
|
||||
.output.js
|
||||
/node_modules/**
|
||||
|
||||
**/*.svg
|
||||
**/*.sh
|
||||
|
||||
/public/*
|
||||
3
.stylelintignore
Normal file
@@ -0,0 +1,3 @@
|
||||
/dist/*
|
||||
/public/*
|
||||
public/*
|
||||
39
Dockerfile
Normal file
@@ -0,0 +1,39 @@
|
||||
# 基础镜像
|
||||
# nodejs请勿使用alpine版本,以免出现依赖安装失败的问题
|
||||
FROM node:20-alpine as build-stage
|
||||
LABEL maintainer=yunzhupaas-team
|
||||
|
||||
# 设置时区
|
||||
ENV TZ=Asia/Shanghai
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
# 指定临时工作目录
|
||||
WORKDIR /temp
|
||||
|
||||
# 安装pnpm
|
||||
RUN npm install -g pnpm@9.9.0 --registry=https://registry.npmmirror.com
|
||||
|
||||
# 复制项目
|
||||
COPY . .
|
||||
|
||||
# 安装依赖
|
||||
RUN pnpm install --registry https://registry.npmmirror.com
|
||||
|
||||
# 构建项目
|
||||
RUN pnpm build
|
||||
|
||||
# 基础镜像
|
||||
FROM nginx:stable-alpine as production-stage
|
||||
|
||||
# 指定运行时的工作目录
|
||||
ENV WORKDIR /data/yunzhupaas/yunzhupaas-web-vue3
|
||||
WORKDIR $WORKDIR
|
||||
|
||||
# 将构建文件拷贝到运行时目录中
|
||||
COPY --from=build-stage /temp/dist ${WORKDIR}
|
||||
|
||||
# 复制Nginx配置
|
||||
COPY deploy/default.conf /etc/nginx/conf.d/
|
||||
|
||||
# 指定容器内运行端口
|
||||
EXPOSE 80
|
||||
157
README.md
Normal file
@@ -0,0 +1,157 @@
|
||||
## 一 环境要求
|
||||
|
||||
### 1.1 开发环境
|
||||
|
||||
- 操作系统:`Windows 10/11`,`MacOS`;
|
||||
- `Node 16.15.0` 及以上版本(某些情况下可能需要安装 `Python3` 环境);
|
||||
- `pnpm v8.1.0`及以上版本;
|
||||
- `Visual Studio Code` (简称 VSCode)
|
||||
|
||||
### 1.2 运行环境
|
||||
|
||||
`Nginx` 建议使用 `1.18.0` 及以上版本、兼容 `OpenResty` 或 `TongHttpServer` 6.0(国产信创)
|
||||
|
||||
## 二 浏览器支持
|
||||
|
||||
> 支持现代浏览器,不支持 IE
|
||||
|
||||
| IE | Edge | Firefox | Chrome | Safari |
|
||||
| ----------- | --------------- | --------------- | --------------- | --------------- |
|
||||
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
|
||||
|
||||
## 三 关联项目
|
||||
|
||||
> 需要使用下表中的对应分支
|
||||
|
||||
| 项目 | 分支 | 说明 |
|
||||
| ------------------------ | ------------- | ---------------------- |
|
||||
| **后端**(任一后端服务) | | |
|
||||
| yunzhupaas-java-boot | v5.2.x-stable | Java 单体项目源码 |
|
||||
| yunzhupaas-java-cloud | v5.2.x-stable | Java 微服务项目源码 |
|
||||
| yunzhupaas-dotnet | v5.2.x-stable | .NET 单体项目源码 |
|
||||
| yunzhupaas-dotnet-cloud | v5.2.x-stable | .NET 微服务项目源码 |
|
||||
| **前端** | | |
|
||||
| yunzhupaas-web-datascreen-vue3 | v5.2.x-stable | 大屏前端项目源码(Vue3) |
|
||||
| yunzhupaas-web-datareport | v5.2.x-stable | 报表前端项目源码 |
|
||||
|
||||
## 四 使用说明
|
||||
|
||||
### 4.1 开发环境
|
||||
|
||||
#### 4.1.1 安装 pnpm
|
||||
|
||||
> 推荐使用 `pnpm`
|
||||
|
||||
在 Windows 的 `PowerShell` 中执行如下命令
|
||||
|
||||
```bash
|
||||
iwr https://get.pnpm.io/install.ps1 -useb | iex
|
||||
```
|
||||
|
||||
MacOS 通过 `Homebrew` 安装 `pnpm`<br/> 若已经安装了 `Homebrew` 软件包管理器,则可以使用如下命令赖安装 pnpm:
|
||||
|
||||
```bash
|
||||
brew install pnpm
|
||||
```
|
||||
|
||||
也可以通过 npm 安装 pnpm
|
||||
|
||||
```bash
|
||||
npm install -g pnpm
|
||||
或
|
||||
npm install -g @pnpm/exe
|
||||
```
|
||||
|
||||
#### 4.1.2 安装依赖
|
||||
|
||||
使用如下命令安装项目依赖
|
||||
|
||||
```bash
|
||||
pnpm install --registry http://registry.npmmirror.com
|
||||
```
|
||||
|
||||
#### 4.1.3 后端接口配置
|
||||
|
||||
修改项目根目录 `.env.development` 中的后端接口地址
|
||||
|
||||
- Java 项目本地开发默认接口地址:`http://localhost:30000`
|
||||
- .NET 项目本地开发默认接口地址:`http://localhost:5000`
|
||||
|
||||
```bash
|
||||
# 第7行,后端接口
|
||||
VITE_PROXY = [["/dev","http://localhost:30000"]]
|
||||
|
||||
# 第17行,websocket地址
|
||||
# 在本地开发环境,将后端默认接口地址的协议改成 ws 即可
|
||||
VITE_GLOB_WEBSOCKET_URL='ws://localhost:30000'
|
||||
```
|
||||
|
||||
#### 4.1.4 关联项目配置
|
||||
|
||||
打开 `/src/hooks/setting/index.ts` 配置文件,默认配置如下所示
|
||||
|
||||
```bash
|
||||
...
|
||||
const glob: Readonly<GlobConfig> = {
|
||||
title: VITE_GLOB_APP_TITLE,
|
||||
apiUrl: VITE_GLOB_API_URL,
|
||||
shortName: VITE_GLOB_APP_SHORT_NAME,
|
||||
urlPrefix: VITE_GLOB_API_URL_PREFIX,
|
||||
uploadUrl: VITE_GLOB_API_URL + '/api/file/Uploader',
|
||||
webSocketUrl: VITE_GLOB_WEBSOCKET_URL,
|
||||
cipherKey: 'EY8WePvjM5GGwQzn', // 加密key
|
||||
aMapJsKey: '26a65601349a5ec88318721884ef81b5',
|
||||
aMapWebKey: '09485f01587712b3c04e5a9abf324237',
|
||||
aMapSecurityJsCode: '243e837c2ba077b4143b9a9dd2893992',
|
||||
// 本地文件预览
|
||||
filePreviewServer: isDevMode() ? 'http://localhost:30090/FileServer' : VITE_GLOB_API_URL + '/FileServer',
|
||||
// 大屏应用前端路径
|
||||
dataVUrl: isDevMode() ? 'http://localhost:8100/DataV/' : prodUrlPrefix + '/DataV/',
|
||||
// 数据报表接口
|
||||
reportServer: isDevMode() ? 'http://localhost:30007' : VITE_GLOB_API_URL + '/ReportServer',
|
||||
// 报表前端路径
|
||||
report: isDevMode() ? 'http://localhost:8200' : VITE_GLOB_API_URL + '/Report',
|
||||
};
|
||||
...
|
||||
```
|
||||
|
||||
#### 4.1.5 本地运行
|
||||
|
||||
完成上述操作后,使用如下命令运行前端项目
|
||||
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
### 4.2 运行环境
|
||||
|
||||
> 测试或生产环境
|
||||
|
||||
如果需要测试或生产环境发布,使用如下命令打包项目
|
||||
|
||||
```bash
|
||||
pnpm build
|
||||
```
|
||||
|
||||
然后将项目根目录下 `/dist/` 中所有的文件上传至服务器。
|
||||
|
||||
## 五 常见问题
|
||||
|
||||
### 5.1 修改项目基本信息
|
||||
|
||||
打开项目根目录 `.env` 文件,可以看到 `本地运行端口号`、`网站标题`、`简称` 等配置。
|
||||
|
||||
```bash
|
||||
# 端口号
|
||||
VITE_PORT = 3100
|
||||
|
||||
# 网站标题
|
||||
VITE_GLOB_APP_TITLE = 云筑项目管理平台
|
||||
|
||||
# 简称,用于配置文件名字 不要出现空格、数字开头等特殊字符
|
||||
VITE_GLOB_APP_SHORT_NAME = yunzhu
|
||||
```
|
||||
|
||||
### 5.2 代码更新后报错
|
||||
|
||||
在开发或打包时报依赖缺失,可以先删除项目根目录下的 `pnpm-lock.yaml` 文件,然后重新执行 `pnpm install` 安装依赖即可解决。
|
||||
67
build/config/themeConfig.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { generate } from '@ant-design/colors';
|
||||
|
||||
export const primaryColor = '#1890ff';
|
||||
|
||||
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('-'));
|
||||
}
|
||||
6
build/constant.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* The name of the configuration file entered in the production environment
|
||||
*/
|
||||
export const GLOB_CONFIG_FILE_NAME = '_app.config.js';
|
||||
|
||||
export const OUTPUT_DIR = 'dist';
|
||||
53
build/generate/generateModifyVars.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { primaryColor } from '../config/themeConfig';
|
||||
import { resolve } from 'path';
|
||||
import { generate } from '@ant-design/colors';
|
||||
import { theme } from 'ant-design-vue/lib';
|
||||
import convertLegacyToken from 'ant-design-vue/lib/theme/convertLegacyToken';
|
||||
const { defaultAlgorithm, defaultSeed } = theme;
|
||||
|
||||
function generateAntColors(color: string, theme: 'default' | 'dark' = 'default') {
|
||||
return generate(color, {
|
||||
theme,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* less global variable
|
||||
*/
|
||||
export function generateModifyVars() {
|
||||
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 mapToken = defaultAlgorithm(defaultSeed);
|
||||
const v3Token = convertLegacyToken(mapToken);
|
||||
return {
|
||||
...v3Token,
|
||||
// Used for global import to avoid the need to import each style file separately
|
||||
// reference: Avoid repeated references
|
||||
hack: `true; @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
|
||||
'btn-info-color': '#909399',
|
||||
'text-color-secondary': 'rgba(0, 0, 0, 0.45)',
|
||||
'border-color-base1': '#f0f0f0',
|
||||
'font-size-base': '14px', // Main font size
|
||||
'border-radius-base': '2px', // Component/float fillet
|
||||
'link-color': primary, // Link color
|
||||
'app-base-background': '#eaecf0',
|
||||
'app-content-background': '#F1F4F8', // Link color
|
||||
'app-main-background': '#ebeef5',
|
||||
'selected-hover-bg': '#f5f5f5',
|
||||
'hover-background': '#f5f7fa',
|
||||
};
|
||||
}
|
||||
72
build/generate/icon/index.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
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();
|
||||
7
build/getConfigFileName.ts
Normal file
@@ -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, '');
|
||||
};
|
||||
47
build/script/buildConf.ts
Normal file
@@ -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 });
|
||||
}
|
||||
23
build/script/postBuild.ts
Normal file
@@ -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();
|
||||
88
build/utils.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
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_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);
|
||||
}
|
||||
49
build/vite/plugin/cdn.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Plugin as importToCDN } from 'vite-plugin-cdn-import';
|
||||
|
||||
/**
|
||||
* @description 打包时采用`cdn`模式,仅限外网使用(默认不采用,如果需要采用cdn模式,请在 .env.production 文件,将 VITE_CDN 设置成true)
|
||||
* 平台采用国内cdn:https://www.bootcdn.cn,当然你也可以选择 https://unpkg.com 或者 https://www.jsdelivr.com
|
||||
* 注意:上面提到的仅限外网使用也不是完全肯定的,如果你们公司内网部署的有相关js、css文件,也可以将下面配置对应改一下,整一套内网版cdn
|
||||
*/
|
||||
export const configCdnPlugin = importToCDN({
|
||||
//(prodUrl解释: name: 对应下面modules的name,version: 自动读取本地package.json中dependencies依赖中对应包的版本号,path: 对应下面modules的path,当然也可写完整路径,会替换prodUrl)
|
||||
prodUrl: 'https://cdn.bootcdn.net/ajax/libs/{name}/{version}/{path}',
|
||||
modules: [
|
||||
{
|
||||
name: 'vue',
|
||||
var: 'Vue',
|
||||
path: 'vue.global.prod.min.js',
|
||||
},
|
||||
{
|
||||
name: 'vue-router',
|
||||
var: 'VueRouter',
|
||||
path: 'vue-router.global.min.js',
|
||||
},
|
||||
// 项目中没有直接安装vue-demi,但是pinia用到了,所以需要在引入pinia前引入vue-demi(https://github.com/vuejs/pinia/blob/v2/packages/pinia/package.json#L77)
|
||||
{
|
||||
name: 'vue-demi',
|
||||
var: 'VueDemi',
|
||||
path: 'https://cdn.bootcdn.net/ajax/libs/vue-demi/0.14.5/index.iife.min.js',
|
||||
},
|
||||
{
|
||||
name: 'pinia',
|
||||
var: 'Pinia',
|
||||
path: 'pinia.iife.min.js',
|
||||
},
|
||||
{
|
||||
name: 'axios',
|
||||
var: 'axios',
|
||||
path: 'axios.min.js',
|
||||
},
|
||||
{
|
||||
name: 'dayjs',
|
||||
var: 'dayjs',
|
||||
path: 'dayjs.min.js',
|
||||
},
|
||||
{
|
||||
name: 'echarts',
|
||||
var: 'echarts',
|
||||
path: 'echarts.min.js',
|
||||
},
|
||||
],
|
||||
});
|
||||
35
build/vite/plugin/compress.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
40
build/vite/plugin/html.ts
Normal file
@@ -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;
|
||||
}
|
||||
69
build/vite/plugin/index.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { PluginOption } from 'vite';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx';
|
||||
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 { configCompressPlugin } from './compress';
|
||||
import { configVisualizerConfig } from './visualizer';
|
||||
import { configThemePlugin } from './theme';
|
||||
import { configSvgIconsPlugin } from './svgSprite';
|
||||
import { configCdnPlugin } from './cdn';
|
||||
|
||||
export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
|
||||
const { VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE, VITE_CDN } = viteEnv;
|
||||
|
||||
const vitePlugins: (PluginOption | PluginOption[])[] = [
|
||||
// have to
|
||||
vue({
|
||||
template: {
|
||||
compilerOptions: {
|
||||
// 解决vue3上marquee标签报错
|
||||
isCustomElement: tag => tag === 'marquee',
|
||||
},
|
||||
},
|
||||
}),
|
||||
// have to
|
||||
vueJsx(),
|
||||
// support name
|
||||
// vueSetupExtend(),
|
||||
VitePluginCertificate({
|
||||
source: 'coding',
|
||||
}),
|
||||
];
|
||||
|
||||
// vite-plugin-windicss
|
||||
vitePlugins.push(windiCSS());
|
||||
|
||||
// vite-plugin-html
|
||||
vitePlugins.push(configHtmlPlugin(viteEnv, isBuild));
|
||||
|
||||
// vite-plugin-svg-icons
|
||||
vitePlugins.push(configSvgIconsPlugin(isBuild));
|
||||
|
||||
// vite-plugin-purge-icons
|
||||
vitePlugins.push(purgeIcons());
|
||||
|
||||
// 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-cdn-import
|
||||
if (VITE_CDN) vitePlugins.push(configCdnPlugin);
|
||||
|
||||
// rollup-plugin-gzip
|
||||
vitePlugins.push(configCompressPlugin(VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE));
|
||||
|
||||
// vite-plugin-pwa
|
||||
vitePlugins.push(configPwaConfig(viteEnv));
|
||||
}
|
||||
|
||||
return vitePlugins;
|
||||
}
|
||||
5
build/vite/plugin/purgeIcons.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import PurgeIcons from 'vite-plugin-purge-icons';
|
||||
|
||||
export function configPurgeIconsPlugin() {
|
||||
return PurgeIcons();
|
||||
}
|
||||
33
build/vite/plugin/pwa.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Yunzhupaas-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 [];
|
||||
}
|
||||
82
build/vite/plugin/styleImport.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* 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 = {
|
||||
textarea: 'input',
|
||||
'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;
|
||||
}
|
||||
10
build/vite/plugin/svgIcons.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
|
||||
import path from 'path';
|
||||
|
||||
export function configSvgIconsPlugin(isBuild: boolean) {
|
||||
return createSvgIconsPlugin({
|
||||
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
|
||||
svgoOptions: isBuild,
|
||||
symbolId: 'icon-[dir]-[name]',
|
||||
});
|
||||
}
|
||||
17
build/vite/plugin/svgSprite.ts
Normal file
@@ -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;
|
||||
}
|
||||
101
build/vite/plugin/theme.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* 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(), 'src/design/index.less')],
|
||||
filter: id => (isBuild ? !id.endsWith('antd.less') : true),
|
||||
// extractCss: false,
|
||||
darkModifyVars: {
|
||||
...generateModifyVars(),
|
||||
'text-color': '#c9d1d9',
|
||||
'primary-1': 'rgb(255 255 255 / 8%)',
|
||||
'text-color-base': '#c9d1d9',
|
||||
'text-color-label': '#606266',
|
||||
'component-background': '#151515',
|
||||
'hover-background': '#333333',
|
||||
'heading-color': 'rgb(255 255 255 / 65%)',
|
||||
// black: '#0e1117',
|
||||
// #8b949e
|
||||
'text-color-secondary': '#8b949e',
|
||||
'border-color-base': '#303030',
|
||||
'border-color-base1': '#303030',
|
||||
// 'border-color-split': '#30363d',
|
||||
'item-active-bg': '#111b26',
|
||||
'app-base-background': '#1e1e1e',
|
||||
'app-content-background': '#1e1e1e',
|
||||
'app-main-background': '#333333',
|
||||
'tree-node-selected-bg': '#11263c',
|
||||
'selected-hover-bg': 'rgba(255, 255, 255, 0.08)',
|
||||
|
||||
'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[];
|
||||
}
|
||||
17
build/vite/plugin/visualizer.ts
Normal file
@@ -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 [];
|
||||
}
|
||||
6
build/vite/plugin/windicss.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import type { Plugin } from 'vite';
|
||||
import WindiCSS from 'vite-plugin-windicss';
|
||||
|
||||
export function configWindiCssPlugin(): Plugin[] {
|
||||
return (WindiCSS() as Plugin[]).filter(Boolean);
|
||||
}
|
||||
34
build/vite/proxy.ts
Normal file
@@ -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;
|
||||
}
|
||||
83
deploy/default.conf
Normal file
@@ -0,0 +1,83 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
root /data/yunzhupaas/yunzhupaas-web-vue3;
|
||||
index index.html;
|
||||
|
||||
gzip on;
|
||||
gzip_static on;
|
||||
gzip_min_length 1k;
|
||||
gzip_comp_level 4;
|
||||
gzip_proxied any;
|
||||
gzip_types text/plain text/xml text/css;
|
||||
gzip_vary on;
|
||||
gzip_http_version 1.0;
|
||||
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
|
||||
|
||||
# YUNZHUPAAS-START
|
||||
# 设置上传文件的大小
|
||||
client_max_body_size 100m;
|
||||
|
||||
# 添加头部信息
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-NginX-Proxy true;
|
||||
# This is necessary to pass the correct IP to be hashed
|
||||
real_ip_header X-Real-IP;
|
||||
proxy_connect_timeout 300;
|
||||
|
||||
# 前端主项目伪静态
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# 大屏伪静态
|
||||
location /DataV {
|
||||
try_files $uri $uri/ /DataV/index.html;
|
||||
}
|
||||
|
||||
# 报表伪静态
|
||||
location /Report/icons/{
|
||||
try_files $uri $uri/ /Report/icons/;
|
||||
}
|
||||
|
||||
# 主项目后端接口
|
||||
location /api/ {
|
||||
proxy_pass http://yunzhupaas-gateway-external.java-cloud-v510:30000;
|
||||
}
|
||||
|
||||
location /websocket {
|
||||
proxy_pass http://yunzhupaas-gateway-external.java-cloud-v510:30000/api/message/websocket;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 600s;
|
||||
}
|
||||
|
||||
# 报表后端接口
|
||||
location /ReportServer/ {
|
||||
proxy_pass http://yunzhupaas-datareport-external.java-cloud-v510:30007/;
|
||||
}
|
||||
|
||||
# Flowable后端接口
|
||||
location /api/Flow {
|
||||
proxy_pass http://yunzhupaas-flowable-external.java-cloud-v510:31000;
|
||||
}
|
||||
|
||||
# Univer后端接口
|
||||
location /api/Report {
|
||||
proxy_pass http://yunzhupaas-univer-external.java-cloud-v510:32000;
|
||||
}
|
||||
|
||||
# 文件预览
|
||||
location /FileServer {
|
||||
proxy_pass http://yunzhupaas-file-preview-external.java-cloud-v510:30090;
|
||||
}
|
||||
|
||||
location ~ /FileServer/*.*\.(js|css)?$ {
|
||||
proxy_pass http://yunzhupaas-file-preview-external.java-cloud-v510:30090;
|
||||
}
|
||||
# YUNZHUPAAS-END
|
||||
}
|
||||
38
index.html
Normal file
@@ -0,0 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" id="htmlRoot">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<link rel="stylesheet" href="/css/index.css" />
|
||||
<link rel="stylesheet" href="/css/print-lock.css" />
|
||||
<link rel="stylesheet" href="/css/fonts/ym/iconfont.css" />
|
||||
<link rel="stylesheet" href="/css/fonts/ym-custom/iconfont.css" />
|
||||
<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" />
|
||||
<!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" /> -->
|
||||
<title><%= title %></title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</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">
|
||||
<div class="app-loading">
|
||||
<div class="app-loading-wrap">
|
||||
<div class="app-loading-dots">
|
||||
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
206
package.json
Normal file
@@ -0,0 +1,206 @@
|
||||
{
|
||||
"name": "yunzhupaas-web-vue3",
|
||||
"version": "5.2.0",
|
||||
"description": "云筑项目管理平台",
|
||||
"author": {
|
||||
"name": "深圳市乐程软件有限公司",
|
||||
"email": "service@yunzhupaas.cn",
|
||||
"url": "https://www.yunzhupaas.cn"
|
||||
},
|
||||
"homepage": "https://www.yunzhupaas.cn",
|
||||
"scripts": {
|
||||
"commit": "czg",
|
||||
"bootstrap": "pnpm install --registry=https://registry.npmmirror.com",
|
||||
"serve": "npm run dev",
|
||||
"dev": "vite",
|
||||
"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",
|
||||
"clean:cache": "rimraf node_modules/.cache/ && rimraf node_modules/.vite",
|
||||
"clean:lib": "rimraf node_modules",
|
||||
"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",
|
||||
"reinstall": "rimraf pnpm-lock.yaml && rimraf package.lock.json && rimraf node_modules && npm run bootstrap",
|
||||
"gen:icon": "esno ./build/generate/icon/index.ts"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,jsx,ts,tsx}": [
|
||||
"eslint --fix",
|
||||
"prettier --write"
|
||||
],
|
||||
"{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [
|
||||
"prettier --write--parser json"
|
||||
],
|
||||
"package.json": [
|
||||
"prettier --write"
|
||||
],
|
||||
"*.vue": [
|
||||
"eslint --fix",
|
||||
"prettier --write",
|
||||
"stylelint --fix"
|
||||
],
|
||||
"*.{scss,less,styl,html}": [
|
||||
"stylelint --fix",
|
||||
"prettier --write"
|
||||
],
|
||||
"*.md": [
|
||||
"prettier --write"
|
||||
]
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
"path": "node_modules/cz-git"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@amap/amap-jsapi-loader": "^1.0.1",
|
||||
"@ant-design/colors": "^7.1.0",
|
||||
"@ant-design/icons-vue": "^7.0.1",
|
||||
"@fullcalendar/core": "^6.1.14",
|
||||
"@fullcalendar/daygrid": "^6.1.14",
|
||||
"@fullcalendar/interaction": "^6.1.14",
|
||||
"@fullcalendar/timegrid": "^6.1.14",
|
||||
"@fullcalendar/vue3": "^6.1.14",
|
||||
"@iconify/iconify": "^3.1.0",
|
||||
"@logicflow/core": "^1.2.1",
|
||||
"@logicflow/extension": "^1.2.1",
|
||||
"@vue/runtime-core": "^3.4.27",
|
||||
"@vue/shared": "^3.4.27",
|
||||
"@vueuse/core": "^10.1.2",
|
||||
"@vueuse/shared": "^10.1.2",
|
||||
"@zxcvbn-ts/core": "^2.2.1",
|
||||
"ant-design-vue": "^4.2.3",
|
||||
"axios": "^1.4.0",
|
||||
"bpmn-js": "16.3.2",
|
||||
"bpmn-js-properties-panel": "5.7.0",
|
||||
"camunda-bpmn-moddle": "6.1.2",
|
||||
"codemirror": "^5.65.12",
|
||||
"cron-parser": "^4.8.1",
|
||||
"cropperjs": "^1.5.13",
|
||||
"crypto-js": "^4.1.1",
|
||||
"dayjs": "^1.11.7",
|
||||
"diagram-js": "11.9.1",
|
||||
"diagram-js-minimap": "4.1.0",
|
||||
"echarts": "^5.4.2",
|
||||
"echarts-stat": "^1.2.0",
|
||||
"inherits-browser": "^0.1.0",
|
||||
"intro.js": "^7.0.1",
|
||||
"jsbarcode": "^3.11.5",
|
||||
"lodash-es": "^4.17.21",
|
||||
"min-dash": "^4.2.1",
|
||||
"min-dom": "^4.1.0",
|
||||
"monaco-editor": "^0.38.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"path-to-regexp": "^6.2.1",
|
||||
"pinia": "^2.1.3",
|
||||
"print-js": "^1.6.0",
|
||||
"qrcode": "^1.5.1",
|
||||
"qs": "^6.11.1",
|
||||
"reconnecting-websocket": "^4.4.0",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"showdown": "^2.1.0",
|
||||
"sortablejs": "^1.15.0",
|
||||
"spark-md5": "^3.0.2",
|
||||
"terser": "^5.14.2",
|
||||
"tiny-svg": "^3.0.1",
|
||||
"tinymce": "^5.10.7",
|
||||
"v-code-diff": "^1.13.1",
|
||||
"vditor": "^3.9.1",
|
||||
"vue": "^3.4.27",
|
||||
"vue-grid-layout": "^3.0.0-beta1",
|
||||
"vue-i18n": "^9.13.1",
|
||||
"vue-json-pretty": "^2.2.4",
|
||||
"vue-plugin-hiprint": "0.0.57-beta24",
|
||||
"vue-router": "^4.3.2",
|
||||
"vue-simple-uploader": "1.0.0",
|
||||
"vue-types": "^5.1.2",
|
||||
"vue3-draggable-resizable": "^1.6.5",
|
||||
"vue3-tree-org": "^4.2.2",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"xlsx": "^0.18.5",
|
||||
"zero-bpmn": "1.1.1",
|
||||
"zero-univer": "1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.8.1",
|
||||
"@commitlint/config-conventional": "^17.8.1",
|
||||
"@iconify/json": "^2.2.43",
|
||||
"@purge-icons/generated": "^0.9.0",
|
||||
"@rys-fe/vite-plugin-theme": "^0.8.6",
|
||||
"@types/codemirror": "^5.60.7",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@types/fs-extra": "^11.0.1",
|
||||
"@types/inquirer": "^8.2.6",
|
||||
"@types/intro.js": "^5.1.1",
|
||||
"@types/lodash-es": "^4.17.7",
|
||||
"@types/node": "^18.15.11",
|
||||
"@types/nprogress": "^0.2.0",
|
||||
"@types/qrcode": "^1.5.0",
|
||||
"@types/qs": "^6.9.7",
|
||||
"@types/showdown": "^2.0.0",
|
||||
"@types/sortablejs": "^1.15.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.57.0",
|
||||
"@typescript-eslint/parser": "^5.57.0",
|
||||
"@vitejs/plugin-vue": "^4.2.3",
|
||||
"@vitejs/plugin-vue-jsx": "^3.0.1",
|
||||
"@vue/compiler-sfc": "^3.4.27",
|
||||
"@vue/test-utils": "^2.4.5",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"conventional-changelog-cli": "^2.2.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"cz-git": "^1.6.1",
|
||||
"czg": "^1.6.1",
|
||||
"dotenv": "^16.0.3",
|
||||
"eslint": "^8.37.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-vue": "^9.10.0",
|
||||
"esno": "^0.16.3",
|
||||
"fs-extra": "^11.1.1",
|
||||
"inquirer": "^9.1.5",
|
||||
"jquery": "^3.7.1",
|
||||
"less": "^4.1.3",
|
||||
"lint-staged": "13.2.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"picocolors": "^1.0.0",
|
||||
"postcss": "^8.4.21",
|
||||
"postcss-html": "^1.5.0",
|
||||
"postcss-less": "^6.0.0",
|
||||
"prettier": "^2.8.8",
|
||||
"rimraf": "^4.4.1",
|
||||
"rollup": "^3.7.4",
|
||||
"rollup-plugin-visualizer": "^5.9.0",
|
||||
"stylelint": "^15.4.0",
|
||||
"stylelint-config-prettier": "^9.0.3",
|
||||
"stylelint-config-recommended": "^11.0.0",
|
||||
"stylelint-config-recommended-vue": "^1.4.0",
|
||||
"stylelint-config-standard": "^32.0.0",
|
||||
"stylelint-order": "^6.0.3",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.4.5",
|
||||
"vite": "^4.5.3",
|
||||
"vite-plugin-cdn-import": "^0.3.5",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-html": "^3.2.0",
|
||||
"vite-plugin-mkcert": "^1.10.1",
|
||||
"vite-plugin-purge-icons": "^0.9.2",
|
||||
"vite-plugin-pwa": "^0.14.0",
|
||||
"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.10",
|
||||
"vue-eslint-parser": "^9.1.1",
|
||||
"vue-tsc": "^2.0.19"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.15.0",
|
||||
"pnpm": ">=8.1.0"
|
||||
}
|
||||
}
|
||||
14173
pnpm-lock.yaml
generated
Normal file
5
postcss.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
13
prettier.config.js
Normal file
@@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
printWidth: 160,
|
||||
semi: true,
|
||||
vueIndentScriptAndStyle: true,
|
||||
singleQuote: true,
|
||||
trailingComma: 'all',
|
||||
proseWrap: 'never',
|
||||
htmlWhitespaceSensitivity: 'strict',
|
||||
endOfLine: 'auto',
|
||||
bracketSameLine: true,
|
||||
jsxBracketSameLine: true,
|
||||
arrowParens: 'avoid',
|
||||
};
|
||||
BIN
public/cdn/socials/dingtalk.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
public/cdn/socials/feishu.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
public/cdn/socials/gitHub.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
public/cdn/socials/qq.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
public/cdn/socials/wechat_open.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
public/cdn/socials/wxWork.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
7203
public/css/fonts/ym-custom/iconfont.css
Normal file
BIN
public/css/fonts/ym-custom/iconfont.ttf
Normal file
BIN
public/css/fonts/ym-custom/iconfont.woff
Normal file
BIN
public/css/fonts/ym-custom/iconfont.woff2
Normal file
2527
public/css/fonts/ym/iconfont.css
Normal file
BIN
public/css/fonts/ym/iconfont.ttf
Normal file
BIN
public/css/fonts/ym/iconfont.woff
Normal file
BIN
public/css/fonts/ym/iconfont.woff2
Normal file
135
public/css/index.css
Normal file
@@ -0,0 +1,135 @@
|
||||
html[data-theme='dark'] .app-loading {
|
||||
background-color: #2c344a;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .app-loading .app-loading-title {
|
||||
color: rgb(255 255 255 / 85%);
|
||||
}
|
||||
html[data-theme="dark"] .ant-steps-navigation .ant-steps-item::after {
|
||||
border-bottom: none;
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.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;
|
||||
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: rgb(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;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.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: 30%;
|
||||
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;
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
.dot i:nth-child(3) {
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
animation-delay: 0.8s;
|
||||
}
|
||||
|
||||
.dot i:nth-child(4) {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
animation-delay: 1.2s;
|
||||
}
|
||||
|
||||
@keyframes antRotate {
|
||||
to {
|
||||
transform: rotate(405deg);
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes antRotate {
|
||||
to {
|
||||
transform: rotate(405deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes antSpinMove {
|
||||
to {
|
||||
opacity: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes antSpinMove {
|
||||
to {
|
||||
opacity: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.app-loading .app-loading-logo,
|
||||
.app-loading .app-loading-title {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
352
public/css/print-lock.css
Normal file
@@ -0,0 +1,352 @@
|
||||
@media print {
|
||||
body {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
@page {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.hiprint-printPaper * {
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box; /* Firefox */
|
||||
-webkit-box-sizing: border-box; /* Safari */
|
||||
}
|
||||
|
||||
.hiprint-printPaper *:focus {
|
||||
outline: -webkit-focus-ring-color auto 0px;
|
||||
}
|
||||
|
||||
.hiprint-printPaper {
|
||||
position: relative;
|
||||
padding: 0 0 0 0;
|
||||
page-break-after: always;
|
||||
-webkit-user-select: none; /* Chrome/Safari/Opera */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
user-select: none;
|
||||
overflow-x: hidden;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hiprint-printPaper-content {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 火狐浏览器打印 第一页过后 重叠问题 */
|
||||
@-moz-document url-prefix() {
|
||||
.hiprint-printPaper .hiprint-printPaper-content {
|
||||
position: relative;
|
||||
margin-top: 20px;
|
||||
top: -20px
|
||||
}
|
||||
}
|
||||
|
||||
.hiprint-printPaper.design {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
|
||||
.hiprint-printTemplate .hiprint-printPanel {
|
||||
page-break-after: always;
|
||||
}
|
||||
|
||||
.hiprint-printPaper, hiprint-printPanel {
|
||||
box-sizing: border-box;
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
.hiprint-printPanel .hiprint-printPaper:last-child {
|
||||
page-break-after: avoid;
|
||||
}
|
||||
|
||||
.hiprint-printTemplate .hiprint-printPanel:last-child {
|
||||
page-break-after: avoid;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hideheaderLinetarget {
|
||||
border-top: 0px dashed rgb(201, 190, 190) !important;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hidefooterLinetarget {
|
||||
border-top: 0px dashed rgb(201, 190, 190) !important;
|
||||
}
|
||||
|
||||
.hiprint-printPaper.design {
|
||||
border: 1px dashed rgba(170, 170, 170, 0.7);
|
||||
}
|
||||
|
||||
.design .hiprint-printElement-table-content, .design .hiprint-printElement-longText-content {
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.design .resize-panel {
|
||||
box-sizing: border-box;
|
||||
border: 1px dotted;
|
||||
}
|
||||
|
||||
.hiprint-printElement-text {
|
||||
background-color: transparent;
|
||||
background-repeat: repeat;
|
||||
padding: 0 0 0 0;
|
||||
border: 0.75pt none rgb(0, 0, 0);
|
||||
direction: ltr;
|
||||
font-family: 'SimSun';
|
||||
font-size: 9pt;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
padding-bottom: 0pt;
|
||||
padding-left: 0pt;
|
||||
padding-right: 0pt;
|
||||
padding-top: 0pt;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
line-height: 9.75pt;
|
||||
box-sizing: border-box;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.design .hiprint-printElement-text-content {
|
||||
border: 1px dashed rgb(206, 188, 188);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hiprint-printElement-longText {
|
||||
background-color: transparent;
|
||||
background-repeat: repeat;
|
||||
border: 0.75pt none rgb(0, 0, 0);
|
||||
direction: ltr;
|
||||
font-family: 'SimSun';
|
||||
font-size: 9pt;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
padding-bottom: 0pt;
|
||||
padding-left: 0pt;
|
||||
padding-right: 0pt;
|
||||
padding-top: 0pt;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
line-height: 9.75pt;
|
||||
box-sizing: border-box;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
/*white-space: pre-wrap*/
|
||||
}
|
||||
|
||||
|
||||
.hiprint-printElement-table {
|
||||
background-color: transparent;
|
||||
background-repeat: repeat;
|
||||
color: rgb(0, 0, 0);
|
||||
border-color: rgb(0, 0, 0);
|
||||
border-style: none;
|
||||
direction: ltr;
|
||||
font-family: 'SimSun';
|
||||
font-size: 9pt;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
padding-bottom: 0pt;
|
||||
padding-left: 0pt;
|
||||
padding-right: 0pt;
|
||||
padding-top: 0pt;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
padding: 0 0 0 0;
|
||||
box-sizing: border-box;
|
||||
line-height: 9.75pt;
|
||||
}
|
||||
|
||||
.hiprint-printElement-table thead {
|
||||
background: #e8e8e8;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
table.hiprint-printElement-tableTarget {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.hiprint-printElement-tableTarget, .hiprint-printElement-tableTarget tr, .hiprint-printElement-tableTarget td {
|
||||
border-color: rgb(0, 0, 0);
|
||||
/*border-style: none;*/
|
||||
/*border: 1px solid rgb(0, 0, 0);*/
|
||||
font-weight: normal;
|
||||
direction: ltr;
|
||||
padding-bottom: 0pt;
|
||||
padding-left: 4pt;
|
||||
padding-right: 4pt;
|
||||
padding-top: 0pt;
|
||||
text-decoration: none;
|
||||
vertical-align: middle;
|
||||
box-sizing: border-box;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
/*line-height: 9.75pt;
|
||||
font-size: 9pt;*/
|
||||
}
|
||||
|
||||
.hiprint-printElement-tableTarget-border-all {
|
||||
border: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-none {
|
||||
border: 0px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-lr {
|
||||
border-left: 1px solid;
|
||||
border-right: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-left {
|
||||
border-left: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-right {
|
||||
border-right: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-tb {
|
||||
border-top: 1px solid;
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-top {
|
||||
border-top: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-bottom {
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
|
||||
.hiprint-printElement-tableTarget-border-td-none td {
|
||||
border: 0px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-td-all td:not(:nth-last-child(-n+2)) {
|
||||
border-right: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-td-all td:not(last-child) {
|
||||
border-right: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-td-all td:last-child {
|
||||
border-left: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-td-all td:last-child:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
/*.hiprint-printElement-tableTarget tr,*/
|
||||
.hiprint-printElement-tableTarget td {
|
||||
height: 18pt;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hiprint-paperNumber {
|
||||
font-size: 9pt;
|
||||
}
|
||||
|
||||
.design .hiprint-printElement-table-handle {
|
||||
position: absolute;
|
||||
height: 21pt;
|
||||
width: 21pt;
|
||||
background: red;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hiprint-paperNumber-disabled {
|
||||
float: right !important;
|
||||
right: 0 !important;
|
||||
color: gainsboro !important;
|
||||
}
|
||||
|
||||
.hiprint-printElement-vline, .hiprint-printElement-hline {
|
||||
border: 0px none rgb(0, 0, 0);
|
||||
|
||||
}
|
||||
|
||||
.hiprint-printElement-vline {
|
||||
border-left: 0.75pt solid #000;
|
||||
border-right: 0px none rgb(0, 0, 0) !important;
|
||||
border-bottom: 0px none rgb(0, 0, 0) !important;
|
||||
border-top: 0px none rgb(0, 0, 0) !important;
|
||||
}
|
||||
|
||||
.hiprint-printElement-hline {
|
||||
border-top: 0.75pt solid #000;
|
||||
border-right: 0px none rgb(0, 0, 0) !important;
|
||||
border-bottom: 0px none rgb(0, 0, 0) !important;
|
||||
border-left: 0px none rgb(0, 0, 0) !important;
|
||||
}
|
||||
|
||||
.hiprint-printElement-oval, .hiprint-printElement-rect {
|
||||
border: 0.75pt solid #000;
|
||||
}
|
||||
|
||||
.hiprint-text-content-middle {
|
||||
}
|
||||
|
||||
.hiprint-text-content-middle > div {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hiprint-text-content-bottom {
|
||||
}
|
||||
|
||||
.hiprint-text-content-bottom > div {
|
||||
display: grid;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.hiprint-text-content-wrap {
|
||||
}
|
||||
|
||||
.hiprint-text-content-wrap .hiprint-text-content-wrap-nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.hiprint-text-content-wrap .hiprint-text-content-wrap-clip {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: clip;
|
||||
}
|
||||
|
||||
.hiprint-text-content-wrap .hiprint-text-content-wrap-ellipsis {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/*hi-grid-row */
|
||||
.hi-grid-row {
|
||||
position: relative;
|
||||
height: auto;
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
zoom: 1;
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hi-grid-row::after, .hi-grid-row::before {
|
||||
display: table;
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hi-grid-col {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
float: left;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.table-grid-row {
|
||||
margin-left: -0pt;
|
||||
margin-right: -0pt;
|
||||
}
|
||||
|
||||
.tableGridColumnsGutterRow {
|
||||
padding-left: 0pt;
|
||||
padding-right: 0pt;
|
||||
}
|
||||
|
||||
.hiprint-gridColumnsFooter {
|
||||
text-align: left;
|
||||
clear: both;
|
||||
}
|
||||
BIN
public/favicon.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
public/resource/emoji/100.gif
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
public/resource/emoji/101.gif
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
public/resource/emoji/102.gif
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
public/resource/emoji/103.gif
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
public/resource/emoji/104.gif
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
public/resource/emoji/105.gif
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
public/resource/emoji/106.gif
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
public/resource/emoji/107.gif
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
public/resource/emoji/108.gif
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
public/resource/emoji/109.gif
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
public/resource/emoji/110.gif
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
public/resource/emoji/111.gif
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
public/resource/emoji/112.gif
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
public/resource/emoji/113.gif
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
public/resource/emoji/114.gif
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
public/resource/emoji/115.gif
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
public/resource/emoji/116.gif
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
public/resource/emoji/117.gif
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
public/resource/emoji/118.gif
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
public/resource/emoji/119.gif
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
public/resource/emoji/120.gif
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
public/resource/emoji/121.gif
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
public/resource/emoji/122.gif
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
public/resource/emoji/123.gif
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
public/resource/emoji/124.gif
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
public/resource/emoji/125.gif
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
public/resource/emoji/126.gif
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
public/resource/emoji/127.gif
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
public/resource/emoji/128.gif
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
public/resource/emoji/129.gif
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
public/resource/emoji/130.gif
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
public/resource/emoji/131.gif
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
public/resource/emoji/132.gif
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
public/resource/emoji/133.gif
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
public/resource/emoji/134.gif
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
public/resource/emoji/135.gif
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
public/resource/emoji/136.gif
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
public/resource/emoji/137.gif
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
public/resource/emoji/138.gif
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
public/resource/emoji/139.gif
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
public/resource/emoji/140.gif
Normal file
|
After Width: | Height: | Size: 9.6 KiB |