This commit is contained in:
bunny 2024-07-08 08:32:40 +08:00
commit 0d03844090
177 changed files with 60446 additions and 0 deletions

14
.editorconfig Normal file
View File

@ -0,0 +1,14 @@
# http://editorconfig.org
root = true
[*] # 表示所有文件适用
charset = utf-8 # 设置文件字符集为 utf-8
end_of_line = lf # 控制换行类型(lf | cr | crlf)
insert_final_newline = false # 始终在文件末尾插入一个新行
indent_style = tab # 缩进风格tab | space
indent_size = 2 # 缩进大小
max_line_length = 130 # 最大行长度
[*.md] # 表示仅 md 文件适用以下规则
max_line_length = off # 关闭最大行长度限制
trim_trailing_whitespace = false # 关闭末尾空格修剪

31
.env Normal file
View File

@ -0,0 +1,31 @@
# 基础请求路径
VITE_BASE_API="/api"
# 模拟请求路径
VITE_MOCK_BASE_API="/mock"
# 线上环境接口地址
VITE_APP_URL=http://localhost:8800
# 线上环境接口地址
VITE_APP_MOCK_URL=http://localhost:6262
# 网络请求延迟时间
VITE_BASE_API_TIMEOUT=15000
# 失败重试次数
VITE_BASE_API_RETRY=5
# 失败重试时间
VITE_BASE_API_RETRY_DELAY=3000
# 端口号
VITE_PORT=6262
# 是否使用CDN加速
VITE_CDN=true
# 是否启用gzip压缩或brotli压缩分两种情况删除原始文件和不删除原始文件
# 压缩时不删除原始文件的配置gzip、brotli、both同时开启 gzip 与 brotli 压缩、none不开启压缩默认
# 压缩时删除原始文件的配置gzip-clear、brotli-clear、both-clear同时开启 gzip 与 brotli 压缩、none不开启压缩默认
VITE_COMPRESSION="both"

31
.env.development Normal file
View File

@ -0,0 +1,31 @@
# 基础请求路径
VITE_BASE_API="/api"
# 模拟请求路径
VITE_MOCK_BASE_API="/mock"
# 线上环境接口地址
VITE_APP_URL=http://localhost:8800
# 线上环境接口地址
VITE_APP_MOCK_URL=http://localhost:6262
# 网络请求延迟时间
VITE_BASE_API_TIMEOUT=15000
# 失败重试次数
VITE_BASE_API_RETRY=5
# 失败重试时间
VITE_BASE_API_RETRY_DELAY=3000
# 端口号
VITE_PORT=6262
# 是否使用CDN加速
VITE_CDN=true
# 是否启用gzip压缩或brotli压缩分两种情况删除原始文件和不删除原始文件
# 压缩时不删除原始文件的配置gzip、brotli、both同时开启 gzip 与 brotli 压缩、none不开启压缩默认
# 压缩时删除原始文件的配置gzip-clear、brotli-clear、both-clear同时开启 gzip 与 brotli 压缩、none不开启压缩默认
VITE_COMPRESSION="both"

22
.eslintignore Normal file
View File

@ -0,0 +1,22 @@
# eslint 忽略检查 (根据项目需要自行添加)
*.sh
node_modules
*.md
*.woff
*.ttf
.vscode
.idea
dist
html
/public
/docs
.husky
.local
/bin
.eslintrc.js
.prettierrc.js
.stylelintrc.js
lint-staged.config.js
/src/mock/*
src/utils/request.js
list

67
.eslintrc.js Normal file
View File

@ -0,0 +1,67 @@
// @see: http://eslint.cn
export default {
root: true,
env: {
browser: true,
node: true,
es6: true,
},
/* 指定如何解析语法 */
parser: 'vue-eslint-parser',
/* 优先级低于 parse 的语法解析配置 */
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'],
/*
* "off" 0 ==> 关闭规则
* "warn" 1 ==> 打开的规则作为警告不影响代码执行
* "error" 2 ==> 规则作为一个错误代码不能执行界面报错
*/
rules: {
// eslint (http://eslint.cn/docs/rules)
'no-var': 'error', // 要求使用 let 或 const 而不是 var
'no-multiple-empty-lines': ['error', { max: 1 }], // 不允许多个空行
'no-use-before-define': 'off', // 禁止在 函数/类/变量 定义之前使用它们
'prefer-const': 'off', // 此规则旨在标记使用 let 关键字声明但在初始分配后从未重新分配的变量,要求使用 const
'no-irregular-whitespace': 'off', // 禁止不规则的空白
// typeScript (https://typescript-eslint.io/rules)
'@typescript-eslint/prefer-ts-expect-error': 'error', // 禁止使用 @ts-ignore
'@typescript-eslint/no-inferrable-types': 'off', // 可以轻松推断的显式类型可能会增加不必要的冗长
'@typescript-eslint/no-namespace': 'off', // 禁止使用自定义 TypeScript 模块和命名空间。
'@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 类型
'@typescript-eslint/ban-types': 'off', // 禁止使用特定类型
'@typescript-eslint/explicit-function-return-type': 'off', // 不允许对初始化为数字、字符串或布尔值的变量或参数进行显式类型声明
'@typescript-eslint/no-var-requires': 'off', // 不允许在 import 语句中使用 require 语句
'@typescript-eslint/no-empty-function': 'off', // 禁止空函数
'@typescript-eslint/no-use-before-define': 'off', // 禁止在变量定义之前使用它们
'@typescript-eslint/ban-ts-comment': 'off', // 禁止 @ts-<directive> 使用注释或要求在指令后进行描述
'@typescript-eslint/no-non-null-assertion': 'off', // 不允许使用后缀运算符的非空断言(!)
'@typescript-eslint/explicit-module-boundary-types': 'off', // 要求导出函数和类的公共类方法的显式返回和参数类型
'@typescript-eslint/no-unused-vars': 'off',
// vue (https://eslint.vuejs.org/rules)
'vue/no-v-html': 'off', // 禁止使用 v-html
'vue/script-setup-uses-vars': 'error', // 防止<script setup>使用的变量<template>被标记为未使用此规则仅在启用该no-unused-vars规则时有效。
'vue/v-slot-style': 'error', // 强制执行 v-slot 指令样式
'vue/no-mutating-props': 'off', // 不允许组件 prop的改变
'vue/custom-event-name-casing': 'off', // 为自定义事件名称强制使用特定大小写
'vue/attributes-order': 'off', // vue api使用顺序强制执行属性顺序
'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', // 此规则要求为每个 prop 为必填时,必须提供默认值
'vue/multi-word-component-names': 'off', // 要求组件名称始终为 “-” 链接的单词
},
};

24
.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

4
.husky/pre-commit Normal file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run lint:lint-staged

10
.prettierignore Normal file
View File

@ -0,0 +1,10 @@
list
/dist/*
/html/*
.local
/node_modules/**
**/*.svg
**/*.sh
/public/*

39
.prettierrc.js Normal file
View File

@ -0,0 +1,39 @@
// @see: https://www.prettier.cn
export default {
// 超过最大值换行
printWidth: 130,
// 缩进字节数
tabWidth: 1,
// 使用制表符而不是空格缩进行
useTabs: true,
// 结尾不用分号(true有false没有)
semi: true,
// 使用单引号(true单引号false双引号)
singleQuote: true,
// 更改引用对象属性的时间 可选值"<as-needed|consistent|preserve>"
quoteProps: "as-needed",
// 在对象,数组括号与文字之间加空格 "{ foo: bar }"
bracketSpacing: true,
// 多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>"默认none
trailingComma: "all",
// 在JSX中使用单引号而不是双引号
jsxSingleQuote: true,
// (x) => {} 箭头函数参数只有一个时是否要有小括号。avoid省略括号 ,always不省略括号
arrowParens: "avoid",
// 如果文件顶部已经有一个 doclock这个选项将新建一行注释并打上@format标记。
insertPragma: false,
// 指定要使用的解析器,不需要写文件开头的 @prettier
requirePragma: false,
// 默认值。因为使用了一些折行敏感型的渲染器如GitHub comment而按照markdown文本样式进行折行
proseWrap: "preserve",
// 在html中空格是否是敏感的 "css" - 遵守CSS显示属性的默认值 "strict" - 空格被认为是敏感的 "ignore" - 空格被认为是不敏感的
htmlWhitespaceSensitivity: "css",
// 换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr>"
endOfLine: "auto",
// 这两个选项可用于格式化以给定字符偏移量(分别包括和不包括)开始和结束的代码
rangeStart: 0,
rangeEnd: Infinity,
vueIndentScriptAndStyle: false // Vue文件脚本和样式标签缩进
};

19
.stylelintignore Normal file
View File

@ -0,0 +1,19 @@
# .stylelintignore
# 旧的不需打包的样式库
*.min.css
# 其他类型文件
*.js
*.jpg
*.woff
# 测试和打包目录
/test/
/dist/*
/public/*
public/*
/node_modules/
.eslintrc.js
.prettierrc.js
.stylelintrc.js
lint-staged.config.js

62
.stylelintrc.js Normal file
View File

@ -0,0 +1,62 @@
// @see: https://stylelint.io
export default {
root: true,
defaultSeverity: "error",
plugins: ["stylelint-order", "stylelint-scss"],
/* 继承某些已有的规则 */
extends: [
"stylelint-config-standard", // 配置stylelint拓展插件
"stylelint-config-html/html", // the shareable html config for Stylelint.
"stylelint-config-html/vue", // 配置 vue 中 template 样式格式化
"stylelint-config-recess-order", // 配置stylelint css属性书写顺序插件,
"stylelint-config-prettier" // 配置stylelint和prettier兼容
],
overrides: [
// 扫描 .vue/html 文件中的<style>标签内的样式
{
files: ["**/*.{vue,html}"],
customSyntax: "postcss-html",
rules: {
// 禁止未知的伪类选择器
"selector-pseudo-class-no-unknown": [true, { ignorePseudoClasses: ["deep", "global"] }],
// 禁止未知的伪元素选择器
"selector-pseudo-element-no-unknown": [true, { ignorePseudoElements: ["v-deep", "v-global", "v-slotted"] }]
}
},
{
files: ["*.less", "**/*.less", "*.scss", "**/*.scss"],
customSyntax: "postcss-less",
rules: {
"less/color-no-invalid-hex": true,
"less/no-duplicate-variables": true
}
}
],
/**
* null => 关闭该规则
*/
rules: {
"value-keyword-case": null, // 在 css 中使用 v-bind不报错
"no-descending-specificity": null, // 禁止在具有较高优先级的选择器后出现被其覆盖的较低优先级的选择器
"function-url-quotes": "always", // 要求或禁止 URL 的引号 "always(必须加上引号)"|"never(没有引号)"
"string-quotes": "double", // 指定字符串使用单引号或双引号
"unit-case": null, // 指定单位的大小写 "lower(全小写)"|"upper(全大写)"
"color-hex-case": "lower", // 指定 16 进制颜色的大小写 "lower(全小写)"|"upper(全大写)"
"color-hex-length": "long", // 指定 16 进制颜色的简写或扩写 "short(16进制简写)"|"long(16进制扩写)"
"rule-empty-line-before": "never", // 要求或禁止在规则之前的空行 "always(规则之前必须始终有一个空行)"|"never(规则前绝不能有空行)"|"always-multi-line(多行规则之前必须始终有一个空行)"|"never-multi-line(多行规则之前绝不能有空行。)"
"font-family-no-missing-generic-family-keyword": null, // 禁止在字体族名称列表中缺少通用字体族关键字
"block-opening-brace-space-before": "always", // 要求在块的开大括号之前必须有一个空格或不能有空白符 "always(大括号前必须始终有一个空格)"|"never(左大括号之前绝不能有空格)"|"always-single-line(在单行块中的左大括号之前必须始终有一个空格)"|"never-single-line(在单行块中的左大括号之前绝不能有空格)"|"always-multi-line(在多行块中,左大括号之前必须始终有一个空格)"|"never-multi-line(多行块中的左大括号之前绝不能有空格)"
"property-no-unknown": null, // 禁止未知的属性(true 为不允许)
"no-empty-source": null, // 禁止空源码
"declaration-block-trailing-semicolon": null, // 要求或不允许在声明块中使用尾随分号 string"always(必须始终有一个尾随分号)"|"never(不得有尾随分号)"
"selector-class-pattern": null, // 强制选择器类名的格式
"value-no-vendor-prefix": null, // 关闭 vendor-prefix(为了解决多行省略 -webkit-box)
"selector-pseudo-class-no-unknown": [
true,
{
ignorePseudoClasses: ["global", "v-deep", "deep"]
}
]
}
};

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

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

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Y_Lao
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 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.

312
README.md Normal file
View File

@ -0,0 +1,312 @@
# Vite相关使用
## .env文件
### 文件名简介
- `.env`:公用配置文件
- `.env.development`:开发环境配置
- `.env.production`:生产话就配置
### 修改环境前缀
在配置文件中加上`envPrefix`
```ts
export default defineConfig(
(): UserConfig => ({
envPrefix: 'BUNNY',
}),
);
```
## 使用gzip
安装
```sh
npm i vite-plugin-compress
```
需要文件中引入
```js
import compress from 'vite-plugin-compress';
export default {
plugins: [compress()],
};
```
## 动态加载路由
```ts
import { routeFilenameHelper } from '@/utils/file/routeFileUtil';
import _ from 'lodash';
import { RouteRecordRaw } from 'vue-router';
// * 最终路由
const routeMap: Record<string, RouteRecordRaw> = {};
// * 所有处理的路由
const contexts = [
{ context: import.meta.glob('@/views/**/index.vue', { eager: true, import: 'default' }), isIndex: true },
{ context: import.meta.glob('@/views/**/page.ts', { eager: true, import: 'default' }), isIndex: false },
];
/**
* 构建路由信息
* @param context 上下文信息
* @param isIndex 是否第一次遍历
* @param route 路由内容
*/
function buildRouteTree(context: any, isIndex: boolean, route: any) {
// 遍历当前子路由
Object.entries(context).forEach(([filePath, _]) => {
// 获取子路由下所有文件对象格式
const childrenFileInfo = routeFilenameHelper(filePath);
// 组装子路由对象
const childrenRoute: any = {
name: childrenFileInfo?.name,
path: childrenFileInfo!.path,
component: isIndex ? context[filePath] : undefined,
children: [],
meta: { isFullScreen: false },
};
// 如果当前路由对象等于当前遍历的路由子对象,将子路由推到父级路由中
if (childrenFileInfo?.path.includes(route.path) && childrenFileInfo?.path !== route.path) {
route.children.push(childrenRoute);
}
});
}
/**
* 遍历路由信息
* @param context 路由上下文
* @param isIndex 是否为索引遍历
*/
const createRouteList = (context: any, isIndex: boolean) => {
Object.entries(context).forEach(([filePath, exportRouteConfig]) => {
const fileInfo = routeFilenameHelper(filePath);
// 组装路由对象
const route: any = {
name: fileInfo?.name,
path: fileInfo!.path,
component: isIndex ? context[filePath] : undefined,
children: [],
meta: { isFullScreen: false },
};
// 初始化赋值
if (isIndex) {
routeMap[route.path] = route;
buildRouteTree(context, isIndex, route);
} else {
// 导出当前存在的路由并重新赋值
const existingRoute = routeMap[route.path];
// 当前路由存在
if (existingRoute) {
// 使用loadsh合并对象
routeMap[route.path] = _.merge(existingRoute, exportRouteConfig);
}
}
});
};
// * 生成路由信息
contexts.forEach(({ context, isIndex }) => createRouteList(context, isIndex));
export const pageRoutes: Array<RouteRecordRaw> = Object.values(routeMap);
```
> 需要注意的是,为了动态导入生产环境也可以运行,需要`context[filePath]`需要使用这段话,才可以
## 输出环境变量内容
```ts
console.log(import.meta.env);
```
## 动态加载CDN
在Module中配置相关内容相关文档查看https://www.npmjs.com/package/vite-plugin-cdn-import
```ts
import vue from '@vitejs/plugin-vue';
import { resolve } from 'path';
import { defineConfig, UserConfig } from 'vite';
import cdn from 'vite-plugin-cdn-import';
export default defineConfig(
(): UserConfig => ({
plugins: [
cdn({
modules: [],
}),
],
}),
);
```
> ```
> npm i vite-plugin-cdn-import
> ```
## 兼容老版本浏览器
在plugin中加入
```ts
legacy({ targets: ["defaults", "not IE 11"] }),
```
详细配置查看https://www.npmjs.com/package/@vitejs/plugin-legacy
## 打包设置
如果打包中包含`node_module`包全部放到`vendor-[hash].js`中
![image-20240527152054024](./images/image-20240527152054024.png)
## 配置跨域
`process.env.BUNNY_APP_URL`设置在这三个文件中,读取是这三个配置
![image-20240527152136447](./images/image-20240527152136447.png)
```ts
server: {
host: "0.0.0.0",
port
:
6261,
open
:
true,
cors
:
true,
proxy
:
{
"/api"
:
{
target: process.env.BUNNY_APP_URL,
changeOrigin
:
true,
rewrite
:
(path: string) => path.replace(/^\/api/, "/api")
}
,
"/mock"
:
{
target: process.env.BUNNY_APP_URL,
changeOrigin
:
true,
rewrite
:
(path: string) => path.replace(/^\/mock/, "/mock")
}
}
}
,
```
## 配置JSX
项目中已经设置好了JSX相关功能
![image-20240527152316666](./images/image-20240527152316666.png)
## Mock和多语言
### Mock设置
在环境已经设置好了Mock只需要在`/src/mock`中写代码即可。
### 多语言设置
多语言现在作为网络请求来发送在pinia中设置本地持久存储。
后端需要按照返回格式进行传送
![image-20240527152545485](./images/image-20240527152545485.png)
发送请求和初始化放在`App.vue`中
![image-20240527153132792](./images/image-20240527153132792.png)
#### 多语言只做本地化
只需要在`i18n`中加入你的语言,之后在`index.ts`中引用即可
![image-20240527153316912](./images/image-20240527153316912.png)
格式大致如下
![image-20240527153421787](./images/image-20240527153421787.png)
#### 后端返回多语言格式
这个格式也可以改,默认的如下。需要包含默认语言`local:xxx`
```
{
"i18n": {
"zh_cn": {
"login": {
"reset": "重置",
"register": "登录"
},
"home": {
"articleModeAlbum": "相册模式",
"articleModeList": "列表模式"
},
"tabs": {},
"header": {
"fullScreen": "全屏",
"exitFullScreen": "退出全屏",
"personalData": "个人信息",
"changePassword": "修改密码",
"logout": "退出登录"
},
"tip": {
"loading": "加载中..."
}
},
"en": {
"login": {
"reset": "reset",
"register": "register"
},
"home": {
"articleModeAlbum": "Album Mode",
"articleModeList": "List Mode"
},
"tabs": {},
"header": {
"fullScreen": "Full Screen",
"exitFullScreen": "Exit Full Screen",
"personalData": "Personal Data",
"changePassword": "Change Password",
"logout": "Logout"
},
"tip": {
"loading": "Loading..."
}
},
"local": "zh_cn"
}
}
```
### Vue指令
配置了打印、复制、水印等指令
![image-20240527153512670](./images/image-20240527153512670.png)

50
build/buildEnv.ts Normal file
View File

@ -0,0 +1,50 @@
import type { BuildOptions } from 'vite';
export const buildEnvironment = () => {
const environment: BuildOptions = {
assetsInlineLimit: 20000,
// 构建输出的目录,默认值为"dist"
outDir: 'dist',
// 用于指定使用的代码压缩工具。在这里minify 被设置为 'terser',表示使用 Terser 进行代码压缩。默认值terser
// esbuild 打包更快,但是不能去除 console.logterser打包慢但能去除 console.log
minify: 'terser',
// 用于配置 Terser 的选项
terserOptions: {
// 用于配置压缩选项
compress: {
drop_console: true, // 是否删除代码中的 console 语句, 默认值false
drop_debugger: true, // 是否删除代码中的 debugger 语句, 默认值false
},
},
// 禁用 gzip 压缩大小报告,可略微减少打包时间
reportCompressedSize: false,
// 用于指定是否生成源映射文件。源映射文件可以帮助调试和定位源代码中的错误。当设置为false时构建过程不会生成源映射文件
sourcemap: false,
// 用于配置 CommonJS 模块的选项
commonjsOptions: {
// 用于指定是否忽略 CommonJS 模块中的 try-catch 语句。当设置为false时构建过程会保留 CommonJS 模块中的 try-catch 语句
ignoreTryCatch: false,
},
// 规定触发警告的 chunk 大小, 当某个代码分块的大小超过该限制时Vite 会发出警告
chunkSizeWarningLimit: 2000,
// 用于配置 Rollup 打包工具的选项
rollupOptions: {
// 用于配置输出选项
output: {
// 静态资源分类和包装
chunkFileNames: 'js/[name]-[hash].js', // 用于指定代码分块的输出文件名格式
entryFileNames: 'js/[name]-[hash].js', // 用于指定入口文件的输出文件名格式
assetFileNames: 'assets/[ext]/[name]-[hash].[ext]', // 用于指定静态资源的输出文件名格式
// ? 配置文件生成方式
manualChunks: (id, meta) => {
// 如果是包含在包中则打包成 vendor
if (id.includes('node_modules')) {
return 'vendor';
}
},
},
},
};
return environment;
};

55
build/cdn.ts Normal file
View File

@ -0,0 +1,55 @@
import { Plugin as importToCDN } from "vite-plugin-cdn-import";
/**
* @description `cdn`使cdn模式 .env.production VITE_CDN true
* cdnhttps://www.bootcdn.cn当然你也可以选择 https://unpkg.com 或者 https://www.jsdelivr.com
* 使jscss文件cdn
*/
export const cdn = importToCDN({
//prodUrl解释 name: 对应下面modules的nameversion: 自动读取本地package.json中dependencies依赖中对应包的版本号path: 对应下面modules的path当然也可写完整路径会替换prodUrl
// prodUrl: 'https://cdn.bootcdn.net/ajax/libs/{name}/{version}/{path}',
prodUrl: 'https://unpkg.com/{name}@{version}/{path}',
modules: [
{
name: 'vue',
var: 'Vue',
path: 'dist/vue.global.js',
},
{
name: 'vue-router',
var: 'VueRouter',
path: 'dist/vue-router.global.js',
},
{
name: 'vue-i18n',
var: 'VueI18n',
path: 'dist/vue-i18n.global.js',
},
// 项目中没有直接安装vue-demi但是pinia用到了所以需要在引入pinia前引入vue-demihttps://github.com/vuejs/pinia/blob/v2/packages/pinia/package.json#L77
{
name: 'vue-demi',
var: 'VueDemi',
path: 'lib/index.iife.js',
},
{
name: 'pinia',
var: 'Pinia',
path: 'dist/pinia.iife.js',
},
{
name: 'axios',
var: 'axios',
path: 'dist/axios.min.js',
},
{
name: 'dayjs',
var: 'dayjs',
path: 'dayjs.min.js',
},
{
name: 'echarts',
var: 'echarts',
path: 'dist/echarts.js',
},
],
});

57
build/compress.ts Normal file
View File

@ -0,0 +1,57 @@
import type { Plugin } from 'vite';
import { isArray } from '@pureadmin/utils';
import compressPlugin from 'vite-plugin-compression';
export const configCompressPlugin = (compress: any): Plugin | Plugin[] | null => {
if (compress === 'none' || compress === void 0) return null;
const gz = {
// 生成的压缩包后缀
ext: '.gz',
// 体积大于threshold才会被压缩
threshold: 0,
// 默认压缩.js|mjs|json|css|html后缀文件设置成true压缩全部文件
filter: () => true,
// 压缩后是否删除原始文件
deleteOriginFile: false,
};
const br = {
ext: '.br',
algorithm: 'brotliCompress',
threshold: 0,
filter: () => true,
deleteOriginFile: false,
};
const codeList = [
{ k: 'gzip', v: gz },
{ k: 'brotli', v: br },
{ k: 'both', v: [gz, br] },
];
const plugins: Plugin[] = [];
codeList.forEach(item => {
if (compress.includes(item.k)) {
if (compress.includes('clear')) {
if (isArray(item.v)) {
item.v.forEach(vItem => {
plugins.push(compressPlugin(Object.assign(vItem, { deleteOriginFile: true })));
});
} else {
plugins.push(compressPlugin(Object.assign(item.v, { deleteOriginFile: true })));
}
} else {
if (isArray(item.v)) {
item.v.forEach(vItem => {
plugins.push(compressPlugin(vItem));
});
} else {
plugins.push(compressPlugin(item.v));
}
}
}
});
return plugins;
};

60
build/info.ts Normal file
View File

@ -0,0 +1,60 @@
import boxen, { type Options as BoxenOptions } from 'boxen';
import dayjs, { type Dayjs } from 'dayjs';
import duration from 'dayjs/plugin/duration';
import gradientString from 'gradient-string';
import type { Plugin } from 'vite';
import { loadEnv } from 'vite';
import { getPackageSize, root, wrapperEnv } from './utils';
dayjs.extend(duration);
const { VITE_PORT } = wrapperEnv(loadEnv('dev', root));
const welcomeMessage = gradientString('cyan', 'magenta').multiline(
`您好! 欢迎使用 bunny 系列开发模板
访
http://localhost:${VITE_PORT}`,
);
const boxenOptions: BoxenOptions = {
padding: 0.5,
borderColor: 'cyan',
borderStyle: 'round',
};
export function viteBuildInfo(): Plugin {
let config: { command: string };
let startTime: Dayjs;
let endTime: Dayjs;
let outDir: string;
return {
name: 'vite:buildInfo',
configResolved(resolvedConfig) {
config = resolvedConfig;
outDir = resolvedConfig.build?.outDir ?? 'dist';
},
buildStart() {
console.log(boxen(welcomeMessage, boxenOptions));
if (config.command === 'build') {
startTime = dayjs(new Date());
}
},
closeBundle() {
if (config.command === 'build') {
endTime = dayjs(new Date());
getPackageSize({
folder: outDir,
callback: (size: string) => {
console.log(
boxen(
gradientString('cyan', 'magenta').multiline(
`🎉 恭喜打包完成(总用时${dayjs.duration(endTime.diff(startTime)).format('mm分ss秒')},打包后的大小为${size}`,
),
boxenOptions,
),
);
},
});
}
},
};
}

60
build/optimize.ts Normal file
View File

@ -0,0 +1,60 @@
/**
* `vite.config.ts` `optimizeDeps.include`
* `vite` include esm node_modules/.vite
* include里vite 使 node_modules/.vite
* 使 src/main.ts include vite node_modules/.vite
*/
const include = [
// 'qs',
'mitt',
'tailwindcss',
// 'xlsx',
'dayjs',
'axios',
'pinia',
// 'typeit',
// 'swiper',
// 'qrcode',
// 'intro.js',
'vue-i18n',
// 'vxe-table',
// 'vue-types',
// 'js-cookie',
// 'vue-tippy',
// 'cropperjs',
// 'jsbarcode',
// 'pinyin-pro',
// 'sortablejs',
// 'swiper/vue',
// 'mint-filter',
// '@vueuse/core',
// 'vue3-danmaku',
// 'v-contextmenu',
// 'vue-pdf-embed',
// 'wavesurfer.js',
// 'swiper/modules',
// 'china-area-data',
// 'vue-json-pretty',
// '@logicflow/core',
'@pureadmin/utils',
// '@wangeditor/editor',
// 'responsive-storage',
// 'plus-pro-components',
// '@howdyjs/mouse-menu',
// '@logicflow/extension',
// 'vue-virtual-scroller',
// '@amap/amap-jsapi-loader',
// 'el-table-infinite-scroll',
// 'vue-waterfall-plugin-next',
// '@infectoone/vue-ganttastic',
// '@wangeditor/editor-for-vue',
// 'vuedraggable/src/vuedraggable',
];
/**
*
* `@iconify-icons/` `exclude` 使
*/
const exclude = ['@iconify-icons/ep', '@iconify-icons/ri', '@pureadmin/theme/dist/browser-utils'];
export { include, exclude };

44
build/plugins.ts Normal file
View File

@ -0,0 +1,44 @@
import { cdn } from './cdn';
import vue from '@vitejs/plugin-vue';
import type { PluginOption } from 'vite';
import vueJsx from '@vitejs/plugin-vue-jsx';
import legacy from '@vitejs/plugin-legacy';
import { compression } from 'vite-plugin-compression2';
import { viteMockServe } from 'vite-plugin-mock';
import { viteBuildInfo } from './info';
import { configCompressPlugin } from './compress.ts';
export function getPluginsList(VITE_CDN: boolean, VITE_COMPRESSION: any): PluginOption[] {
return [
vue(),
legacy({
targets: ['android 4', 'ios 8', 'chrome 30', 'ie 6'],
additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
renderLegacyChunks: true,
polyfills: [
'es.symbol',
'es.array.filter',
'es.promise',
'es.promise.finally',
'es/map',
'es/set',
'es.array.for-each',
'es.object.define-properties',
'es.object.define-property',
'es.object.get-own-property-descriptor',
'es.object.get-own-property-descriptors',
'es.object.keys',
'es.object.to-string',
'web.dom-collections.for-each',
'esnext.global-this',
'esnext.string.match-all',
],
}),
vueJsx(),
compression(),
viteBuildInfo(),
VITE_CDN ? cdn : null,
configCompressPlugin(VITE_COMPRESSION),
viteMockServe({ mockPath: 'src/api/mock' }),
];
}

27
build/server.ts Normal file
View File

@ -0,0 +1,27 @@
import { loadEnv, type ServerOptions } from 'vite';
import { root, wrapperEnv } from './utils';
export const serverOptions = (mode: string) => {
const { VITE_APP_URL, VITE_APP_MOCK_URL, VITE_PORT } = wrapperEnv(loadEnv(mode, root));
const options: ServerOptions = {
port: VITE_PORT,
host: '0.0.0.0',
open: true,
cors: true,
proxy: {
'/api': {
target: VITE_APP_URL,
changeOrigin: true,
rewrite: (path: string) => path.replace(/^\/api/, '/api'),
},
'/mock': {
target: VITE_APP_MOCK_URL,
changeOrigin: true,
rewrite: (path: string) => path.replace(/^\/mock/, '/mock'),
},
},
};
return options;
};

89
build/utils.ts Normal file
View File

@ -0,0 +1,89 @@
import { Recordable, formatBytes, sum } from '@pureadmin/utils';
import { readdir, stat } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
/** 启动`node`进程时所在工作目录的绝对路径 */
const root: string = process.cwd();
const fileListTotal: number[] = [];
/** 获取指定文件夹中所有文件的总大小 */
const getPackageSize = (options: any) => {
const { folder = 'dist', callback, format = true } = options;
readdir(folder, (err, files: string[]) => {
if (err) throw err;
let count = 0;
const checkEnd = () => {
++count == files.length && callback(format ? formatBytes(sum(fileListTotal)) : sum(fileListTotal));
};
files.forEach((item: string) => {
stat(`${folder}/${item}`, async (err, stats) => {
if (err) throw err;
if (stats.isFile()) {
fileListTotal.push(stats.size);
checkEnd();
} else if (stats.isDirectory()) {
getPackageSize({
folder: `${folder}/${item}/`,
callback: checkEnd,
});
}
});
});
files.length === 0 && callback(0);
});
};
/**
* @description
* @param dir `build`
* @param metaUrl `url``build``import.meta.url`
*/
const pathResolve = (dir = '.', metaUrl = import.meta.url) => {
// 当前文件目录的绝对路径
const currentFileDir = dirname(fileURLToPath(metaUrl));
// build 目录的绝对路径
const buildDir = resolve(currentFileDir, 'build');
// 解析的绝对路径
const resolvedPath = resolve(currentFileDir, dir);
// 检查解析的绝对路径是否在 build 目录内
if (resolvedPath.startsWith(buildDir)) {
// 在 build 目录内,返回当前文件路径
return fileURLToPath(metaUrl);
}
// 不在 build 目录内,返回解析后的绝对路径
return resolvedPath;
};
/** 处理环境变量 */
const wrapperEnv = (envConf: Recordable): any => {
// TODO 默认值
const ret: any = {
VITE_BASE_API: '',
VITE_MOCK_BASE_API: '',
VITE_PORT: 6262,
VITE_APP_URL: '',
VITE_APP_MOCK_URL: '',
VITE_CDN: false,
};
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);
}
ret[envName] = realName;
if (typeof realName === 'string') {
process.env[envName] = realName;
} else if (typeof realName === 'object') {
process.env[envName] = JSON.stringify(realName);
}
}
return ret;
};
export { getPackageSize, pathResolve, root, wrapperEnv };

145
build/version.js Normal file
View File

@ -0,0 +1,145 @@
// 使用细节:
// 1、导入方式在 src 文件夹中使用可以 const version = require('@/utils/version') 这样引入使用,在根目录也就是 src 之外的文件夹则只能 const version = require('./src/utils/version') 这样引入使用
// 引入请求库(如果想使用 axios 请求,打开注释即可,下面 get 方法中也需要打开注释默认使用JS原生请求
// const axios = require('axios')
// 引入文件管理模块(基于 node 环境,如果为原生前端开发,则注释掉 fs 相关的代码即可,直接手动创建一个文件使用 get 方法获取即可,注意统一存储内容格式看 create 方法注释)
import fs from 'fs';
// 本地版本号缓存 key
const storageKey = 'currentVersion';
// 创建版本文件(由于 fs 基于 node且只需要每次编译时创建更新一遍所以推荐放置于 vue.config.js 文件顶部使用,然后使用 build 命令时会被成功执行创建好文件)
// path: 文件路径以及文件名称例如verify.text, public/verify.json 都是存在 public 文件夹中)
// version: 版本号(例如:版本号、时间戳 ...,统一存储内容为:{ version: xxx }
// result: 回调创建于写入结果
function create(path = 'public/verify.json', version = new Date().getTime(), result) {
// 在指定目录中添加校验文件
fs.writeFile(path, JSON.stringify({ version }), err => {
const isOK = !!err;
if (result) {
result({ isOK });
}
});
}
// 获取版本号(下面 get 方法)升级版(返回:当前版本号、是否有新版本。样例:{ version: xxxnew: true }并缓存好新的版本号可选择直接刷新页面。vue 推荐放到路由守卫 router.afterEach(路由跳转后) 回调中,切换页面时随时检查版本是否更新,这个请求很快的,占用的时间几乎可以忽略,而且就是切换页面完成之后,就算失败或者网不好也不影响正常操作)
// path: 看下面 get 方法中的注释
// isReload: 如果有新版本使用是否重新加载当前页面强制浏览器重服务器获取当前页面资源false 为后续自行手动刷新
function getPro(path = 'verify.json', isReload = true) {
return new Promise((resolve, reject) => {
// 获取版本号
get(path)
.then(res => {
// 服务器版本号
const version = res.version;
// 检查是否有新版本
const isNew = isNewAvailable(version);
// 缓存版本号
save(version);
// 有新版本的话是否重新从服务器加载页面数据
if (isNew && isReload) {
reload();
}
// 返回
resolve({ version: version, new: isNew });
})
.catch(err => {
// 返回
reject(err);
});
});
}
// 获取版本号(返回:当前版本号。样例:{ version: xxx }vue 推荐放到路由守卫 router.afterEach(路由跳转后) 回调中,切换页面时随时检查版本是否更新,这个请求很快的,占用的时间几乎可以忽略,而且就是切换页面完成之后,就算失败或者网不好也不影响正常操作)
// path: 服务器文件路径(例如上 create() 中的路径,文件存 build 后存放在 public 文件夹中,服务器路径则直接域 + 文件名既可,如果为原生前端开发也是一样)
function get(path = 'verify.json') {
// 服务器文件路径
const url = `${window.location.origin}/${path}?timestamp=${new Date().getTime()}`;
// axios 请求
// return new Promise((resolve, reject) => {
// // 获取内容
// axios.get(url).then(res => {
// resolve(res)
// }).catch(err => {
// reject(err)
// })
// })
// JS原生请求
return new Promise((resolve, reject) => {
// 创建 XMLHttpRequest 对象
var xhr = null;
if (window.XMLHttpRequest) {
// 现代主流浏览器的写法
xhr = new XMLHttpRequest();
} else {
// IE浏览器的写法
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
// 创建网络请求对象
xhr.open('get', url, true);
// 发送请求
xhr.send();
// 请求回调
xhr.onreadystatechange = () => {
// 连接成功
if (xhr.status === 200) {
// 请求成功
if (xhr.readyState === 4) {
// 返回
resolve(JSON.parse(xhr.responseText));
}
} else {
// 连接失败
reject(new Error('获取失败'));
}
};
});
}
// 缓存版本号
// version: 版本号(服务器获取到的版本号)
function save(version) {
localStorage.setItem(storageKey, version);
}
// 检查是否有新版本true有新版本 false没有新版本
// version: 版本号(服务器获取到的版本号)
function isNewAvailable(version) {
// 没值(不清楚是否为新版本,默认返回 false, 如果这种情况下需要刷新,可修改返回 true
if (!version) {
return false;
}
// 获取本地缓存的版本号
const storageVersion = localStorage.getItem(storageKey);
// 本地没有版本号,说明本机第一次加载,不算新版本
if (!storageVersion || storageVersion === 'undefined') {
return false;
}
// 本地有版本号,进行对比
return `${version}` !== `${storageVersion}`;
}
// 刷新当前网页
function reload() {
// 重新加载当前页面,强制浏览器重服务器获取当前页面资源
window.location.reload(true);
}
// 导出
export {
// 创建版本文件
create,
// 获取版本号
get,
// 获取版本号升级版
getPro,
// 缓存版本号
save,
// 检查是否有新版本
isNewAvailable,
// 刷新当前页面,强制浏览器重服务器获取当前页面资源
reload,
};

108
commitlint.config.js Normal file
View File

@ -0,0 +1,108 @@
// @see: https://cz-git.qbenben.com/zh/guide
/** @type {import("cz-git").UserConfig} */
export default {
ignores: [commit => commit === "init"],
extends: ["@commitlint/config-conventional"],
rules: {
// @see: https://commitlint.js.org/#/reference-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"],
"subject-case": [0],
"type-enum": [
2,
"always",
[
"init",
"feat",
"page",
"media",
"completepage",
"fix",
"fixbug",
"docs",
"style",
"refactor",
"perf",
"test",
"build",
"ci",
"chore",
"revert",
"wip",
"workflow",
"types",
"release",
"optimize"
]
]
},
prompt: {
messages: {
type: "选择你要提交的类型 :",
scope: "选择一个提交范围(可选):",
customScope: "请输入自定义的提交范围 :",
subject: "填写简短精炼的变更描述 :\n",
body: "填写更加详细的变更描述(可选)。使用 \"|\" 换行 :\n",
breaking: "列举非兼容性重大的变更(可选)。使用 \"|\" 换行 :\n",
footerPrefixsSelect: "选择关联issue前缀可选:",
customFooterPrefixs: "输入自定义issue前缀 :",
footer: "列举关联issue (可选) 例如: #31, #I3244 :\n",
confirmCommit: "是否提交或修改commit ?"
},
types: [
{ value: "init", name: "初始化: ⏳ 初始化项目", emoji: "⏳" },
{ value: "optimize", name: "优化代码: ♻️ 优化项目代码", emoji: "♻️" },
{ value: "feat", name: "新增: 🚀 新增功能", emoji: "🚀" },
{ value: "media", name: "媒体: 🎁 新增媒体资源", emoji: "🎁" },
{ value: "page", name: "页面: 📄 新增页面", emoji: "📄" },
{ value: "completepage", name: "完成页面: 🍻 完成页面", emoji: "🍻" },
{ value: "fixbug", name: "bug: 🐛 修改bug", emoji: "🐛" },
{ value: "fix", name: "修复: 🧩 修复缺陷", emoji: "🧩" },
{ value: "docs", name: "文档: 📚 文档变更", emoji: "📚" },
{ value: "style", name: "格式: 🎨 代码格式(不影响功能,例如空格、分号等格式修正)", emoji: "🎨" },
{ value: "refactor", name: "重构: 〽️ 代码重构(不包括 bug 修复、功能新增)", emoji: "〽️" },
{ value: "perf", name: "性能: ⚡️ 性能优化", emoji: "⚡️" },
{ value: "test", name: "测试: ✅ 添加疏漏测试或已有测试改动", emoji: "✅" },
{
value: "chore",
name: "构建: 📦️ 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)",
emoji: "📦️"
},
{ value: "ci", name: "集成: 🎡 修改 CI 配置、脚本", emoji: "🎡" },
{ value: "revert", name: "回退: ⏪️ 回滚 commit", emoji: "⏪️" },
{ value: "build", name: "打包: 🔨 项目打包发布", emoji: "🔨" }
],
useEmoji: true,
themeColorCode: "",
scopes: [],
allowCustomScopes: true,
allowEmptyScopes: true,
customScopesAlign: "bottom",
customScopesAlias: "custom",
emptyScopesAlias: "empty",
upperCaseSubject: false,
allowBreakingChanges: ["feat", "fix"],
breaklineNumber: 100,
breaklineChar: "|",
skipQuestions: [],
issuePrefixs: [{ value: "closed", name: "closed: ISSUES has been processed" }],
customIssuePrefixsAlign: "top",
emptyIssuePrefixsAlias: "skip",
customIssuePrefixsAlias: "custom",
allowCustomIssuePrefixs: true,
allowEmptyIssuePrefixs: true,
confirmColorize: true,
maxHeaderLength: Infinity,
maxSubjectLength: Infinity,
minSubjectLength: 0,
scopeOverrides: undefined,
defaultBody: "",
defaultIssues: "",
defaultScope: "",
defaultSubject: ""
}
};

23
docker/dockerfile Normal file
View File

@ -0,0 +1,23 @@
# 使用官方的 Nginx 镜像作为基础镜像
FROM nginx
# 删除默认的 Nginx 配置文件
RUN rm /etc/nginx/conf.d/default.conf
# 将自定义的 Nginx 配置文件复制到容器中
COPY nginx.conf /etc/nginx/conf.d/
# 创建一个目录来存放前端项目文件
WORKDIR /usr/share/nginx/html
# 将前端项目打包文件复制到 Nginx 的默认静态文件目录
COPY dist/ /usr/share/nginx/html
# 复制到nginx目录下
COPY dist/ /etc/nginx/html
# 暴露 Nginx 的默认端口
EXPOSE 80
# 自动启动 Nginx
CMD ["nginx", "-g", "daemon off;"]

27
docker/nginx.conf Normal file
View File

@ -0,0 +1,27 @@
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /etc/nginx/html;
index index.html index.htm;
try_files $uri /index.html;
}
# 后端跨域请求
location ~/api/ {
proxy_pass http://192.168.3.98:1001;
}
# mock 跨域
location ~/mock/ {
proxy_pass http://192.168.3.98:1001;
}
error_page 404 404.html;
location = /50x.html {
root html;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

13
index.html Normal file
View File

@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue + TS</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

8
lint-staged.config.js Normal file
View File

@ -0,0 +1,8 @@
export default {
'*.{js,jsx,ts,tsx}': ['prettier --write'],
'{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': ['prettier --write--parser json'],
'package.json': ['prettier --write'],
// "*.vue": ["eslint --fix", "prettier --write"],
'*.{scss,less,styl,html}': ['prettier --write'], // 'stylelint --fix',
'*.md': ['prettier --write'],
};

133
package.json Normal file
View File

@ -0,0 +1,133 @@
{
"name": "vite_ts_auto",
"private": true,
"version": "1.0.0",
"type": "module",
"description": "Bunny-Vite模板",
"author": {
"name": "Bunny0212",
"email": "1319900154@qq.com",
"url": "https://github.com/BunnyMaster"
},
"license": "MIT",
"keywords": [
"bunny-cli",
"tailwindcss",
"typescript",
"pinia",
"vue3",
"vite",
"esm"
],
"scripts": {
"dev": "vite",
"serve": "vite",
"start": "vite",
"build": "vite build",
"preview": "vite preview",
"lint:eslint": "eslint --fix --ext .js,.ts,.vue ./src",
"lint:prettier": "prettier --write --loglevel warn \"src/**/*.{js,ts,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",
"prepare": "husky install",
"commit": "git pull && git add -A && git-cz && git push"
},
"dependencies": {
"@pureadmin/utils": "^2.4.7",
"@vitejs/plugin-legacy": "^5.4.0",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"@vitejs/plugin-vue2-jsx": "^1.1.1",
"autoprefixer": "^10.4.19",
"axios": "^1.6.7",
"boxen": "^7.1.1",
"compression-webpack-plugin": "^11.1.0",
"core-js": "^3.36.0",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.10",
"dotenv": "^16.4.5",
"echarts": "^5.5.0",
"gradient-string": "^2.0.2",
"lodash": "^4.17.21",
"mitt": "^3.0.1",
"moment": "^2.30.1",
"pinia": "^2.1.7",
"pinia-plugin-persistedstate": "^3.2.1",
"postcss-import": "^16.1.0",
"punycode": "^2.3.1",
"stylelint-scss": "^6.3.0",
"tailwindcss": "^3.4.4",
"uuid": "^9.0.1",
"vite-plugin-cdn-import": "^1.0.1",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-compression2": "^1.1.1",
"vue": "^3.4.21",
"vue-cookies": "^1.8.3",
"vue-demi": "^0.14.8",
"vue-i18n": "^9.13.1",
"vue-lazyload": "^3.0.0",
"vue-router": "^4.3.0"
},
"devDependencies": {
"@commitlint/cli": "^17.8.1",
"@commitlint/config-conventional": "^17.8.1",
"@types/crypto-js": "^4.2.2",
"@types/node": "^20.12.10",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^7.1.0",
"@typescript-eslint/parser": "^7.1.0",
"@vitejs/plugin-vue": "^5.0.4",
"@vue/cli-plugin-babel": "~5.0.8",
"@vue/cli-plugin-eslint": "~5.0.8",
"@vue/cli-plugin-router": "~5.0.8",
"@vue/cli-plugin-typescript": "~5.0.8",
"@vue/cli-service": "~5.0.8",
"@vue/eslint-config-typescript": "^12.0.0",
"commitizen": "^4.3.0",
"cz-git": "^1.9.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-vue": "^9.22.0",
"file-loader": "^6.2.0",
"husky": "^8.0.1",
"lint-staged": "^15.2.2",
"mockjs": "^1.1.0",
"postcss": "^8.4.35",
"postcss-html": "^1.6.0",
"prettier": "^3.2.5",
"sass": "^1.71.1",
"sass-loader": "^14.1.1",
"typescript": "~5.3.3",
"vite": "^5.2.0",
"vite-plugin-mock": "^3.0.2",
"vue-tsc": "^2.0.6"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0",
"pnpm": ">=8.6.10"
},
"pnpm": {
"allowedDeprecatedVersions": {
"sourcemap-codec": "*",
"domexception": "*",
"w3c-hr-time": "*",
"stable": "*",
"abab": "*"
},
"peerDependencyRules": {
"allowedVersions": {
"eslint": "9"
}
}
},
"gitHooks": {
"pre-commit": "lint-staged"
},
"config": {
"commitizen": {
"path": "node_modules/cz-git"
}
}
}

12014
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

12
postcss.config.js Normal file
View File

@ -0,0 +1,12 @@
// @ts-check
/** @type {import('postcss-load-config').Config} */
export default {
plugins: {
'postcss-import': {},
'tailwindcss/nesting': {},
tailwindcss: {},
autoprefixer: {},
...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {}),
},
};

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

1
public/verify.json Normal file
View File

@ -0,0 +1 @@
{"version":1720007747647}

30
src/App.vue Normal file
View File

@ -0,0 +1,30 @@
<template>
<RouterView />
</template>
<script lang="ts" setup>
import { userI18nStore } from '@/store/i18n.ts';
import { useI18n } from 'vue-i18n';
import { onMounted } from 'vue';
const i18nStore = userI18nStore();
const i18n = useI18n();
/**
* * 设置多语言内容
*/
const setI18n = async () => {
await i18nStore.fetchI18n();
const languageData = JSON.parse(localStorage.getItem('i18nStore') as any);
const local = languageData.i18n.local;
//
i18n.locale.value = local;
i18n.mergeLocaleMessage(local, languageData.i18n[local]);
};
onMounted(async () => {
await setI18n();
});
</script>
<style scoped></style>

8
src/api/api-mock/i18n.ts Normal file
View File

@ -0,0 +1,8 @@
import Request from '@/api/service/request-mock.ts';
export const fetchGetI18n = () => {
return Request({
url: '/getI18n',
method: 'GET',
});
};

5
src/api/api-v1/test.ts Normal file
View File

@ -0,0 +1,5 @@
import Request from '@/api/service/request';
export const fetchTestApi = () => {
return Request({ url: '/user/getCurrentUserInfo', method: 'GET' });
};

View File

@ -0,0 +1,53 @@
// src/api/mock/i18n/modules/zh_cn.ts
var zh_cn = {
login: {
reset: "\u91CD\u7F6E",
register: "\u767B\u5F55"
},
home: {},
tabs: {},
header: {
fullScreen: "\u5168\u5C4F",
exitFullScreen: "\u9000\u51FA\u5168\u5C4F",
personalData: "\u4E2A\u4EBA\u4FE1\u606F",
changePassword: "\u4FEE\u6539\u5BC6\u7801",
logout: "\u9000\u51FA\u767B\u5F55"
},
tip: {
loading: "\u52A0\u8F7D\u4E2D..."
}
};
// src/api/mock/i18n/modules/en.ts
var en = {
login: {
reset: "reset",
register: "register"
},
home: {},
tabs: {},
header: {
fullScreen: "Full Screen",
exitFullScreen: "Exit Full Screen",
personalData: "Personal Data",
changePassword: "Change Password",
logout: "Logout"
},
tip: {
loading: "Loading..."
}
};
// src/api/mock/i18n/index.ts
var list = [
{
url: "/mock/getI18n",
method: "get",
response: () => ({ data: { zh_cn, en, local: "zh_cn" } })
}
];
var i18n_default = list;
export {
i18n_default as default
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsic3JjL2FwaS9tb2NrL2kxOG4vbW9kdWxlcy96aF9jbi50cyIsICJzcmMvYXBpL21vY2svaTE4bi9tb2R1bGVzL2VuLnRzIiwgInNyYy9hcGkvbW9jay9pMThuL2luZGV4LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJjb25zdCBfX2luamVjdGVkX2ZpbGVuYW1lX18gPSBcIkQ6XFxcXFByb2plY3RcXFxcd2ViXFxcXEJ1bm55LUNsaVxcXFx0ZW1wbGF0ZVxcXFx2dWVcXFxcdml0ZV90c19hdXRvXFxcXHNyY1xcXFxhcGlcXFxcbW9ja1xcXFxpMThuXFxcXG1vZHVsZXNcXFxcemhfY24udHNcIjtjb25zdCBfX2luamVjdGVkX2Rpcm5hbWVfXyA9IFwiRDpcXFxcUHJvamVjdFxcXFx3ZWJcXFxcQnVubnktQ2xpXFxcXHRlbXBsYXRlXFxcXHZ1ZVxcXFx2aXRlX3RzX2F1dG9cXFxcc3JjXFxcXGFwaVxcXFxtb2NrXFxcXGkxOG5cXFxcbW9kdWxlc1wiO2NvbnN0IF9faW5qZWN0ZWRfaW1wb3J0X21ldGFfdXJsX18gPSBcImZpbGU6Ly8vRDovUHJvamVjdC93ZWIvQnVubnktQ2xpL3RlbXBsYXRlL3Z1ZS92aXRlX3RzX2F1dG8vc3JjL2FwaS9tb2NrL2kxOG4vbW9kdWxlcy96aF9jbi50c1wiO2V4cG9ydCBjb25zdCB6aF9jbiA9IHtcclxuXHRsb2dpbjoge1xyXG5cdFx0cmVzZXQ6ICdcdTkxQ0RcdTdGNkUnLFxyXG5cdFx0cmVnaXN0ZXI6ICdcdTc2N0JcdTVGNTUnLFxyXG5cdH0sXHJcblx0aG9tZToge30sXHJcblx0dGFiczoge30sXHJcblx0aGVhZGVyOiB7XHJcblx0XHRmdWxsU2NyZWVuOiAnXHU1MTY4XHU1QzRGJyxcclxuXHRcdGV4aXRGdWxsU2NyZWVuOiAnXHU5MDAwXHU1MUZBXHU1MTY4XHU1QzRGJyxcclxuXHRcdHBlcnNvbmFsRGF0YTogJ1x1NEUyQVx1NEVCQVx1NEZFMVx1NjA2RicsXHJcblx0XHRjaGFuZ2VQYXNzd29yZDogJ1x1NEZFRVx1NjUzOVx1NUJDNlx1NzgwMScsXHJcblx0XHRsb2dvdXQ6ICdcdTkwMDBcdTUxRkFcdTc2N0JcdTVGNTUnLFxyXG5cdH0sXHJcblx0dGlwOiB7XHJcblx0XHRsb2FkaW5nOiAnXHU1MkEwXHU4RjdEXHU0RTJELi4uJyxcclxuXHR9LFxyXG59O1xyXG4iLCAiY29uc3QgX19pbmplY3RlZF9maWxlbmFtZV9fID0gXCJEOlxcXFxQcm9qZWN0XFxcXHdlYlxcXFxCdW5ueS1DbGlcXFxcdGVtcGxhdGVcXFxcdnVlXFxcXHZpdGVfdHNfYXV0b1xcXFxzcmNcXFxcYXBpXFxcXG1vY2tcXFxcaTE4blxcXFxtb2R1bGVzXFxcXGVuLnRzXCI7Y29uc3QgX19pbmplY3RlZF9kaXJuYW1lX18gPSBcIkQ6XFxcXFByb2plY3RcXFxcd2ViXFxcXEJ1bm55LUNsaVxcXFx0ZW1wbGF0ZVxcXFx2dWVcXFxcdml0ZV90c19hdXRvXFxcXHNyY1xcXFxhcGlcXFxcbW9ja1xcXFxpMThuXFxcXG1vZHVsZXNcIjtjb25zdCBfX2luamVjdGVkX2ltcG9ydF9tZXRhX3VybF9fID0gXCJmaWxlOi8vL0Q6L1Byb2plY3Qvd2ViL0J1bm55LUNsaS90ZW1wbGF0ZS92dWUvdml0ZV90c19hdXRvL3NyYy9hcGkvbW9jay9pMThuL21vZHVsZXMvZW4udHNcIjtleHBvcnQgY29uc3QgZW4gPSB7XHJcblx0bG9naW46IHtcclxuXHRcdHJlc2V0OiAncmVzZXQnLFxyXG5cdFx0cmVnaXN0ZXI6ICdyZWdpc3RlcicsXHJcblx0fSxcclxuXHRob21lOiB7fSxcclxuXHR0YWJzOiB7fSxcclxuXHRoZWFkZXI6IHtcclxuXHRcdGZ1bGxTY3JlZW46ICdGdWxsIFNjcmVlbicsXHJcblx0XHRleGl0RnVsbFNjcmVlbjogJ0V4aXQgRnVsbCBTY3JlZW4nLFxyXG5cdFx0cGVyc29uYWxEYXRhOiAnUGVyc29uYWwgRGF0YScsXHJcblx0XHRjaGFuZ2VQYXNzd29yZDogJ0NoYW5nZSBQYXNzd29yZCcsXHJcblx0XHRsb2dvdXQ6ICdMb2dvdXQnLFxyXG5cdH0sXHJcblx0dGlwOiB7XHJcblx0XHRsb2FkaW5nOiAnTG9hZGluZy4uLicsXHJcblx0fSxcclxufTtcclxuIiwgImNvbnN0IF9faW5qZWN0ZWRfZmlsZW5hbWVfXyA9IFwiRDpcXFxcUHJvamVjdFxcXFx3ZWJcXFxcQnVubnktQ2xpXFxcXHRlbXBsYXRlXFxcXHZ1ZVxcXFx2aXRlX3RzX2F1dG9cXFxcc3JjXFxcXGFwaVxcXFxtb2NrXFxcXGkxOG5cXFxcaW5kZXgudHNcIjtjb25zdCBfX2luamVjdGVkX2Rpcm5hbWVfXyA9IFwiRDpcXFxcUHJvamVjdFxcXFx3ZWJcXFxcQnVubnktQ2xpXFxcXHRlbXBsYXRlXFxcXHZ1ZVxcXFx2aXRlX3RzX2F1dG9cXFxcc3JjXFxcXGFwaVxcXFxtb2NrXFxcXGkxOG5cIjtjb25zdCBfX2luamVjdGVkX2ltcG9ydF9tZXRhX3VybF9fID0gXCJmaWxlOi8vL0Q6L1Byb2plY3Qvd2ViL0J1bm55LUNsaS90ZW1wbGF0ZS92dWUvdml0ZV90c19hdXRvL3NyYy9hcGkvbW9jay9pMThuL2luZGV4LnRzXCI7aW1wb3J0IHsgTW9ja01ldGhvZCB9IGZyb20gJ3ZpdGUtcGx1Z2luLW1vY2snO1xyXG5pbXBvcnQgeyB6aF9jbiB9IGZyb20gJy4vbW9kdWxlcy96aF9jbi50cyc7XHJcbmltcG9ydCB7IGVuIH0gZnJvbSAnLi9tb2R1bGVzL2VuLnRzJztcclxuXHJcbmNvbnN0IGxpc3Q6IE1vY2tNZXRob2RbXSA9IFtcclxuXHR7XHJcblx0XHR1cmw6ICcvbW9jay9nZXRJMThuJyxcclxuXHRcdG1ldGhvZDogJ2dldCcsXHJcblx0XHRyZXNwb25zZTogKCkgPT4gKHsgZGF0YTogeyB6aF9jbiwgZW4sIGxvY2FsOiAnemhfY24nIH0gfSksXHJcblx0fSxcclxuXTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IGxpc3Q7XHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBcVksSUFBTSxRQUFRO0FBQUEsRUFDbFosT0FBTztBQUFBLElBQ04sT0FBTztBQUFBLElBQ1AsVUFBVTtBQUFBLEVBQ1g7QUFBQSxFQUNBLE1BQU0sQ0FBQztBQUFBLEVBQ1AsTUFBTSxDQUFDO0FBQUEsRUFDUCxRQUFRO0FBQUEsSUFDUCxZQUFZO0FBQUEsSUFDWixnQkFBZ0I7QUFBQSxJQUNoQixjQUFjO0FBQUEsSUFDZCxnQkFBZ0I7QUFBQSxJQUNoQixRQUFRO0FBQUEsRUFDVDtBQUFBLEVBQ0EsS0FBSztBQUFBLElBQ0osU0FBUztBQUFBLEVBQ1Y7QUFDRDs7O0FDakIrWCxJQUFNLEtBQUs7QUFBQSxFQUN6WSxPQUFPO0FBQUEsSUFDTixPQUFPO0FBQUEsSUFDUCxVQUFVO0FBQUEsRUFDWDtBQUFBLEVBQ0EsTUFBTSxDQUFDO0FBQUEsRUFDUCxNQUFNLENBQUM7QUFBQSxFQUNQLFFBQVE7QUFBQSxJQUNQLFlBQVk7QUFBQSxJQUNaLGdCQUFnQjtBQUFBLElBQ2hCLGNBQWM7QUFBQSxJQUNkLGdCQUFnQjtBQUFBLElBQ2hCLFFBQVE7QUFBQSxFQUNUO0FBQUEsRUFDQSxLQUFLO0FBQUEsSUFDSixTQUFTO0FBQUEsRUFDVjtBQUNEOzs7QUNiQSxJQUFNLE9BQXFCO0FBQUEsRUFDMUI7QUFBQSxJQUNDLEtBQUs7QUFBQSxJQUNMLFFBQVE7QUFBQSxJQUNSLFVBQVUsT0FBTyxFQUFFLE1BQU0sRUFBRSxPQUFPLElBQUksT0FBTyxRQUFRLEVBQUU7QUFBQSxFQUN4RDtBQUNEO0FBRUEsSUFBTyxlQUFROyIsCiAgIm5hbWVzIjogW10KfQo=

View File

@ -0,0 +1,13 @@
import { MockMethod } from 'vite-plugin-mock';
import { zh_cn } from './modules/zh_cn.ts';
import { en } from './modules/en.ts';
const list: MockMethod[] = [
{
url: '/mock/getI18n',
method: 'get',
response: () => ({ data: { zh_cn, en, local: 'zh_cn' } }),
},
];
export default list;

View File

@ -0,0 +1,18 @@
export const en = {
login: {
reset: 'reset',
register: 'register',
},
home: {},
tabs: {},
header: {
fullScreen: 'Full Screen',
exitFullScreen: 'Exit Full Screen',
personalData: 'Personal Data',
changePassword: 'Change Password',
logout: 'Logout',
},
tip: {
loading: 'Loading...',
},
};

View File

@ -0,0 +1,18 @@
export const zh_cn = {
login: {
reset: '重置',
register: '登录',
},
home: {},
tabs: {},
header: {
fullScreen: '全屏',
exitFullScreen: '退出全屏',
personalData: '个人信息',
changePassword: '修改密码',
logout: '退出登录',
},
tip: {
loading: '加载中...',
},
};

View File

@ -0,0 +1,24 @@
import axios from 'axios';
const request = axios.create({
baseURL: import.meta.env.VITE_MOCK_BASE_API,
timeout: import.meta.env.VITE_BASE_API_TIMEOUT,
});
// 请求拦截器
request.interceptors.request.use(config => {
return config;
});
// 响应拦截器
request.interceptors.response.use(
response => {
return response.data;
},
error => {
console.log(error);
return Promise.reject(new Error('网络错误'));
},
);
export default request;

View File

@ -0,0 +1,95 @@
import router from '@/router';
import { localGet, localRemove } from '@/utils/util.ts';
import axios from 'axios';
import mittBus from '@/utils/mittBus.ts';
const request = axios.create({
// 默认请求地址
baseURL: import.meta.env.VITE_BASE_API,
// 设置超时时间
timeout: import.meta.env.VITE_BASE_API_TIMEOUT,
// @ts-ignore
retry: import.meta.env.VITE_BASE_API_RETRY, //设置全局重试请求次数(最多重试几次请求)
retryDelay: import.meta.env.VITE_BASE_API_RETRY_DELAY, //设置全局请求间隔
// 跨域允许携带凭证
// withCredentials: true,
});
// 请求拦截器
request.interceptors.request.use(config => {
// TODO 当本地有token表示登录了请求时将token带上
const token = localGet('token');
if (token !== null) {
config.headers['token'] = token;
}
return config;
});
// 响应拦截器
request.interceptors.response.use(
(response: any) => {
// 返回相应数据
const data = response.data;
// 登录过期
if (data.code === 208) {
// TODO 登录过期
console.log('登录过期');
router.push('/').then();
localRemove('token');
}
// 账户被封禁
if (data.code === 209) {
// TODO 账户被封禁
console.log('账户被封禁');
router.push('/').then();
localRemove('token');
}
// 统一处理异常
if (data.code !== 200 && data.code < 300) {
// TODO 统一处理异常
console.log('统一处理异常');
} else if (data.code > 300) {
console.log('统一处理异常');
}
// 返回消息内容
mittBus.emit('system-request-error', { retry: 0, retryCount: 0, isSuccess: true });
return data;
},
async error => {
const config = error.config;
// 重试次数
const retry = config.retry;
// 重试时间
const retryDelay = config.retryDelay;
// 当前重试次数
config._retryCount = config._retryCount || 0;
// 如果重试次数大于定义次数返回错误
if (config._retryCount > retry) {
return Promise.reject(new Error(error.response.statusText));
}
// 失败后打开到500页面
await router.push('/500');
mittBus.emit('system-request-error', { retry, retryCount: config._retryCount, isSuccess: false });
// 设置请求间隔 在发送下一次请求之前停留一段时间,时间为上方设置好的请求间隔时间
const backoff = new Promise(function (resolve) {
setTimeout(() => resolve(true), retryDelay || 1000);
});
// 如果失败次数加1
config._retryCount += 1;
// 再次发送请求
return backoff.then(() => request(error.config));
},
);
export default request;

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,603 @@
/*!
* Bootstrap Reboot v5.3.0-alpha1 (https://getbootstrap.com/)
* Copyright 2011-2022 The Bootstrap Authors
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
:root,
[data-bs-theme=light] {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
--bs-pink: #d63384;
--bs-red: #dc3545;
--bs-orange: #fd7e14;
--bs-yellow: #ffc107;
--bs-green: #198754;
--bs-teal: #20c997;
--bs-cyan: #0dcaf0;
--bs-black: #000;
--bs-white: #fff;
--bs-gray: #6c757d;
--bs-gray-dark: #343a40;
--bs-gray-100: #f8f9fa;
--bs-gray-200: #e9ecef;
--bs-gray-300: #dee2e6;
--bs-gray-400: #ced4da;
--bs-gray-500: #adb5bd;
--bs-gray-600: #6c757d;
--bs-gray-700: #495057;
--bs-gray-800: #343a40;
--bs-gray-900: #212529;
--bs-primary: #0d6efd;
--bs-secondary: #6c757d;
--bs-success: #198754;
--bs-info: #0dcaf0;
--bs-warning: #ffc107;
--bs-danger: #dc3545;
--bs-light: #f8f9fa;
--bs-dark: #212529;
--bs-primary-rgb: 13, 110, 253;
--bs-secondary-rgb: 108, 117, 125;
--bs-success-rgb: 25, 135, 84;
--bs-info-rgb: 13, 202, 240;
--bs-warning-rgb: 255, 193, 7;
--bs-danger-rgb: 220, 53, 69;
--bs-light-rgb: 248, 249, 250;
--bs-dark-rgb: 33, 37, 41;
--bs-primary-text: #0a58ca;
--bs-secondary-text: #6c757d;
--bs-success-text: #146c43;
--bs-info-text: #087990;
--bs-warning-text: #997404;
--bs-danger-text: #b02a37;
--bs-light-text: #6c757d;
--bs-dark-text: #495057;
--bs-primary-bg-subtle: #cfe2ff;
--bs-secondary-bg-subtle: #f8f9fa;
--bs-success-bg-subtle: #d1e7dd;
--bs-info-bg-subtle: #cff4fc;
--bs-warning-bg-subtle: #fff3cd;
--bs-danger-bg-subtle: #f8d7da;
--bs-light-bg-subtle: #fcfcfd;
--bs-dark-bg-subtle: #ced4da;
--bs-primary-border-subtle: #9ec5fe;
--bs-secondary-border-subtle: #e9ecef;
--bs-success-border-subtle: #a3cfbb;
--bs-info-border-subtle: #9eeaf9;
--bs-warning-border-subtle: #ffe69c;
--bs-danger-border-subtle: #f1aeb5;
--bs-light-border-subtle: #e9ecef;
--bs-dark-border-subtle: #adb5bd;
--bs-white-rgb: 255, 255, 255;
--bs-black-rgb: 0, 0, 0;
--bs-body-color-rgb: 33, 37, 41;
--bs-body-bg-rgb: 255, 255, 255;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
--bs-body-font-family: var(--bs-font-sans-serif);
--bs-body-font-size: 1rem;
--bs-body-font-weight: 400;
--bs-body-line-height: 1.5;
--bs-body-color: #212529;
--bs-emphasis-color: #000;
--bs-emphasis-color-rgb: 0, 0, 0;
--bs-secondary-color: rgba(33, 37, 41, 0.75);
--bs-secondary-color-rgb: 33, 37, 41;
--bs-secondary-bg: #e9ecef;
--bs-secondary-bg-rgb: 233, 236, 239;
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
--bs-tertiary-color-rgb: 33, 37, 41;
--bs-tertiary-bg: #f8f9fa;
--bs-tertiary-bg-rgb: 248, 249, 250;
--bs-body-bg: #fff;
--bs-body-bg-rgb: 255, 255, 255;
--bs-link-color: #0d6efd;
--bs-link-color-rgb: 13, 110, 253;
--bs-link-decoration: underline;
--bs-link-hover-color: #0a58ca;
--bs-link-hover-color-rgb: 10, 88, 202;
--bs-code-color: #d63384;
--bs-highlight-bg: #fff3cd;
--bs-border-width: 1px;
--bs-border-style: solid;
--bs-border-color: #dee2e6;
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
--bs-border-radius: 0.375rem;
--bs-border-radius-sm: 0.25rem;
--bs-border-radius-lg: 0.5rem;
--bs-border-radius-xl: 1rem;
--bs-border-radius-2xl: 2rem;
--bs-border-radius-pill: 50rem;
--bs-box-shadow: 0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15);
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(var(--bs-body-color-rgb), 0.075);
--bs-box-shadow-lg: 0 1rem 3rem rgba(var(--bs-body-color-rgb), 0.175);
--bs-box-shadow-inset: inset 0 1px 2px rgba(var(--bs-body-color-rgb), 0.075);
--bs-emphasis-color: #000;
--bs-form-control-bg: var(--bs-body-bg);
--bs-form-control-disabled-bg: var(--bs-secondary-bg);
--bs-highlight-bg: #fff3cd;
--bs-breakpoint-xs: 0;
--bs-breakpoint-sm: 576px;
--bs-breakpoint-md: 768px;
--bs-breakpoint-lg: 992px;
--bs-breakpoint-xl: 1200px;
--bs-breakpoint-xxl: 1400px;
}
[data-bs-theme=dark] {
--bs-body-color: #adb5bd;
--bs-body-color-rgb: 173, 181, 189;
--bs-body-bg: #212529;
--bs-body-bg-rgb: 33, 37, 41;
--bs-emphasis-color: #f8f9fa;
--bs-emphasis-color-rgb: 248, 249, 250;
--bs-secondary-color: rgba(173, 181, 189, 0.75);
--bs-secondary-color-rgb: 173, 181, 189;
--bs-secondary-bg: #343a40;
--bs-secondary-bg-rgb: 52, 58, 64;
--bs-tertiary-color: rgba(173, 181, 189, 0.5);
--bs-tertiary-color-rgb: 173, 181, 189;
--bs-tertiary-bg: #2b3035;
--bs-tertiary-bg-rgb: 43, 48, 53;
--bs-emphasis-color: #fff;
--bs-primary-text: #6ea8fe;
--bs-secondary-text: #dee2e6;
--bs-success-text: #75b798;
--bs-info-text: #6edff6;
--bs-warning-text: #ffda6a;
--bs-danger-text: #ea868f;
--bs-light-text: #f8f9fa;
--bs-dark-text: #dee2e6;
--bs-primary-bg-subtle: #031633;
--bs-secondary-bg-subtle: #212529;
--bs-success-bg-subtle: #051b11;
--bs-info-bg-subtle: #032830;
--bs-warning-bg-subtle: #332701;
--bs-danger-bg-subtle: #2c0b0e;
--bs-light-bg-subtle: #343a40;
--bs-dark-bg-subtle: #1a1d20;
--bs-primary-border-subtle: #084298;
--bs-secondary-border-subtle: #495057;
--bs-success-border-subtle: #0f5132;
--bs-info-border-subtle: #055160;
--bs-warning-border-subtle: #664d03;
--bs-danger-border-subtle: #842029;
--bs-light-border-subtle: #495057;
--bs-dark-border-subtle: #343a40;
--bs-heading-color: #fff;
--bs-link-color: #6ea8fe;
--bs-link-hover-color: #9ec5fe;
--bs-link-color-rgb: 110, 168, 254;
--bs-link-hover-color-rgb: 158, 197, 254;
--bs-code-color: #e685b5;
--bs-border-color: #495057;
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
}
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
border: 0;
border-top: var(--bs-border-width) solid;
opacity: 0.25;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
color: var(--bs-heading-color, inherit);
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-left: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.1875em;
background-color: var(--bs-highlight-bg);
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
text-decoration: underline;
}
a:hover {
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: var(--bs-font-monospace);
font-size: 1em;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: var(--bs-code-color);
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.1875rem 0.375rem;
font-size: 0.875em;
color: var(--bs-body-bg);
background-color: var(--bs-body-color);
border-radius: 0.25rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: var(--bs-secondary-color);
text-align: left;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
display: none !important;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: left;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: left;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
/* rtl:raw:
[types="tel"],
[types="url"],
[types="email"],
[types="number"] {
direction: ltr;
}
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
::file-selector-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,588 @@
/*!
* Bootstrap Reboot v5.3.0-alpha1 (https://getbootstrap.com/)
* Copyright 2011-2022 The Bootstrap Authors
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
:root,
[data-bs-theme=light] {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
--bs-pink: #d63384;
--bs-red: #dc3545;
--bs-orange: #fd7e14;
--bs-yellow: #ffc107;
--bs-green: #198754;
--bs-teal: #20c997;
--bs-cyan: #0dcaf0;
--bs-black: #000;
--bs-white: #fff;
--bs-gray: #6c757d;
--bs-gray-dark: #343a40;
--bs-gray-100: #f8f9fa;
--bs-gray-200: #e9ecef;
--bs-gray-300: #dee2e6;
--bs-gray-400: #ced4da;
--bs-gray-500: #adb5bd;
--bs-gray-600: #6c757d;
--bs-gray-700: #495057;
--bs-gray-800: #343a40;
--bs-gray-900: #212529;
--bs-primary: #0d6efd;
--bs-secondary: #6c757d;
--bs-success: #198754;
--bs-info: #0dcaf0;
--bs-warning: #ffc107;
--bs-danger: #dc3545;
--bs-light: #f8f9fa;
--bs-dark: #212529;
--bs-primary-rgb: 13, 110, 253;
--bs-secondary-rgb: 108, 117, 125;
--bs-success-rgb: 25, 135, 84;
--bs-info-rgb: 13, 202, 240;
--bs-warning-rgb: 255, 193, 7;
--bs-danger-rgb: 220, 53, 69;
--bs-light-rgb: 248, 249, 250;
--bs-dark-rgb: 33, 37, 41;
--bs-primary-text: #0a58ca;
--bs-secondary-text: #6c757d;
--bs-success-text: #146c43;
--bs-info-text: #087990;
--bs-warning-text: #997404;
--bs-danger-text: #b02a37;
--bs-light-text: #6c757d;
--bs-dark-text: #495057;
--bs-primary-bg-subtle: #cfe2ff;
--bs-secondary-bg-subtle: #f8f9fa;
--bs-success-bg-subtle: #d1e7dd;
--bs-info-bg-subtle: #cff4fc;
--bs-warning-bg-subtle: #fff3cd;
--bs-danger-bg-subtle: #f8d7da;
--bs-light-bg-subtle: #fcfcfd;
--bs-dark-bg-subtle: #ced4da;
--bs-primary-border-subtle: #9ec5fe;
--bs-secondary-border-subtle: #e9ecef;
--bs-success-border-subtle: #a3cfbb;
--bs-info-border-subtle: #9eeaf9;
--bs-warning-border-subtle: #ffe69c;
--bs-danger-border-subtle: #f1aeb5;
--bs-light-border-subtle: #e9ecef;
--bs-dark-border-subtle: #adb5bd;
--bs-white-rgb: 255, 255, 255;
--bs-black-rgb: 0, 0, 0;
--bs-body-color-rgb: 33, 37, 41;
--bs-body-bg-rgb: 255, 255, 255;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
--bs-body-font-family: var(--bs-font-sans-serif);
--bs-body-font-size: 1rem;
--bs-body-font-weight: 400;
--bs-body-line-height: 1.5;
--bs-body-color: #212529;
--bs-emphasis-color: #000;
--bs-emphasis-color-rgb: 0, 0, 0;
--bs-secondary-color: rgba(33, 37, 41, 0.75);
--bs-secondary-color-rgb: 33, 37, 41;
--bs-secondary-bg: #e9ecef;
--bs-secondary-bg-rgb: 233, 236, 239;
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
--bs-tertiary-color-rgb: 33, 37, 41;
--bs-tertiary-bg: #f8f9fa;
--bs-tertiary-bg-rgb: 248, 249, 250;
--bs-body-bg: #fff;
--bs-body-bg-rgb: 255, 255, 255;
--bs-link-color: #0d6efd;
--bs-link-color-rgb: 13, 110, 253;
--bs-link-decoration: underline;
--bs-link-hover-color: #0a58ca;
--bs-link-hover-color-rgb: 10, 88, 202;
--bs-code-color: #d63384;
--bs-highlight-bg: #fff3cd;
--bs-border-width: 1px;
--bs-border-style: solid;
--bs-border-color: #dee2e6;
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
--bs-border-radius: 0.375rem;
--bs-border-radius-sm: 0.25rem;
--bs-border-radius-lg: 0.5rem;
--bs-border-radius-xl: 1rem;
--bs-border-radius-2xl: 2rem;
--bs-border-radius-pill: 50rem;
--bs-box-shadow: 0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15);
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(var(--bs-body-color-rgb), 0.075);
--bs-box-shadow-lg: 0 1rem 3rem rgba(var(--bs-body-color-rgb), 0.175);
--bs-box-shadow-inset: inset 0 1px 2px rgba(var(--bs-body-color-rgb), 0.075);
--bs-emphasis-color: #000;
--bs-form-control-bg: var(--bs-body-bg);
--bs-form-control-disabled-bg: var(--bs-secondary-bg);
--bs-highlight-bg: #fff3cd;
--bs-breakpoint-xs: 0;
--bs-breakpoint-sm: 576px;
--bs-breakpoint-md: 768px;
--bs-breakpoint-lg: 992px;
--bs-breakpoint-xl: 1200px;
--bs-breakpoint-xxl: 1400px;
}
[data-bs-theme=dark] {
--bs-body-color: #adb5bd;
--bs-body-color-rgb: 173, 181, 189;
--bs-body-bg: #212529;
--bs-body-bg-rgb: 33, 37, 41;
--bs-emphasis-color: #f8f9fa;
--bs-emphasis-color-rgb: 248, 249, 250;
--bs-secondary-color: rgba(173, 181, 189, 0.75);
--bs-secondary-color-rgb: 173, 181, 189;
--bs-secondary-bg: #343a40;
--bs-secondary-bg-rgb: 52, 58, 64;
--bs-tertiary-color: rgba(173, 181, 189, 0.5);
--bs-tertiary-color-rgb: 173, 181, 189;
--bs-tertiary-bg: #2b3035;
--bs-tertiary-bg-rgb: 43, 48, 53;
--bs-emphasis-color: #fff;
--bs-primary-text: #6ea8fe;
--bs-secondary-text: #dee2e6;
--bs-success-text: #75b798;
--bs-info-text: #6edff6;
--bs-warning-text: #ffda6a;
--bs-danger-text: #ea868f;
--bs-light-text: #f8f9fa;
--bs-dark-text: #dee2e6;
--bs-primary-bg-subtle: #031633;
--bs-secondary-bg-subtle: #212529;
--bs-success-bg-subtle: #051b11;
--bs-info-bg-subtle: #032830;
--bs-warning-bg-subtle: #332701;
--bs-danger-bg-subtle: #2c0b0e;
--bs-light-bg-subtle: #343a40;
--bs-dark-bg-subtle: #1a1d20;
--bs-primary-border-subtle: #084298;
--bs-secondary-border-subtle: #495057;
--bs-success-border-subtle: #0f5132;
--bs-info-border-subtle: #055160;
--bs-warning-border-subtle: #664d03;
--bs-danger-border-subtle: #842029;
--bs-light-border-subtle: #495057;
--bs-dark-border-subtle: #343a40;
--bs-heading-color: #fff;
--bs-link-color: #6ea8fe;
--bs-link-hover-color: #9ec5fe;
--bs-link-color-rgb: 110, 168, 254;
--bs-link-hover-color-rgb: 158, 197, 254;
--bs-code-color: #e685b5;
--bs-border-color: #495057;
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
}
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
border: 0;
border-top: var(--bs-border-width) solid;
opacity: 0.25;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
color: var(--bs-heading-color, inherit);
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-right: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-right: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.1875em;
background-color: var(--bs-highlight-bg);
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
text-decoration: underline;
}
a:hover {
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: var(--bs-font-monospace);
font-size: 1em;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: var(--bs-code-color);
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.1875rem 0.375rem;
font-size: 0.875em;
color: var(--bs-body-bg);
background-color: var(--bs-body-color);
border-radius: 0.25rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: var(--bs-secondary-color);
text-align: right;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
display: none !important;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: right;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: right;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
::file-selector-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

13448
src/assets/css/bootstrap/bootstrap.css vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

11747
src/assets/css/bootstrap/bootstrap.rtl.css vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
@import 'bootstrap/bootstrap.css';
@import 'utils';
:root {
--primary-color: #eaa261;
--primary-color-hover: #f1b27c;
--bg-color-dialog: #7f7f7f7f;
}

View File

@ -0,0 +1,21 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components {
.flex-c {
@apply flex justify-center items-center;
}
.flex-ac {
@apply flex justify-around items-center;
}
.flex-bc {
@apply flex justify-between items-center;
}
.navbar-bg-hover {
@apply dark:text-white dark:hover:!bg-[#242424];
}
}

75
src/assets/css/utils.scss Normal file
View File

@ -0,0 +1,75 @@
/* 选中文字颜色 */
*::selection {
color: #1f1f1f;
background: #b3d4fc;
}
/*定义滚动条高宽及背景高宽分别对应横竖滚动条的尺寸*/
::-webkit-scrollbar {
width: 8px;
height: 8px;
background-color: #f5f5f5;
}
/*定义滚动条轨道内阴影+圆角*/
::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px #ccc;
border-radius: 5px;
background-color: #f5f5f5;
}
/*定义滑块内阴影+圆角*/
::-webkit-scrollbar-thumb {
border-radius: 5px;
-webkit-box-shadow: inset 0 0 6px #ccc;
background-color: #ccc;
}
.thumb {
cursor: pointer;
}
.cursor-pointer {
cursor: pointer;
}
.hover-text {
transition: all 0.3s;
&:hover {
color: var(--bs-link-hover-color) !important;
}
}
// 鼠标移入显示手指+下划线
.hover-text-pointer-underline {
cursor: pointer;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
.active {
text-decoration: none;
color: var(--bs-link-hover-color) !important;
}
.img-hover {
transition: all 0.5s;
&:hover {
transform: scale(1.2);
transform-origin: center;
}
}
.none-select {
-webkit-user-drag: none; /* Safari */
user-drag: none; /* 其他浏览器 */
-moz-user-select: none; /* 禁止选择,针对 Firefox */
-webkit-user-select: none; /* 禁止选择,针对 Safari 和 Chrome */
-ms-user-select: none; /* 禁止选择,针对 IE/Edge */
user-select: none; /* 其他浏览器 */
}

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18.5303 6.53033C18.8232 6.23744 18.8232 5.76256 18.5303 5.46967C18.2374 5.17678 17.7626 5.17678 17.4697 5.46967L12 10.9393L6.53033 5.46967C6.23744 5.17678 5.76256 5.17678 5.46967 5.46967C5.17678 5.76256 5.17678 6.23744 5.46967 6.53033L10.9393 12L5.46967 17.4697C5.17678 17.7626 5.17678 18.2374 5.46967 18.5303C5.76256 18.8232 6.23744 18.8232 6.53033 18.5303L12 13.0607L17.4697 18.5303C17.7626 18.8232 18.2374 18.8232 18.5303 18.5303C18.8232 18.2374 18.8232 17.7626 18.5303 17.4697L13.0607 12L18.5303 6.53033Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 645 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1680886419224" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6634" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M768 64q59.008 0.992 106.016 32t70.016 85.504 12.512 110.016-51.488 98.016-96.512 54.496-110.496-8.992l-218.016 290.016v171.008h96q14.016 0 23.008 8.992t8.992 23.008-8.992 23.008-23.008 8.992h-256q-14.016 0-23.008-8.992t-8.992-23.008 8.992-23.008 23.008-8.992h96v-171.008L77.024 274.048q-12.992-18.016-12.992-39.008v-11.008q0-12.992 8.992-22.016T96.032 192h72L102.016 108.992q-8-11.008-6.496-24T108.032 64t23.488-6.496 21.504 11.488l96 123.008h338.016q20.992-58.016 70.016-92.512T768.064 64z m-111.008 128H800q14.016 0.992 23.008 10.016t8.992 22.016v11.008q0 20.992-12.992 38.016l-80 108q48.992 10.016 91.008-12.992t58.016-71.008-3.008-92-64.992-64.512-91.488-6.016-71.488 58.496v-0.992zM299.008 256l128.992 166.016q8 11.008 6.496 23.488t-12 20.512-23.008 7.008-21.504-11.008L217.984 256H143.968l304 404.992L751.968 256H298.976z" p-id="6635"></path></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1681139654009" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2528" width="48" height="48" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M433.834667 337.706667a21.333333 21.333333 0 0 1 1.493333-32.768 29.397333 29.397333 0 0 1 37.461333 0.938666l202.709334 190.037334a21.077333 21.077333 0 0 1 1.365333 30.421333c-0.341333 0.426667-204.117333 191.573333-204.117333 191.573333a29.354667 29.354667 0 0 1-37.632 1.152 21.333333 21.333333 0 0 1-1.28-32.938666l185.813333-174.293334-185.813333-174.122666z" fill="#707070" p-id="2529"></path></svg>

After

Width:  |  Height:  |  Size: 737 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1683095054996" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14355" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M258.048 568.832l253.952 279.04 253.952-279.04c22.016-24.064 13.312-43.52-18.944-43.52l-117.248 0 0-322.56c0-32.76800001-26.112-58.88000001-58.368-58.88l-117.248 0c-32.25599999 0-58.36799999 26.112-58.88 58.368l0 323.072-117.248 0c-32.76800001 0-41.47199999 19.456-19.968 43.52z" p-id="14356" fill="#D03050"></path></svg>

After

Width:  |  Height:  |  Size: 653 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1680624798338" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2733" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M392.533333 806.4L85.333333 503.466667l59.733334-59.733334 247.466666 247.466667L866.133333 213.333333l59.733334 59.733334L392.533333 806.4z" fill="#ffffff" p-id="2734"></path></svg>

After

Width:  |  Height:  |  Size: 513 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1681015819371" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="30341" width="48" height="48" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M626.504285 375.563329a26.383253 26.383253 0 0 1-25.98523-26.724415c0-73.918596-58.338831-134.020101-129.983009-134.020101a26.383253 26.383253 0 0 1-25.985229-26.724416c0-14.783719 11.656394-26.838136 25.985229-26.838136 71.644178 0 129.983008-60.101505 129.983009-133.963241 0-14.783719 11.656394-26.781276 25.98523-26.781276 14.385696 0 25.98523 11.997557 25.985229 26.781276 0 73.861736 58.338831 133.963241 129.983009 133.963241 14.328836 0 25.98523 11.997557 25.985229 26.781276s-11.656394 26.781276-25.985229 26.781276c-71.644178 0-129.983008 60.158365-129.983009 133.96324 0 14.783719-11.599534 26.781276-25.985229 26.781276zM564.185222 188.037537c25.473485 15.920928 46.966739 37.925926 62.319063 64.252318 15.352324-26.269532 36.845577-48.33139 62.375923-64.252318a186.729746 186.729746 0 0 1-62.375923-64.252318c-15.352324 26.269532-36.788717 48.38825-62.319063 64.252318zM106.629111 536.307846a26.383253 26.383253 0 0 1-25.98523-26.724415 26.383253 26.383253 0 0 0-25.985229-26.838137A26.383253 26.383253 0 0 1 28.673422 455.964018c0-14.783719 11.656394-26.781276 25.98523-26.781276a26.383253 26.383253 0 0 0 25.985229-26.838137c0-14.783719 11.656394-26.724416 25.98523-26.724415 14.385696 0 26.04209 11.940696 26.04209 26.724415s11.599534 26.838136 25.98523 26.838137c14.328836 0 25.98523 11.940696 25.985229 26.724416s-11.656394 26.838136-25.985229 26.838136a26.383253 26.383253 0 0 0-25.98523 26.781276c0 14.783719-11.656394 26.781276-26.04209 26.781276zM972.102152 854.555833l-550.40924-567.239935a76.420456 76.420456 0 0 0-110.309289 0l-30.420346 31.443833c-14.726859 15.124882-22.744183 35.253484-22.744183 56.860459 0 21.493253 8.074185 41.621856 22.744183 56.860459l550.35238 567.183075a76.420456 76.420456 0 0 0 110.309289 0l30.477206-31.443834c14.669998-15.124882 22.744183-35.253484 22.744184-56.860459 0-21.493253-8.131046-41.678716-22.744184-56.860458zM342.656875 334.73752a25.587206 25.587206 0 0 1 36.788717 0l74.771503 77.102782-53.27825 50.605808L326.053621 385.400189a27.406741 27.406741 0 0 1 0-37.869066l16.489533-12.736742z m567.012494 617.618302a25.416625 25.416625 0 0 1-36.674996 0L434.259074 500.201455l54.017436-50.890111 438.735299 452.211228a27.406741 27.406741 0 0 1 0 37.869066l-17.34244 12.964184zM210.62689 268.438225a26.383253 26.383253 0 0 1-25.98523-26.838136c0-44.294297-34.969182-80.343828-78.012549-80.343828a26.383253 26.383253 0 0 1-25.98523-26.781276c0-14.783719 11.656394-26.781276 25.98523-26.781276 43.043367 0 78.012549-36.106391 78.012549-80.400689 0-14.783719 11.656394-26.781276 25.98523-26.781276s25.98523 11.997557 25.98523 26.781276c0 44.351158 34.969182 80.400689 78.012549 80.400689 14.328836 0 25.98523 11.940696 25.985229 26.724415s-11.656394 26.838136-25.985229 26.838137c-43.043367 0-78.012549 36.049531-78.012549 80.343828 0 14.783719-11.656394 26.838136-25.98523 26.838136z m-26.098951-133.96324c9.89372 7.676162 18.65023 16.716975 26.098951 26.894997a134.190682 134.190682 0 0 1 26.09895-26.894997 134.190682 134.190682 0 0 1-26.09895-26.894997 134.190682 134.190682 0 0 1-26.098951 26.894997zM210.62689 804.234327a26.383253 26.383253 0 0 1-25.98523-26.781276c0-44.351158-34.969182-80.400689-78.012549-80.400688a26.383253 26.383253 0 0 1-25.98523-26.724416c0-14.783719 11.656394-26.838136 25.98523-26.838136 43.043367 0 78.012549-36.049531 78.012549-80.400689 0-14.783719 11.656394-26.724416 25.98523-26.724415s25.98523 11.940696 25.98523 26.724415c0 44.351158 34.969182 80.400689 78.012549 80.400689 14.328836 0 25.98523 11.997557 25.985229 26.781276s-11.656394 26.781276-25.985229 26.781276c-43.043367 0-78.012549 36.049531-78.012549 80.400688 0 14.783719-11.656394 26.781276-25.98523 26.781276z m-26.098951-133.96324c9.89372 7.676162 18.65023 16.716975 26.098951 26.894997a134.190682 134.190682 0 0 1 26.09895-26.894997 134.190682 134.190682 0 0 1-26.09895-26.894997 134.190682 134.190682 0 0 1-26.098951 26.894997z" fill="#001529" p-id="30342"></path></svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1679578965190" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15232" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M335.22 240.91c0-57.08 10.68-111.66 30.15-161.87-167.51 64.86-286.3 227.51-286.3 417.92 0 247.42 200.58 448 448 448 190.34 0 352.95-118.71 417.85-286.13-50.16 19.42-104.69 30.08-161.71 30.08-247.41 0-447.99-200.57-447.99-448z" fill="#FFD500" p-id="15233"></path></svg>

After

Width:  |  Height:  |  Size: 600 B

View File

@ -0,0 +1,8 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.08337 6.66699C7.77373 6.66699 8.33337 6.10735 8.33337 5.41699C8.33337 4.72664 7.77373 4.16699 7.08337 4.16699C6.39302 4.16699 5.83337 4.72664 5.83337 5.41699C5.83337 6.10735 6.39302 6.66699 7.08337 6.66699Z" fill="#666666"/>
<path d="M12.9167 6.66699C13.6071 6.66699 14.1667 6.10735 14.1667 5.41699C14.1667 4.72664 13.6071 4.16699 12.9167 4.16699C12.2264 4.16699 11.6667 4.72664 11.6667 5.41699C11.6667 6.10735 12.2264 6.66699 12.9167 6.66699Z" fill="#666666"/>
<path d="M8.33337 10.0003C8.33337 10.6907 7.77373 11.2503 7.08337 11.2503C6.39302 11.2503 5.83337 10.6907 5.83337 10.0003C5.83337 9.30997 6.39302 8.75033 7.08337 8.75033C7.77373 8.75033 8.33337 9.30997 8.33337 10.0003Z" fill="#666666"/>
<path d="M12.9167 11.2503C13.6071 11.2503 14.1667 10.6907 14.1667 10.0003C14.1667 9.30997 13.6071 8.75033 12.9167 8.75033C12.2264 8.75033 11.6667 9.30997 11.6667 10.0003C11.6667 10.6907 12.2264 11.2503 12.9167 11.2503Z" fill="#666666"/>
<path d="M8.33337 14.5837C8.33337 15.274 7.77373 15.8337 7.08337 15.8337C6.39302 15.8337 5.83337 15.274 5.83337 14.5837C5.83337 13.8933 6.39302 13.3337 7.08337 13.3337C7.77373 13.3337 8.33337 13.8933 8.33337 14.5837Z" fill="#666666"/>
<path d="M12.9167 15.8337C13.6071 15.8337 14.1667 15.274 14.1667 14.5837C14.1667 13.8933 13.6071 13.3337 12.9167 13.3337C12.2264 13.3337 11.6667 13.8933 11.6667 14.5837C11.6667 15.274 12.2264 15.8337 12.9167 15.8337Z" fill="#666666"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1631454216260" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2219" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><defs><style type="text/css"></style></defs><path d="M697.652 256c-23.565 0-42.667-19.103-42.667-42.667s19.102-42.666 42.667-42.666h124.651c40.288 0 73.697 31.956 73.697 72.347v85.783c0 23.564-19.103 42.667-42.667 42.667s-42.666-19.103-42.666-42.667V256H697.652z m113.015 597.333V496.565c0-23.564 19.102-42.666 42.666-42.666C876.897 453.899 896 473 896 496.565V866.32c0 40.391-33.41 72.348-73.697 72.348H201.697c-40.288 0-73.697-31.957-73.697-72.348V243.014c0-40.39 33.41-72.347 73.697-72.347h124.727c23.564 0 42.667 19.102 42.667 42.666 0 23.564-19.103 42.667-42.667 42.667h-113.09v597.333h597.333zM368.485 541.418c-23.564 0-42.667-19.102-42.667-42.666 0-23.564 19.103-42.667 42.667-42.667h320c23.564 0 42.667 19.103 42.667 42.667s-19.103 42.666-42.667 42.666h-320z m58.182-370.751c-23.564 0-42.667 19.102-42.667 42.666C384 236.897 403.103 256 426.667 256h170.666C620.897 256 640 236.897 640 213.333s-19.103-42.666-42.667-42.666H426.667z m0-85.334h170.666c70.693 0 128 57.308 128 128 0 70.693-57.307 128-128 128H426.667c-70.693 0-128-57.307-128-128 0-70.692 57.307-128 128-128zM368.485 696.57c-23.564 0-42.667-19.103-42.667-42.667s19.103-42.666 42.667-42.666h320c23.564 0 42.667 19.102 42.667 42.666 0 23.564-19.103 42.667-42.667 42.667h-320z" p-id="2220" fill="#f49776"></path></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1683094815057" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14060" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M765.792 455.168L512.032 176l-253.76 279.168c-21.856 24.064-13.312 43.52 19.04 43.52H394.72V821.28c0 32.544 26.24 58.752 58.624 58.752h117.44a58.56 58.56 0 0 0 58.624-58.752V498.656h117.408c32.192 0 40.832-19.456 18.976-43.488z" p-id="14061" fill="#18A058"></path></svg>

After

Width:  |  Height:  |  Size: 602 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1631454148586" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1906" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M826.666667 644.266667A341.333333 341.333333 0 0 0 342.613333 215.594667l-42.325333-74.112A426.666667 426.666667 0 0 1 900.992 687.36l57.258667 33.024-177.706667 94.549333-7.04-201.130666 53.162667 30.677333zM197.333333 379.733333A341.333333 341.333333 0 0 0 681.386667 808.405333l42.325333 74.112A426.666667 426.666667 0 0 1 123.008 336.64L65.706667 303.658667 243.2 209.066667l7.253333 201.258666L197.290667 379.733333zM554.666667 577.536h128v85.333333h-128v85.333334h-85.333334v-85.333334H341.333333v-85.333333h128v-42.666667H341.333333v-85.333333h110.336L361.130667 358.997333 421.546667 298.666667 512 389.162667 602.496 298.666667l60.373333 60.330666-90.538666 90.538667H682.666667v85.333333h-128v42.666667z" p-id="1907" fill="#b37feb"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1679577781791" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2924" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M501.48 493.55m-233.03 0a233.03 233.03 0 1 0 466.06 0 233.03 233.03 0 1 0-466.06 0Z" fill="#F9C626" p-id="2925"></path><path d="M501.52 185.35H478.9c-8.28 0-15-6.72-15-15V87.59c0-8.28 6.72-15 15-15h22.62c8.28 0 15 6.72 15 15v82.76c0 8.28-6.72 15-15 15zM281.37 262.76l-16 16c-5.86 5.86-15.36 5.86-21.21 0l-58.52-58.52c-5.86-5.86-5.86-15.36 0-21.21l16-16c5.86-5.86 15.36-5.86 21.21 0l58.52 58.52c5.86 5.86 5.86 15.35 0 21.21zM185.76 478.48v22.62c0 8.28-6.72 15-15 15H88c-8.28 0-15-6.72-15-15v-22.62c0-8.28 6.72-15 15-15h82.76c8.28 0 15 6.72 15 15zM270.69 698.63l16 16c5.86 5.86 5.86 15.36 0 21.21l-58.52 58.52c-5.86 5.86-15.36 5.86-21.21 0l-16-16c-5.86-5.86-5.86-15.36 0-21.21l58.52-58.52c5.85-5.86 15.35-5.86 21.21 0zM486.41 794.24h22.62c8.28 0 15 6.72 15 15V892c0 8.28-6.72 15-15 15h-22.62c-8.28 0-15-6.72-15-15v-82.76c0-8.28 6.72-15 15-15zM706.56 709.31l16-16c5.86-5.86 15.36-5.86 21.21 0l58.52 58.52c5.86 5.86 5.86 15.36 0 21.21l-16 16c-5.86 5.86-15.36 5.86-21.21 0l-58.52-58.52c-5.86-5.85-5.86-15.35 0-21.21zM802.17 493.59v-22.62c0-8.28 6.72-15 15-15h82.76c8.28 0 15 6.72 15 15v22.62c0 8.28-6.72 15-15 15h-82.76c-8.28 0-15-6.72-15-15zM717.24 273.44l-16-16c-5.86-5.86-5.86-15.36 0-21.21l58.52-58.52c5.86-5.86 15.36-5.86 21.21 0l16 16c5.86 5.86 5.86 15.36 0 21.21l-58.52 58.52c-5.86 5.86-15.35 5.86-21.21 0z" fill="#F9C626" p-id="2926"></path></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1631453917190" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1531" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M300.032 558.08V427.52c0-19.968 13.312-35.84 29.696-35.84s29.696 15.872 29.696 35.84V558.08c0 19.968-13.312 35.84-29.696 35.84s-29.696-15.872-29.696-35.84zM480.256 558.08V363.52c0-19.968 13.312-35.84 29.696-35.84 16.384 0 29.696 15.872 29.696 35.84v194.56c0 19.968-13.312 35.84-29.696 35.84-16.384 0-29.696-15.872-29.696-35.84zM660.48 558.08V299.52c0-19.968 13.312-35.84 29.696-35.84s29.696 15.872 29.696 35.84V558.08c0 19.968-13.312 35.84-29.696 35.84s-29.696-15.872-29.696-35.84z" p-id="1532" fill="#2d8cf0"></path><path d="M861.696 781.312H568.32v117.248h146.944c16.384 0 29.184 13.312 29.184 29.184 0 16.384-13.312 29.184-29.184 29.184H362.496c-16.384-1.024-28.672-14.848-27.648-30.72 1.024-14.848 12.8-27.136 27.648-27.648h146.944v-117.248H157.184c-65.024 0-117.248-52.736-117.248-117.248V194.048C39.936 129.024 92.16 76.8 157.184 76.8h704.512c65.024 0 117.248 52.736 117.248 117.248v470.016c0.512 64.512-52.224 117.248-117.248 117.248z m58.88-587.264c0-32.256-26.112-58.88-58.88-58.88H157.184c-32.256 0-58.88 26.112-58.88 58.88v470.016c0 32.256 26.112 58.88 58.88 58.88h704.512c32.256 0 58.88-26.112 58.88-58.88V194.048z" p-id="1533" fill="#2d8cf0"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

Some files were not shown because too many files have changed in this diff Show More