初始化

This commit is contained in:
dqz 2025-03-04 09:11:33 +08:00
commit 454615e8f4
315 changed files with 34671 additions and 0 deletions

21
.dockerignore Normal file
View File

@ -0,0 +1,21 @@
node_modules
.DS_Store
dist
dist-ssr
*.local
.eslintcache
report.html
yarn.lock
npm-debug.log*
.pnpm-error.log*
.pnpm-debug.log
tests/**/coverage/
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
tsconfig.tsbuildinfo

14
.editorconfig Normal file
View File

@ -0,0 +1,14 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

5
.env Normal file
View File

@ -0,0 +1,5 @@
# 平台本地运行端口号
VITE_PORT = 8848
# 是否隐藏首页 隐藏 true 不隐藏 false 勿删除VITE_HIDE_HOME只需在.env文件配置
VITE_HIDE_HOME = false

11
.env.development Normal file
View File

@ -0,0 +1,11 @@
# 平台本地运行端口号
VITE_PORT = 80
# 开发环境读取配置文件路径
VITE_PUBLIC_PATH = ./
# 开发环境路由历史模式Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数"
VITE_ROUTER_HISTORY = "hash"
# 后端地址
VITE_APP_BASE_API = '/dev-api'

16
.env.production Normal file
View File

@ -0,0 +1,16 @@
# 线上环境平台打包路径
VITE_PUBLIC_PATH = ./
# 线上环境路由历史模式Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数"
VITE_ROUTER_HISTORY = "hash"
# 是否在打包时使用cdn替换本地库 替换 true 不替换 false
VITE_CDN = false
# 是否启用gzip压缩或brotli压缩分两种情况删除原始文件和不删除原始文件
# 压缩时不删除原始文件的配置gzip、brotli、both同时开启 gzip 与 brotli 压缩、none不开启压缩默认
# 压缩时删除原始文件的配置gzip-clear、brotli-clear、both-clear同时开启 gzip 与 brotli 压缩、none不开启压缩默认
VITE_COMPRESSION = "none"
# 后端地址
VITE_APP_BASE_API = '/prod-api'

19
.env.staging Normal file
View File

@ -0,0 +1,19 @@
# 预发布也需要生产环境的行为
# https://cn.vitejs.dev/guide/env-and-mode.html#modes
# NODE_ENV = development
VITE_PUBLIC_PATH = ./
# 预发布环境路由历史模式Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数"
VITE_ROUTER_HISTORY = "hash"
# 是否在打包时使用cdn替换本地库 替换 true 不替换 false
VITE_CDN = true
# 是否启用gzip压缩或brotli压缩分两种情况删除原始文件和不删除原始文件
# 压缩时不删除原始文件的配置gzip、brotli、both同时开启 gzip 与 brotli 压缩、none不开启压缩默认
# 压缩时删除原始文件的配置gzip-clear、brotli-clear、both-clear同时开启 gzip 与 brotli 压缩、none不开启压缩默认
VITE_COMPRESSION = "none"
# 后端地址
VITE_APP_BASE_API = '/stage-api'

11
.eslintignore Normal file
View File

@ -0,0 +1,11 @@
public
dist
*.d.ts
/src/assets
package.json
.eslintrc.js
.prettierrc.js
commitlint.config.js
postcss.config.js
tailwind.config.js
stylelint.config.js

120
.eslintrc.js Normal file
View File

@ -0,0 +1,120 @@
module.exports = {
root: true,
env: {
node: true
},
globals: {
// Ref sugar (take 2)
$: "readonly",
$$: "readonly",
$ref: "readonly",
$shallowRef: "readonly",
$computed: "readonly",
// index.d.ts
// global.d.ts
Fn: "readonly",
PromiseFn: "readonly",
RefType: "readonly",
LabelValueOptions: "readonly",
EmitType: "readonly",
TargetContext: "readonly",
ComponentElRef: "readonly",
ComponentRef: "readonly",
ElRef: "readonly",
global: "readonly",
ForDataType: "readonly",
ComponentRoutes: "readonly",
// script setup
defineProps: "readonly",
defineEmits: "readonly",
defineExpose: "readonly",
withDefaults: "readonly"
},
extends: [
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/typescript/recommended",
"@vue/prettier",
"@vue/eslint-config-typescript"
],
parser: "vue-eslint-parser",
parserOptions: {
parser: "@typescript-eslint/parser",
ecmaVersion: 2020,
sourceType: "module",
jsxPragma: "React",
ecmaFeatures: {
jsx: true
}
},
overrides: [
{
files: ["*.ts", "*.vue"],
rules: {
"no-undef": "off"
}
},
{
files: ["*.vue"],
parser: "vue-eslint-parser",
parserOptions: {
parser: "@typescript-eslint/parser",
extraFileExtensions: [".vue"],
ecmaVersion: "latest",
ecmaFeatures: {
jsx: true
}
},
rules: {
"no-undef": "off"
}
}
],
rules: {
"vue/no-v-html": "off",
"vue/require-default-prop": "off",
"vue/require-explicit-emits": "off",
"vue/multi-word-component-names": "off",
"@typescript-eslint/no-explicit-any": "off", // any
"no-debugger": "off",
"@typescript-eslint/explicit-module-boundary-types": "off", // setup()
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"vue/html-self-closing": [
"error",
{
html: {
void: "always",
normal: "always",
component: "always"
},
svg: "always",
math: "always"
}
],
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_"
}
],
"no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_"
}
],
"prettier/prettier": [
"error",
{
endOfLine: "auto"
}
]
}
};

24
.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
node_modules
.DS_Store
dist
dist-ssr
*.local
.eslintcache
report.html
yarn.lock
npm-debug.log*
.pnpm-error.log*
.pnpm-debug.log
tests/**/coverage/
# 本机调试debug配置文件
.vscode/launch.json
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
tsconfig.tsbuildinfo

6
.husky/commit-msg Normal file
View File

@ -0,0 +1,6 @@
#!/bin/sh
# shellcheck source=./_/husky.sh
. "$(dirname "$0")/_/husky.sh"
npx --no-install commitlint --edit "$1"

9
.husky/common.sh Normal file
View File

@ -0,0 +1,9 @@
#!/bin/sh
command_exists () {
command -v "$1" >/dev/null 2>&1
}
# Workaround for Windows 10, Git Bash and Pnpm
if command_exists winpty && test -t 1; then
exec < /dev/tty
fi

8
.husky/lintstagedrc.js Normal file
View File

@ -0,0 +1,8 @@
module.exports = {
"*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
"{!(package)*.json}": ["prettier --write--parser json"],
"package.json": ["prettier --write"],
"*.vue": ["eslint --fix", "prettier --write", "stylelint --fix"],
"*.{vue,css,scss,postcss,less}": ["stylelint --fix", "prettier --write"],
"*.md": ["prettier --write"]
};

10
.husky/pre-commit Normal file
View File

@ -0,0 +1,10 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
. "$(dirname "$0")/common.sh"
[ -n "$CI" ] && exit 0
# Format and submit code according to lintstagedrc.js configuration
npm run lint:lint-staged
npm run lint:pretty

11
.markdownlint.json Normal file
View File

@ -0,0 +1,11 @@
{
"default": true,
"MD003": false,
"MD033": false,
"MD013": false,
"MD001": false,
"MD025": false,
"MD024": false,
"MD007": { "indent": 4 },
"no-hard-tabs": false
}

3
.npmrc Normal file
View File

@ -0,0 +1,3 @@
shamefully-hoist=true
strict-peer-dependencies=false
shell-emulator=true

6
.prettierrc.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
bracketSpacing: true,
singleQuote: false,
arrowParens: "avoid",
trailingComma: "none"
};

4
.stylelintignore Normal file
View File

@ -0,0 +1,4 @@
/dist/*
/public/*
public/*
src/style/reset.scss

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

@ -0,0 +1,31 @@
{
"recommendations": [
"akamud.vscode-theme-onedark",
"antfu.iconify",
"bradlc.vscode-tailwindcss",
"christian-kohler.npm-intellisense",
"christian-kohler.path-intellisense",
"Codeium.codeium",
"csstools.postcss",
"DavidAnson.vscode-markdownlint",
"dbaeumer.vscode-eslint",
"donjayamanne.githistory",
"dsznajder.es7-react-js-snippets",
"eamodio.gitlens",
"ecmel.vscode-html-css",
"esbenp.prettier-vscode",
"genieai.chatgpt-vscode",
"hollowtree.vue-snippets",
"lokalise.i18n-ally",
"mhutchie.git-graph",
"mikestead.dotenv",
"pmneo.tsimporter",
"streetsidesoftware.code-spell-checker",
"stylelint.vscode-stylelint",
"syler.sass-indented",
"sysoev.language-stylus",
"vscode-icons-team.vscode-icons",
"Vue.volar",
"xabikos.JavaScriptSnippets"
]
}

37
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,37 @@
{
"editor.formatOnType": true,
"editor.formatOnSave": true,
"[vue]": {
"editor.defaultFormatter": "Vue.volar"
},
"editor.tabSize": 2,
"editor.formatOnPaste": true,
"editor.guides.bracketPairs": "active",
"files.autoSave": "off",
"git.confirmSync": false,
"workbench.startupEditor": "newUntitledFile",
"editor.suggestSelection": "first",
"editor.acceptSuggestionOnCommitCharacter": false,
"css.lint.propertyIgnoredDueToDisplay": "ignore",
"editor.quickSuggestions": {
"other": true,
"comments": true,
"strings": true
},
"files.associations": {
"editor.snippetSuggestions": "top"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"iconify.excludes": [
"el"
],
"cSpell.words": [
"iconify",
"Qrcode"
]
}

22
.vscode/vue3.0.code-snippets vendored Normal file
View File

@ -0,0 +1,22 @@
{
"Vue3.0快速生成模板": {
"scope": "vue",
"prefix": "Vue3.0",
"body": [
"<template>",
"\t<div>test</div>",
"</template>\n",
"<script lang='ts'>",
"export default {",
"\tsetup() {",
"\t\treturn {}",
"\t}",
"}",
"</script>\n",
"<style lang='scss' scoped>\n",
"</style>",
"$2"
],
"description": "Vue3.0"
}
}

17
.vscode/vue3.2.code-snippets vendored Normal file
View File

@ -0,0 +1,17 @@
{
"Vue3.2+快速生成模板": {
"scope": "vue",
"prefix": "Vue3.2+",
"body": [
"<script setup lang='ts'>",
"</script>\n",
"<template>",
"\t<div>test</div>",
"</template>\n",
"<style lang='scss' scoped>\n",
"</style>",
"$2"
],
"description": "Vue3.2+"
}
}

20
.vscode/vue3.3.code-snippets vendored Normal file
View File

@ -0,0 +1,20 @@
{
"Vue3.3+defineOptions快速生成模板": {
"scope": "vue",
"prefix": "Vue3.3+",
"body": [
"<script setup lang='ts'>",
"defineOptions({",
"\tname: ''",
"})",
"</script>\n",
"<template>",
"\t<div>test</div>",
"</template>\n",
"<style lang='scss' scoped>\n",
"</style>",
"$2"
],
"description": "Vue3.3+defineOptions快速生成模板"
}
}

20
Dockerfile Normal file
View File

@ -0,0 +1,20 @@
FROM node:16-alpine as build-stage
WORKDIR /app
RUN corepack enable
RUN corepack prepare pnpm@7.32.1 --activate
RUN npm config set registry https://registry.npmmirror.com
COPY .npmrc package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020-present, pure-admin
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.

36
README.en-US.md Normal file
View File

@ -0,0 +1,36 @@
<h1>vue-pure-admin Lite Editionno i18n version</h1>
[![license](https://img.shields.io/github/license/pure-admin/vue-pure-admin.svg)](LICENSE)
**English** | [中文](./README.md)
## Introduce
The simplified version is based on the shelf extracted from [vue-pure-admin](https://github.com/pure-admin/vue-pure-admin), which contains main functions and is more suitable for actual project development. The packaged size is introduced globally [element-plus](https://element-plus.org) is still below `2.3MB`, and the full version of the code will be permanently synchronized. After enabling `brotli` compression and `cdn` to replace the local library mode, the package size is less than `350kb`
## Supporting Video
- [Click Watch Tutorial](https://www.bilibili.com/video/BV1kg411v7QT)
- [Click Watch UI Design](https://www.bilibili.com/video/BV17g411T7rq)
## Docs
- [documentation site](https://yiming_chang.gitee.io/pure-admin-doc)
## Preview
- [Click me to view the preview station](https://pure-admin-thin.netlify.app/#/login)
## Maintainer
[xiaoxian521](https://github.com/xiaoxian521)
## ⚠️ Attention
- The Lite version does not accept any issues and prs. If you have any questions, please go to the full version [issues](https://github.com/pure-admin/vue-pure-admin/issues/new/choose) to mention, thank you!
## License
In principle, no fees and copyrights are charged, and it is commercially available, but if you need secondary open source (such as using this platform for secondary development and open source, the front-end code must be open source and free), please contact the author for permission! (Free, just take a record)
[MIT © 2020-present, pure-admin](./LICENSE)

145
README.md Normal file
View File

@ -0,0 +1,145 @@
<p align="center">
<img src="https://img.shields.io/badge/Release-V1.8.0-green.svg" alt="Downloads">
<img src="https://img.shields.io/badge/JDK-1.8+-green.svg" alt="Build Status">
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="Build Status">
<img src="https://img.shields.io/badge/Spring%20Boot-2.7.1-blue.svg" alt="Downloads">
<a target="_blank" href="https://bladex.vip">
<img src="https://img.shields.io/badge/Author-valarchie-ff69b4.svg" alt="Downloads">
</a>
<a target="_blank" href="https://bladex.vip">
<img src="https://img.shields.io/badge/Copyright%20-@Agileboot-%23ff3f59.svg" alt="Downloads">
</a>
</p>
<p align="center">
<img alt="logo" height="200" src="https://oscimg.oschina.net/oscnet/up-eda2a402cc061f1f5f40d9ac4c084f4c98c.png">
</p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">AgileBoot v2.0.0</h1>
<h4 align="center">基于SpringBoot+Vue3前后端分离的Java快速开发框架</h4>
<p align="center">
</p>
## ⚡ 平台简介 ⚡
- 本仓库是 Agilboot 快速开发脚手架的配套前端项目。前端是基于优秀的开源项目[Pure-Admin](https://github.com/pure-admin/vue-pure-admin)开发而成。在此感谢 Pure-Admin 作者。
- 本仓库前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) 版本。
- 配套后端代码仓库地址[AgileBoot-Back-End](https://github.com/valarchie/AgileBoot-Back-End) 版本。
- 规范请参照该文档 [前端规范](https://gitee.com/MinJieLiu/web-standard#/MinJieLiu/web-standard)
### 前端配套资料
#### 配套视频
- [点我查看教程](https://www.bilibili.com/video/BV1kg411v7QT)
- [点我查看 UI 设计](https://www.bilibili.com/video/BV17g411T7rq)
#### 配套保姆级文档
- [查看文档](https://yiming_chang.gitee.io/pure-admin-doc)
#### Pure-Admin 框架预览
- [查看预览](https://pure-admin-thin.netlify.app/#/login)
#### Pure-Admin 维护者
- [xiaoxian521](https://github.com/xiaoxian521)
## ✨ 使用 ✨
### 开发环境
Node.js 版本要求16.0+
pnpm 版本要求6.0+
优先选择 node=16, pnpm=7.30.5的环境.
如果您还没安装 pnpm请执行下面命令进行安装mac 用户遇到安装报错请在命令前加上 sudo 如果是 windows 用户,使用 power shell 管理员权限执行
```
npm install -g pnpm
```
安装依赖
```
pnpm install
```
启动平台
```
pnpm run dev
```
不管是什么源,我们都可以不用管,直接执行下面命令即可
npm config set registry https://registry.npmmirror.com
上面的命令是将本地的源换成国内源 npmmirror
(opens new window),经过几轮测试,发现它的下载速度快且同步率高,同步频率 10 分钟一次,如果您之前的源是这个 http://registry.npm.taobao.org ,那您必须换成 npmmirror 啦,因为原淘宝 npm 域名即将停止解析
## 🙊 系统内置功能 🙊
🙂 大部分功能,均有通过 **单元测试** **集成测试** 保证质量。
| | 功能 | 描述 |
| --- | ---------- | ------------------------------------------------------------- |
| | 用户管理 | 用户是系统操作者,该功能主要完成系统用户配置 |
| ⭐ | 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限 |
| ⭐ | 岗位管理 | 配置系统用户所属担任职务 |
| | 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等,本地缓存提供性能 |
| ⭐ | 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 |
| | 参数管理 | 对系统动态配置常用参数 |
| | 通知公告 | 系统通知公告信息发布维护 |
| 🚀 | 操作日志 | 系统正常操作日志记录和查询;系统异常信息日志记录和查询 |
| | 登录日志 | 系统登录日志记录查询包含登录异常 |
| | 在线用户 | 当前系统中活跃用户状态监控 |
| | 系统接口 | 根据业务代码自动生成相关的 api 接口文档 |
| | 服务监控 | 监视当前系统 CPU、内存、磁盘、堆栈等相关信息 |
| | 缓存监控 | 对系统的缓存信息查询,命令统计等 |
| | 连接池监视 | 监视当前系统数据库连接池状态,可进行分析 SQL 找出系统性能瓶颈 |
## 💥 在线体验 💥
演示地址:
- <www.agileboot.vip>
- <www.agileboot.cc>
> 账号密码admin/admin123
[项目文档](https://juejin.cn/column/7159946528827080734)
## 🎬 AgileBoot 全栈交流群 🎬
QQ 群: [![加入QQ群](https://img.shields.io/badge/1398880-blue.svg)](https://qm.qq.com/cgi-bin/qm/qr?k=TR5guoXS0HssErVWefmdFRirJvfpEvp1&jump_from=webapi&authKey=VkWMmVhp/pNdWuRD8sqgM+Sv2+Vy2qCJQSeLmeXlLtfER2RJBi6zL56PdcRlCmTs) 点击按钮入群。
如果觉得该项目对您有帮助,可以小额捐赠支持本项目演示网站服务器等费用~
<img alt="logo" height="200" src="https://oscimg.oschina.net/oscnet/up-28b63fdd7b3ce003bd30c25883f2276212b.png">
### 用法
#### 安装依赖
```
pnpm install
```
#### 安装一个包
```
pnpm add 包名
```
#### 卸载一个包
```
pnpm remove 包名
```
### 许可证
原则上不收取任何费用及版权,可商用,不过如需二次开源(比如用此平台二次开发并开源,要求前端代码必须开源免费)请联系作者获取许可!(免费,走个记录而已)

56
build/cdn.ts Normal file
View File

@ -0,0 +1,56 @@
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
* mockjs不能用cdn模式引入mockjs使
* 使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}",
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-demihttps://github.com/vuejs/pinia/blob/v2/packages/pinia/package.json#L77
{
name: "vue-demi",
var: "VueDemi",
path: "index.iife.min.js"
},
{
name: "pinia",
var: "Pinia",
path: "pinia.iife.min.js"
},
{
name: "element-plus",
var: "ElementPlus",
path: "index.full.min.js",
css: "index.min.css"
},
{
name: "axios",
var: "axios",
path: "axios.min.js"
},
{
name: "dayjs",
var: "dayjs",
path: "dayjs.min.js"
},
{
name: "echarts",
var: "echarts",
path: "echarts.min.js"
}
]
});

63
build/compress.ts Normal file
View File

@ -0,0 +1,63 @@
import type { Plugin } from "vite";
import { isArray } from "@pureadmin/utils";
import compressPlugin from "vite-plugin-compression";
export const configCompressPlugin = (
compress: ViteCompression
): Plugin | Plugin[] => {
if (compress === "none") 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;
};

37
build/index.ts Normal file
View File

@ -0,0 +1,37 @@
/** 处理环境变量 */
const wrapperEnv = (envConfigs: Recordable): ViteEnv => {
/** 此处为默认值 */
const defaultEnvConfigs: ViteEnv = {
VITE_PORT: 8848,
VITE_PUBLIC_PATH: "",
VITE_ROUTER_HISTORY: "",
VITE_CDN: false,
VITE_HIDE_HOME: "false",
VITE_COMPRESSION: "none",
VITE_APP_BASE_API: ""
};
for (const configName of Object.keys(envConfigs)) {
let realConfigValue = envConfigs[configName].replace(/\\n/g, "\n");
realConfigValue =
realConfigValue === "true"
? true
: realConfigValue === "false"
? false
: realConfigValue;
if (configName === "VITE_PORT") {
realConfigValue = Number(realConfigValue);
}
defaultEnvConfigs[configName] = realConfigValue;
if (typeof realConfigValue === "string") {
process.env[configName] = realConfigValue;
} else if (typeof realConfigValue === "object") {
process.env[configName] = JSON.stringify(realConfigValue);
}
}
return defaultEnvConfigs;
};
export { wrapperEnv };

53
build/info.ts Normal file
View File

@ -0,0 +1,53 @@
import type { Plugin } from "vite";
import dayjs, { Dayjs } from "dayjs";
import utils from "@pureadmin/utils";
import duration from "dayjs/plugin/duration";
import { green, blue, bold } from "picocolors";
dayjs.extend(duration);
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(
bold(
green(
`👏欢迎使用${blue(
"[Agileboot全栈项目]"
)}star哦💖 https://github.com/valarchie/agileboot-back-end`
)
)
);
if (config.command === "build") {
startTime = dayjs(new Date());
}
},
closeBundle() {
if (config.command === "build") {
endTime = dayjs(new Date());
utils.getPackageSize({
folder: outDir,
callback: (size: string) => {
console.log(
bold(
green(
`🎉恭喜打包完成(总用时${dayjs
.duration(endTime.diff(startTime))
.format("mm分ss秒")}${size}`
)
)
);
}
});
}
}
};
}

32
build/optimize.ts Normal file
View File

@ -0,0 +1,32 @@
/**
* `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",
"xlsx",
"dayjs",
"axios",
"pinia",
"js-cookie",
"sortablejs",
"pinyin-pro",
"@vueuse/core",
"@pureadmin/utils",
"responsive-storage"
];
/**
*
* `@iconify-icons/` `exclude` 使
*/
const exclude = [
"@iconify-icons/ep",
"@iconify-icons/ri",
"@pureadmin/theme/dist/browser-utils"
];
export { include, exclude };

56
build/plugins.ts Normal file
View File

@ -0,0 +1,56 @@
import { cdn } from "./cdn";
import vue from "@vitejs/plugin-vue";
import { viteBuildInfo } from "./info";
import svgLoader from "vite-svg-loader";
import vueJsx from "@vitejs/plugin-vue-jsx";
// import { viteMockServe } from "vite-plugin-mock";
import { configCompressPlugin } from "./compress";
// import ElementPlus from "unplugin-element-plus/vite";
import { visualizer } from "rollup-plugin-visualizer";
import removeConsole from "vite-plugin-remove-console";
import { themePreprocessorPlugin } from "@pureadmin/theme";
import { genScssMultipleScopeVars } from "../src/layout/theme";
export function getPluginsList(
command: string,
VITE_CDN: boolean,
VITE_COMPRESSION: ViteCompression
) {
// const prodMock = true;
const lifecycle = process.env.npm_lifecycle_event;
return [
vue(),
// jsx、tsx语法支持
vueJsx(),
VITE_CDN ? cdn : null,
configCompressPlugin(VITE_COMPRESSION),
// 线上环境删除console
removeConsole({ external: ["src/assets/iconfont/iconfont.js"] }),
viteBuildInfo(),
// 自定义主题
themePreprocessorPlugin({
scss: {
multipleScopeVars: genScssMultipleScopeVars(),
extract: true
}
}),
// svg组件化支持
svgLoader(),
// ElementPlus({}),
// mock支持
// viteMockServe({
// mockPath: "mock",
// localEnabled: command === "serve",
// prodEnabled: command !== "serve" && prodMock,
// injectCode: `
// import { setupProdMockServer } from './mockProdServer';
// setupProdMockServer();
// `,
// logger: false
// }),
// 打包分析
lifecycle === "report"
? visualizer({ open: true, brotliSize: true, filename: "report.html" })
: null
];
}

32
commitlint.config.js Normal file
View File

@ -0,0 +1,32 @@
module.exports = {
ignores: [commit => commit.includes("init")],
extends: ["@commitlint/config-conventional"],
rules: {
"body-leading-blank": [2, "always"],
"footer-leading-blank": [1, "always"],
"header-max-length": [2, "always", 108],
"subject-empty": [2, "never"],
"type-empty": [2, "never"],
"type-enum": [
2,
"always",
[
"feat",
"fix",
"perf",
"style",
"docs",
"test",
"refactor",
"build",
"ci",
"chore",
"revert",
"wip",
"workflow",
"types",
"release"
]
]
}
};

87
index.html Normal file
View File

@ -0,0 +1,87 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="renderer" content="webkit" />
<meta
name="viewport"
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
/>
<title>Agileboot管理系统</title>
<link rel="icon" href="/favicon.ico" />
<script>
window.process = {};
</script>
</head>
<body>
<div id="app">
<style>
html,
body,
#app {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
overflow: hidden;
}
.loader,
.loader::before,
.loader::after {
width: 2.5em;
height: 2.5em;
border-radius: 50%;
animation: load-animation 1.8s infinite ease-in-out;
animation-fill-mode: both;
}
.loader {
position: relative;
top: 0;
margin: 80px auto;
font-size: 10px;
color: #406eeb;
text-indent: -9999em;
transform: translateZ(0);
transform: translate(-50%, 0);
animation-delay: -0.16s;
}
.loader::before,
.loader::after {
position: absolute;
top: 0;
content: "";
}
.loader::before {
left: -3.5em;
animation-delay: -0.32s;
}
.loader::after {
left: 3.5em;
}
@keyframes load-animation {
0%,
80%,
100% {
box-shadow: 0 2.5em 0 -1.3em;
}
40% {
box-shadow: 0 2.5em 0 0;
}
}
</style>
<div class="loader"></div>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

49
mock/asyncRoutes.ts Normal file
View File

@ -0,0 +1,49 @@
// 模拟后端动态生成路由
import { MockMethod } from "vite-plugin-mock";
/**
* roles "admin""common"
* admin
* common
*/
const permissionRouter = {
path: "/permission",
meta: {
title: "权限管理",
icon: "lollipop",
rank: 10
},
children: [
{
path: "/permission/page/index",
name: "PermissionPage",
meta: {
title: "页面权限",
roles: ["admin", "common"]
}
},
{
path: "/permission/button/index",
name: "PermissionButton",
meta: {
title: "按钮权限",
roles: ["admin", "common"],
auths: ["btn_add", "btn_edit", "btn_delete"]
}
}
]
};
export default [
{
url: "/getAsyncRoutes",
method: "get",
response: () => {
return {
success: true,
data: [permissionRouter]
};
}
}
] as MockMethod[];

36
mock/login.ts Normal file
View File

@ -0,0 +1,36 @@
// 根据角色动态生成路由
import { MockMethod } from "vite-plugin-mock";
export default [
{
url: "/login",
method: "post",
response: ({ body }) => {
if (body.username === "admin") {
return {
success: true,
data: {
username: "admin",
// 一个用户可能有多个角色
roles: ["admin"],
accessToken: "eyJhbGciOiJIUzUxMiJ9.admin",
refreshToken: "eyJhbGciOiJIUzUxMiJ9.adminRefresh",
expires: "2023/10/30 00:00:00"
}
};
} else {
return {
success: true,
data: {
username: "common",
// 一个用户可能有多个角色
roles: ["common"],
accessToken: "eyJhbGciOiJIUzUxMiJ9.common",
refreshToken: "eyJhbGciOiJIUzUxMiJ9.commonRefresh",
expires: "2023/10/30 00:00:00"
}
};
}
}
}
] as MockMethod[];

27
mock/refreshToken.ts Normal file
View File

@ -0,0 +1,27 @@
import { MockMethod } from "vite-plugin-mock";
// 模拟刷新token接口
export default [
{
url: "/refreshToken",
method: "post",
response: ({ body }) => {
if (body.refreshToken) {
return {
success: true,
data: {
accessToken: "eyJhbGciOiJIUzUxMiJ9.newAdmin",
refreshToken: "eyJhbGciOiJIUzUxMiJ9.newAdminRefresh",
// `expires`选择这种日期格式是为了方便调试,后端直接设置时间戳或许更方便(每次都应该递增)。如果后端返回的是时间戳格式,前端开发请来到这个目录`src/utils/auth.ts`,把第`38`行的代码换成expires = data.expires即可。
expires: "2023/10/30 23:59:59"
}
};
} else {
return {
success: false,
data: {}
};
}
}
}
] as MockMethod[];

142
package.json Normal file
View File

@ -0,0 +1,142 @@
{
"name": "agileboot-front-end-pure",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "NODE_OPTIONS=--max-old-space-size=4096 vite",
"serve": "pnpm dev",
"build": "rimraf dist && NODE_OPTIONS=--max-old-space-size=8192 vite build",
"build:staging": "rimraf dist && vite build --mode staging",
"report": "rimraf dist && vite build",
"preview": "vite preview",
"preview:build": "pnpm build && vite preview",
"typecheck": "tsc --noEmit && vue-tsc --noEmit --skipLibCheck",
"svgo": "svgo -f src/assets/svg -o src/assets/svg",
"cloc": "NODE_OPTIONS=--max-old-space-size=4096 cloc . --exclude-dir=node_modules --exclude-lang=YAML",
"clean:cache": "rimraf node_modules && rimraf .eslintcache && pnpm install",
"lint:eslint": "eslint --cache --max-warnings 0 \"{src,mock,build}/**/*.{vue,js,ts,tsx}\" --fix",
"lint:prettier": "prettier --write \"src/**/*.{js,ts,json,tsx,css,scss,vue,html,md}\"",
"lint:stylelint": "stylelint \"**/*.{html,vue,css,scss}\" --fix --cache --cache-location node_modules/.cache/stylelint/",
"lint:lint-staged": "lint-staged -c ./.husky/lintstagedrc.js",
"lint:pretty": "pretty-quick --staged",
"lint": "pnpm lint:eslint && pnpm lint:prettier && pnpm lint:stylelint",
"prepare": "husky install",
"preinstall": "npx only-allow pnpm"
},
"browserslist": [
"> 1%",
"not ie 11",
"not op_mini all"
],
"dependencies": {
"@pureadmin/descriptions": "^1.1.1",
"@pureadmin/table": "^2.3.2",
"@pureadmin/utils": "^1.9.6",
"@vueuse/core": "^10.2.0",
"@vueuse/motion": "^2.0.0",
"animate.css": "^4.1.1",
"axios": "^1.4.0",
"crypto-js": "^4.1.1",
"dayjs": "^1.11.8",
"echarts": "^5.4.2",
"element-plus": "2.3.6",
"js-cookie": "^3.0.5",
"jsencrypt": "^3.3.2",
"mitt": "^3.0.0",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"path": "^0.12.7",
"pinia": "^2.1.4",
"pinyin-pro": "^3.15.2",
"cropperjs": "^1.5.13",
"vue-tippy": "^6.2.0",
"qrcode": "^1.5.3",
"qs": "^6.11.2",
"responsive-storage": "^2.2.0",
"sortablejs": "^1.15.0",
"typeit": "^8.7.1",
"vue": "^3.3.4",
"vue-router": "^4.2.2",
"vue-types": "^5.1.0",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@commitlint/cli": "^17.6.6",
"@commitlint/config-conventional": "^17.6.6",
"@iconify-icons/ep": "^1.2.12",
"@iconify-icons/ri": "^1.2.9",
"@iconify/vue": "^4.1.1",
"@pureadmin/theme": "^3.1.0",
"@types/js-cookie": "^3.0.3",
"@types/mockjs": "^1.0.7",
"@types/node": "^20.3.1",
"@types/nprogress": "0.2.0",
"@types/qs": "^6.9.7",
"@types/sortablejs": "^1.15.1",
"@typescript-eslint/eslint-plugin": "^5.60.0",
"@typescript-eslint/parser": "^5.60.0",
"@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.1",
"@vue/eslint-config-prettier": "^7.1.0",
"@vue/eslint-config-typescript": "^11.0.3",
"autoprefixer": "^10.4.14",
"cloc": "^2.11.0",
"cssnano": "^6.0.1",
"eslint": "^8.43.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.15.1",
"husky": "^8.0.3",
"lint-staged": "^13.2.2",
"picocolors": "^1.0.0",
"postcss": "^8.4.24",
"postcss-html": "^1.5.0",
"postcss-import": "^15.1.0",
"postcss-scss": "^4.0.6",
"prettier": "^2.8.8",
"pretty-quick": "^3.1.3",
"rimraf": "^5.0.1",
"rollup-plugin-visualizer": "^5.9.2",
"sass": "^1.63.6",
"sass-loader": "^13.3.2",
"stylelint": "^15.9.0",
"stylelint-config-html": "^1.1.0",
"stylelint-config-recess-order": "^4.2.0",
"stylelint-config-recommended": "^12.0.0",
"stylelint-config-recommended-scss": "^12.0.0",
"stylelint-config-recommended-vue": "^1.4.0",
"stylelint-config-standard": "^33.0.0",
"stylelint-config-standard-scss": "^9.0.0",
"stylelint-order": "^6.0.3",
"stylelint-prettier": "^3.0.0",
"stylelint-scss": "^5.0.1",
"svgo": "^3.0.2",
"tailwindcss": "^3.3.2",
"terser": "^5.18.1",
"typescript": "5.0.4",
"vite": "^4.3.9",
"vite-plugin-cdn-import": "^0.3.5",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-mock": "2.9.6",
"vite-plugin-remove-console": "^2.1.1",
"vite-svg-loader": "^4.0.0",
"vue-eslint-parser": "^9.3.1",
"vue-tsc": "^1.8.1"
},
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"rollup",
"webpack",
"core-js"
]
},
"allowedDeprecatedVersions": {
"sourcemap-codec": "*",
"w3c-hr-time": "*",
"stable": "*"
}
},
"repository": "git@github.com:valarchie/agileboot-front-end-pure.git",
"author": "valarchie",
"license": "MIT"
}

8590
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

9
postcss.config.js Normal file
View File

@ -0,0 +1,9 @@
module.exports = {
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: 1.2 KiB

BIN
public/img/10.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
public/img/11.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

BIN
public/img/12.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
public/img/13.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
public/img/14.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
public/img/15.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

BIN
public/img/16.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
public/img/17.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
public/img/18.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

BIN
public/img/19.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

BIN
public/img/20.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

BIN
public/img/21.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
public/img/22.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
public/img/23.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
public/img/24.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
public/img/25.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
public/img/26.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

BIN
public/img/27.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
public/img/28.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
public/img/29.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
public/img/30.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

BIN
public/img/31.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
public/img/32.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
public/img/33.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

BIN
public/img/4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
public/img/5.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
public/img/6.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

BIN
public/img/7.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

BIN
public/img/8.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
public/img/9.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

1
public/logo.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" class="icon" viewBox="0 0 1024 1024"><path fill="#386BF3" d="M410.558.109c0 210.974-300.876 361.752-300.876 633.548 0 174.943 134.704 316.787 300.876 316.787s300.877-141.817 300.877-316.787C711.408 361.752 410.558 210.974 410.558.109z"/><path fill="#C3D2FB" d="M613.469 73.665c0 211.055-300.877 361.914-300.877 633.547C312.592 882.156 447.296 1024 613.47 1024s300.876-141.817 300.876-316.788C914.29 435.58 613.469 284.72 613.469 73.665z"/><path fill="#303F5B" d="M312.592 707.212c0-183.713 137.636-312.171 226.723-441.39 81.702 106.112 172.12 218.74 172.12 367.726A309.755 309.755 0 0 1 420.36 950.064a323.114 323.114 0 0 1-107.769-242.852z"/></svg>

After

Width:  |  Height:  |  Size: 712 B

22
public/serverConfig.json Normal file
View File

@ -0,0 +1,22 @@
{
"Version": "4.4.0",
"Title": "Agileboot",
"FixedHeader": true,
"HiddenSideBar": false,
"MultiTagsCache": false,
"KeepAlive": true,
"Layout": "vertical",
"Theme": "default",
"DarkMode": false,
"Grey": false,
"Weak": false,
"HideTabs": false,
"SidebarStatus": true,
"EpThemeColor": "#409EFF",
"ShowLogo": true,
"ShowModel": "smart",
"MenuArrowIconNoTransition": true,
"CachingAsyncRoutes": false,
"TooltipEffect": "light",
"ResponsiveStorageNameSpace": "responsive-"
}

25
src/App.vue Normal file
View File

@ -0,0 +1,25 @@
<template>
<el-config-provider :locale="currentLocale">
<router-view />
<ReDialog />
</el-config-provider>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { ElConfigProvider } from "element-plus";
import zhCn from "element-plus/lib/locale/lang/zh-cn";
import { ReDialog } from "@/components/ReDialog";
export default defineComponent({
name: "app",
components: {
[ElConfigProvider.name]: ElConfigProvider,
ReDialog
},
computed: {
currentLocale() {
return zhCn;
}
}
});
</script>

108
src/api/common/login.ts Normal file
View File

@ -0,0 +1,108 @@
import { http } from "@/utils/http";
export type CaptchaDTO = {
/** 验证码的base64图片 */
captchaCodeImg: string;
/** 验证码对应的缓存key */
captchaCodeKey: string;
};
export type ConfigDTO = {
/** 验证码开关 */
isCaptchaOn: boolean;
/** 系统字典配置(下拉选项之类的) */
dictionary: Map<String, Array<DictionaryData>>;
};
export type LoginByPasswordDTO = {
/** 用户名 */
username: string;
/** 密码 */
password: string;
/** 验证码 */
captchaCode: string;
/** 验证码对应的缓存key */
captchaCodeKey: string;
};
/**
* token实现
*/
export type TokenDTO = {
/** token */
token: string;
/** 当前登录的用户 */
currentUser: CurrentLoginUserDTO;
};
export type CurrentLoginUserDTO = {
userInfo: CurrentUserInfoDTO;
roleKey: string;
permissions: Set<string>;
};
/**
* User
*/
export interface CurrentUserInfoDTO {
avatar?: string;
createTime?: Date;
creatorId?: number;
creatorName?: string;
deptId?: number;
deptName?: string;
email?: string;
loginDate?: Date;
loginIp?: string;
nickName?: string;
phoneNumber?: string;
postId?: number;
postName?: string;
remark?: string;
roleId?: number;
roleName?: string;
sex?: number;
status?: number;
updaterId?: number;
updaterName?: string;
updateTime?: Date;
userId?: number;
username?: string;
userType?: number;
}
export type DictionaryData = {
label: string;
value: number;
cssTag: string;
};
/** 获取系统配置接口 */
export const getConfig = () => {
return http.request<ResponseData<ConfigDTO>>("get", "/getConfig");
};
/** 验证码接口 */
export const getCaptchaCode = () => {
return http.request<ResponseData<CaptchaDTO>>("get", "/captchaImage");
};
/** 登录接口 */
export const loginByPassword = (data: LoginByPasswordDTO) => {
return http.request<ResponseData<TokenDTO>>("post", "/login", { data });
};
/** 获取当前登录用户接口 */
export const getLoginUserInfo = () => {
return http.request<ResponseData<TokenDTO>>("get", "/getLoginUserInfo");
};
type Result = {
success: boolean;
data: Array<any>;
};
/** 获取动态菜单 */
export const getAsyncRoutes = () => {
return http.request<Result>("get", "/getRouters");
};

82
src/api/shop/goods.ts Normal file
View File

@ -0,0 +1,82 @@
import { http } from "@/utils/http";
export interface GoodsQuery extends BasePageQuery {
goodsName?: string;
categoryId?: number;
status?: number;
goodsId?: number;
}
/** 商品DTO */
export interface GoodsDTO {
goodsId?: number;
goodsName?: string;
categoryId?: number;
price?: number;
stock?: number;
status?: number;
coverImg?: string;
goodsDetail?: string;
creatorId?: number;
createTime?: Date;
updaterId?: number;
updateTime?: Date;
remark?: string;
deleted?: number;
}
/** 商品请求参数 */
export interface GoodsRequest {
goodsName: string;
categoryId: number;
price: number;
stock: number;
status: number;
coverImg?: string;
goodsDetail: string;
remark?: string;
}
/** 获取商品列表 */
export const getGoodsListApi = (params?: GoodsQuery) => {
return http.request<ResponseData<PageDTO<GoodsDTO>>>("get", "/shop/goods/list", {
params
});
};
/** 新增商品 */
export const addGoodsApi = (data: GoodsRequest) => {
return http.request<ResponseData<void>>("post", "/shop/goods", {
data
});
};
/** 编辑商品 */
export const updateGoodsApi = (goodsId: number, data: GoodsRequest) => {
return http.request<ResponseData<void>>("put", `/shop/goods/${goodsId}`, {
data
});
};
/** 删除商品 */
export const deleteGoodsApi = (goodsId: number) => {
return http.request<ResponseData<void>>("delete", `/shop/goods/${goodsId}`);
};
/** 修改商品状态 */
export const updateGoodsStatusApi = (goodsId: number, status: number) => {
return http.request<ResponseData<void>>(
"put",
`/shop/goods/${goodsId}/status`,
{
data: { status }
}
);
};
/** 批量导出商品 */
export const exportGoodsExcelApi = (params: GoodsQuery, fileName: string) => {
return http.download("/shop/goods/excel", fileName, {
params
});
};

76
src/api/system/config.ts Normal file
View File

@ -0,0 +1,76 @@
import { http } from "@/utils/http";
export interface ConfigQuery extends BasePageQuery {
/**
* key
*/
configKey?: string;
/**
*
*/
configName?: string;
/**
*
*/
isAllowChange?: string;
}
/**
* ConfigDTO,
*/
export interface ConfigDTO {
configId?: string;
configKey?: string;
configName?: string;
configOptions?: string[];
configValue?: string;
createTime?: Date;
isAllowChange?: string;
isAllowChangeStr?: string;
remark?: string;
}
/**
* ConfigUpdateCommand
*/
export interface UpdateConfigRequest {
configValue: string;
}
/** 获取配置列表 */
export const getConfigListApi = (params?: ConfigQuery) => {
return http.request<ResponseData<PageDTO<ConfigDTO>>>(
"get",
"/system/configs",
{
params
}
);
};
/** 获取配置信息 */
export const getConfigInfoApi = (configId: string) => {
return http.request<ResponseData<ConfigDTO>>(
"get",
`/system/config/${configId}`
);
};
/** 刷新配置缓存 */
export const updateConfigApi = (
configId: number,
data: UpdateConfigRequest
) => {
return http.request<ResponseData<PageDTO<ConfigDTO>>>(
"put",
`/system/config/${configId}`,
{
data
}
);
};
/** 刷新配置缓存 */
export const refreshConfigCacheApi = () => {
return http.request<ResponseData<void>>("delete", "/system/configs/cache");
};

83
src/api/system/dept.ts Normal file
View File

@ -0,0 +1,83 @@
import { http } from "@/utils/http";
export interface DeptQuery extends BaseQuery {
// TODO 目前不需要这个参数
deptId?: number;
parentId?: number;
}
/**
* DeptDTO
*/
export interface DeptDTO {
createTime?: Date;
id?: number;
deptName?: string;
email?: string;
leaderName?: string;
orderNum?: number;
parentId?: number;
phone?: string;
status?: number;
statusStr?: string;
}
/**
* AddDeptCommand
*/
export interface DeptRequest {
deptName: string;
email?: string;
leaderName?: string;
orderNum: number;
parentId: number;
phone?: string;
status: number;
}
export interface DeptTreeDTO {
id: number;
parentId: number;
label: string;
children: [DeptTreeDTO];
}
/** 获取部门列表 */
export const getDeptListApi = (params?: DeptQuery) => {
return http.request<ResponseData<Array<DeptDTO>>>("get", "/system/depts", {
params
});
};
/** 新增部门 */
export const addDeptApi = (data: DeptRequest) => {
console.log(data);
return http.request<ResponseData<void>>("post", "/system/dept", {
data
});
};
/** 部门详情 */
export const getDeptInfoApi = (deptId: string) => {
return http.request<ResponseData<DeptDTO>>("get", `/system/dept/${deptId}`);
};
/** 修改部门 */
export const updateDeptApi = (deptId: string, data: DeptRequest) => {
return http.request<ResponseData<void>>("put", `/system/dept/${deptId}`, {
data
});
};
/** 删除部门 */
export const deleteDeptApi = (deptId: string) => {
return http.request<ResponseData<void>>("delete", `/system/dept/${deptId}`);
};
/** 获取部门树级结构 */
export const getDeptTree = () => {
return http.request<ResponseData<DeptTreeDTO>>(
"get",
"/system/depts/dropdown"
);
};

116
src/api/system/log.ts Normal file
View File

@ -0,0 +1,116 @@
import { http } from "@/utils/http";
export interface OperationLogsQuery extends BasePageQuery {
businessType?: string;
requestModule?: string;
status?: string;
username?: string;
}
export interface OperationLogDTO {
businessType?: number;
businessTypeStr?: string;
calledMethod?: string;
deptId?: number;
deptName?: string;
errorStack?: string;
operationId?: number;
operationParam?: string;
operationResult?: string;
operationTime?: Date;
operatorIp?: string;
operatorLocation?: string;
operatorType?: number;
operatorTypeStr?: string;
requestMethod?: string;
requestModule?: string;
requestUrl?: string;
status?: number;
statusStr?: string;
userId?: number;
username?: string;
}
/** 获取操作日志列表 */
export const getOperationLogListApi = (params?: OperationLogsQuery) => {
return http.request<ResponseData<PageDTO<OperationLogDTO>>>(
"get",
"/logs/operationLogs",
{
params
}
);
};
export const exportOperationLogExcelApi = (
params: OperationLogsQuery,
fileName: string
) => {
return http.download("/logs/operationLogs/excel", fileName, {
params
});
};
export const deleteOperationLogApi = (data: Array<number>) => {
return http.request<ResponseData<void>>("delete", "/logs/operationLogs", {
params: {
// 需要将数组转换为字符串 否则Axios会将参数变成 noticeIds[0]:1 noticeIds[1]:2 这种格式,后端接收参数不成功
operationIds: data.toString()
}
});
};
/** 登录日志查询类 */
export interface LoginLogQuery extends BasePageQuery {
beginTime?: string;
endTime?: string;
ipAddress?: string;
status?: string;
username?: string;
}
/**
*
*/
export interface LoginLogsDTO {
browser?: string;
infoId?: string;
ipAddress?: string;
loginLocation?: string;
loginTime?: Date;
msg?: string;
operationSystem?: string;
/** TODO 这个登录状态的设计很奇怪 需要重构掉 */
status?: number;
statusStr?: string;
username?: string;
}
/** 获取操作日志列表 */
export const getLoginLogListApi = (params?: LoginLogQuery) => {
return http.request<ResponseData<PageDTO<LoginLogsDTO>>>(
"get",
"/logs/loginLogs",
{
params
}
);
};
export const exportLoginLogExcelApi = (
params: LoginLogQuery,
fileName: string
) => {
return http.download("/logs/loginLogs/excel", fileName, {
params
});
};
export const deleteLoginLogApi = (data: Array<number>) => {
return http.request<ResponseData<void>>("delete", "/logs/loginLogs", {
params: {
// 需要将数组转换为字符串 否则Axios会将参数变成 noticeIds[0]:1 noticeIds[1]:2 这种格式,后端接收参数不成功
ids: data.toString()
}
});
};

118
src/api/system/menu.ts Normal file
View File

@ -0,0 +1,118 @@
import { http } from "@/utils/http";
import { Tree } from "@/utils/tree";
export interface MenuQuery {
isButton: boolean;
}
/**
* MenuDTO
*/
export interface MenuDTO extends Tree {
createTime?: Date;
isButton?: number;
id?: number;
menuName?: string;
parentId?: number;
menuType: number;
menuTypeStr: string;
path?: string;
permission?: string;
routerName?: string;
status?: number;
statusStr?: string;
}
/**
* MenuDetailDTO
*/
export interface MenuDetailDTO extends MenuDTO {
meta: MetaDTO;
permission?: string;
}
/**
* AddMenuCommand
*/
export interface MenuRequest {
id: number;
parentId: number;
menuName: string;
routerName?: string;
path?: string;
permission?: string;
status: number;
isButton: boolean;
menuType: number;
meta: MetaDTO;
}
/**
* MetaDTO
*/
export interface MetaDTO {
auths?: string[];
dynamicLevel?: number;
extraIcon?: ExtraIconDTO;
frameLoading?: boolean;
frameSrc?: string;
hiddenTag?: boolean;
icon?: string;
isFrameSrcInternal?: boolean;
keepAlive?: boolean;
rank?: number;
roles?: string[];
showLink?: boolean;
showParent?: boolean;
title?: string;
transition?: TransitionDTO;
}
/**
* ExtraIconDTO
*/
export interface ExtraIconDTO {
name?: string;
svg?: boolean;
}
/**
* TransitionDTO
*/
export interface TransitionDTO {
enterTransition?: string;
leaveTransition?: string;
name?: string;
}
/** 获取菜单列表 */
export const getMenuListApi = (params: MenuQuery) => {
return http.request<ResponseData<Array<MenuDTO>>>("get", "/system/menus", {
params
});
};
/** 添加菜单 */
export const addMenuApi = (data: MenuRequest) => {
return http.request<ResponseData<void>>("post", "/system/menus", { data });
};
/** 修改菜单 */
export const updateMenuApi = (menuId: string, data: MenuRequest) => {
return http.request<ResponseData<void>>("put", `/system/menus/${menuId}`, {
data
});
};
/** 删除菜单 */
export const deleteMenuApi = (menuId: string) => {
return http.request<ResponseData<void>>("delete", `/system/menus/${menuId}`);
};
/** 菜单详情 */
export const getMenuInfoApi = (menuId: string) => {
return http.request<ResponseData<MenuDetailDTO>>(
"get",
`/system/menus/${menuId}`
);
};

137
src/api/system/monitor.ts Normal file
View File

@ -0,0 +1,137 @@
import { http } from "@/utils/http";
export interface OnlineUserQuery {
ipAddress: string;
username: string;
}
export interface OnlineUserInfo {
browser?: string;
deptName?: string;
ipAddress?: string;
loginLocation?: string;
loginTime?: number;
operationSystem?: string;
tokenId?: string;
username?: string;
}
/** 获取操作日志列表 */
export const getOnlineUserListApi = (params?: OnlineUserQuery) => {
return http.request<ResponseData<PageDTO<OnlineUserInfo>>>(
"get",
"/monitor/onlineUsers",
{
params
}
);
};
/** 强制登出用户 */
export const logoutOnlineUserApi = (tokenId: string) => {
return http.request<ResponseData<void>>(
"delete",
`/monitor/onlineUser/${tokenId}`
);
};
/**
* ServerInfo
*/
export interface ServerInfo {
cpuInfo?: CpuInfo;
diskInfos?: DiskInfo[];
jvmInfo?: JvmInfo;
memoryInfo?: MemoryInfo;
systemInfo?: SystemInfo;
}
/**
* CpuInfo
*/
export interface CpuInfo {
cpuNum?: number;
free?: number;
sys?: number;
total?: number;
used?: number;
wait?: number;
}
/**
* DiskInfo
*/
export interface DiskInfo {
dirName?: string;
free?: string;
sysTypeName?: string;
total?: string;
typeName?: string;
usage?: number;
used?: string;
}
/**
* JvmInfo
*/
export interface JvmInfo {
free?: number;
home?: string;
inputArgs?: string;
max?: number;
name?: string;
runTime?: string;
startTime?: string;
total?: number;
usage?: number;
used?: number;
version?: string;
}
/**
* MemoryInfo
*/
export interface MemoryInfo {
free?: number;
total?: number;
usage?: number;
used?: number;
}
/**
* SystemInfo
*/
export interface SystemInfo {
computerIp?: string;
computerName?: string;
osArch?: string;
osName?: string;
userDir?: string;
}
/** 获取服务器信息 */
export const getServerInfoApi = () => {
return http.request<ResponseData<ServerInfo>>("get", "/monitor/serverInfo");
};
/**
* RedisCacheInfoDTO
*/
export interface RedisCacheInfoDTO {
commandStats?: CommandStatusDTO[];
dbSize?: number;
info?: { [key: string]: string };
}
/**
* CommandStatusDTO
*/
export interface CommandStatusDTO {
name?: string;
value?: string;
}
/** 获取Redis信息 */
export const getCacheInfoApi = () => {
return http.request<ResponseData<ServerInfo>>("get", "/monitor/cacheInfo");
};

64
src/api/system/notice.ts Normal file
View File

@ -0,0 +1,64 @@
import { http } from "@/utils/http";
export interface SystemNoticeQuery extends BasePageQuery {
noticeType: string;
noticeTitle: string;
creatorName: string;
}
type SystemNoticeDTO = {
noticeId: string;
noticeTitle: string;
noticeType: number;
noticeContent: string;
status: number;
createTime: Date;
creatorName: string;
};
export type SystemNoticeRequest = {
noticeId?: number;
noticeTitle: string;
noticeType: number;
noticeContent: string;
status: number;
};
/** 获取系统通知列表 */
export const getSystemNoticeListApi = (params?: SystemNoticeQuery) => {
return http.request<ResponseData<PageDTO<SystemNoticeDTO>>>(
"get",
"/system/notices",
{
params
}
);
};
/** 添加系统通知 */
export const addSystemNoticeApi = (data: SystemNoticeRequest) => {
return http.request<ResponseData<void>>("post", "/system/notices", {
data
});
};
/** 修改系统通知 */
export const updateSystemNoticeApi = (data: SystemNoticeRequest) => {
return http.request<ResponseData<void>>(
"put",
`/system/notices/${data.noticeId}`,
{
data
}
);
};
/** 删除系统通知 */
export const deleteSystemNoticeApi = (data: Array<number>) => {
return http.request<ResponseData<void>>("delete", "/system/notices", {
params: {
// 需要将数组转换为字符串 否则Axios会将参数变成 noticeIds[0]:1 noticeIds[1]:2 这种格式,后端接收参数不成功
noticeIds: data.toString()
}
});
};

70
src/api/system/post.ts Normal file
View File

@ -0,0 +1,70 @@
import { http } from "@/utils/http";
export interface PostListCommand extends BasePageQuery {
postCode?: string;
postName?: string;
status?: number;
}
export interface PostPageResponse {
createTime: string;
postCode: string;
postId: number;
postName: string;
postSort: number;
remark: string;
status: number;
statusStr: string;
}
export function getPostListApi(params: PostListCommand) {
return http.request<ResponseData<PageDTO<PostPageResponse>>>(
"get",
"/system/post/list",
{
params
}
);
}
export const exportPostExcelApi = (
params: PostListCommand,
fileName: string
) => {
return http.download("/system/post/excel", fileName, {
params
});
};
export const deletePostApi = (data: Array<number>) => {
return http.request<ResponseData<void>>("delete", "/system/post", {
params: {
// 需要将数组转换为字符串 否则Axios会将参数变成 noticeIds[0]:1 noticeIds[1]:2 这种格式,后端接收参数不成功
ids: data.toString()
}
});
};
export interface AddPostCommand {
postCode: string;
postName: string;
postSort: number;
remark?: string;
status?: string;
}
export const addPostApi = (data: AddPostCommand) => {
return http.request<ResponseData<void>>("post", "/system/post", {
data
});
};
export interface UpdatePostCommand extends AddPostCommand {
postId: number;
}
export const updatePostApi = (data: UpdatePostCommand) => {
return http.request<ResponseData<void>>("put", "/system/post", {
data
});
};

65
src/api/system/role.ts Normal file
View File

@ -0,0 +1,65 @@
import { http } from "@/utils/http";
export interface RoleQuery extends BasePageQuery {
roleKey?: string;
roleName?: string;
status?: string;
timeRangeColumn?: string;
}
export interface RoleDTO {
createTime: Date;
dataScope: number;
remark: string;
roleId: number;
roleKey: string;
roleName: string;
roleSort: number;
selectedDeptList: number[];
selectedMenuList: number[];
status: number;
}
export function getRoleListApi(params: RoleQuery) {
return http.request<ResponseData<PageDTO<RoleDTO>>>(
"get",
"/system/role/list",
{
params
}
);
}
export function getRoleInfoApi(roleId: number) {
return http.request<ResponseData<RoleDTO>>("get", "/system/role/" + roleId);
}
export interface AddRoleCommand {
dataScope?: string;
menuIds: number[];
remark?: string;
roleKey: string;
roleName: string;
roleSort: number;
status?: string;
}
export function addRoleApi(data: AddRoleCommand) {
return http.request<void>("post", "/system/role", {
data
});
}
export interface UpdateRoleCommand extends AddRoleCommand {
roleId: number;
}
export function updateRoleApi(data: UpdateRoleCommand) {
return http.request<void>("put", "/system/role", {
data
});
}
export function deleteRoleApi(roleId: number) {
return http.request<void>("delete", "/system/role/" + roleId);
}

176
src/api/system/user.ts Normal file
View File

@ -0,0 +1,176 @@
import { http } from "@/utils/http";
export interface UserQuery extends BasePageQuery {
deptId?: number;
phoneNumber?: string;
status?: number;
userId?: number;
username?: string;
}
/**
* UserDTO
*/
export interface UserDTO {
avatar?: string;
createTime?: Date;
creatorId?: number;
creatorName?: string;
deptId?: number;
deptName?: string;
email?: string;
loginDate?: Date;
loginIp?: string;
nickname?: string;
phoneNumber?: string;
postId?: number;
remark?: string;
roleId?: number;
roleName?: string;
sex?: number;
status?: number;
updaterId?: number;
updaterName?: string;
updateTime?: Date;
userId?: number;
username?: string;
userType?: number;
}
/**
* AddUserCommand
*/
export interface UserRequest {
userId: number;
avatar?: string;
deptId?: number;
email?: string;
nickname?: string;
phoneNumber?: string;
password: string;
postId?: number;
remark?: string;
roleId?: number;
sex?: number;
status?: number;
username?: string;
}
/**
* UpdateProfileCommand
*/
export interface UserProfileRequest {
email?: string;
nickName?: string;
phoneNumber?: string;
sex?: number;
userId?: number;
}
/**
* ResetPasswordCommand
*/
export interface ResetPasswordRequest {
newPassword?: string;
oldPassword?: string;
userId?: number;
}
/**
*
*/
export interface PasswordRequest {
userId: number;
password: string;
}
/** 获取用户列表 */
export const getUserListApi = (params?: UserQuery) => {
return http.request<ResponseData<PageDTO<UserDTO>>>("get", "/system/users", {
params
});
};
/** 新增用户 */
export const addUserApi = (data?: UserRequest) => {
return http.request<ResponseData<void>>("post", "/system/users", {
data
});
};
/** 编辑用户 */
export const updateUserApi = (userId: number, data?: UserRequest) => {
return http.request<ResponseData<void>>("put", `/system/users/${userId}`, {
data
});
};
/** 更改用户密码 */
export const updateUserPasswordApi = (data?: PasswordRequest) => {
return http.request<ResponseData<void>>(
"put",
`/system/users/${data.userId}/password`,
{
data
}
);
};
/** 删除用户 */
export const deleteUserApi = (userId: number) => {
return http.request<ResponseData<void>>("delete", `/system/users/${userId}`);
};
/** 修改用户状态 */
export const updateUserStatusApi = (userId: number, status: number) => {
return http.request<ResponseData<PageDTO<UserDTO>>>(
"put",
`/system/users/${userId}/status`,
{
data: {
status: status
}
}
);
};
/** 批量导出用户 */
export const exportUserExcelApi = (params: UserQuery, fileName: string) => {
return http.download("/system/users/excel", fileName, {
params
});
};
/** 用户头像上传 */
export const uploadUserAvatarApi = data => {
return http.request<ResponseData<void>>(
"post",
"/system/user/profile/avatar",
{
data
},
{
headers: {
"Content-Type": "multipart/form-data"
}
}
);
};
/** 更改用户资料 */
export const updateUserProfileApi = (data?: UserProfileRequest) => {
return http.request<ResponseData<void>>("put", "/system/user/profile", {
data
});
};
/** 更改当前用户密码 */
export const updateCurrentUserPasswordApi = (data?: ResetPasswordRequest) => {
return http.request<ResponseData<void>>(
"put",
"/system/user/profile/password",
{
data
}
);
};

View File

@ -0,0 +1,26 @@
@font-face {
font-family: "iconfont"; /* Project id 2208059 */
src: url("iconfont.woff2?t=1671895108120") format("woff2"),
url("iconfont.woff?t=1671895108120") format("woff"),
url("iconfont.ttf?t=1671895108120") format("truetype");
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.pure-iconfont-tabs:before {
content: "\e63e";
}
.pure-iconfont-logo:before {
content: "\e620";
}
.pure-iconfont-new:before {
content: "\e615";
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,30 @@
{
"id": "2208059",
"name": "pure-admin",
"font_family": "iconfont",
"css_prefix_text": "pure-iconfont-",
"description": "pure-admin-iconfont",
"glyphs": [
{
"icon_id": "20594647",
"name": "Tabs",
"font_class": "tabs",
"unicode": "e63e",
"unicode_decimal": 58942
},
{
"icon_id": "22129506",
"name": "PureLogo",
"font_class": "logo",
"unicode": "e620",
"unicode_decimal": 58912
},
{
"icon_id": "7795615",
"name": "New",
"font_class": "new",
"unicode": "e615",
"unicode_decimal": 58901
}
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" class="icon" viewBox="0 0 1024 1024"><path fill="#386BF3" d="M410.558.109c0 210.974-300.876 361.752-300.876 633.548 0 174.943 134.704 316.787 300.876 316.787s300.877-141.817 300.877-316.787C711.408 361.752 410.558 210.974 410.558.109z"/><path fill="#C3D2FB" d="M613.469 73.665c0 211.055-300.877 361.914-300.877 633.547C312.592 882.156 447.296 1024 613.47 1024s300.876-141.817 300.876-316.788C914.29 435.58 613.469 284.72 613.469 73.665z"/><path fill="#303F5B" d="M312.592 707.212c0-183.713 137.636-312.171 226.723-441.39 81.702 106.112 172.12 218.74 172.12 367.726A309.755 309.755 0 0 1 420.36 950.064a323.114 323.114 0 0 1-107.769-242.852z"/></svg>

After

Width:  |  Height:  |  Size: 712 B

BIN
src/assets/login/bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 20 20"><g fill="none"><path d="M3 5a2 2 0 0 1 2-2h2a.5.5 0 0 1 0 1H5a1 1 0 0 0-1 1v2a.5.5 0 0 1-1 0V5zm9.5-1.5A.5.5 0 0 1 13 3h2a2 2 0 0 1 2 2v2a.5.5 0 0 1-1 0V5a1 1 0 0 0-1-1h-2a.5.5 0 0 1-.5-.5zm-9 9a.5.5 0 0 1 .5.5v2a1 1 0 0 0 1 1h2a.5.5 0 0 1 0 1H5a2 2 0 0 1-2-2v-2a.5.5 0 0 1 .5-.5zm13 0a.5.5 0 0 1 .5.5v2a2 2 0 0 1-2 2h-2a.5.5 0 0 1 0-1h2a1 1 0 0 0 1-1v-2a.5.5 0 0 1 .5-.5z" fill="currentColor"/></g></svg>

After

Width:  |  Height:  |  Size: 508 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24"><g fill="none"><path d="M8.5 3.75a.75.75 0 0 0-1.5 0v2.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 0 0 1.5h2.5A2.25 2.25 0 0 0 8.5 6.25v-2.5zm0 16.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 0-.75-.75h-2.5a.75.75 0 0 1 0-1.5h2.5a2.25 2.25 0 0 1 2.25 2.25v2.5zM16.25 3a.75.75 0 0 0-.75.75v2.5a2.25 2.25 0 0 0 2.25 2.25h2.5a.75.75 0 0 0 0-1.5h-2.5a.75.75 0 0 1-.75-.75v-2.5a.75.75 0 0 0-.75-.75zm-.75 17.25a.75.75 0 0 0 1.5 0v-2.5a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 0 0-1.5h-2.5a2.25 2.25 0 0 0-2.25 2.25v2.5z" fill="currentColor"/></g></svg>

After

Width:  |  Height:  |  Size: 631 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M2.88 18.054a35.897 35.897 0 0 1 8.531-16.32.8.8 0 0 1 1.178 0c.166.18.304.332.413.455a35.897 35.897 0 0 1 8.118 15.865c-2.141.451-4.34.747-6.584.874l-2.089 4.178a.5.5 0 0 1-.894 0l-2.089-4.178a44.019 44.019 0 0 1-6.584-.874zm6.698-1.123 1.157.066L12 19.527l1.265-2.53 1.157-.066a42.137 42.137 0 0 0 4.227-.454A33.913 33.913 0 0 0 12 4.09a33.913 33.913 0 0 0-6.649 12.387c1.395.222 2.805.374 4.227.454zM12 15a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></svg>

After

Width:  |  Height:  |  Size: 588 B

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