前端代码

This commit is contained in:
yvan 2026-08-13 22:35:13 +08:00
parent 9044bafdff
commit f1a0b17bb0
412 changed files with 36769 additions and 6617 deletions

3
.gitignore vendored
View File

@ -38,3 +38,6 @@ bin/
.cache/
.idea/
*.swp
web/dist/
web/node_modules/

21
LICENSE
View File

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

52
docs/ADMIN_BACKEND.md Normal file
View File

@ -0,0 +1,52 @@
# Kra 管理后台
## 范围
Kra 管理后台由 Kratos 应用承载生命周期Gin 提供兼容管理端的 HTTP 路由。后端按 `service -> biz -> data` 分层,前端位于 `web/`
保留的业务模块:
- 初始化、认证、用户和个人中心
- 角色、菜单、API、Casbin 和按钮权限
- 部门、岗位和数据范围
- 字典、字典项和系统参数
- 安全策略、系统配置和 API Token
- Excel 导入导出与版本管理
- 操作日志、登录日志、数据访问日志、错误日志和文件日志
- 定时任务、SSE、媒体上传和附件分类
- 公告管理与邮件发送
不包含代码生成、智能辅助、模块安装发布、客户示例和测试页面。
## 目录
| 目录 | 职责 |
|---|---|
| `internal/server` | Gin 路由、中间件和 Kratos transport 生命周期 |
| `internal/service` | HTTP DTO 与领域对象转换、用例编排 |
| `internal/biz` | 领域对象、业务规则和仓储接口 |
| `internal/data` | GORM、MySQL、Redis 和本地文件存储实现 |
| `web` | Vue 3 管理端 |
## 兼容约定
- HTTP 响应为 `{code, data, msg}`,成功码为 `0`
- JWT 接受 `x-token` Header 和同名 Cookie。
- 初始化创建后台数据表、管理员、菜单,并从 Gin 路由同步 API 权限数据。
- 超级管理员角色 `888` 保留全权限旁路,其他角色由 Casbin 控制。
- SMTP 配置位于 `admin.email`;未配置时错误邮件告警保持关闭。
- 媒体文件默认使用本地 `uploads/file` 存储。
## 验证
```bash
go generate ./cmd/kratos-admin
go test ./...
go vet ./...
go build ./...
cd web
pnpm install
pnpm run lint
pnpm run build
```

View File

@ -1,58 +0,0 @@
# GVA 管理后端迁移清单
## 基线与范围
- 参考基线:工作区 `gva/server`Git `02f37833`
- 目标:保留 GVA Vue 管理端使用的 HTTP 路径、方法、请求字段、统一响应结构和核心业务语义,同时按 Kratos 的 `service -> biz -> data` 分层落地。
- 明确排除:代码生成、代码生成历史、插件打包/安装、AI/LLM、MCP、Skills以及测试文件。
- 公告与邮件位于 `gva/server/plugin`;两者均已按 Kratos 分层迁移,不保留 GVA 的插件式全局变量结构。
- 推荐范围包含 177 个 GVA HTTP 路由,目标端全部覆盖;另增加 `GET /health`,目标实际注册路由总数为 178。
## 模块契约矩阵
| 模块 | 路由数 | 迁移内容 |
|---|---:|---|
| 初始化、登录、用户、个人中心 | 17 | 初始化、验证码、登录、JWT、用户 CRUD、多角色、个人资料、密码、菜单、注销 |
| 角色 | 9 | 角色树、创建、复制、更新、删除、用户关联、数据范围 |
| 菜单 | 10 | 菜单树、CRUD、角色菜单、菜单角色、菜单按钮 |
| API 与 Casbin | 19 | API CRUD/同步/忽略、角色 API、Casbin 策略、按钮权限 |
| 组织 | 16 | 部门树、岗位、用户关联、自定义数据范围 |
| 字典与参数 | 24 | 字典/字典项 CRUD、树、路径、导入导出、系统参数 |
| 安全、系统配置、API Token | 9 | 安全策略热更新、限流、锁定、密码策略、配置、服务器信息、Token 签发/作废 |
| Excel 导入导出 | 12 | 模板 CRUD、SQL 预览、一次性下载令牌、Excel 导入导出 |
| 版本管理 | 7 | 菜单/API/字典版本打包、记录、下载和导入 |
| 审计与日志 | 20 | 操作、登录、数据访问、错误日志以及安全的文件日志查看 |
| 定时任务与 SSE | 9 | Cron CRUD/启停/触发、HTTP/本地执行器、执行日志、失败告警 SSE |
| 媒体 | 15 | 文件库、附件分类、本地存储枚举、普通上传、秒传与分片续传 |
| 公告 | 8 | 公告 CRUD、批量删除、分页、发布者数据源和公开接口 |
| 邮件 | 2 | SMTP 测试、主动发送,以及失败请求邮件告警中间件 |
## 分层映射
| Kratos 层 | 职责 |
|---|---|
| `internal/server` | Gin 路由、鉴权/审计中间件、HTTP 请求绑定与响应写出、Kratos transport 生命周期 |
| `internal/service` | HTTP DTO 与领域数据的适配、用例编排 |
| `internal/biz` | 用户、权限、设置、审计、任务、媒体等领域对象、仓储接口与业务规则 |
| `internal/data` | GORM PO、MySQL 仓储、Redis/内存缓存、本地文件存储 |
| `cmd/kratos-admin` | Wire 依赖注入与 Kratos 应用组装 |
## 兼容性说明
- HTTP 响应保持 `{code, data, msg}`,成功码为 `0`
- JWT 继续接受 `x-token` Header 和同名 Cookie角色切换返回 `new-token`、`new-expires-at`。
- 初始化会自动迁移表、写入管理员与菜单,并从 Gin 实际路由同步 API 表。
- 超级管理员角色 `888` 保留全权限旁路;其他角色由 Casbin 策略控制。
- 代码中的 `*-gva` 字符串仅是原 Vue 图标库的图标标识为页面显示兼容而保留Go 文件、类型、变量和方法均使用实际职责命名。
- 当前首先实现 MySQL、Redis不可用时退化为进程缓存和本地文件存储云 OSS 驱动没有混入领域层。
- SMTP 参数位于 `admin.email`;未配置服务器、发件人或密钥时错误告警保持关闭,邮件接口会返回明确的配置错误。
## 验证命令
```bash
go generate ./cmd/kratos-admin
go test ./...
go vet ./...
go build ./...
git diff --check
```

1
gva

@ -1 +0,0 @@
Subproject commit 02f37833255e0e339c3d69199cb5a468f17de9fc

View File

@ -22,7 +22,7 @@ type announcementPO struct {
Attachments []byte `gorm:"type:json"`
}
func (announcementPO) TableName() string { return "gva_announcements_info" }
func (announcementPO) TableName() string { return "kra_announcements_info" }
type announcementRepo struct{ data *Data }

View File

@ -419,13 +419,13 @@ func defaultMenus() []menuPO {
}
return []menuPO{
{Path: "dashboard", Name: "dashboard", Component: "view/dashboard/index.vue", Title: "仪表盘", Icon: "odometer", Sort: 1},
root("permission", "permission", "权限管理", "perm-gva", 2), root("org", "org", "组织管理", "share", 3), root("systemConfig", "systemConfig", "系统设置", "config-gva", 4), root("monitor", "monitor", "运维监控", "monitor-gva", 5), root("media", "media", "媒体管理", "folder-opened", 6), root("plugin", "plugin", "插件系统", "cherry", 10),
root("permission", "permission", "权限管理", "perm-kra", 2), root("org", "org", "组织管理", "share", 3), root("systemConfig", "systemConfig", "系统设置", "config-kra", 4), root("monitor", "monitor", "运维监控", "monitor-kra", 5), root("media", "media", "媒体管理", "folder-opened", 6), root("extensions", "extensions", "扩展功能", "cherry", 10),
{Path: "person", Name: "person", Component: "view/person/person.vue", Title: "个人信息", Icon: "postcard", Hidden: true, Sort: 13},
child("permission", "authority", "authority", "view/superAdmin/authority/authority.vue", "角色管理", "role-gva", 1), child("permission", "menu", "menu", "view/superAdmin/menu/menu.vue", "菜单管理", "tickets", 2), child("permission", "api", "api", "view/superAdmin/api/api.vue", "api管理", "api-gva", 3), child("permission", "apiToken", "apiToken", "view/systemTools/apiToken/index.vue", "API Token", "key", 4),
child("permission", "authority", "authority", "view/superAdmin/authority/authority.vue", "角色管理", "role-kra", 1), child("permission", "menu", "menu", "view/superAdmin/menu/menu.vue", "菜单管理", "tickets", 2), child("permission", "api", "api", "view/superAdmin/api/api.vue", "api管理", "api-kra", 3), child("permission", "apiToken", "apiToken", "view/systemTools/apiToken/index.vue", "API Token", "key", 4),
child("org", "user", "user", "view/superAdmin/user/user.vue", "用户管理", "user", 1), child("org", "department", "department", "view/superAdmin/department/department.vue", "部门管理", "office-building", 2), child("org", "position", "position", "view/superAdmin/position/position.vue", "岗位管理", "postcard", 3),
child("systemConfig", "system", "system", "view/systemTools/system/system.vue", "配置文件", "config-file-gva", 1), child("systemConfig", "dictionary", "dictionary", "view/superAdmin/dictionary/sysDictionary.vue", "字典管理", "notebook", 2), child("systemConfig", "sysParams", "sysParams", "view/superAdmin/params/sysParams.vue", "参数管理", "set-up", 3), child("systemConfig", "security", "security", "view/system/security/index.vue", "安全配置", "security-gva", 4),
child("monitor", "operation", "operation", "view/superAdmin/operation/sysOperationRecord.vue", "操作历史", "document", 1), child("monitor", "loginLog", "loginLog", "view/systemTools/loginLog/index.vue", "登录日志", "clock", 2), child("monitor", "sysError", "sysError", "view/systemTools/sysError/sysError.vue", "错误日志", "error-gva", 3), child("monitor", "sysVersion", "sysVersion", "view/systemTools/version/version.vue", "版本管理", "version-gva", 4), child("monitor", "state", "state", "view/system/state.vue", "服务器状态", "server", 5), child("monitor", "dataAccessLog", "dataAccessLog", "view/superAdmin/dataAccessLog/dataAccessLog.vue", "数据权限审计", "warning", 6), child("monitor", "timedTask", "timedTask", "view/systemTools/timedTask/index.vue", "定时任务", "timer", 7), child("monitor", "logViewer", "logViewer", "view/systemTools/logViewer/index.vue", "文件日志", "document", 8),
child("systemConfig", "system", "system", "view/systemTools/system/system.vue", "配置文件", "config-file-kra", 1), child("systemConfig", "dictionary", "dictionary", "view/superAdmin/dictionary/sysDictionary.vue", "字典管理", "notebook", 2), child("systemConfig", "sysParams", "sysParams", "view/superAdmin/params/sysParams.vue", "参数管理", "set-up", 3), child("systemConfig", "security", "security", "view/system/security/index.vue", "安全配置", "security-kra", 4),
child("monitor", "operation", "operation", "view/superAdmin/operation/sysOperationRecord.vue", "操作历史", "document", 1), child("monitor", "loginLog", "loginLog", "view/systemTools/loginLog/index.vue", "登录日志", "clock", 2), child("monitor", "sysError", "sysError", "view/systemTools/sysError/sysError.vue", "错误日志", "error-kra", 3), child("monitor", "sysVersion", "sysVersion", "view/systemTools/version/version.vue", "版本管理", "version-kra", 4), child("monitor", "state", "state", "view/system/state.vue", "服务器状态", "server", 5), child("monitor", "dataAccessLog", "dataAccessLog", "view/superAdmin/dataAccessLog/dataAccessLog.vue", "数据权限审计", "warning", 6), child("monitor", "timedTask", "timedTask", "view/systemTools/timedTask/index.vue", "定时任务", "timer", 7), child("monitor", "logViewer", "logViewer", "view/systemTools/logViewer/index.vue", "文件日志", "document", 8),
child("media", "upload", "upload", "view/media/upload.vue", "媒体库(上传下载)", "upload", 1), child("media", "chunkUpload", "chunkUpload", "view/media/chunkUpload.vue", "大文件上传", "folder-add", 2),
child("plugin", "plugin-email", "plugin-email", "plugin/email/view/index.vue", "邮件插件", "message", 4), child("plugin", "anInfo", "anInfo", "plugin/announcement/view/info.vue", "公告管理[示例]", "bell", 5),
child("extensions", "email", "email", "modules/email/view/index.vue", "邮件发送", "message", 4), child("extensions", "anInfo", "anInfo", "modules/announcement/view/info.vue", "公告管理", "bell", 5),
}
}

View File

@ -216,15 +216,6 @@ func registerAuditRoutes(group, public *gin.RouterGroup, svc *service.AuditServi
}
writeResult(c, codeSuccess, pageResult{List: items, Total: total, Page: page, PageSize: size}, "获取成功")
})
errorsRoute.GET("/getSysErrorSolution", func(c *gin.Context) {
id, _ := strconv.ParseUint(c.Query("ID"), 10, 64)
item, err := svc.Error(c.Request.Context(), uint(id))
if err != nil {
fail(c, "查询失败")
return
}
writeResult(c, codeSuccess, gin.H{"solution": item["solution"]}, "获取成功")
})
public.Group("/sysError").POST("/createSysError", func(c *gin.Context) {
var req struct {
Form string `json:"form"`

View File

@ -1 +0,0 @@
module.exports = { extends: ['@commitlint/config-conventional'] };

View File

@ -0,0 +1,26 @@
server {
listen 8080;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /usr/share/nginx/html;
add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
try_files $uri $uri/ /index.html;
}
location /api {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
rewrite ^/api/(.*)$ /$1 break; #重写
proxy_pass http://177.7.0.12:8888; # 设置代理服务器的协议和地址
}
location /api/swagger/index.html {
proxy_pass http://127.0.0.1:8888/swagger/index.html;
}
}

View File

@ -0,0 +1,32 @@
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /usr/share/nginx/html/dist;
add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
try_files $uri $uri/ /index.html;
}
location /api {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
rewrite ^/api/(.*)$ /$1 break; #重写
proxy_pass http://127.0.0.1:8888; # 设置代理服务器的协议和地址
}
location /form-generator {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:8888;
}
location /api/swagger/index.html {
proxy_pass http://127.0.0.1:8888/swagger/index.html;
}
}

1
web/.dockerignore Normal file
View File

@ -0,0 +1 @@
node_modules/

View File

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

11
web/.env.development Normal file
View File

@ -0,0 +1,11 @@
ENV = 'development'
VITE_CLI_PORT = 8080
VITE_SERVER_PORT = 8000
VITE_BASE_API = /api
VITE_FILE_API = /api
VITE_BASE_PATH = http://127.0.0.1
VITE_POSITION = open
VITE_EDITOR = code
// VITE_EDITOR = webstorm 如果使用webstorm开发且要使用dom定位到代码行功能 请先自定添加 webstorm到环境变量 再将VITE_EDITOR值修改为webstorm
// 如果使用docker-compose开发模式设置为下面的地址或本机主机IP
//VITE_BASE_PATH = http://177.7.0.12

5
web/.env.production Normal file
View File

@ -0,0 +1,5 @@
ENV = 'production'
#下方为上线需要用到的程序代理前缀一般用于nginx代理转发
VITE_BASE_API = /api
VITE_FILE_API = /api

45
web/.gitignore vendored
View File

@ -1,41 +1,6 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
**/node_modules
# roadhog-api-doc ignore
/src/utils/request-temp.js
_roadhog-api-doc
# production
/dist
# misc
.DS_Store
npm-debug.log*
yarn-error.log
/coverage
.idea
yarn.lock
/node_modules/
/dist/
package-lock.json
*bak
.vscode
# visual studio code
.history
*.log
functions/*
.temp/**
# umi
.umi
.umi-production
.umi-test
.turbopack
# screenshot
screenshot
.firebase
build
yarn.lock
bun.lockb
config.yaml

View File

@ -1 +0,0 @@
npx --no -- commitlint --edit $1

View File

@ -1 +0,0 @@
lint-staged

View File

@ -1,5 +0,0 @@
{
"**/*.{js,jsx,tsx,ts,md,css,less,json}": [
"npx @biomejs/biome check --write"
]
}

View File

@ -1 +0,0 @@
legacy-peer-deps=true

12
web/.prettierrc Normal file
View File

@ -0,0 +1,12 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": true,
"arrowParens": "always",
"vueIndentScriptAndStyle": true,
"endOfLine": "lf"
}

24
web/Dockerfile Normal file
View File

@ -0,0 +1,24 @@
# 如果需要用 cicd ,请设置环境变量:
# variables:
# DOCKER_BUILDKIT: 1
FROM node:20-slim AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
COPY . /app
WORKDIR /app
FROM base AS prod-deps
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod
FROM base AS build
COPY --from=prod-deps /app/node_modules /app/node_modules
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install && pnpm run build
FROM nginx:alpine
COPY --from=base /app/.docker-compose/nginx/conf.d/my.conf /etc/nginx/conf.d/my.conf
COPY --from=build /app/dist /usr/share/nginx/html
RUN ls -al /usr/share/nginx/html

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2019-present Alipay.inc
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.

16
web/README.md Normal file
View File

@ -0,0 +1,16 @@
# Kra 管理后台
Kra 的 Vue 3 管理端,与仓库中的 Kratos + Gin 后端配套使用。
```bash
npm install
npm run dev
```
生产构建:
```bash
npm run build
```
开发环境默认把 `/api` 代理到 `http://127.0.0.1:8000`

13
web/babel.config.cjs Normal file
View File

@ -0,0 +1,13 @@
// Babel 配置
//
// 用 .cjs 而非 .js本项目 package.json 为 "type": "module".js 会被当作 ESM
// 而 @babel/eslint-parser 需要「同步」读取 babel 配置ESLint 是同步解析的),
// ESM 配置无法同步加载。.cjs 强制 CommonJS保证 eslint 能正常读取本文件。
//
// 目前主要供 @babel/eslint-parser 解析 .js / .vue<script> 使用;
// 如日后需要 babel 做实际转译,可直接复用这份 preset。
module.exports = {
presets: [
['@babel/preset-env', { targets: 'defaults' }]
]
}

View File

@ -1,49 +0,0 @@
{
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"files": {
"ignoreUnknown": true,
"includes": [
"**/*",
"!**/.umi",
"!**/.umi-production",
"!**/.umi-test",
"!**/.umi-test-production",
"!**/src/services",
"!**/mock",
"!**/dist",
"!**/server",
"!**/public",
"!**/coverage",
"!**/node_modules",
"!biome.json"
]
},
"formatter": {
"enabled": true,
"indentStyle": "space"
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"suspicious": {
"noExplicitAny": "off"
},
"correctness": {
"useUniqueElementIds": "off",
"useExhaustiveDependencies": "off"
},
"a11y": {
"noStaticElementInteractions": "off",
"useValidAnchor": "off",
"useKeyWithClickEvents": "off"
}
}
},
"javascript": {
"jsxRuntime": "reactClassic",
"formatter": {
"quoteStyle": "single"
}
}
}

View File

@ -1,157 +0,0 @@
// https://umijs.org/config/
import { defineConfig } from "@umijs/max";
import { join } from "node:path";
import defaultSettings from "./defaultSettings";
import proxy from "./proxy";
import routes from "./routes";
const { UMI_ENV = "dev" } = process.env;
/**
* @name 使
* @description
* @doc https://umijs.org/docs/api/config#publicpath
*/
const PUBLIC_PATH: string = "/";
export default defineConfig({
/**
* @name hash
* @description build hash
* @doc https://umijs.org/docs/api/config#hash
*/
hash: true,
publicPath: PUBLIC_PATH,
/**
* @name
* @description ie11 使
* @doc https://umijs.org/docs/api/config#targets
*/
// targets: {
// ie: 11,
// },
/**
* @name
* @description pathcomponentroutesredirectwrapperstitle
* @doc https://umijs.org/docs/guides/routes
*/
// umi routes: https://umijs.org/docs/routing
routes,
/**
* @name
* @description less
* @doc antd的主题设置 https://ant.design/docs/react/customize-theme-cn
* @doc umi theme https://umijs.org/docs/api/config#theme
*/
// theme: { '@primary-color': '#1DA57A' }
/**
* @name moment
* @description js的包大小
* @doc https://umijs.org/docs/api/config#ignoremomentlocale
*/
ignoreMomentLocale: true,
/**
* @name
* @description 访
* @see 使build 使
* @doc https://umijs.org/docs/guides/proxy
* @doc https://umijs.org/docs/api/config#proxy
*/
proxy: proxy[UMI_ENV as keyof typeof proxy],
/**
* @name
* @description state
*/
fastRefresh: true,
//============== 以下都是max的插件配置 ===============
/**
* @name
* @@doc https://umijs.org/docs/max/data-flow
*/
model: {},
/**
*
* @description Umi
* @doc https://umijs.org/docs/max/data-flow#%E5%85%A8%E5%B1%80%E5%88%9D%E5%A7%8B%E7%8A%B6%E6%80%81
*/
initialState: {},
/**
* @name layout
* @doc https://umijs.org/docs/max/layout-menu
*/
title: "Ant Design Pro",
layout: {
locale: true,
...defaultSettings,
},
/**
* @name moment2dayjs
* @description moment dayjs
* @doc https://umijs.org/docs/max/moment2dayjs
*/
moment2dayjs: {
preset: "antd",
plugins: ["duration"],
},
/**
* @name
* @doc https://umijs.org/docs/max/i18n
*/
locale: {
// default zh-CN
default: "zh-CN",
antd: true,
// default true, when it is true, will use `navigator.language` overwrite default
baseNavigator: true,
},
/**
* @name antd
* @description babel import
* @doc https://umijs.org/docs/max/antd#antd
*/
antd: {
appConfig: {},
configProvider: {
theme: {
token: {
fontFamily: "AlibabaSans, sans-serif",
},
},
},
},
/**
* @name
* @description axios ahooks useRequest
* @doc https://umijs.org/docs/max/request
*/
request: {},
/**
* @name
* @description initialState initialState
* @doc https://umijs.org/docs/max/access
*/
access: {},
/**
* @name <head> script
* @description <head> script
*/
headScripts: [
// 解决首次加载时白屏的问题
{ src: join(PUBLIC_PATH, "scripts/loading.js"), async: true },
],
//================ pro 插件配置 =================
presets: ["umi-presets-pro"],
mock: {
include: ["mock/**/*", "src/pages/**/_mock.ts"],
},
utoopack: {},
requestRecord: {},
exportStatic: {},
define: {
"process.env.CI": process.env.CI,
},
});

View File

@ -1,28 +0,0 @@
import type { ProLayoutProps } from '@ant-design/pro-components';
/**
* @name
*/
const Settings: ProLayoutProps & {
pwa?: boolean;
logo?: string;
} = {
navTheme: 'light',
// 拂晓蓝
colorPrimary: '#1890ff',
layout: 'mix',
contentWidth: 'Fluid',
fixedHeader: false,
fixSiderbar: true,
colorWeak: false,
title: 'Ant Design Pro',
pwa: true,
logo: 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg',
iconfontUrl: '',
token: {
// 参见ts声明demo 见文档通过token 修改样式
//https://procomponents.ant.design/components/layout#%E9%80%9A%E8%BF%87-token-%E4%BF%AE%E6%94%B9%E6%A0%B7%E5%BC%8F
},
};
export default Settings;

View File

@ -1,23 +0,0 @@
/**
* @name
* @see
* -------------------------------
* The agent cannot take effect in the production environment
* so there is no configuration of the production environment
* For details, please see
* https://pro.ant.design/docs/deploy
*
* @doc https://umijs.org/docs/guides/proxy
*/
export default {
/**
* @name
* @doc https://github.com/chimurai/http-proxy-middleware
*/
dev: {
"/v1/": {
target: "http://localhost:8000",
changeOrigin: true,
},
},
};

View File

@ -1,47 +0,0 @@
/**
* @name umi
* @description path,component,routes,redirect,wrappers,name,icon
* @param path path 第一种是动态参数 :id *
* @param component location path React src/pages
* @param routes layout 使
* @param redirect
* @param wrappers
* @param name menu.ts menu.xxxx name login menu.ts menu.login
* @param icon https://ant.design/components/icon-cn 注意去除风格后缀和大小写,如想要配置图标为 <StepBackwardOutlined /> 则取值应为 stepBackward 或 StepBackward如想要配置图标为 <UserOutlined /> 则取值应为 user 或者 User
* @doc https://umijs.org/docs/guides/routes
*/
export default [
{
path: "/user",
layout: false,
routes: [
{
name: "login",
path: "/user/login",
component: "./user/login",
},
],
},
{
path: "/welcome",
name: "welcome",
icon: "smile",
component: "./Welcome",
},
{
name: "admin",
icon: "crown",
path: "/admins",
access: "canAdmin",
component: "./admins",
},
{
path: "/",
redirect: "/welcome",
},
{
component: "404",
layout: false,
path: "./*",
},
];

83
web/eslint.config.mjs Normal file
View File

@ -0,0 +1,83 @@
/**
* ESLint 扁平配置flat config
*
* 解析链.js/.jsx 交给 @babel/eslint-parser babel.config.cjs.vue 顶层由
* vue-eslint-parser 解析 <template> <script> 再委托给 babel统一走 babel 而非默认
* espree是为了和项目 babel 工具链保持一致日后引入 espree 尚不支持的语法也无需换解析器
*/
import js from '@eslint/js'
import pluginVue from 'eslint-plugin-vue'
import globals from 'globals'
import babelParser from '@babel/eslint-parser'
import vueParser from 'vue-eslint-parser'
// .js 与 .vue<script> 复用的一份 babel 解析选项,改一处即两处生效,避免漂移
const BABEL_PARSER_OPTIONS = {
requireConfigFile: true, // 必须读到 babel.config.cjs缺失即报错杜绝悄悄回退到无配置
ecmaFeatures: { jsx: true } // 放开 JSX渲染函数 / 个别组件偶有用到
}
// 不参与检查的构建产物与静态资源
const IGNORE_GLOBS = ['**/dist/**', '**/build/*.js', '**/src/assets/**', '**/public/**']
export default [
// 基线规则集ESLint 官方推荐 + Vue3 基础必备,后面的块只在此之上做增量覆盖
js.configs.recommended,
...pluginVue.configs['flat/essential'],
// 纯脚本文件:整段交给 babel 解析
{
name: 'app/js-babel',
files: ['**/*.{js,mjs,jsx}'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
parser: babelParser,
parserOptions: BABEL_PARSER_OPTIONS,
globals: globals.node
}
},
// 单文件组件:顶层用 vue 解析器吃 <template><script> 再转交 babel
{
name: 'app/vue-babel',
files: ['**/*.vue'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
parser: vueParser,
parserOptions: { parser: babelParser, ...BABEL_PARSER_OPTIONS },
globals: globals.node
}
},
// CommonJS 配置文件(如 babel.config.cjs走 Node 环境,别把 module/require 判成未定义
{
name: 'app/commonjs',
files: ['**/*.cjs'],
languageOptions: {
sourceType: 'commonjs',
globals: globals.node
}
},
// 规则微调:只列与本项目习惯相冲、需显式放宽/收紧的项,其余沿用基线
{
name: 'app/rules',
files: ['**/*.{js,mjs,jsx,vue}'],
rules: {
'vue/max-attributes-per-line': 0, // 每行属性数不限,排版交给人工
'vue/no-v-model-argument': 0, // 允许 v-model:argEP 等组件写法)
'vue/multi-word-component-names': 'off', // 允许单词组件名(大量既有页面如此)
'no-lone-blocks': 'off', // 允许独立块级作用域
'no-extend-native': 'off', // 允许扩展原生原型(个别工具函数依赖)
'no-unused-vars': ['error', { argsIgnorePattern: '^_' }] // 未用变量报错;下划线前缀参数放行
}
},
// 忽略目录
{
name: 'app/files-to-ignore',
ignores: IGNORE_GLOBS
}
]

151
web/index.html Normal file
View File

@ -0,0 +1,151 @@
<!doctype html>
<html lang="zh-cn" class="transition-colors">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<meta
content="Kra,管理后台,Vue,Kratos,Gin"
name="keywords"
/>
<link rel="icon" href="/logo.svg" />
<title>Kra</title>
<script>
;(() => {
try {
// 必须与 THEME_SETTINGS_VERSION 保持一致:首屏防闪脚本无法 import 常量,
// 缓存形态为版本信封 { version, settings },版本不匹配时与 store 一样回落默认。
const VERSION = 1
const raw = localStorage.getItem('kra-theme-settings')
const parsed = raw ? JSON.parse(raw) : null
const settings =
parsed && parsed.version === VERSION && parsed.settings ? parsed.settings : null
const scheme = settings && settings.themeScheme ? settings.themeScheme : 'auto'
const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
const isDark = scheme === 'dark' || (scheme === 'auto' && prefersDark)
const root = document.documentElement
root.classList.toggle('dark', isDark)
root.classList.toggle('light', !isDark)
if (settings && settings.themeColor) root.style.setProperty('--64f90c3645474bd5', settings.themeColor)
} catch {}
})()
</script>
<style>
:root {
--64f90c3645474bd5: #2264f2;
/* 首屏 loading 背景/文字:默认浅色,与 App 的 bg-gray-50 对齐 */
--kra-loading-bg: #f9fafb;
--kra-loading-text: #6b7280;
}
/* 暗黑下与 App 的 dark:bg-slate-800 对齐,避免首屏 loading 白屏闪烁
class 由 head 内联 bootstrap 脚本在首次绘制前写入) */
html.dark {
--kra-loading-bg: #1e293b;
--kra-loading-text: #94a3b8;
}
html,
body {
background-color: var(--kra-loading-bg);
}
.transition-colors {
transition-property: color, background-color, border-color,
text-decoration-color, fill, stroke;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
body {
margin: 0;
}
#kra-loading-box {
position: relative;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
width: 100vw;
background-color: var(--kra-loading-bg);
}
#loading-text {
position: absolute;
bottom: calc(50% - 100px);
left: 0;
width: 100%;
text-align: center;
color: var(--kra-loading-text);
font-size: 14px;
}
#loading {
position: absolute;
top: calc(50% - 20px);
left: calc(50% - 20px);
}
@keyframes loader {
0% {
left: -100px;
}
100% {
left: 110%;
}
}
#box {
width: 50px;
height: 50px;
background: var(--64f90c3645474bd5);
animation: animate 0.5s linear infinite;
position: absolute;
top: 0;
left: 0;
border-radius: 3px;
}
@keyframes animate {
17% {
border-bottom-right-radius: 3px;
}
25% {
transform: translateY(9px) rotate(22.5deg);
}
50% {
transform: translateY(18px) scale(1, 0.9) rotate(45deg);
border-bottom-right-radius: 40px;
}
75% {
transform: translateY(9px) rotate(67.5deg);
}
100% {
transform: translateY(0) rotate(90deg);
}
}
#shadow {
width: 50px;
height: 5px;
background: #000;
opacity: 0.1;
position: absolute;
top: 59px;
left: 0;
border-radius: 50%;
animation: shadow 0.5s linear infinite;
}
.dark #shadow {
background: #fff;
}
@keyframes shadow {
50% {
transform: scale(1.2, 1);
}
}
</style>
</head>
<body>
<div id="kra-loading-box">
<div id="loading">
<div id="shadow"></div>
<div id="box"></div>
</div>
<div id="loading-text">系统正在加载中,请稍候...</div>
</div>
<div id="app"></div>
<script type="module" src="./src/main.js"></script>
</body>
</html>

View File

@ -1,21 +0,0 @@
import { configUmiAlias, createConfig } from '@umijs/max/test';
export default async (): Promise<any> => {
const config = await configUmiAlias({
...createConfig({
target: 'browser',
}),
});
return {
...config,
testEnvironmentOptions: {
...(config?.testEnvironmentOptions || {}),
url: 'http://localhost:8000',
},
setupFiles: [...(config.setupFiles || []), './tests/setupTests.jsx'],
globals: {
...config.globals,
localStorage: null,
},
};
};

10
web/jsconfig.json Normal file
View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"exclude": ["node_modules", "dist"],
"include": ["src/**/*"]
}

View File

@ -1,96 +1,74 @@
{
"name": "ant-design-pro",
"version": "6.0.0",
"name": "kra",
"version": "3.0.0",
"private": true,
"description": "An out-of-box UI solution for enterprise applications",
"repository": "git@github.com:ant-design/ant-design-pro.git",
"scripts": {
"analyze": "cross-env ANALYZE=1 max build",
"build": "max build",
"deploy": "npm run build && npm run gh-pages",
"dev": "npm run start:dev",
"gh-pages": "gh-pages -d dist",
"i18n-remove": "pro i18n-remove --locale=zh-CN --write",
"postinstall": "max setup",
"jest": "jest",
"lint": "npm run biome:lint && npm run tsc",
"lint-staged": "lint-staged",
"biome:lint": "npx @biomejs/biome lint",
"prepare": "husky",
"preview": "npm run build && max preview --port 8000",
"record": "cross-env NODE_ENV=development UMI_ENV=test max record --scene=login",
"serve": "umi-serve",
"start": "cross-env UMI_ENV=dev max dev",
"start:dev": "cross-env UMI_ENV=dev PORT=3000 MOCK=none max dev",
"start:no-mock": "cross-env MOCK=none max dev",
"start:pre": "cross-env UMI_ENV=pre MOCK=none max dev",
"start:test": "cross-env UMI_ENV=test MOCK=none max dev",
"test": "jest",
"test:coverage": "npm run jest -- --coverage",
"test:update": "npm run jest -- -u",
"tsc": "tsc --noEmit"
"dev": "vite --host --mode development",
"serve": "vite --host --mode development",
"build": "vite build --mode production",
"preview": "vite preview --host 0.0.0.0 --mode development",
"lint": "eslint .",
"lint:fix": "eslint . --fix"
},
"browserslist": ["defaults"],
"type": "module",
"dependencies": {
"@ant-design/icons": "^6.2.5",
"@ant-design/pro-components": "^3.1.12-0",
"antd": "^6.4.4",
"antd-style": "^4.1.0",
"classnames": "^2.5.1",
"dayjs": "^1.11.13",
"react": "^19.1.0",
"react-dom": "^19.1.0"
"@element-plus/icons-vue": "^2.3.1",
"@iconify/vue": "^5.0.0",
"@simple-prism/core": "^0.1.4",
"@unocss/transformer-directives": "^66.4.2",
"@vue-office/docx": "^1.6.2",
"@vue-office/excel": "^1.7.11",
"@vue-office/pdf": "^2.0.2",
"@vueuse/core": "^12.8.2",
"@vueuse/integrations": "^12.8.2",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
"arcdash": "^0.0.60",
"axios": "1.8.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"echarts": "5.5.1",
"element-plus": "^2.13.6",
"highlight.js": "^11.10.0",
"mitt": "^3.0.1",
"nprogress": "^0.2.0",
"pinia": "^2.2.2",
"qs": "^6.13.0",
"reka-ui": "^2.10.0",
"screenfull": "^6.0.2",
"sortablejs": "^1.15.3",
"spark-md5": "^3.0.2",
"tailwind-merge": "^3.6.0",
"universal-cookie": "^7",
"vite-auto-import-svg": "^2.9.8",
"vue": "^3.5.31",
"vue-cropper": "^1.1.4",
"vue-echarts": "^7.0.3",
"vue-qr": "^4.0.9",
"vue-router": "^4.4.3",
"vuedraggable": "^4.1.0"
},
"devDependencies": {
"@ant-design/pro-cli": "^3.3.0",
"@commitlint/cli": "^20.1.0",
"@commitlint/config-conventional": "^20.0.0",
"@testing-library/dom": "^10.4.0",
"@testing-library/react": "^16.3.0",
"@types/express": "^5.0.3",
"@types/jest": "^30.0.0",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@types/react-helmet": "^6.1.11",
"@umijs/lint": "^4.6.1",
"@umijs/max": "^4.6.2",
"cross-env": "^10.0.0",
"express": "^5.2.0",
"gh-pages": "^6.1.1",
"husky": "^9.1.7",
"jest": "^30.0.4",
"jest-environment-jsdom": "^30.0.5",
"lint-staged": "^16.1.2",
"mockjs": "^1.1.0",
"ts-node": "^10.9.2",
"typescript": "^5.6.3",
"umi-presets-pro": "^2.0.3",
"umi-serve": "^1.9.11",
"@biomejs/biome": "^2.1.1",
"@types/node": "^24.0.13"
},
"engines": {
"node": ">=20.0.0"
},
"create-umi": {
"ignoreScript": ["docker*", "functions*", "site", "generateMock"],
"ignoreDependencies": ["netlify*", "serverless"],
"ignore": [
".dockerignore",
".git",
".github",
".gitpod.yml",
"CODE_OF_CONDUCT.md",
"Dockerfile",
"Dockerfile.*",
"lambda",
"LICENSE",
"netlify.toml",
"README.*.md",
"azure-pipelines.yml",
"docker",
"CNAME",
"create-umi"
]
"@babel/core": "^7.25.0",
"@babel/eslint-parser": "^7.25.1",
"@babel/preset-env": "^7.25.0",
"@eslint/js": "^8.56.0",
"@unocss/extractor-svelte": "^66.4.2",
"@unocss/preset-wind3": "^66.4.2",
"@unocss/vite": "^66.5.0",
"@vitejs/plugin-vue": "^6.0.6",
"@vue/compiler-sfc": "^3.5.1",
"autoprefixer": "^10.4.20",
"chalk": "^5.3.0",
"chokidar": "^4.0.0",
"dotenv": "^16.4.5",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.19.2",
"globals": "^16.3.0",
"sass": "^1.78.0",
"vite": "^8.0.10",
"vite-check-multiple-dom": "0.2.1",
"vite-plugin-vue-devtools": "^8.1.1",
"vue-eslint-parser": "^9.4.3"
}
}

5340
web/pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

7
web/pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,7 @@
allowBuilds:
'@parcel/watcher': set this to true or false
'@vue-office/docx': set this to true or false
'@vue-office/excel': set this to true or false
'@vue-office/pdf': set this to true or false
es5-ext: set this to true or false
vue-demi: set this to true or false

View File

@ -1 +0,0 @@
preview.pro.ant.design

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -1 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" version="1.1" viewBox="0 0 200 200"><title>Group 28 Copy 5</title><desc>Created with Sketch.</desc><defs><linearGradient id="linearGradient-1" x1="62.102%" x2="108.197%" y1="0%" y2="37.864%"><stop offset="0%" stop-color="#4285EB"/><stop offset="100%" stop-color="#2EC7FF"/></linearGradient><linearGradient id="linearGradient-2" x1="69.644%" x2="54.043%" y1="0%" y2="108.457%"><stop offset="0%" stop-color="#29CDFF"/><stop offset="37.86%" stop-color="#148EFF"/><stop offset="100%" stop-color="#0A60FF"/></linearGradient><linearGradient id="linearGradient-3" x1="69.691%" x2="16.723%" y1="-12.974%" y2="117.391%"><stop offset="0%" stop-color="#FA816E"/><stop offset="41.473%" stop-color="#F74A5C"/><stop offset="100%" stop-color="#F51D2C"/></linearGradient><linearGradient id="linearGradient-4" x1="68.128%" x2="30.44%" y1="-35.691%" y2="114.943%"><stop offset="0%" stop-color="#FA8E7D"/><stop offset="51.264%" stop-color="#F74A5C"/><stop offset="100%" stop-color="#F51D2C"/></linearGradient></defs><g id="Page-1" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="logo" transform="translate(-20.000000, -20.000000)"><g id="Group-28-Copy-5" transform="translate(20.000000, 20.000000)"><g id="Group-27-Copy-3"><g id="Group-25" fill-rule="nonzero"><g id="2"><path id="Shape" fill="url(#linearGradient-1)" d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28.285908,101.993122 C27.1162831,100.824459 27.1162831,99.050775 28.285908,97.8821118 L98.0875359,28.1378823 C99.2571609,26.9692191 101.032305,26.9692191 102.20193,28.1378823 L129.985225,55.8983314 C134.193707,60.1033528 141.017005,60.1033528 145.225487,55.8983314 C149.433969,51.69331 149.433969,44.8756232 145.225487,40.6706018 L108.58055,4.05574592 C103.862049,-0.537986846 96.2692618,-0.500797906 91.5880863,4.17652823 Z"/><path id="Shape" fill="url(#linearGradient-2)" d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28.285908,101.993122 C27.1162831,100.824459 27.1162831,99.050775 28.285908,97.8821118 L98.0875359,28.1378823 C100.999864,25.6271836 105.751642,20.541824 112.729652,19.3524487 C117.915585,18.4685261 123.585219,20.4140239 129.738554,25.1889424 C125.624663,21.0784292 118.571995,14.0340304 108.58055,4.05574592 C103.862049,-0.537986846 96.2692618,-0.500797906 91.5880863,4.17652823 Z"/></g><path id="Shape" fill="url(#linearGradient-3)" d="M153.685633,135.854579 C157.894115,140.0596 164.717412,140.0596 168.925894,135.854579 L195.959977,108.842726 C200.659183,104.147384 200.659183,96.5636133 195.960527,91.8688194 L168.690777,64.7181159 C164.472332,60.5180858 157.646868,60.5241425 153.435895,64.7316526 C149.227413,68.936674 149.227413,75.7543607 153.435895,79.9593821 L171.854035,98.3623765 C173.02366,99.5310396 173.02366,101.304724 171.854035,102.473387 L153.685633,120.626849 C149.47715,124.83187 149.47715,131.649557 153.685633,135.854579 Z"/></g><ellipse id="Combined-Shape" cx="100.519" cy="100.437" fill="url(#linearGradient-4)" rx="23.6" ry="23.581"/></g></g></g></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" role="img" aria-label="Kra">
<rect width="128" height="128" rx="28" fill="#2264f2"/>
<path d="M34 26v76h16V72l33 30h22L65 64l38-38H82L50 59V26H34z" fill="#fff"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 235 B

View File

@ -1,5 +0,0 @@
<svg width="42" height="42" xmlns="http://www.w3.org/2000/svg">
<g>
<path fill="#070707" d="m6.717392,13.773912l5.6,0c2.8,0 4.7,1.9 4.7,4.7c0,2.8 -2,4.7 -4.9,4.7l-2.5,0l0,4.3l-2.9,0l0,-13.7zm2.9,2.2l0,4.9l1.9,0c1.6,0 2.6,-0.9 2.6,-2.4c0,-1.6 -0.9,-2.4 -2.6,-2.4l-1.9,0l0,-0.1zm8.9,11.5l2.7,0l0,-5.7c0,-1.4 0.8,-2.3 2.2,-2.3c0.4,0 0.8,0.1 1,0.2l0,-2.4c-0.2,-0.1 -0.5,-0.1 -0.8,-0.1c-1.2,0 -2.1,0.7 -2.4,2l-0.1,0l0,-1.9l-2.7,0l0,10.2l0.1,0zm11.7,0.1c-3.1,0 -5,-2 -5,-5.3c0,-3.3 2,-5.3 5,-5.3s5,2 5,5.3c0,3.4 -1.9,5.3 -5,5.3zm0,-2.1c1.4,0 2.2,-1.1 2.2,-3.2c0,-2 -0.8,-3.2 -2.2,-3.2c-1.4,0 -2.2,1.2 -2.2,3.2c0,2.1 0.8,3.2 2.2,3.2z" class="st0" id="Ant-Design-Pro"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 677 B

View File

@ -1,202 +0,0 @@
/**
* loading 占位
* 解决首次加载时白屏的问题
*/
(function () {
const _root = document.querySelector('#root');
if (_root && _root.innerHTML === '') {
_root.innerHTML = `
<style>
html,
body,
#root {
height: 100%;
margin: 0;
padding: 0;
}
#root {
background-repeat: no-repeat;
background-size: 100% auto;
}
.loading-title {
font-size: 1.1rem;
}
.loading-sub-title {
margin-top: 20px;
font-size: 1rem;
color: #888;
}
.page-loading-warp {
display: flex;
align-items: center;
justify-content: center;
padding: 26px;
}
.ant-spin {
position: absolute;
display: none;
-webkit-box-sizing: border-box;
box-sizing: border-box;
margin: 0;
padding: 0;
color: rgba(0, 0, 0, 0.65);
color: #1890ff;
font-size: 14px;
font-variant: tabular-nums;
line-height: 1.5;
text-align: center;
list-style: none;
opacity: 0;
-webkit-transition: -webkit-transform 0.3s
cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: -webkit-transform 0.3s
cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
-webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
-webkit-font-feature-settings: "tnum";
font-feature-settings: "tnum";
}
.ant-spin-spinning {
position: static;
display: inline-block;
opacity: 1;
}
.ant-spin-dot {
position: relative;
display: inline-block;
width: 20px;
height: 20px;
font-size: 20px;
}
.ant-spin-dot-item {
position: absolute;
display: block;
width: 9px;
height: 9px;
background-color: #1890ff;
border-radius: 100%;
-webkit-transform: scale(0.75);
-ms-transform: scale(0.75);
transform: scale(0.75);
-webkit-transform-origin: 50% 50%;
-ms-transform-origin: 50% 50%;
transform-origin: 50% 50%;
opacity: 0.3;
-webkit-animation: antspinmove 1s infinite linear alternate;
animation: antSpinMove 1s infinite linear alternate;
}
.ant-spin-dot-item:nth-child(1) {
top: 0;
left: 0;
}
.ant-spin-dot-item:nth-child(2) {
top: 0;
right: 0;
-webkit-animation-delay: 0.4s;
animation-delay: 0.4s;
}
.ant-spin-dot-item:nth-child(3) {
right: 0;
bottom: 0;
-webkit-animation-delay: 0.8s;
animation-delay: 0.8s;
}
.ant-spin-dot-item:nth-child(4) {
bottom: 0;
left: 0;
-webkit-animation-delay: 1.2s;
animation-delay: 1.2s;
}
.ant-spin-dot-spin {
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
-webkit-animation: antrotate 1.2s infinite linear;
animation: antRotate 1.2s infinite linear;
}
.ant-spin-lg .ant-spin-dot {
width: 32px;
height: 32px;
font-size: 32px;
}
.ant-spin-lg .ant-spin-dot i {
width: 14px;
height: 14px;
}
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
.ant-spin-blur {
background: #fff;
opacity: 0.5;
}
}
@-webkit-keyframes antSpinMove {
to {
opacity: 1;
}
}
@keyframes antSpinMove {
to {
opacity: 1;
}
}
@-webkit-keyframes antRotate {
to {
-webkit-transform: rotate(405deg);
transform: rotate(405deg);
}
}
@keyframes antRotate {
to {
-webkit-transform: rotate(405deg);
transform: rotate(405deg);
}
}
</style>
<div style="
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
min-height: 362px;
">
<div class="page-loading-warp">
<div class="ant-spin ant-spin-lg ant-spin-spinning">
<span class="ant-spin-dot ant-spin-dot-spin">
<i class="ant-spin-dot-item"></i>
<i class="ant-spin-dot-item"></i>
<i class="ant-spin-dot-item"></i>
<i class="ant-spin-dot-item"></i>
</span>
</div>
</div>
<div class="loading-title">
正在加载资源
</div>
<div class="loading-sub-title">
初次加载资源可能需要较多时间 请耐心等待
</div>
</div>
`;
}
})();

46
web/src/App.vue Normal file
View File

@ -0,0 +1,46 @@
<template>
<div
id="app"
class="bg-gray-50 text-slate-700 text-sm !dark:text-slate-500 dark:bg-slate-800"
>
<el-config-provider :locale="zhCn" v-bind="themeStore.elConfig">
<router-view />
<Application />
</el-config-provider>
</div>
</template>
<script setup>
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import Application from '@/components/application/index.vue'
import { useThemeStore } from '@/pinia'
const themeStore = useThemeStore()
defineOptions({
name: 'App'
})
</script>
<style lang="scss">
//
#app {
height: 100vh;
overflow: hidden;
font-weight: 400 !important;
}
.el-button {
font-weight: 400 !important;
}
.kra-body-h {
min-height: calc(100% - 3rem);
}
.kra-container {
height: calc(100% - 2.5rem);
}
.kra-container2 {
height: calc(100% - 2.5rem);
}
</style>

View File

@ -1,13 +0,0 @@
import type { Admin } from "@/services";
/**
* @see https://umijs.org/docs/max/access#access
* */
export default function access(
initialState: { currentUser?: Admin } | undefined,
) {
const { currentUser } = initialState ?? {};
return {
canAdmin: currentUser && currentUser.access === "admin",
};
}

206
web/src/api/api.js Normal file
View File

@ -0,0 +1,206 @@
import service from '@/utils/request'
// @Tags api
// @Summary 分页获取角色列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body modelInterface.PageInfo true "分页获取用户列表"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /api/getApiList [post]
// {
// page int
// pageSize int
// }
export const getApiList = (data) => {
return service({
url: '/api/getApiList',
method: 'post',
data
})
}
// @Tags Api
// @Summary 创建基础api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.CreateApiParams true "创建api"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /api/createApi [post]
export const createApi = (data) => {
return service({
url: '/api/createApi',
method: 'post',
data
})
}
// @Tags menu
// @Summary 根据id获取菜单
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.GetById true "根据id获取菜单"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /menu/getApiById [post]
export const getApiById = (data) => {
return service({
url: '/api/getApiById',
method: 'post',
data
})
}
// @Tags Api
// @Summary 更新api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.CreateApiParams true "更新api"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /api/updateApi [post]
export const updateApi = (data) => {
return service({
url: '/api/updateApi',
method: 'post',
data
})
}
// @Tags Api
// @Summary 更新api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.CreateApiParams true "更新api"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /api/setAuthApi [post]
export const setAuthApi = (data) => {
return service({
url: '/api/setAuthApi',
method: 'post',
data
})
}
// @Tags Api
// @Summary 获取所有的Api 不分页
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /api/getAllApis [post]
export const getAllApis = (data) => {
return service({
url: '/api/getAllApis',
method: 'post',
data
})
}
// @Tags Api
// @Summary 删除指定api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body dbModel.Api true "删除api"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /api/deleteApi [post]
export const deleteApi = (data) => {
return service({
url: '/api/deleteApi',
method: 'post',
data
})
}
// @Tags SysApi
// @Summary 删除选中Api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.IdsReq true "ID"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /api/deleteApisByIds [delete]
export const deleteApisByIds = (data) => {
return service({
url: '/api/deleteApisByIds',
method: 'delete',
data
})
}
// FreshCasbin
// @Tags SysApi
// @Summary 刷新casbin缓存
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{msg=string} "刷新成功"
// @Router /api/freshCasbin [get]
export const freshCasbin = () => {
return service({
url: '/api/freshCasbin',
method: 'get'
})
}
export const syncApi = () => {
return service({
url: '/api/syncApi',
method: 'get'
})
}
export const getApiGroups = () => {
return service({
url: '/api/getApiGroups',
method: 'get'
})
}
export const ignoreApi = (data) => {
return service({
url: '/api/ignoreApi',
method: 'post',
data
})
}
export const enterSyncApi = (data) => {
return service({
url: '/api/enterSyncApi',
method: 'post',
data
})
}
/**
* 获取拥有指定API权限的角色ID列表
* @param {string} path API路径
* @param {string} method 请求方法
* @returns {Promise<number[]>} 角色ID数组
*/
export const getApiRoles = (path, method) => {
return service({
url: '/api/getApiRoles',
method: 'get',
params: { path, method }
})
}
/**
* 全量覆盖某API关联的角色列表
* @param {Object} data
* @param {string} data.path API路径
* @param {string} data.method 请求方法
* @param {number[]} data.authorityIds 角色ID列表
* @returns {Promise}
*/
export const setApiRoles = (data) => {
return service({
url: '/api/setApiRoles',
method: 'post',
data
})
}

View File

@ -0,0 +1,26 @@
import service from '@/utils/request'
// 分类列表
export const getCategoryList = () => {
return service({
url: '/attachmentCategory/getCategoryList',
method: 'get',
})
}
// 添加/编辑分类
export const addCategory = (data) => {
return service({
url: '/attachmentCategory/addCategory',
method: 'post',
data
})
}
// 删除分类
export const deleteCategory = (data) => {
return service({
url: '/attachmentCategory/deleteCategory',
method: 'post',
data
})
}

122
web/src/api/authority.js Normal file
View File

@ -0,0 +1,122 @@
import service from '@/utils/request'
// @Router /authority/getAuthorityList [post]
export const getAuthorityList = (data) => {
return service({
url: '/authority/getAuthorityList',
method: 'post',
data
})
}
// @Summary 删除角色
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body {authorityId uint} true "删除角色"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /authority/deleteAuthority [post]
export const deleteAuthority = (data) => {
return service({
url: '/authority/deleteAuthority',
method: 'post',
data
})
}
// @Summary 创建角色
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.CreateAuthorityPatams true "创建角色"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /authority/createAuthority [post]
export const createAuthority = (data) => {
return service({
url: '/authority/createAuthority',
method: 'post',
data
})
}
// @Tags authority
// @Summary 拷贝角色
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.CreateAuthorityPatams true "拷贝角色"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"拷贝成功"}"
// @Router /authority/copyAuthority [post]
export const copyAuthority = (data) => {
return service({
url: '/authority/copyAuthority',
method: 'post',
data
})
}
// @Summary 设置角色数据范围(数据权限)
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body {authorityId:uint,dataScope:int} true "设置角色数据范围"
// @Router /authority/setDataScope [post]
export const setDataScope = (data) => {
return service({
url: '/authority/setDataScope',
method: 'post',
data
})
}
// @Summary 获取角色自定义部门集(数据权限第5档)
// @Router /authority/getDataScopeDepts [get]
export const getDataScopeDepts = (authorityId) => {
return service({
url: '/authority/getDataScopeDepts',
method: 'get',
params: { authorityId }
})
}
// @Summary 修改角色
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysAuthority true "修改角色"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"设置成功"}"
// @Router /authority/updateAuthority [put]
export const updateAuthority = (data) => {
return service({
url: '/authority/updateAuthority',
method: 'put',
data
})
}
/**
* 获取拥有指定角色的用户ID列表
* @param {number} authorityId 角色ID
* @returns {Promise<number[]>} 用户ID数组
*/
export const getUsersByAuthorityId = (authorityId) => {
return service({
url: '/authority/getUsersByAuthority',
method: 'get',
params: { authorityId }
})
}
/**
* 全量覆盖某角色关联的用户列表
* @param {Object} data
* @param {number} data.authorityId 角色ID
* @param {number[]} data.userIds 用户ID列表
* @returns {Promise}
*/
export const setRoleUsers = (data) => {
return service({
url: '/authority/setRoleUsers',
method: 'post',
data
})
}

View File

@ -0,0 +1,25 @@
import service from '@/utils/request'
export const getAuthorityBtnApi = (data) => {
return service({
url: '/authorityBtn/getAuthorityBtn',
method: 'post',
data
})
}
export const setAuthorityBtnApi = (data) => {
return service({
url: '/authorityBtn/setAuthorityBtn',
method: 'post',
data
})
}
export const canRemoveAuthorityBtnApi = (params) => {
return service({
url: '/authorityBtn/canRemoveAuthorityBtn',
method: 'post',
params
})
}

32
web/src/api/casbin.js Normal file
View File

@ -0,0 +1,32 @@
import service from '@/utils/request'
// @Tags authority
// @Summary 更改角色api权限
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.CreateAuthorityPatams true "更改角色api权限"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /casbin/UpdateCasbin [post]
export const UpdateCasbin = (data) => {
return service({
url: '/casbin/updateCasbin',
method: 'post',
data
})
}
// @Tags casbin
// @Summary 获取权限列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.CreateAuthorityPatams true "获取权限列表"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /casbin/getPolicyPathByAuthorityId [post]
export const getPolicyPathByAuthorityId = (data) => {
return service({
url: '/casbin/getPolicyPathByAuthorityId',
method: 'post',
data
})
}

View File

@ -0,0 +1,19 @@
import service from '@/utils/request'
// 分页获取数据权限审计日志 @Router /dataAccessLog/getDataAccessLogList [post]
export const getDataAccessLogList = (data) => {
return service({
url: '/dataAccessLog/getDataAccessLogList',
method: 'post',
data
})
}
// 批量删除数据权限审计日志 @Router /dataAccessLog/deleteDataAccessLogByIds [delete]
export const deleteDataAccessLogByIds = (data) => {
return service({
url: '/dataAccessLog/deleteDataAccessLogByIds',
method: 'delete',
data
})
}

64
web/src/api/department.js Normal file
View File

@ -0,0 +1,64 @@
import service from '@/utils/request'
// @Router /department/getDepartmentList [post]
export const getDepartmentList = (data) => {
return service({
url: '/department/getDepartmentList',
method: 'post',
data
})
}
// @Router /department/createDepartment [post]
export const createDepartment = (data) => {
return service({
url: '/department/createDepartment',
method: 'post',
data
})
}
// @Router /department/updateDepartment [put]
export const updateDepartment = (data) => {
return service({
url: '/department/updateDepartment',
method: 'put',
data
})
}
// @Router /department/deleteDepartment [delete]
export const deleteDepartment = (data) => {
return service({
url: '/department/deleteDepartment',
method: 'delete',
data
})
}
// @Router /department/findDepartment [get]
export const findDepartment = (params) => {
return service({
url: '/department/findDepartment',
method: 'get',
params
})
}
// 获取部门成员ID列表 @Router /department/getDepartmentUsers [get]
export const getDepartmentUsers = (params) => {
return service({
url: '/department/getDepartmentUsers',
method: 'get',
params
})
}
// 设置部门成员(反向分配) @Router /department/setDepartmentUsers [post]
export const setDepartmentUsers = (data) => {
return service({
url: '/department/setDepartmentUsers',
method: 'post',
data
})
}

14
web/src/api/email.js Normal file
View File

@ -0,0 +1,14 @@
import service from '@/utils/request'
// @Tags email
// @Summary 发送测试邮件
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
// @Router /email/emailTest [post]
export const emailTest = (data) => {
return service({
url: '/email/emailTest',
method: 'post',
data
})
}

View File

@ -0,0 +1,145 @@
import service from '@/utils/request'
// @Tags SysExportTemplate
// @Summary 创建导出模板
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysExportTemplate true "创建导出模板"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /sysExportTemplate/createSysExportTemplate [post]
export const createSysExportTemplate = (data) => {
return service({
url: '/sysExportTemplate/createSysExportTemplate',
method: 'post',
data
})
}
// @Tags SysExportTemplate
// @Summary 删除导出模板
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysExportTemplate true "删除导出模板"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysExportTemplate/deleteSysExportTemplate [delete]
export const deleteSysExportTemplate = (data) => {
return service({
url: '/sysExportTemplate/deleteSysExportTemplate',
method: 'delete',
data
})
}
// @Tags SysExportTemplate
// @Summary 批量删除导出模板
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.IdsReq true "批量删除导出模板"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysExportTemplate/deleteSysExportTemplate [delete]
export const deleteSysExportTemplateByIds = (data) => {
return service({
url: '/sysExportTemplate/deleteSysExportTemplateByIds',
method: 'delete',
data
})
}
// @Tags SysExportTemplate
// @Summary 更新导出模板
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysExportTemplate true "更新导出模板"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /sysExportTemplate/updateSysExportTemplate [put]
export const updateSysExportTemplate = (data) => {
return service({
url: '/sysExportTemplate/updateSysExportTemplate',
method: 'put',
data
})
}
// @Tags SysExportTemplate
// @Summary 用id查询导出模板
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query model.SysExportTemplate true "用id查询导出模板"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /sysExportTemplate/findSysExportTemplate [get]
export const findSysExportTemplate = (params) => {
return service({
url: '/sysExportTemplate/findSysExportTemplate',
method: 'get',
params
})
}
// @Tags SysExportTemplate
// @Summary 分页获取导出模板列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query request.PageInfo true "分页获取导出模板列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysExportTemplate/getSysExportTemplateList [get]
export const getSysExportTemplateList = (params) => {
return service({
url: '/sysExportTemplate/getSysExportTemplateList',
method: 'get',
params
})
}
// ExportExcel 导出表格token
// @Tags SysExportTemplate
// @Summary 导出表格
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Router /sysExportTemplate/exportExcel [get]
export const exportExcel = (params) => {
return service({
url: '/sysExportTemplate/exportExcel',
method: 'get',
params
})
}
// ExportTemplate 导出表格模板
// @Tags SysExportTemplate
// @Summary 导出表格模板
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Router /sysExportTemplate/exportTemplate [get]
export const exportTemplate = (params) => {
return service({
url: '/sysExportTemplate/exportTemplate',
method: 'get',
params
})
}
// PreviewSQL 预览最终生成的SQL
// @Tags SysExportTemplate
// @Summary 预览最终生成的SQL
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Router /sysExportTemplate/previewSQL [get]
// @Param templateID query string true "导出模板ID"
// @Param params query string false "查询参数编码字符串,参考 ExportExcel 组件"
export const previewSQL = (params) => {
return service({
url: '/sysExportTemplate/previewSQL',
method: 'get',
params
})
}

View File

@ -0,0 +1,67 @@
import service from '@/utils/request'
// @Tags FileUploadAndDownload
// @Summary 分页文件列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body modelInterface.PageInfo true "分页获取文件户列表"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /fileUploadAndDownload/getFileList [post]
export const getFileList = (data) => {
return service({
url: '/fileUploadAndDownload/getFileList',
method: 'post',
data
})
}
// @Tags FileUploadAndDownload
// @Summary 删除文件
// @Security ApiKeyAuth
// @Produce application/json
// @Param data body dbModel.FileUploadAndDownload true "传入文件里面id即可"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"返回成功"}"
// @Router /fileUploadAndDownload/deleteFile [post]
export const deleteFile = (data) => {
return service({
url: '/fileUploadAndDownload/deleteFile',
method: 'post',
data
})
}
/**
* 编辑文件名或者备注
* @param data
* @returns {*}
*/
export const editFileName = (data) => {
return service({
url: '/fileUploadAndDownload/editFileName',
method: 'post',
data
})
}
/**
* 导入URL
* @param data
* @returns {*}
*/
export const importURL = (data) => {
return service({
url: '/fileUploadAndDownload/importURL',
method: 'post',
data
})
}
// 上传文件 暂时用于头像上传
export const uploadFile = (data) => {
return service({
url: "/fileUploadAndDownload/upload",
method: "post",
data,
});
};

27
web/src/api/initdb.js Normal file
View File

@ -0,0 +1,27 @@
import service from '@/utils/request'
// @Tags InitDB
// @Summary 初始化用户数据库
// @Produce application/json
// @Param data body request.InitDB true "初始化数据库参数"
// @Success 200 {string} string "{"code":0,"data":{},"msg":"自动创建数据库成功"}"
// @Router /init/initdb [post]
export const initDB = (data) => {
return service({
url: '/init/initdb',
method: 'post',
data,
donNotShowLoading: true
})
}
// @Tags CheckDB
// @Summary 初始化用户数据库
// @Produce application/json
// @Success 200 {string} string "{"code":0,"data":{},"msg":"探测完成"}"
// @Router /init/checkdb [post]
export const checkDB = () => {
return service({
url: '/init/checkdb',
method: 'post'
})
}

14
web/src/api/jwt.js Normal file
View File

@ -0,0 +1,14 @@
import service from '@/utils/request'
// @Tags jwt
// @Summary jwt加入黑名单
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"拉黑成功"}"
// @Router /jwt/jsonInBlacklist [post]
export const jsonInBlacklist = () => {
return service({
url: '/jwt/jsonInBlacklist',
method: 'post'
})
}

34
web/src/api/logViewer.js Normal file
View File

@ -0,0 +1,34 @@
import service from '@/utils/request'
// @Summary 获取指定月份存在日志的日期
// @Router /logViewer/dates [get]
export const getLogDates = (params) => {
return service({
url: '/logViewer/dates',
method: 'get',
params,
donNotShowLoading: true
})
}
// @Summary 获取指定日期的日志文件
// @Router /logViewer/files [get]
export const getLogFiles = (params) => {
return service({
url: '/logViewer/files',
method: 'get',
params,
donNotShowLoading: true
})
}
// @Summary 分块读取日志文件内容
// @Router /logViewer/content [get]
export const getLogContent = (params) => {
return service({
url: '/logViewer/content',
method: 'get',
params,
donNotShowLoading: true
})
}

13
web/src/api/media.js Normal file
View File

@ -0,0 +1,13 @@
import service from '@/utils/request'
export const uploadInit = (data) =>
service({ url: '/mediaUpload/init', method: 'post', data })
export const uploadChunk = (formData, signal) =>
service({ url: '/mediaUpload/chunk', method: 'post', data: formData, signal, headers: { 'Content-Type': 'multipart/form-data' } })
export const uploadComplete = (data) =>
service({ url: '/mediaUpload/complete', method: 'post', data })
export const uploadCancel = (uploadId) =>
service({ url: `/mediaUpload/${uploadId}`, method: 'delete' })

141
web/src/api/menu.js Normal file
View File

@ -0,0 +1,141 @@
import service from '@/utils/request'
// @Summary 用户登录 获取动态路由
// @Produce application/json
// @Param 可以什么都不填 调一下即可
// @Router /menu/getMenu [post]
export const asyncMenu = () => {
return service({
url: '/menu/getMenu',
method: 'post'
})
}
// @Summary 获取menu列表
// @Produce application/json
// @Param {
// page int
// pageSize int
// }
// @Router /menu/getMenuList [post]
export const getMenuList = (data) => {
return service({
url: '/menu/getMenuList',
method: 'post',
data
})
}
// @Summary 新增基础menu
// @Produce application/json
// @Param menu Object
// @Router /menu/getMenuList [post]
export const addBaseMenu = (data) => {
return service({
url: '/menu/addBaseMenu',
method: 'post',
data
})
}
// @Summary 获取基础路由列表
// @Produce application/json
// @Param 可以什么都不填 调一下即可
// @Router /menu/getBaseMenuTree [post]
export const getBaseMenuTree = () => {
return service({
url: '/menu/getBaseMenuTree',
method: 'post'
})
}
// @Summary 添加用户menu关联关系
// @Produce application/json
// @Param menus Object authorityId string
// @Router /menu/getMenuList [post]
export const addMenuAuthority = (data) => {
return service({
url: '/menu/addMenuAuthority',
method: 'post',
data
})
}
// @Summary 获取用户menu关联关系
// @Produce application/json
// @Param authorityId string
// @Router /menu/getMenuAuthority [post]
export const getMenuAuthority = (data) => {
return service({
url: '/menu/getMenuAuthority',
method: 'post',
data
})
}
// @Summary 删除menu
// @Produce application/json
// @Param ID float64
// @Router /menu/deleteBaseMenu [post]
export const deleteBaseMenu = (data) => {
return service({
url: '/menu/deleteBaseMenu',
method: 'post',
data
})
}
// @Summary 修改menu列表
// @Produce application/json
// @Param menu Object
// @Router /menu/updateBaseMenu [post]
export const updateBaseMenu = (data) => {
return service({
url: '/menu/updateBaseMenu',
method: 'post',
data
})
}
// @Tags menu
// @Summary 根据id获取菜单
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.GetById true "根据id获取菜单"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /menu/getBaseMenuById [post]
export const getBaseMenuById = (data) => {
return service({
url: '/menu/getBaseMenuById',
method: 'post',
data
})
}
/**
* 获取拥有指定菜单的角色ID列表
* @param {number} menuId 菜单ID
* @returns {Promise<number[]>} 角色ID数组
*/
export const getMenuRoles = (menuId) => {
return service({
url: '/menu/getMenuRoles',
method: 'get',
params: { menuId }
})
}
/**
* 全量覆盖某菜单关联的角色列表
* @param {Object} data
* @param {number} data.menuId 菜单ID
* @param {number[]} data.authorityIds 角色ID列表
* @returns {Promise}
*/
export const setMenuRoles = (data) => {
return service({
url: '/menu/setMenuRoles',
method: 'post',
data
})
}

64
web/src/api/position.js Normal file
View File

@ -0,0 +1,64 @@
import service from '@/utils/request'
// @Router /position/getPositionList [post]
export const getPositionList = (data) => {
return service({
url: '/position/getPositionList',
method: 'post',
data
})
}
// @Router /position/createPosition [post]
export const createPosition = (data) => {
return service({
url: '/position/createPosition',
method: 'post',
data
})
}
// @Router /position/updatePosition [put]
export const updatePosition = (data) => {
return service({
url: '/position/updatePosition',
method: 'put',
data
})
}
// @Router /position/deletePosition [delete]
export const deletePosition = (data) => {
return service({
url: '/position/deletePosition',
method: 'delete',
data
})
}
// @Router /position/findPosition [get]
export const findPosition = (params) => {
return service({
url: '/position/findPosition',
method: 'get',
params
})
}
// 获取岗位成员ID列表 @Router /position/getPositionUsers [get]
export const getPositionUsers = (params) => {
return service({
url: '/position/getPositionUsers',
method: 'get',
params
})
}
// 设置岗位成员(反向分配) @Router /position/setPositionUsers [post]
export const setPositionUsers = (data) => {
return service({
url: '/position/setPositionUsers',
method: 'post',
data
})
}

View File

@ -0,0 +1,29 @@
import service from '@/utils/request'
// @Tags SecurityConfig
// @Summary 获取安全配置
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {object} response.Response{data=system.SysSecurityConfig,msg=string} "获取安全配置"
// @Router /securityConfig/getSecurityConfig [get]
export const getSecurityConfig = () => {
return service({
url: '/securityConfig/getSecurityConfig',
method: 'get'
})
}
// @Tags SecurityConfig
// @Summary 设置安全配置
// @Security ApiKeyAuth
// @Produce application/json
// @Param data body system.SysSecurityConfig true "安全配置"
// @Success 200 {object} response.Response{data=system.SysSecurityConfig,msg=string} "设置安全配置"
// @Router /securityConfig/setSecurityConfig [post]
export const setSecurityConfig = (data) => {
return service({
url: '/securityConfig/setSecurityConfig',
method: 'post',
data
})
}

View File

@ -0,0 +1,25 @@
import service from '@/utils/request'
export const createApiToken = (data) => {
return service({
url: '/sysApiToken/createApiToken',
method: 'post',
data
})
}
export const getApiTokenList = (data) => {
return service({
url: '/sysApiToken/getApiTokenList',
method: 'post',
data
})
}
export const deleteApiToken = (data) => {
return service({
url: '/sysApiToken/deleteApiToken',
method: 'post',
data
})
}

View File

@ -0,0 +1,112 @@
import service from '@/utils/request'
// @Tags SysDictionary
// @Summary 创建SysDictionary
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysDictionary true "创建SysDictionary"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysDictionary/createSysDictionary [post]
export const createSysDictionary = (data) => {
return service({
url: '/sysDictionary/createSysDictionary',
method: 'post',
data
})
}
// @Tags SysDictionary
// @Summary 删除SysDictionary
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysDictionary true "删除SysDictionary"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysDictionary/deleteSysDictionary [delete]
export const deleteSysDictionary = (data) => {
return service({
url: '/sysDictionary/deleteSysDictionary',
method: 'delete',
data
})
}
// @Tags SysDictionary
// @Summary 更新SysDictionary
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysDictionary true "更新SysDictionary"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /sysDictionary/updateSysDictionary [put]
export const updateSysDictionary = (data) => {
return service({
url: '/sysDictionary/updateSysDictionary',
method: 'put',
data
})
}
// @Tags SysDictionary
// @Summary 用id查询SysDictionary
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysDictionary true "用id查询SysDictionary"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /sysDictionary/findSysDictionary [get]
export const findSysDictionary = (params) => {
return service({
url: '/sysDictionary/findSysDictionary',
method: 'get',
params
})
}
// @Tags SysDictionary
// @Summary 分页获取SysDictionary列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.PageInfo true "分页获取SysDictionary列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysDictionary/getSysDictionaryList [get]
export const getSysDictionaryList = (params) => {
return service({
url: '/sysDictionary/getSysDictionaryList',
method: 'get',
params
})
}
// @Tags SysDictionary
// @Summary 导出字典JSON包含字典详情
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query model.SysDictionary true "字典ID"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"导出成功"}"
// @Router /sysDictionary/exportSysDictionary [get]
export const exportSysDictionary = (params) => {
return service({
url: '/sysDictionary/exportSysDictionary',
method: 'get',
params
})
}
// @Tags SysDictionary
// @Summary 导入字典JSON包含字典详情
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body object true "字典JSON数据"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"导入成功"}"
// @Router /sysDictionary/importSysDictionary [post]
export const importSysDictionary = (data) => {
return service({
url: '/sysDictionary/importSysDictionary',
method: 'post',
data
})
}

View File

@ -0,0 +1,145 @@
import service from '@/utils/request'
// @Tags SysDictionaryDetail
// @Summary 创建SysDictionaryDetail
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysDictionaryDetail true "创建SysDictionaryDetail"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysDictionaryDetail/createSysDictionaryDetail [post]
export const createSysDictionaryDetail = (data) => {
return service({
url: '/sysDictionaryDetail/createSysDictionaryDetail',
method: 'post',
data
})
}
// @Tags SysDictionaryDetail
// @Summary 删除SysDictionaryDetail
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysDictionaryDetail true "删除SysDictionaryDetail"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysDictionaryDetail/deleteSysDictionaryDetail [delete]
export const deleteSysDictionaryDetail = (data) => {
return service({
url: '/sysDictionaryDetail/deleteSysDictionaryDetail',
method: 'delete',
data
})
}
// @Tags SysDictionaryDetail
// @Summary 更新SysDictionaryDetail
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysDictionaryDetail true "更新SysDictionaryDetail"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /sysDictionaryDetail/updateSysDictionaryDetail [put]
export const updateSysDictionaryDetail = (data) => {
return service({
url: '/sysDictionaryDetail/updateSysDictionaryDetail',
method: 'put',
data
})
}
// @Tags SysDictionaryDetail
// @Summary 用id查询SysDictionaryDetail
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysDictionaryDetail true "用id查询SysDictionaryDetail"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /sysDictionaryDetail/findSysDictionaryDetail [get]
export const findSysDictionaryDetail = (params) => {
return service({
url: '/sysDictionaryDetail/findSysDictionaryDetail',
method: 'get',
params
})
}
// @Tags SysDictionaryDetail
// @Summary 分页获取SysDictionaryDetail列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.PageInfo true "分页获取SysDictionaryDetail列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysDictionaryDetail/getSysDictionaryDetailList [get]
export const getSysDictionaryDetailList = (params) => {
return service({
url: '/sysDictionaryDetail/getSysDictionaryDetailList',
method: 'get',
params
})
}
// @Tags SysDictionaryDetail
// @Summary 获取层级字典详情树形结构根据字典ID
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param sysDictionaryID query string true "字典ID"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysDictionaryDetail/getDictionaryTreeList [get]
export const getDictionaryTreeList = (params) => {
return service({
url: '/sysDictionaryDetail/getDictionaryTreeList',
method: 'get',
params
})
}
// @Tags SysDictionaryDetail
// @Summary 获取层级字典详情树形结构(根据字典类型)
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param dictType query string true "字典类型"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysDictionaryDetail/getDictionaryTreeListByType [get]
export const getDictionaryTreeListByType = (params) => {
return service({
url: '/sysDictionaryDetail/getDictionaryTreeListByType',
method: 'get',
params
})
}
// @Tags SysDictionaryDetail
// @Summary 根据父级ID获取字典详情
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param parentID query string true "父级ID"
// @Param includeChildren query boolean false "是否包含子级"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysDictionaryDetail/getDictionaryDetailsByParent [get]
export const getDictionaryDetailsByParent = (params) => {
return service({
url: '/sysDictionaryDetail/getDictionaryDetailsByParent',
method: 'get',
params
})
}
// @Tags SysDictionaryDetail
// @Summary 获取字典详情的完整路径
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param ID query string true "字典详情ID"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysDictionaryDetail/getDictionaryPath [get]
export const getDictionaryPath = (params) => {
return service({
url: '/sysDictionaryDetail/getDictionaryPath',
method: 'get',
params
})
}

View File

@ -0,0 +1,33 @@
import service from '@/utils/request'
export const deleteLoginLog = (data) => {
return service({
url: '/sysLoginLog/deleteLoginLog',
method: 'delete',
data
})
}
export const deleteLoginLogByIds = (data) => {
return service({
url: '/sysLoginLog/deleteLoginLogByIds',
method: 'delete',
data
})
}
export const getLoginLogList = (params) => {
return service({
url: '/sysLoginLog/getLoginLogList',
method: 'get',
params
})
}
export const findLoginLog = (params) => {
return service({
url: '/sysLoginLog/findLoginLog',
method: 'get',
params
})
}

View File

@ -0,0 +1,48 @@
import service from '@/utils/request'
// @Tags SysOperationRecord
// @Summary 删除SysOperationRecord
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysOperationRecord true "删除SysOperationRecord"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysOperationRecord/deleteSysOperationRecord [delete]
export const deleteSysOperationRecord = (data) => {
return service({
url: '/sysOperationRecord/deleteSysOperationRecord',
method: 'delete',
data
})
}
// @Tags SysOperationRecord
// @Summary 删除SysOperationRecord
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.IdsReq true "删除SysOperationRecord"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysOperationRecord/deleteSysOperationRecord [delete]
export const deleteSysOperationRecordByIds = (data) => {
return service({
url: '/sysOperationRecord/deleteSysOperationRecordByIds',
method: 'delete',
data
})
}
// @Tags SysOperationRecord
// @Summary 分页获取SysOperationRecord列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.PageInfo true "分页获取SysOperationRecord列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysOperationRecord/getSysOperationRecordList [get]
export const getSysOperationRecordList = (params) => {
return service({
url: '/sysOperationRecord/getSysOperationRecordList',
method: 'get',
params
})
}

111
web/src/api/sysParams.js Normal file
View File

@ -0,0 +1,111 @@
import service from '@/utils/request'
// @Tags SysParams
// @Summary 创建参数
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysParams true "创建参数"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /sysParams/createSysParams [post]
export const createSysParams = (data) => {
return service({
url: '/sysParams/createSysParams',
method: 'post',
data
})
}
// @Tags SysParams
// @Summary 删除参数
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysParams true "删除参数"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysParams/deleteSysParams [delete]
export const deleteSysParams = (params) => {
return service({
url: '/sysParams/deleteSysParams',
method: 'delete',
params
})
}
// @Tags SysParams
// @Summary 批量删除参数
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.IdsReq true "批量删除参数"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysParams/deleteSysParams [delete]
export const deleteSysParamsByIds = (params) => {
return service({
url: '/sysParams/deleteSysParamsByIds',
method: 'delete',
params
})
}
// @Tags SysParams
// @Summary 更新参数
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysParams true "更新参数"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /sysParams/updateSysParams [put]
export const updateSysParams = (data) => {
return service({
url: '/sysParams/updateSysParams',
method: 'put',
data
})
}
// @Tags SysParams
// @Summary 用id查询参数
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query model.SysParams true "用id查询参数"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /sysParams/findSysParams [get]
export const findSysParams = (params) => {
return service({
url: '/sysParams/findSysParams',
method: 'get',
params
})
}
// @Tags SysParams
// @Summary 分页获取参数列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query request.PageInfo true "分页获取参数列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysParams/getSysParamsList [get]
export const getSysParamsList = (params) => {
return service({
url: '/sysParams/getSysParamsList',
method: 'get',
params
})
}
// @Tags SysParams
// @Summary 不需要鉴权的参数接口
// @accept application/json
// @Produce application/json
// @Param data query systemReq.SysParamsSearch true "分页获取参数列表"
// @Success 200 {object} response.Response{data=object,msg=string} "获取成功"
// @Router /sysParams/getSysParam [get]
export const getSysParam = (params) => {
return service({
url: '/sysParams/getSysParam',
method: 'get',
params
})
}

55
web/src/api/system.js Normal file
View File

@ -0,0 +1,55 @@
import service from '@/utils/request'
// @Tags systrm
// @Summary 获取配置文件内容
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
// @Router /system/getSystemConfig [post]
export const getSystemConfig = () => {
return service({
url: '/system/getSystemConfig',
method: 'post'
})
}
// @Tags system
// @Summary 设置配置文件内容
// @Security ApiKeyAuth
// @Produce application/json
// @Param data body sysModel.System true
// @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
// @Router /system/setSystemConfig [post]
export const setSystemConfig = (data) => {
return service({
url: '/system/setSystemConfig',
method: 'post',
data
})
}
// @Tags system
// @Summary 获取服务器运行状态
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
// @Router /system/getServerInfo [post]
export const getSystemState = () => {
return service({
url: '/system/getServerInfo',
method: 'post',
donNotShowLoading: true
})
}
/**
* 重载服务
* @param data
* @returns {*}
*/
export const reloadSystem = (data) => {
return service({
url: '/system/reloadSystem',
method: 'post',
data
})
}

View File

@ -0,0 +1,110 @@
import service from '@/utils/request'
// @Tags SysError
// @Summary 创建错误日志
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body model.SysError true "创建错误日志"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /sysError/createSysError [post]
export const createSysError = (data) => {
return service({
url: '/sysError/createSysError',
method: 'post',
data
})
}
// @Tags SysError
// @Summary 删除错误日志
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body model.SysError true "删除错误日志"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysError/deleteSysError [delete]
export const deleteSysError = (params) => {
return service({
url: '/sysError/deleteSysError',
method: 'delete',
params
})
}
// @Tags SysError
// @Summary 批量删除错误日志
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body request.IdsReq true "批量删除错误日志"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysError/deleteSysError [delete]
export const deleteSysErrorByIds = (params) => {
return service({
url: '/sysError/deleteSysErrorByIds',
method: 'delete',
params
})
}
// @Tags SysError
// @Summary 更新错误日志
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body model.SysError true "更新错误日志"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /sysError/updateSysError [put]
export const updateSysError = (data) => {
return service({
url: '/sysError/updateSysError',
method: 'put',
data
})
}
// @Tags SysError
// @Summary 用id查询错误日志
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data query model.SysError true "用id查询错误日志"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /sysError/findSysError [get]
export const findSysError = (params) => {
return service({
url: '/sysError/findSysError',
method: 'get',
params
})
}
// @Tags SysError
// @Summary 分页获取错误日志列表
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data query request.PageInfo true "分页获取错误日志列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysError/getSysErrorList [get]
export const getSysErrorList = (params) => {
return service({
url: '/sysError/getSysErrorList',
method: 'get',
params
})
}
// @Tags SysError
// @Summary 不需要鉴权的错误日志接口
// @Accept application/json
// @Produce application/json
// @Param data query systemReq.SysErrorSearch true "分页获取错误日志列表"
// @Success 200 {object} response.Response{data=object,msg=string} "获取成功"
// @Router /sysError/getSysErrorPublic [get]
export const getSysErrorPublic = () => {
return service({
url: '/sysError/getSysErrorPublic',
method: 'get',
})
}

33
web/src/api/timedTask.js Normal file
View File

@ -0,0 +1,33 @@
import service from '@/utils/request'
export const createTimedTask = (data) => {
return service({ url: '/timedTask/createTimedTask', method: 'post', data })
}
export const updateTimedTask = (data) => {
return service({ url: '/timedTask/updateTimedTask', method: 'put', data })
}
export const deleteTimedTask = (data) => {
return service({ url: '/timedTask/deleteTimedTask', method: 'delete', data })
}
export const toggleTimedTask = (data) => {
return service({ url: '/timedTask/toggleTimedTask', method: 'post', data })
}
export const triggerTimedTask = (data) => {
return service({ url: '/timedTask/triggerTimedTask', method: 'post', data })
}
export const getTimedTaskList = (params) => {
return service({ url: '/timedTask/getTimedTaskList', method: 'get', params })
}
export const getTimedTaskLogList = (params) => {
return service({ url: '/timedTask/getTimedTaskLogList', method: 'get', params })
}
export const getRegisteredMethods = () => {
return service({ url: '/timedTask/getRegisteredMethods', method: 'get' })
}

205
web/src/api/user.js Normal file
View File

@ -0,0 +1,205 @@
import service from '@/utils/request'
// @Summary 用户登录
// @Produce application/json
// @Param data body {username:"string",password:"string"}
// @Router /base/login [post]
export const login = (data) => {
return service({
url: '/base/login',
method: 'post',
data: data
})
}
// @Summary 获取验证码
// @Produce application/json
// @Param data body {username:"string",password:"string"}
// @Router /base/captcha [post]
export const captcha = () => {
return service({
url: '/base/captcha',
method: 'post'
})
}
// @Summary 用户注册
// @Produce application/json
// @Param data body {username:"string",password:"string"}
// @Router /base/resige [post]
export const register = (data) => {
return service({
url: '/user/admin_register',
method: 'post',
data: data
})
}
// @Summary 修改密码
// @Produce application/json
// @Param data body {username:"string",password:"string",newPassword:"string"}
// @Router /user/changePassword [post]
export const changePassword = (data) => {
return service({
url: '/user/changePassword',
method: 'post',
data: data
})
}
// @Tags User
// @Summary 分页获取用户列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body modelInterface.PageInfo true "分页获取用户列表"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /user/getUserList [post]
export const getUserList = (data) => {
return service({
url: '/user/getUserList',
method: 'post',
data: data
})
}
// @Tags User
// @Summary 设置用户权限
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.SetUserAuth true "设置用户权限"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"修改成功"}"
// @Router /user/setUserAuthority [post]
export const setUserAuthority = (data) => {
return service({
url: '/user/setUserAuthority',
method: 'post',
data: data
})
}
// @Tags SysUser
// @Summary 删除用户
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.SetUserAuth true "删除用户"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}"
// @Router /user/deleteUser [delete]
export const deleteUser = (data) => {
return service({
url: '/user/deleteUser',
method: 'delete',
data: data
})
}
// @Tags SysUser
// @Summary 设置用户信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysUser true "设置用户信息"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}"
// @Router /user/setUserInfo [put]
export const setUserInfo = (data) => {
return service({
url: '/user/setUserInfo',
method: 'put',
data: data
})
}
// @Tags SysUser
// @Summary 设置用户信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysUser true "设置用户信息"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}"
// @Router /user/setSelfInfo [put]
export const setSelfInfo = (data) => {
return service({
url: '/user/setSelfInfo',
method: 'put',
data: data
})
}
// @Tags SysUser
// @Summary 设置自身界面配置
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysUser true "设置自身界面配置"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}"
// @Router /user/setSelfSetting [put]
export const setSelfSetting = (data) => {
return service({
url: '/user/setSelfSetting',
method: 'put',
data: data
})
}
// @Tags User
// @Summary 设置用户权限
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.setUserAuthorities true "设置用户权限"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"修改成功"}"
// @Router /user/setUserAuthorities [post]
export const setUserAuthorities = (data) => {
return service({
url: '/user/setUserAuthorities',
method: 'post',
data: data
})
}
// @Tags User
// @Summary 设置用户归属部门
// @Security ApiKeyAuth
// @Router /user/setUserDepartments [post]
export const setUserDepartments = (data) => {
return service({
url: '/user/setUserDepartments',
method: 'post',
data: data
})
}
// @Tags User
// @Summary 设置用户岗位
// @Security ApiKeyAuth
// @Router /user/setUserPositions [post]
export const setUserPositions = (data) => {
return service({
url: '/user/setUserPositions',
method: 'post',
data: data
})
}
// @Tags User
// @Summary 获取用户信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /user/getUserInfo [get]
export const getUserInfo = () => {
return service({
url: '/user/getUserInfo',
method: 'get'
})
}
export const resetPassword = (data) => {
return service({
url: '/user/resetPassword',
method: 'post',
data: data
})
}

114
web/src/api/version.js Normal file
View File

@ -0,0 +1,114 @@
import service from '@/utils/request'
// @Tags SysVersion
// @Summary 删除版本管理
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body model.SysVersion true "删除版本管理"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysVersion/deleteSysVersion [delete]
export const deleteSysVersion = (params) => {
return service({
url: '/sysVersion/deleteSysVersion',
method: 'delete',
params
})
}
// @Tags SysVersion
// @Summary 批量删除版本管理
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body request.IdsReq true "批量删除版本管理"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysVersion/deleteSysVersion [delete]
export const deleteSysVersionByIds = (params) => {
return service({
url: '/sysVersion/deleteSysVersionByIds',
method: 'delete',
params
})
}
// @Tags SysVersion
// @Summary 用id查询版本管理
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data query model.SysVersion true "用id查询版本管理"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /sysVersion/findSysVersion [get]
export const findSysVersion = (params) => {
return service({
url: '/sysVersion/findSysVersion',
method: 'get',
params
})
}
// @Tags SysVersion
// @Summary 分页获取版本管理列表
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data query request.PageInfo true "分页获取版本管理列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysVersion/getSysVersionList [get]
export const getSysVersionList = (params) => {
return service({
url: '/sysVersion/getSysVersionList',
method: 'get',
params
})
}
// @Tags SysVersion
// @Summary 导出版本数据
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body object true "导出版本数据"
// @Success 200 {string} string "{\"success\":true,\"data\":{},\"msg\":\"导出成功\"}"
// @Router /sysVersion/exportVersion [post]
export const exportVersion = (data) => {
return service({
url: '/sysVersion/exportVersion',
method: 'post',
data
})
}
// @Tags SysVersion
// @Summary 下载版本JSON数据
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param ID query string true "版本ID"
// @Success 200 {string} string "{\"success\":true,\"data\":{},\"msg\":\"下载成功\"}"
// @Router /sysVersion/downloadVersionJson [get]
export const downloadVersionJson = (params) => {
return service({
url: '/sysVersion/downloadVersionJson',
method: 'get',
params,
responseType: 'blob'
})
}
// @Tags SysVersion
// @Summary 导入版本数据
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body object true "版本JSON数据"
// @Success 200 {string} string "{\"success\":true,\"data\":{},\"msg\":\"导入成功\"}"
// @Router /sysVersion/importVersion [post]
export const importVersion = (data) => {
return service({
url: '/sysVersion/importVersion',
method: 'post',
data
})
}

View File

@ -1,143 +0,0 @@
import {
AvatarDropdown,
AvatarName,
Footer,
Question,
SelectLang,
} from "@/components";
import { type Admin, services } from "@/services";
import type { Settings as LayoutSettings } from "@ant-design/pro-components";
import { SettingDrawer } from "@ant-design/pro-components";
import type { RequestConfig, RunTimeLayoutConfig } from "@umijs/max";
import { history } from "@umijs/max";
import defaultSettings from "../config/defaultSettings";
import { errorConfig } from "./requestErrorConfig";
const isDev = process.env.NODE_ENV === "development";
const isDevOrTest = isDev || process.env.CI;
const loginPath = "/user/login";
/**
* @see https://umijs.org/docs/api/runtime-config#getinitialstate
* */
export async function getInitialState(): Promise<{
settings?: Partial<LayoutSettings>;
currentUser?: Admin;
loading?: boolean;
fetchUserInfo?: () => Promise<Admin | undefined>;
}> {
const fetchUserInfo = async () => {
try {
return await services.admin.Current({});
} catch {
// Redirecting on 401 is handled globally in requestErrorConfig.
return undefined;
}
};
// 如果不是登录页面,执行
const { location } = history;
if (
![loginPath, "/user/register", "/user/register-result"].includes(
location.pathname
)
) {
const currentUser = await fetchUserInfo();
return {
fetchUserInfo,
currentUser,
settings: defaultSettings as Partial<LayoutSettings>,
};
}
return {
fetchUserInfo,
settings: defaultSettings as Partial<LayoutSettings>,
};
}
// ProLayout 支持的api https://procomponents.ant.design/components/layout
export const layout: RunTimeLayoutConfig = ({
initialState,
setInitialState,
}) => {
return {
actionsRender: () => [
<Question key="doc" />,
<SelectLang key="SelectLang" />,
],
avatarProps: {
src: initialState?.currentUser?.avatar,
title: <AvatarName />,
render: (_, avatarChildren) => (
<AvatarDropdown>{avatarChildren}</AvatarDropdown>
),
},
waterMarkProps: {
content: initialState?.currentUser?.name,
},
footerRender: () => <Footer />,
onPageChange: () => {
const { location } = history;
// 如果没有登录,重定向到 login
if (!initialState?.currentUser && location.pathname !== loginPath) {
history.push(loginPath);
}
},
bgLayoutImgList: [
{
src: "https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/D2LWSqNny4sAAAAAAAAAAAAAFl94AQBr",
left: 85,
bottom: 100,
height: "303px",
},
{
src: "https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/C2TWRpJpiC0AAAAAAAAAAAAAFl94AQBr",
bottom: -68,
right: -45,
height: "303px",
},
{
src: "https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/F6vSTbj8KpYAAAAAAAAAAAAAFl94AQBr",
bottom: 0,
left: 0,
width: "331px",
},
],
links: [],
menuHeaderRender: undefined,
// 自定义 403 页面
// unAccessible: <div>unAccessible</div>,
// 增加一个 loading 的状态
childrenRender: (children) => {
// if (initialState?.loading) return <PageLoading />;
return (
<>
{children}
{isDevOrTest && (
<SettingDrawer
disableUrlParams
enableDarkTheme
settings={initialState?.settings}
onSettingChange={(settings) => {
setInitialState((preInitialState) => ({
...preInitialState,
settings,
}));
}}
/>
)}
</>
);
},
...initialState?.settings,
};
};
/**
* @name request
* axios ahooks useRequest
* @doc https://umijs.org/docs/max/request#配置
*/
export const request: RequestConfig = {
baseURL: isDev ? "" : "https://proapi.azurewebsites.net",
...errorConfig,
};

BIN
web/src/assets/404.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -0,0 +1,208 @@
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 1080 1350"
preserveAspectRatio="xMidYMid meet"
role="img" aria-label="KRA cover">
<!-- ════════════════════════════════════════════════
GIN Cover Redesign — SVG 版
品牌色 #2264f2 · viewBox 矢量缩放2K/4K 无损
字体JetBrains Mono页面已加载则自动继承
否则回退到系统等宽字体)
═════════════════════════════════════════════════ -->
<style>
text {
font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular,
'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;
}
.cursor { animation: blink 1.2s steps(1) infinite; }
@keyframes blink { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
.cursor { animation: none; }
}
</style>
<defs>
<!-- 整体圆角裁切(对应 overflow:hidden + border-radius:4px -->
<clipPath id="posterClip">
<rect x="0" y="0" width="1080" height="1350" rx="4"/>
</clipPath>
<!-- 细网格 30px -->
<pattern id="gridFine" width="30" height="30" patternUnits="userSpaceOnUse">
<path d="M 30 0 L 0 0 0 30" fill="none"
stroke="rgba(255,255,255,.07)" stroke-width="1"/>
</pattern>
<!-- 粗网格 150px -->
<pattern id="gridCoarse" width="150" height="150" patternUnits="userSpaceOnUse">
<path d="M 150 0 L 0 0 0 150" fill="none"
stroke="rgba(255,255,255,.12)" stroke-width="1"/>
</pattern>
<!-- 网格径向渐隐遮罩
mask: radial-gradient(85% 75% at 50% 45%, #000 30%, transparent 100%) -->
<radialGradient id="gridMaskGrad" gradientUnits="userSpaceOnUse"
cx="540" cy="607.5" r="918"
gradientTransform="translate(540 607.5) scale(1 1.103) translate(-540 -607.5)">
<stop offset="0%" stop-color="#ffffff"/>
<stop offset="30%" stop-color="#ffffff"/>
<stop offset="100%" stop-color="#000000"/>
</radialGradient>
<mask id="gridMask">
<rect x="0" y="0" width="1080" height="1350" fill="url(#gridMaskGrad)"/>
</mask>
<!-- 环境光斑
radial-gradient(50% 50%, rgba(120,165,255,.25), transparent 70%) -->
<radialGradient id="glowGrad">
<stop offset="0%" stop-color="rgba(120,165,255,.25)"/>
<stop offset="70%" stop-color="rgba(120,165,255,0)"/>
</radialGradient>
<!-- 编辑器卡片渐变
linear-gradient(160deg, rgba(10,24,64,.92), rgba(13,30,80,.88)) -->
<linearGradient id="editorGrad" x1="0" y1="0" x2="0.342" y2="0.94">
<stop offset="0%" stop-color="rgba(10,24,64,.92)"/>
<stop offset="100%" stop-color="rgba(13,30,80,.88)"/>
</linearGradient>
<!-- 编辑器投影:单层贴身软阴影(纯色块上不分层) -->
<filter id="editorShadow" x="-30%" y="-30%" width="160%" height="170%">
<feDropShadow dx="0" dy="20" stdDeviation="24"
flood-color="#08143c" flood-opacity="0.35"/>
</filter>
<!-- 基线水平渐变
linear-gradient(90deg, transparent, w40 20%, w40 80%, transparent) -->
<linearGradient id="baselineGrad" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="rgba(255,255,255,0)"/>
<stop offset="20%" stop-color="rgba(255,255,255,.4)"/>
<stop offset="80%" stop-color="rgba(255,255,255,.4)"/>
<stop offset="100%" stop-color="rgba(255,255,255,0)"/>
</linearGradient>
</defs>
<!-- ═══ 全部内容裁切在圆角画布内 ═══ -->
<g clip-path="url(#posterClip)">
<!-- ── 透明底:背景渐变已移除,元素直接叠在页面色块上 ── -->
<!-- ── 蓝图网格(细 + 粗,径向渐隐)── -->
<g mask="url(#gridMask)">
<rect x="0" y="0" width="1080" height="1350" fill="url(#gridFine)"/>
<rect x="0" y="0" width="1080" height="1350" fill="url(#gridCoarse)"/>
</g>
<!-- ── 环境光斑 ── -->
<ellipse cx="540" cy="540" rx="450" ry="250" fill="url(#glowGrad)"/>
<!-- ── 工程图角标26×261.5pxw40── -->
<path d="M 44 70 V 44 H 70" fill="none" stroke="rgba(255,255,255,.4)" stroke-width="1.5"/>
<path d="M 1010 44 H 1036 V 70" fill="none" stroke="rgba(255,255,255,.4)" stroke-width="1.5"/>
<path d="M 44 1280 V 1306 H 70" fill="none" stroke="rgba(255,255,255,.4)" stroke-width="1.5"/>
<path d="M 1010 1306 H 1036 V 1280" fill="none" stroke="rgba(255,255,255,.4)" stroke-width="1.5"/>
<!-- ── 顶部元信息行 ── -->
<text x="96" y="63" font-size="12.5" letter-spacing="2.75"
fill="rgba(255,255,255,.6)">KRA</text>
<text x="984" y="63" text-anchor="end" font-size="12.5" letter-spacing="2.75"
fill="rgba(255,255,255,.6)">KRA 3.0</text>
<!-- ── 中央视觉簇(标题 + 代码卡片 + 基线)整体下移 112px
使其落在画面光学中心附近 ── -->
<g transform="translate(0 112)">
<!-- ── 标题区 ── -->
<!-- [GIN] 主标92px / 700 / ls .04em -->
<text x="540" y="243" text-anchor="middle"
font-size="92" font-weight="700" letter-spacing="3.68"
fill="#ffffff"><tspan fill="rgba(255,255,255,.4)" font-weight="400">[</tspan>GIN<tspan fill="rgba(255,255,255,.4)" font-weight="400">]</tspan></text>
<!-- 副标HELLO, WORLD + 两侧短线 + 闪烁光标 -->
<line x1="365" y1="290" x2="421" y2="290"
stroke="rgba(255,255,255,.25)" stroke-width="1"/>
<text x="533" y="296" text-anchor="middle"
font-size="17" letter-spacing="5.78"
fill="rgba(255,255,255,.6)">HELLO, WORLD</text>
<rect class="cursor" x="633" y="280" width="9" height="19"
fill="rgba(255,255,255,.9)"/>
<line x1="660" y1="290" x2="716" y2="290"
stroke="rgba(255,255,255,.25)" stroke-width="1"/>
<!-- ── 主视觉代码编辑器窗口680×380── -->
<g filter="url(#editorShadow)">
<rect x="200" y="420" width="680" height="380" rx="14"
fill="url(#editorGrad)"
stroke="rgba(255,255,255,.25)" stroke-width="1"/>
</g>
<!-- 内侧 1px 高光 -->
<rect x="201.5" y="421.5" width="677" height="377" rx="13"
fill="none" stroke="rgba(255,255,255,.04)" stroke-width="1"/>
<!-- 标题栏 -->
<g>
<!-- 三个圆点 -->
<circle cx="228" cy="447" r="6" fill="rgba(255,255,255,.25)"/>
<circle cx="248" cy="447" r="6" fill="rgba(255,255,255,.25)"/>
<circle cx="268" cy="447" r="6" fill="rgba(255,255,255,.25)"/>
<!-- GO 徽标 -->
<rect x="290" y="437" width="33" height="20" rx="4"
fill="rgba(255,255,255,.12)"/>
<text x="306.5" y="451.5" text-anchor="middle"
font-size="11" font-weight="700" letter-spacing="0.9"
fill="rgba(255,255,255,.9)">GO</text>
<!-- 文件路径 -->
<text x="333" y="452" font-size="14" letter-spacing="0.7"
fill="rgba(255,255,255,.6)">images / GinVueAdmin.go</text>
<!-- 分隔线 -->
<line x1="201" y1="474" x2="879" y2="474"
stroke="rgba(255,255,255,.12)" stroke-width="1"/>
</g>
<!-- 代码区19px · 行距 44 -->
<g font-size="19">
<!-- 行号列 -->
<text x="270" y="530" text-anchor="end" fill="rgba(255,255,255,.25)">1</text>
<text x="270" y="574" text-anchor="end" fill="rgba(255,255,255,.25)">2</text>
<text x="270" y="618" text-anchor="end" fill="rgba(255,255,255,.25)">3</text>
<text x="270" y="662" text-anchor="end" fill="rgba(255,255,255,.25)">4</text>
<text x="270" y="706" text-anchor="end" fill="rgba(255,255,255,.25)">5</text>
<!-- 代码行 -->
<text x="298" y="530" xml:space="preserve"><tspan fill="#9db8ff">type</tspan><tspan fill="#ffffff" font-weight="500"> GinVueAdmin </tspan><tspan fill="#9db8ff">struct</tspan><tspan fill="rgba(220,230,255,.75)"> {</tspan></text>
<text x="298" y="574" xml:space="preserve"><tspan fill="#7fa5ff"> gorm.Model</tspan></text>
<text x="298" y="618" xml:space="preserve"><tspan fill="#e8eeff"> Name </tspan><tspan fill="#7fa5ff">string</tspan><tspan fill="rgba(190,208,255,.55)" font-style="italic"> `mapstructure:"name"`</tspan></text>
<text x="298" y="662" xml:space="preserve"><tspan fill="#e8eeff"> Version </tspan><tspan fill="#7fa5ff">string</tspan><tspan fill="rgba(190,208,255,.55)" font-style="italic"> `mapstructure:"version"`</tspan></text>
<text x="298" y="706" xml:space="preserve"><tspan fill="rgba(220,230,255,.75)">}</tspan></text>
</g>
<!-- ── 基线 + 尺寸标注 ── -->
<rect x="200" y="844" width="680" height="1" fill="url(#baselineGrad)"/>
<line x1="336" y1="839.5" x2="336" y2="850.5"
stroke="rgba(255,255,255,.4)" stroke-width="1"/>
<line x1="744" y1="839.5" x2="744" y2="850.5"
stroke="rgba(255,255,255,.4)" stroke-width="1"/>
<text x="540" y="872" text-anchor="middle"
font-size="11.5" letter-spacing="3.45"
fill="rgba(255,255,255,.4)">STRUCT · 5 LINES · UTF-8</text>
</g>
<!-- ── 中央视觉簇结束 ── -->
<!-- ── 底部信息 ── -->
<text x="96" y="1291" font-size="13" letter-spacing="2.34"
fill="rgba(255,255,255,.6)">GIN <tspan fill="rgba(255,255,255,.9)" font-weight="500">+</tspan> VUE <tspan fill="rgba(255,255,255,.9)" font-weight="500">+</tspan> GORM</text>
<!-- v2.x 胶囊徽标 -->
<rect x="911" y="1261" width="73" height="33" rx="16.5"
fill="none" stroke="rgba(255,255,255,.25)" stroke-width="1"/>
<text x="947.5" y="1282.5" text-anchor="middle"
font-size="13" letter-spacing="2.34"
fill="rgba(255,255,255,.6)">3.0</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="m18 16l4-4l-4-4M6 8l-4 4l4 4m8.5-12l-5 16"/></svg>

After

Width:  |  Height:  |  Size: 224 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024"><path fill="currentColor" d="M195.2 195.2a64 64 0 0 1 90.496 0L512 421.504L738.304 195.2a64 64 0 0 1 90.496 90.496L602.496 512L828.8 738.304a64 64 0 0 1-90.496 90.496L512 602.496L285.696 828.8a64 64 0 0 1-90.496-90.496L421.504 512L195.2 285.696a64 64 0 0 1 0-90.496"/></svg>

After

Width:  |  Height:  |  Size: 366 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M15 8a1 1 0 0 1-1-1V2a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8zm5 0v12a2 2 0 0 1-2 2h-4.182M3.305 19.53l.923-.382M4 10.592V4a2 2 0 0 1 2-2h8M4.228 16.852l-.924-.383m2.548-1.241l-.383-.923m.383 6.467l-.383.924m2.679-6.468l.383-.923m-.001 7.391l-.382-.924m1.625-3.92l.922-.383m-.922 2.679l.922.383"/><circle cx="7" cy="18" r="3"/></svg>

After

Width:  |  Height:  |  Size: 522 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0a2.34 2.34 0 0 0 3.319 1.915a2.34 2.34 0 0 1 2.33 4.033a2.34 2.34 0 0 0 0 3.831a2.34 2.34 0 0 1-2.33 4.033a2.34 2.34 0 0 0-3.319 1.915a2.34 2.34 0 0 1-4.659 0a2.34 2.34 0 0 0-3.32-1.915a2.34 2.34 0 0 1-2.33-4.033a2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915"/><circle cx="12" cy="12" r="3"/></svg>

After

Width:  |  Height:  |  Size: 541 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="m10.586 5.414l-5.172 5.172m13.172 2.828l-5.172 5.172M6 12h12"/><circle cx="12" cy="20" r="2"/><circle cx="12" cy="4" r="2"/><circle cx="20" cy="12" r="2"/><circle cx="4" cy="12" r="2"/></svg>

After

Width:  |  Height:  |  Size: 365 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Zm-3 7v4m0 4h.01"/></svg>

After

Width:  |  Height:  |  Size: 256 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><rect width="7" height="7" x="3" y="3" rx="1"/><rect width="7" height="7" x="14" y="3" rx="1"/><rect width="7" height="7" x="14" y="14" rx="1"/><rect width="7" height="7" x="3" y="14" rx="1"/></svg>

After

Width:  |  Height:  |  Size: 363 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M6.09 14.999a6.9 6.9 0 0 1-.59-2.794C5.5 8.5 8.41 5.499 12 5.499s6.5 3.002 6.5 6.706a6.9 6.9 0 0 1-.59 2.794m-5.91-13v1m10 9h-1m-18 0H2m17.07-7.071l-.707.707m-12.726.001l-.707-.707m9.587 14.377c1.01-.327 1.416-1.252 1.53-2.182c.034-.278-.195-.509-.475-.509H8.477a.483.483 0 0 0-.488.534c.112.928.394 1.606 1.464 2.156m5.064 0H9.453m5.064 0c-.121 1.945-.683 2.716-2.51 2.694c-1.954.036-2.404-.916-2.554-2.693"/></svg>

After

Width:  |  Height:  |  Size: 590 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M12 2a5 5 0 0 1 5 5v3a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H7a3 3 0 0 1-3-3v-6a3 3 0 0 1 3-3V7a5 5 0 0 1 5-5m0 12a2 2 0 0 0-1.995 1.85L10 16a2 2 0 1 0 2-2m0-10a3 3 0 0 0-3 3v3h6V7a3 3 0 0 0-3-3"/></svg>

After

Width:  |  Height:  |  Size: 307 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2"/></svg>

After

Width:  |  Height:  |  Size: 305 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="14" x="2" y="3" rx="2"/><path d="M8 21h8m-4-4v4"/></svg>

After

Width:  |  Height:  |  Size: 246 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/><path d="m9 12l2 2l4-4"/></svg>

After

Width:  |  Height:  |  Size: 370 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M16 3.128a4 4 0 0 1 0 7.744M22 21v-2a4 4 0 0 0-3-3.87"/><circle cx="9" cy="7" r="4"/></svg>

After

Width:  |  Height:  |  Size: 306 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>

After

Width:  |  Height:  |  Size: 264 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="8" x="2" y="2" rx="2" ry="2"/><rect width="20" height="8" x="2" y="14" rx="2" ry="2"/><path d="M6 6h.01M6 18h.01"/></svg>

After

Width:  |  Height:  |  Size: 311 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><path d="m8.59 13.51l6.83 3.98m-.01-10.98l-6.82 3.98"/></svg>

After

Width:  |  Height:  |  Size: 317 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M15 21v-5a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v5m8.774-10.69a1.12 1.12 0 0 0-1.549 0a2.5 2.5 0 0 1-3.451 0a1.12 1.12 0 0 0-1.548 0a2.5 2.5 0 0 1-3.452 0a1.12 1.12 0 0 0-1.549 0a2.5 2.5 0 0 1-3.77-3.248l2.889-4.184A2 2 0 0 1 7 2h10a2 2 0 0 1 1.653.873l2.895 4.192a2.5 2.5 0 0 1-3.774 3.244"/><path d="M4 10.95V19a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8.05"/></svg>

After

Width:  |  Height:  |  Size: 525 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M15 6a9 9 0 0 0-9 9V3"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/></svg>

After

Width:  |  Height:  |  Size: 264 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024"><path fill="currentColor" d="M928.99 755.83L574.6 203.25c-12.89-20.16-36.76-32.58-62.6-32.58s-49.71 12.43-62.6 32.58L95.01 755.83c-12.91 20.12-12.9 44.91.01 65.03c12.92 20.12 36.78 32.51 62.59 32.49h708.78c25.82.01 49.68-12.37 62.59-32.49s12.92-44.91.01-65.03M554.67 768h-85.33v-85.33h85.33zm0-426.67v298.66h-85.33V341.32z"/></svg>

After

Width:  |  Height:  |  Size: 423 B

4
web/src/assets/logo.svg Normal file
View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" role="img" aria-label="Kra">
<rect width="128" height="128" rx="28" fill="#2264f2"/>
<path d="M34 26v76h16V72l33 30h22L65 64l38-38H82L50 59V26H34z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 235 B

BIN
web/src/assets/noBody.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
web/src/assets/notFound.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

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