@ -0,0 +1,4 @@ |
|||
.github |
|||
.vscode/ |
|||
dist/ |
|||
node_modules/ |
|||
@ -0,0 +1 @@ |
|||
VITE_GLOB_APP_TITLE = Vite React TS Template |
|||
@ -0,0 +1,12 @@ |
|||
VITE_APP_BASE_API= |
|||
VITE_APP_HOMEPAGE=/dashboard/workbench |
|||
VITE_APP_BASE_PATH=/ |
|||
# VITE_GLOB_CLIENT_ID=react-admin-client |
|||
# VITE_GLOB_CLIENT_SECRET='' |
|||
# VITE_GLOB_SCOPE="openid email address phone profile offline_access miwen-abp-application" |
|||
# VITE_PROXY_API=http://192.168.31.246:30001 |
|||
|
|||
VITE_GLOB_CLIENT_ID=vue-admin-client |
|||
VITE_GLOB_CLIENT_SECRET=1q2w3e* |
|||
VITE_GLOB_SCOPE="openid email address phone profile offline_access lingyun-abp-application" |
|||
VITE_PROXY_API=http://124.223.5.95:30001 |
|||
@ -0,0 +1,3 @@ |
|||
VITE_APP_BASE_API=/api |
|||
VITE_APP_HOMEPAGE=/dashboard/workbench |
|||
VITE_APP_BASE_PATH=/ |
|||
@ -0,0 +1,28 @@ |
|||
# Logs |
|||
logs |
|||
*.log |
|||
npm-debug.log* |
|||
yarn-debug.log* |
|||
yarn-error.log* |
|||
pnpm-debug.log* |
|||
lerna-debug.log* |
|||
|
|||
node_modules |
|||
dist |
|||
dist-ssr |
|||
*.local |
|||
|
|||
# Editor directories and files |
|||
.idea |
|||
.DS_Store |
|||
*.suo |
|||
*.ntvs* |
|||
*.njsproj |
|||
*.sln |
|||
*.sw? |
|||
|
|||
# vite 打包分析产物 |
|||
stats.html |
|||
|
|||
# 取消上层忽略 |
|||
!.vscode/ |
|||
@ -0,0 +1,7 @@ |
|||
{ |
|||
"recommendations": [ |
|||
"biomejs.biome", |
|||
"bradlc.vscode-tailwindcss", |
|||
"lokalise.i18n-ally" |
|||
] |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
{ |
|||
"typescript.tsdk": "./node_modules/typescript/lib", |
|||
"editor.tabSize": 2, |
|||
"editor.formatOnSave": true, |
|||
"editor.codeActionsOnSave": { |
|||
"quickfix.biome": "explicit", |
|||
"source.organizeImports.biome": "explicit" |
|||
}, |
|||
"editor.quickSuggestions": { |
|||
"strings": "on" |
|||
}, |
|||
"tailwindCSS.experimental.classRegex": [ |
|||
["cn\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"] |
|||
], |
|||
"npm.packageManager": "pnpm", |
|||
"i18n-ally.localesPaths": ["src/locales/lang"], |
|||
"i18n-ally.enabledParsers": ["json"], |
|||
"i18n-ally.pathMatcher": "{locale}/{namespaces}.{ext}", |
|||
"i18n-ally.keystyle": "flat", |
|||
"i18n-ally.sortKeys": true, |
|||
"i18n-ally.sourceLanguage": "en_US", |
|||
"i18n-ally.displayLanguage": "zh_CN", |
|||
"[javascript]": { |
|||
"editor.defaultFormatter": "biomejs.biome" |
|||
}, |
|||
"[typescript]": { |
|||
"editor.defaultFormatter": "biomejs.biome" |
|||
}, |
|||
"[typescriptreact]": { |
|||
"editor.defaultFormatter": "biomejs.biome" |
|||
}, |
|||
"[json]": { |
|||
"editor.defaultFormatter": "biomejs.biome" |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
# Stage 1: build stage |
|||
FROM node:22-alpine as build-stage |
|||
# make the 'app' folder the current working directory |
|||
WORKDIR /app |
|||
# config node options |
|||
ENV NODE_OPTIONS=--max_old_space_size=8192 |
|||
# config pnpm, install dependencies |
|||
COPY package.json pnpm-lock.yaml* ./ |
|||
RUN npm install pnpm@9.x -g && \ |
|||
pnpm install --frozen-lockfile |
|||
# copy project files and folders to the current working directory (i.e. 'app' folder) |
|||
COPY . ./ |
|||
# build the project |
|||
RUN pnpm build |
|||
RUN echo "build successful 🎉 🎉 🎉" |
|||
|
|||
|
|||
# Stage 2: production stage |
|||
FROM nginx:latest as production-stage |
|||
COPY --from=build-stage /app/dist /usr/share/nginx/html |
|||
EXPOSE 80 |
|||
CMD ["nginx", "-g", "daemon off;"] |
|||
RUN echo "deploy to nginx successful 🎉 🎉 🎉" |
|||
|
|||
@ -0,0 +1,21 @@ |
|||
MIT License |
|||
|
|||
Copyright (c) 2023 d3george |
|||
|
|||
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. |
|||
@ -0,0 +1,132 @@ |
|||
<div align="center"> |
|||
<br> |
|||
<br> |
|||
<img src="./src/assets/images/logo.png" height="140" /> |
|||
<h3> Slash Admin </h3> |
|||
<p> |
|||
<p style="font-size: 14px"> |
|||
Slash Admin is a modern admin dashboard template built with React 18, Vite, Ant Design, and TypeScript. It is designed to help developers quickly create powerful admin management systems. |
|||
</p> |
|||
<br /> |
|||
<br /> |
|||
<a href="https://admin.slashspaces.com/">Preview</a> |
|||
· |
|||
<a href="https://discord.gg/fXemAXVNDa">Discord</a> |
|||
· |
|||
<a href="https://docs-admin.slashspaces.com/">Document</a> |
|||
<br /> |
|||
<br /> |
|||
<a href="https://trendshift.io/repositories/6387" target="_blank"><img src="https://trendshift.io/api/badge/repositories/6387" alt="d3george%2Fslash-admin | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a> |
|||
</div> |
|||
|
|||
**English** | [中文](./README.zh-CN.md) |
|||
|
|||
## Sponsor |
|||
<div style="display: flex; gap: 50px"> |
|||
<img style="width:300px" src="https://d3george.github.io/github-static/pay/weixin.jpg" > |
|||
<img style="width:280px" src="https://d3george.github.io/github-static/pay/buymeacoffee.png" /> |
|||
</div> |
|||
|
|||
## Preview |
|||
+ https://admin.slashspaces.com/ |
|||
|
|||
|| |
|||
| ----------------------------------------------------------------- | ------------------------------------------------------------------- | |
|||
|| |
|||
|
|||
## Features |
|||
|
|||
- Built using React 18 hooks. |
|||
- Powered by Vite for rapid development and hot module replacement. |
|||
- Integrates Ant Design, providing a rich set of UI components and design patterns. |
|||
- Written in TypeScript, offering type safety and an improved development experience. |
|||
- Responsive design, adapting to various screen sizes and devices. |
|||
- Flexible routing configuration, supporting nested routes. |
|||
- Integrated access control based on user roles. |
|||
- Supports internationalization for easy language switching. |
|||
- Includes common admin features like user management, role management, and permission management. |
|||
- Customizable themes and styles to meet your branding needs. |
|||
- Mocking solution based on MSW and Faker.js. |
|||
- State management using Zustand. |
|||
- Data fetching using React-Query. |
|||
|
|||
## Quick Start |
|||
|
|||
### Get the Project Code |
|||
|
|||
```bash |
|||
git clone https://github.com/d3george/slash-admin.git |
|||
``` |
|||
|
|||
### Install Dependencies |
|||
|
|||
In the project's root directory, run the following command to install project dependencies: |
|||
|
|||
```bash |
|||
pnpm install |
|||
``` |
|||
|
|||
### Start the Development Server |
|||
|
|||
Run the following command to start the development server: |
|||
|
|||
```bash |
|||
pnpm dev |
|||
``` |
|||
|
|||
Visit [http://localhost:3001](http://localhost:3001) to view your application. |
|||
|
|||
### Build for Production |
|||
|
|||
Run the following command to build the production version: |
|||
|
|||
```bash |
|||
pnpm build |
|||
``` |
|||
|
|||
## Docker deployment |
|||
|
|||
|
|||
### Build image and Run container |
|||
#### build image |
|||
Enter the project root directory in the terminal and execute the following command to build the Docker image: |
|||
``` |
|||
docker build -t your-image-name . |
|||
``` |
|||
Make sure to replace `your-image-name` with your own image name |
|||
|
|||
#### run container |
|||
Run your application in the Docker container using the following command: |
|||
``` |
|||
docker run -p 3001:80 your-image-name |
|||
``` |
|||
This will run your application on port `80`(exposed in `Dockerfile`) of the container and map it to port `3001` on your host. |
|||
|
|||
Now you can access http://localhost:3001 to view the deployed applications. |
|||
|
|||
### use docker-compose.yaml |
|||
Enter the project root directory in the terminal and execute the following command to start Docker Compose: |
|||
``` |
|||
docker-compose up -d |
|||
``` |
|||
Docker Compose will build an image based on the configuration defined by 'docker-compose. yaml' and run the container in the background. |
|||
|
|||
After the container runs successfully, it can also be accessed through http://localhost:3001 To view the deployed applications. |
|||
|
|||
|
|||
## Git Contribution submission specification |
|||
|
|||
reference[.commitlint.config.js](./commitlint.config.js) |
|||
|
|||
- `feat` new features |
|||
- `fix` fix the |
|||
- `docs` documentation or comments |
|||
- `style` code format (changes that do not affect code execution) |
|||
- `refactor` refactor |
|||
- `perf` performance optimization |
|||
- `revert` revert commit |
|||
- `test` test related |
|||
- `chore` changes in the construction process or auxiliary tools |
|||
- `ci` modify CI configuration and scripts |
|||
- `types` type definition file changes |
|||
- `wip` in development |
|||
@ -0,0 +1,131 @@ |
|||
<div align="center"> |
|||
<br> |
|||
<br> |
|||
<img src="./src/assets/images/logo.png" height="140" /> |
|||
<h3> Slash Admin </h3> |
|||
<p> |
|||
<p style="font-size: 14px"> |
|||
Slash Admin 是一款现代化的后台管理模板,基于 React 18、Vite、Ant Design 和 TypeScript 构建。它旨在帮助开发人员快速搭建功能强大的后台管理系统。 |
|||
</p> |
|||
<br /> |
|||
<br /> |
|||
<a href="https://admin.slashspaces.com/">Preview</a> |
|||
· |
|||
<a href="https://discord.gg/fXemAXVNDa">Discord</a> |
|||
· |
|||
<a href="https://docs-admin.slashspaces.com/">Document</a> |
|||
<br /> |
|||
<br /> |
|||
<a href="https://trendshift.io/repositories/6387" target="_blank"><img src="https://trendshift.io/api/badge/repositories/6387" alt="d3george%2Fslash-admin | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a> |
|||
</div> |
|||
|
|||
**中文** | [English](./README.md) |
|||
|
|||
## 赞助 |
|||
<div style="display: flex; gap: 50px"> |
|||
<img style="width:300px" src="https://d3george.github.io/github-static/pay/weixin.jpg" > |
|||
<img style="width:280px" src="https://d3george.github.io/github-static/pay/buymeacoffee.png" /> |
|||
</div> |
|||
|
|||
|
|||
## 预览 |
|||
+ https://admin.slashspaces.com/ |
|||
|
|||
|| |
|||
| ----------------------------------------------------------------- | ------------------------------------------------------------------- | |
|||
|| |
|||
## 特性 |
|||
|
|||
- 使用 React 18 hooks 进行构建。 |
|||
- 基于 Vite 进行快速开发和热模块替换。 |
|||
- 集成 Ant Design,提供丰富的 UI 组件和设计模式。 |
|||
- 使用 TypeScript 编写,提供类型安全性和更好的开发体验。 |
|||
- 响应式设计,适应各种屏幕尺寸和设备。 |
|||
- 灵活的路由配置,支持多级嵌套路由。 |
|||
- 集成权限管理,根据用户角色控制页面访问权限。 |
|||
- 集成国际化支持,轻松切换多语言。 |
|||
- 集成常见的后台管理功能,如用户管理、角色管理、权限管理等。 |
|||
- 可定制的主题和样式,以满足您的品牌需求。 |
|||
- 基于 MSW 和 Faker.js 的Mock方案 |
|||
- 使用 Zustand 进行状态管理 |
|||
- 使用 React-Query 进行数据获取 |
|||
|
|||
## 快速开始 |
|||
|
|||
### 获取项目代码 |
|||
|
|||
```bash |
|||
git clone https://github.com/d3george/slash-admin.git |
|||
``` |
|||
|
|||
### 安装依赖 |
|||
|
|||
在项目根目录下运行以下命令安装项目依赖: |
|||
|
|||
```bash |
|||
pnpm install |
|||
``` |
|||
|
|||
### 启动开发服务器 |
|||
|
|||
运行以下命令以启动开发服务器: |
|||
|
|||
```bash |
|||
pnpm dev |
|||
``` |
|||
|
|||
访问 [http://localhost:3001](http://localhost:3001) 查看您的应用程序。 |
|||
|
|||
### 构建生产版本 |
|||
|
|||
运行以下命令以构建生产版本: |
|||
|
|||
```bash |
|||
pnpm build |
|||
``` |
|||
|
|||
构建后的文件将位于 `dist` 目录中。 |
|||
|
|||
## 容器化部署 |
|||
|
|||
### 构建镜像并运行容器 |
|||
#### 构建镜像 |
|||
在终端中进入项目根目录,并执行以下命令来构建 Docker 镜像: |
|||
``` |
|||
docker build -t your-image-name . |
|||
``` |
|||
确保将 `your-image-name` 替换为你自己的镜像名称 |
|||
|
|||
#### 运行容器 |
|||
使用以下命令在 Docker 容器中运行你的应用: |
|||
``` |
|||
docker run -p 3001:80 your-image-name |
|||
``` |
|||
这将在容器的端口 `80` (暴露在`Dockerfile`中) 上运行你的应用,并将其映射到你主机的端口 `3001` 上。 |
|||
|
|||
现在,你可以通过访问 http://localhost:3001 来查看部署的应用。 |
|||
|
|||
|
|||
### 使用docker-compose.yaml |
|||
在终端中进入项目根目录,并执行以下命令来启动 Docker Compose: |
|||
``` |
|||
docker-compose up -d |
|||
``` |
|||
Docker Compose 根据`docker-compose.yaml`定义的配置构建镜像并在后台运行容器. |
|||
|
|||
容器运行成功后,同样可以通过访问 http://localhost:3001来查看部署的应用。 |
|||
|
|||
参考[.commitlint.config.js](./commitlint.config.js) |
|||
|
|||
- `feat` 新功能 |
|||
- `fix` 修复bug |
|||
- `docs` 文档注释 |
|||
- `style` 代码格式(不影响代码运行的变动) |
|||
- `refactor` 重构 |
|||
- `perf` 性能优化 |
|||
- `revert` 回滚commit |
|||
- `test` 测试相关 |
|||
- `chore` 构建过程或辅助工具的变动 |
|||
- `ci` 修改CI配置、脚本 |
|||
- `types` 类型定义文件修改 |
|||
- `wip` 开发中 |
|||
@ -0,0 +1,44 @@ |
|||
{ |
|||
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", |
|||
"vcs": { |
|||
"enabled": true, |
|||
"clientKind": "git", |
|||
"useIgnoreFile": true, |
|||
"defaultBranch": "main" |
|||
}, |
|||
"files": { |
|||
"ignoreUnknown": false, |
|||
"ignore": ["public", ".vscode", "src/api/gen"] |
|||
}, |
|||
"formatter": { |
|||
"enabled": true, |
|||
"lineWidth": 120, |
|||
"indentStyle": "tab" |
|||
}, |
|||
"organizeImports": { |
|||
"enabled": true |
|||
}, |
|||
"linter": { |
|||
"enabled": true, |
|||
"rules": { |
|||
"recommended": true, |
|||
"suspicious": { |
|||
"noExplicitAny": "off" |
|||
}, |
|||
"a11y": { |
|||
"useKeyWithClickEvents": "off" |
|||
}, |
|||
"complexity": { |
|||
"noForEach": "off" |
|||
}, |
|||
"correctness": { |
|||
"useExhaustiveDependencies": "off" |
|||
} |
|||
} |
|||
}, |
|||
"javascript": { |
|||
"formatter": { |
|||
"quoteStyle": "double" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
services: |
|||
slash: |
|||
build: |
|||
context: . |
|||
ports: |
|||
- "3001:80" |
|||
restart: always |
|||
@ -0,0 +1,13 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8" /> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
|||
<title>Slash Admin</title> |
|||
</head> |
|||
<body> |
|||
<noscript>You need to enable JavaScript to run this app.</noscript> |
|||
<div id="root"></div> |
|||
<script type="module" src="/src/main.tsx"></script> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,26 @@ |
|||
# SKIP CI in commit message to skip hooks |
|||
skip_output: |
|||
- meta |
|||
- success |
|||
- summary |
|||
|
|||
pre-commit: |
|||
parallel: true |
|||
commands: |
|||
format: |
|||
glob: "*.{js,jsx,ts,tsx,json,md}" |
|||
run: npx @biomejs/biome format --write --no-errors-on-unmatched {staged_files} |
|||
stage_fixed: true |
|||
lint: |
|||
glob: "*.{js,jsx,ts,tsx}" |
|||
run: npx @biomejs/biome lint --no-errors-on-unmatched {staged_files} |
|||
check-types: |
|||
glob: "*.{ts,tsx}" |
|||
run: npx tsc --noEmit |
|||
|
|||
commit-msg: |
|||
commands: |
|||
commitlint: |
|||
run: npx commitlint --edit {1} |
|||
# 允许空提交信息 |
|||
skip: merge|rebase |
|||
@ -0,0 +1,18 @@ |
|||
import { defineConfig } from "@hey-api/openapi-ts"; |
|||
import { defaultPlugins } from "@hey-api/openapi-ts"; |
|||
export default defineConfig({ |
|||
client: "@hey-api/client-axios", |
|||
input: "http://192.168.31.246:30001/swagger/v1/swagger.json", |
|||
output: { |
|||
format: "biome", |
|||
lint: "biome", |
|||
path: "src/api/gen", |
|||
}, |
|||
plugins: [ |
|||
...defaultPlugins, |
|||
{ |
|||
enums: "typescript", |
|||
name: "@hey-api/typescript", |
|||
}, |
|||
], |
|||
}); |
|||
@ -0,0 +1,117 @@ |
|||
{ |
|||
"name": "slash-admin", |
|||
"private": true, |
|||
"version": "0.0.0", |
|||
"type": "module", |
|||
"homepage": "https://github.com/d3george/slash-admin", |
|||
"scripts": { |
|||
"dev": "vite", |
|||
"build": "tsc && vite build", |
|||
"preview": "vite preview", |
|||
"preinstall": "lefthook install", |
|||
"gen-api": "openapi-ts" |
|||
}, |
|||
"dependencies": { |
|||
"@ant-design/cssinjs": "^1.17.2", |
|||
"@ant-design/icons": "^5.2.6", |
|||
"@ant-design/pro-table": "^3.18.3", |
|||
"@fullcalendar/common": "^5.11.5", |
|||
"@fullcalendar/core": "^6.1.9", |
|||
"@fullcalendar/daygrid": "^6.1.9", |
|||
"@fullcalendar/interaction": "^6.1.9", |
|||
"@fullcalendar/list": "^6.1.9", |
|||
"@fullcalendar/react": "^6.1.9", |
|||
"@fullcalendar/timegrid": "^6.1.9", |
|||
"@fullcalendar/timeline": "^6.1.9", |
|||
"@hey-api/client-axios": "^0.2.12", |
|||
"@iconify/react": "^4.1.1", |
|||
"@microsoft/signalr": "^8.0.7", |
|||
"@tanstack/react-query": "^5.50.1", |
|||
"@tanstack/react-query-devtools": "^5.50.1", |
|||
"@vanilla-extract/css": "^1.17.0", |
|||
"@vanilla-extract/vite-plugin": "^4.0.19", |
|||
"@vercel/analytics": "^1.2.2", |
|||
"@vitejs/plugin-react": "^4.1.0", |
|||
"antd": "^5.9.3", |
|||
"apexcharts": "^3.43.0", |
|||
"autosuggest-highlight": "^3.3.4", |
|||
"axios": "^1.5.1", |
|||
"classnames": "^2.3.2", |
|||
"clsx": "^2.1.1", |
|||
"color": "^4.2.3", |
|||
"dayjs": "^1.11.10", |
|||
"defu": "^6.1.4", |
|||
"framer-motion": "^10.16.4", |
|||
"highlight.js": "^11.9.0", |
|||
"i18next": "^23.5.1", |
|||
"i18next-browser-languagedetector": "^7.1.0", |
|||
"json-edit-react": "^1.19.2", |
|||
"nprogress": "^0.2.0", |
|||
"numeral": "^2.0.6", |
|||
"ramda": "^0.29.1", |
|||
"react": "18.2.0", |
|||
"react-apexcharts": "^1.4.1", |
|||
"react-beautiful-dnd": "^13.1.1", |
|||
"react-dom": "18.2.0", |
|||
"react-error-boundary": "^4.0.13", |
|||
"react-helmet-async": "^2.0.5", |
|||
"react-i18next": "^13.2.2", |
|||
"react-icons": "^4.11.0", |
|||
"react-markdown": "^8.0.7", |
|||
"react-organizational-chart": "^2.2.1", |
|||
"react-quill": "^2.0.0", |
|||
"react-router": "^7.0.2", |
|||
"react-use": "^17.4.0", |
|||
"rehype-highlight": "^6.0.0", |
|||
"rehype-raw": "^6.1.1", |
|||
"remark-gfm": "^3.0.1", |
|||
"reset-css": "^5.0.2", |
|||
"screenfull": "^6.0.2", |
|||
"simplebar-react": "^3.2.4", |
|||
"sonner": "^1.7.0", |
|||
"styled-components": "^6.0.9", |
|||
"tailwind-merge": "^2.5.4", |
|||
"zustand": "^4.4.3" |
|||
}, |
|||
"devDependencies": { |
|||
"@biomejs/biome": "1.9.4", |
|||
"@commitlint/cli": "^17.7.2", |
|||
"@commitlint/config-conventional": "^17.7.0", |
|||
"@faker-js/faker": "^8.1.0", |
|||
"@hey-api/openapi-ts": "^0.59.1", |
|||
"@types/autosuggest-highlight": "^3.2.0", |
|||
"@types/color": "^3.0.4", |
|||
"@types/nprogress": "^0.2.1", |
|||
"@types/numeral": "^2.0.3", |
|||
"@types/ramda": "^0.29.6", |
|||
"@types/react": "^18.2.28", |
|||
"@types/react-beautiful-dnd": "^13.1.6", |
|||
"@types/react-dom": "^18.2.13", |
|||
"@types/styled-components": "^5.1.28", |
|||
"autoprefixer": "^10.4.16", |
|||
"axios-mock-adapter": "^2.1.0", |
|||
"lefthook": "^1.8.2", |
|||
"msw": "^2.4.9", |
|||
"postcss": "^8.4.31", |
|||
"postcss-import": "^15.1.0", |
|||
"postcss-nesting": "^11.3.0", |
|||
"rollup-plugin-visualizer": "^5.9.2", |
|||
"tailwindcss": "^3.3.3", |
|||
"ts-node": "^10.9.1", |
|||
"typescript": "^5.2.2", |
|||
"vite": "^5.4.9", |
|||
"vite-plugin-svg-icons": "^2.0.1", |
|||
"vite-tsconfig-paths": "^5.0.1", |
|||
"vitest": "^2.1.8" |
|||
}, |
|||
"engines": { |
|||
"node": "20.*" |
|||
}, |
|||
"packageManager": "pnpm@9.1.0", |
|||
"msw": { |
|||
"workerDirectory": "public" |
|||
}, |
|||
"commitlint": { |
|||
"extends": ["@commitlint/config-conventional"] |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
export default { |
|||
plugins: { |
|||
"postcss-import": {}, |
|||
"tailwindcss/nesting": "postcss-nesting", |
|||
tailwindcss: {}, |
|||
autoprefixer: {}, |
|||
}, |
|||
}; |
|||
@ -0,0 +1,295 @@ |
|||
/* eslint-disable */ |
|||
/* tslint:disable */ |
|||
|
|||
/** |
|||
* Mock Service Worker. |
|||
* @see https://github.com/mswjs/msw
|
|||
* - Please do NOT modify this file. |
|||
* - Please do NOT serve this file on production. |
|||
*/ |
|||
|
|||
const PACKAGE_VERSION = '2.6.4' |
|||
const INTEGRITY_CHECKSUM = 'ca7800994cc8bfb5eb961e037c877074' |
|||
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse') |
|||
const activeClientIds = new Set() |
|||
|
|||
self.addEventListener('install', function () { |
|||
self.skipWaiting() |
|||
}) |
|||
|
|||
self.addEventListener('activate', function (event) { |
|||
event.waitUntil(self.clients.claim()) |
|||
}) |
|||
|
|||
self.addEventListener('message', async function (event) { |
|||
const clientId = event.source.id |
|||
|
|||
if (!clientId || !self.clients) { |
|||
return |
|||
} |
|||
|
|||
const client = await self.clients.get(clientId) |
|||
|
|||
if (!client) { |
|||
return |
|||
} |
|||
|
|||
const allClients = await self.clients.matchAll({ |
|||
type: 'window', |
|||
}) |
|||
|
|||
switch (event.data) { |
|||
case 'KEEPALIVE_REQUEST': { |
|||
sendToClient(client, { |
|||
type: 'KEEPALIVE_RESPONSE', |
|||
}) |
|||
break |
|||
} |
|||
|
|||
case 'INTEGRITY_CHECK_REQUEST': { |
|||
sendToClient(client, { |
|||
type: 'INTEGRITY_CHECK_RESPONSE', |
|||
payload: { |
|||
packageVersion: PACKAGE_VERSION, |
|||
checksum: INTEGRITY_CHECKSUM, |
|||
}, |
|||
}) |
|||
break |
|||
} |
|||
|
|||
case 'MOCK_ACTIVATE': { |
|||
activeClientIds.add(clientId) |
|||
|
|||
sendToClient(client, { |
|||
type: 'MOCKING_ENABLED', |
|||
payload: { |
|||
client: { |
|||
id: client.id, |
|||
frameType: client.frameType, |
|||
}, |
|||
}, |
|||
}) |
|||
break |
|||
} |
|||
|
|||
case 'MOCK_DEACTIVATE': { |
|||
activeClientIds.delete(clientId) |
|||
break |
|||
} |
|||
|
|||
case 'CLIENT_CLOSED': { |
|||
activeClientIds.delete(clientId) |
|||
|
|||
const remainingClients = allClients.filter((client) => { |
|||
return client.id !== clientId |
|||
}) |
|||
|
|||
// Unregister itself when there are no more clients
|
|||
if (remainingClients.length === 0) { |
|||
self.registration.unregister() |
|||
} |
|||
|
|||
break |
|||
} |
|||
} |
|||
}) |
|||
|
|||
self.addEventListener('fetch', function (event) { |
|||
const { request } = event |
|||
|
|||
// Bypass navigation requests.
|
|||
if (request.mode === 'navigate') { |
|||
return |
|||
} |
|||
|
|||
// Opening the DevTools triggers the "only-if-cached" request
|
|||
// that cannot be handled by the worker. Bypass such requests.
|
|||
if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') { |
|||
return |
|||
} |
|||
|
|||
// Bypass all requests when there are no active clients.
|
|||
// Prevents the self-unregistered worked from handling requests
|
|||
// after it's been deleted (still remains active until the next reload).
|
|||
if (activeClientIds.size === 0) { |
|||
return |
|||
} |
|||
|
|||
// Generate unique request ID.
|
|||
const requestId = crypto.randomUUID() |
|||
event.respondWith(handleRequest(event, requestId)) |
|||
}) |
|||
|
|||
async function handleRequest(event, requestId) { |
|||
const client = await resolveMainClient(event) |
|||
const response = await getResponse(event, client, requestId) |
|||
|
|||
// Send back the response clone for the "response:*" life-cycle events.
|
|||
// Ensure MSW is active and ready to handle the message, otherwise
|
|||
// this message will pend indefinitely.
|
|||
if (client && activeClientIds.has(client.id)) { |
|||
;(async function () { |
|||
const responseClone = response.clone() |
|||
|
|||
sendToClient( |
|||
client, |
|||
{ |
|||
type: 'RESPONSE', |
|||
payload: { |
|||
requestId, |
|||
isMockedResponse: IS_MOCKED_RESPONSE in response, |
|||
type: responseClone.type, |
|||
status: responseClone.status, |
|||
statusText: responseClone.statusText, |
|||
body: responseClone.body, |
|||
headers: Object.fromEntries(responseClone.headers.entries()), |
|||
}, |
|||
}, |
|||
[responseClone.body], |
|||
) |
|||
})() |
|||
} |
|||
|
|||
return response |
|||
} |
|||
|
|||
// Resolve the main client for the given event.
|
|||
// Client that issues a request doesn't necessarily equal the client
|
|||
// that registered the worker. It's with the latter the worker should
|
|||
// communicate with during the response resolving phase.
|
|||
async function resolveMainClient(event) { |
|||
const client = await self.clients.get(event.clientId) |
|||
|
|||
if (activeClientIds.has(event.clientId)) { |
|||
return client |
|||
} |
|||
|
|||
if (client?.frameType === 'top-level') { |
|||
return client |
|||
} |
|||
|
|||
const allClients = await self.clients.matchAll({ |
|||
type: 'window', |
|||
}) |
|||
|
|||
return allClients |
|||
.filter((client) => { |
|||
// Get only those clients that are currently visible.
|
|||
return client.visibilityState === 'visible' |
|||
}) |
|||
.find((client) => { |
|||
// Find the client ID that's recorded in the
|
|||
// set of clients that have registered the worker.
|
|||
return activeClientIds.has(client.id) |
|||
}) |
|||
} |
|||
|
|||
async function getResponse(event, client, requestId) { |
|||
const { request } = event |
|||
|
|||
// Clone the request because it might've been already used
|
|||
// (i.e. its body has been read and sent to the client).
|
|||
const requestClone = request.clone() |
|||
|
|||
function passthrough() { |
|||
// Cast the request headers to a new Headers instance
|
|||
// so the headers can be manipulated with.
|
|||
const headers = new Headers(requestClone.headers) |
|||
|
|||
// Remove the "accept" header value that marked this request as passthrough.
|
|||
// This prevents request alteration and also keeps it compliant with the
|
|||
// user-defined CORS policies.
|
|||
headers.delete('accept', 'msw/passthrough') |
|||
|
|||
return fetch(requestClone, { headers }) |
|||
} |
|||
|
|||
// Bypass mocking when the client is not active.
|
|||
if (!client) { |
|||
return passthrough() |
|||
} |
|||
|
|||
// Bypass initial page load requests (i.e. static assets).
|
|||
// The absence of the immediate/parent client in the map of the active clients
|
|||
// means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
|
|||
// and is not ready to handle requests.
|
|||
if (!activeClientIds.has(client.id)) { |
|||
return passthrough() |
|||
} |
|||
|
|||
// Notify the client that a request has been intercepted.
|
|||
const requestBuffer = await request.arrayBuffer() |
|||
const clientMessage = await sendToClient( |
|||
client, |
|||
{ |
|||
type: 'REQUEST', |
|||
payload: { |
|||
id: requestId, |
|||
url: request.url, |
|||
mode: request.mode, |
|||
method: request.method, |
|||
headers: Object.fromEntries(request.headers.entries()), |
|||
cache: request.cache, |
|||
credentials: request.credentials, |
|||
destination: request.destination, |
|||
integrity: request.integrity, |
|||
redirect: request.redirect, |
|||
referrer: request.referrer, |
|||
referrerPolicy: request.referrerPolicy, |
|||
body: requestBuffer, |
|||
keepalive: request.keepalive, |
|||
}, |
|||
}, |
|||
[requestBuffer], |
|||
) |
|||
|
|||
switch (clientMessage.type) { |
|||
case 'MOCK_RESPONSE': { |
|||
return respondWithMock(clientMessage.data) |
|||
} |
|||
|
|||
case 'PASSTHROUGH': { |
|||
return passthrough() |
|||
} |
|||
} |
|||
|
|||
return passthrough() |
|||
} |
|||
|
|||
function sendToClient(client, message, transferrables = []) { |
|||
return new Promise((resolve, reject) => { |
|||
const channel = new MessageChannel() |
|||
|
|||
channel.port1.onmessage = (event) => { |
|||
if (event.data && event.data.error) { |
|||
return reject(event.data.error) |
|||
} |
|||
|
|||
resolve(event.data) |
|||
} |
|||
|
|||
client.postMessage( |
|||
message, |
|||
[channel.port2].concat(transferrables.filter(Boolean)), |
|||
) |
|||
}) |
|||
} |
|||
|
|||
async function respondWithMock(response) { |
|||
// Setting response status code to 0 is a no-op.
|
|||
// However, when responding with a "Response.error()", the produced Response
|
|||
// instance will have status code set to 0. Since it's not possible to create
|
|||
// a Response instance with status code 0, handle that use-case separately.
|
|||
if (response.status === 0) { |
|||
return Response.error() |
|||
} |
|||
|
|||
const mockedResponse = new Response(response.body, response) |
|||
|
|||
Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, { |
|||
value: true, |
|||
enumerable: true, |
|||
}) |
|||
|
|||
return mockedResponse |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
import { Helmet } from "react-helmet-async"; |
|||
|
|||
import Logo from "@/assets/images/logo.png"; |
|||
import Router from "@/router/index"; |
|||
|
|||
import { MotionLazy } from "./components/animate/motion-lazy"; |
|||
import Toast from "./components/toast"; |
|||
import { AntdAdapter } from "./theme/adapter/antd.adapter"; |
|||
import { ThemeProvider } from "./theme/theme-provider"; |
|||
import { useEffect } from "react"; |
|||
|
|||
import { useSetLocale } from "./store/localeI18nStore"; |
|||
import { useTranslation } from "react-i18next"; |
|||
import { getStringItem } from "./utils/storage"; |
|||
import { LocalEnum, StorageEnum } from "#/enum"; |
|||
import { useSessions } from "./hooks/abp/use-sessions"; |
|||
|
|||
function App() { |
|||
const { i18n } = useTranslation(); |
|||
const setLocale = useSetLocale(); |
|||
const defaultLng = getStringItem(StorageEnum.I18N) || LocalEnum.en_US; |
|||
useSessions(); |
|||
useEffect(() => { |
|||
async function initializeI18n() { |
|||
await setLocale(defaultLng as LocalEnum, i18n); |
|||
} |
|||
initializeI18n(); //触发abp语言包加载
|
|||
}, [defaultLng, i18n, setLocale]); |
|||
return ( |
|||
<ThemeProvider adapters={[AntdAdapter]}> |
|||
<MotionLazy> |
|||
<Helmet> |
|||
<title>Slash Admin</title> |
|||
<link rel="icon" href={Logo} /> |
|||
</Helmet> |
|||
<Toast /> |
|||
|
|||
<Router /> |
|||
</MotionLazy> |
|||
</ThemeProvider> |
|||
); |
|||
} |
|||
|
|||
export default App; |
|||
@ -0,0 +1,610 @@ |
|||
import useUserStore from "@/store/userStore"; |
|||
import { faker } from "@faker-js/faker"; |
|||
|
|||
import { BasicStatus, PermissionType } from "#/enum"; |
|||
/** |
|||
* Organization data mock |
|||
*/ |
|||
export const ORG_LIST = [ |
|||
{ |
|||
id: "1", |
|||
name: "East China Branch", |
|||
status: "enable", |
|||
desc: faker.lorem.words(), |
|||
order: 1, |
|||
children: [ |
|||
{ |
|||
id: "1-1", |
|||
name: "R&D Department", |
|||
status: "disable", |
|||
desc: "", |
|||
order: 1, |
|||
}, |
|||
{ |
|||
id: "1-2", |
|||
name: "Marketing Department", |
|||
status: "enable", |
|||
desc: "", |
|||
order: 2, |
|||
}, |
|||
{ |
|||
id: "1-3", |
|||
name: "Finance Department", |
|||
status: "enable", |
|||
desc: "", |
|||
order: 3, |
|||
}, |
|||
], |
|||
}, |
|||
{ |
|||
id: "2", |
|||
name: "South China Branch", |
|||
status: "enable", |
|||
desc: faker.lorem.words(), |
|||
order: 2, |
|||
children: [ |
|||
{ |
|||
id: "2-1", |
|||
name: "R&D Department", |
|||
status: "disable", |
|||
desc: "", |
|||
order: 1, |
|||
}, |
|||
{ |
|||
id: "2-2", |
|||
name: "Marketing Department", |
|||
status: "enable", |
|||
desc: "", |
|||
order: 2, |
|||
}, |
|||
{ |
|||
id: "2-3", |
|||
name: "Finance Department", |
|||
status: "enable", |
|||
desc: "", |
|||
order: 3, |
|||
}, |
|||
], |
|||
}, |
|||
]; |
|||
|
|||
/** |
|||
* User permission mock |
|||
*/ |
|||
const DASHBOARD_PERMISSION = { |
|||
id: "9100714781927703", |
|||
parentId: "", |
|||
label: "sys.menu.dashboard", |
|||
name: "Dashboard", |
|||
icon: "ic-analysis", |
|||
type: PermissionType.CATALOGUE, |
|||
route: "dashboard", |
|||
order: 1, |
|||
children: [ |
|||
{ |
|||
id: "8426999229400979", |
|||
parentId: "9100714781927703", |
|||
label: "sys.menu.workbench", |
|||
name: "Workbench", |
|||
type: PermissionType.MENU, |
|||
route: "workbench", |
|||
component: "/dashboard/workbench/index.tsx", |
|||
}, |
|||
{ |
|||
id: "9710971640510357", |
|||
parentId: "9100714781927703", |
|||
label: "sys.menu.analysis", |
|||
name: "Analysis", |
|||
type: PermissionType.MENU, |
|||
route: "analysis", |
|||
component: "/dashboard/analysis/index.tsx", |
|||
}, |
|||
], |
|||
}; |
|||
const MANAGEMENT_PERMISSION = { |
|||
id: "0901673425580518", |
|||
parentId: "", |
|||
label: "sys.menu.management", |
|||
name: "Management", |
|||
icon: "ic-management", |
|||
type: PermissionType.CATALOGUE, |
|||
route: "management", |
|||
order: 2, |
|||
children: [ |
|||
{ |
|||
id: "2781684678535711", |
|||
parentId: "0901673425580518", |
|||
label: "sys.menu.user.index", |
|||
name: "User", |
|||
type: PermissionType.CATALOGUE, |
|||
route: "user", |
|||
children: [ |
|||
{ |
|||
id: "4754063958766648", |
|||
parentId: "2781684678535711", |
|||
label: "sys.menu.user.profile", |
|||
name: "Profile", |
|||
type: PermissionType.MENU, |
|||
route: "profile", |
|||
component: "/management/user/profile/index.tsx", |
|||
}, |
|||
{ |
|||
id: "2516598794787938", |
|||
parentId: "2781684678535711", |
|||
label: "sys.menu.user.account", |
|||
name: "Account", |
|||
type: PermissionType.MENU, |
|||
route: "account", |
|||
component: "/management/user/account/index.tsx", |
|||
}, |
|||
], |
|||
}, |
|||
{ |
|||
id: "0249937641030250", |
|||
parentId: "0901673425580518", |
|||
label: "sys.menu.system.index", |
|||
name: "System", |
|||
type: PermissionType.CATALOGUE, |
|||
route: "system", |
|||
children: [ |
|||
{ |
|||
id: "1985890042972842", |
|||
parentId: "0249937641030250", |
|||
label: "sys.menu.system.organization", |
|||
name: "Organization", |
|||
type: PermissionType.MENU, |
|||
route: "organization", |
|||
component: "/management/system/organization/index.tsx", |
|||
}, |
|||
{ |
|||
id: "4359580910369984", |
|||
parentId: "0249937641030250", |
|||
label: "sys.menu.system.permission", |
|||
name: "Permission", |
|||
type: PermissionType.MENU, |
|||
route: "permission", |
|||
component: "/management/system/permission/index.tsx", |
|||
}, |
|||
{ |
|||
id: "1689241785490759", |
|||
parentId: "0249937641030250", |
|||
label: "sys.menu.system.role", |
|||
name: "Role", |
|||
type: PermissionType.MENU, |
|||
route: "role", |
|||
component: "/management/system/role/index.tsx", |
|||
}, |
|||
{ |
|||
id: "0157880245365433", |
|||
parentId: "0249937641030250", |
|||
label: "sys.menu.system.user", |
|||
name: "User", |
|||
type: PermissionType.MENU, |
|||
route: "user", |
|||
component: "/management/system/user/index.tsx", |
|||
}, |
|||
{ |
|||
id: "0157880245365434", |
|||
parentId: "0249937641030250", |
|||
label: "sys.menu.system.user_detail", |
|||
name: "User Detail", |
|||
type: PermissionType.MENU, |
|||
route: "user/:id", |
|||
component: "/management/system/user/detail.tsx", |
|||
hide: true, |
|||
}, |
|||
], |
|||
}, |
|||
], |
|||
}; |
|||
const COMPONENTS_PERMISSION = { |
|||
id: "2271615060673773", |
|||
parentId: "", |
|||
label: "sys.menu.components", |
|||
name: "Components", |
|||
icon: "solar:widget-5-bold-duotone", |
|||
type: PermissionType.CATALOGUE, |
|||
route: "components", |
|||
order: 3, |
|||
children: [ |
|||
{ |
|||
id: "2478488238255411", |
|||
parentId: "2271615060673773", |
|||
label: "sys.menu.icon", |
|||
name: "Icon", |
|||
type: PermissionType.MENU, |
|||
route: "icon", |
|||
component: "/components/icon/index.tsx", |
|||
}, |
|||
{ |
|||
id: "6755238352318767", |
|||
parentId: "2271615060673773", |
|||
label: "sys.menu.animate", |
|||
name: "Animate", |
|||
type: PermissionType.MENU, |
|||
route: "animate", |
|||
component: "/components/animate/index.tsx", |
|||
}, |
|||
{ |
|||
id: "9992476513546805", |
|||
parentId: "2271615060673773", |
|||
label: "sys.menu.scroll", |
|||
name: "Scroll", |
|||
type: PermissionType.MENU, |
|||
route: "scroll", |
|||
component: "/components/scroll/index.tsx", |
|||
}, |
|||
{ |
|||
id: "1755562695856395", |
|||
parentId: "2271615060673773", |
|||
label: "sys.menu.markdown", |
|||
name: "Markdown", |
|||
type: PermissionType.MENU, |
|||
route: "markdown", |
|||
component: "/components/markdown/index.tsx", |
|||
}, |
|||
{ |
|||
id: "2122547769468069", |
|||
parentId: "2271615060673773", |
|||
label: "sys.menu.editor", |
|||
name: "Editor", |
|||
type: PermissionType.MENU, |
|||
route: "editor", |
|||
component: "/components/editor/index.tsx", |
|||
}, |
|||
{ |
|||
id: "2501920741714350", |
|||
parentId: "2271615060673773", |
|||
label: "sys.menu.i18n", |
|||
name: "Multi Language", |
|||
type: PermissionType.MENU, |
|||
route: "i18n", |
|||
component: "/components/multi-language/index.tsx", |
|||
}, |
|||
{ |
|||
id: "2013577074467956", |
|||
parentId: "2271615060673773", |
|||
label: "sys.menu.upload", |
|||
name: "upload", |
|||
type: PermissionType.MENU, |
|||
route: "Upload", |
|||
component: "/components/upload/index.tsx", |
|||
}, |
|||
{ |
|||
id: "7749726274771764", |
|||
parentId: "2271615060673773", |
|||
label: "sys.menu.chart", |
|||
name: "Chart", |
|||
type: PermissionType.MENU, |
|||
route: "chart", |
|||
component: "/components/chart/index.tsx", |
|||
}, |
|||
{ |
|||
id: "2013577074467957", |
|||
parentId: "2271615060673773", |
|||
label: "sys.menu.toast", |
|||
name: "Toast", |
|||
type: PermissionType.MENU, |
|||
route: "toast", |
|||
component: "/components/toast/index.tsx", |
|||
}, |
|||
], |
|||
}; |
|||
const FUNCTIONS_PERMISSION = { |
|||
id: "8132044808088488", |
|||
parentId: "", |
|||
label: "sys.menu.functions", |
|||
name: "functions", |
|||
icon: "solar:plain-2-bold-duotone", |
|||
type: PermissionType.CATALOGUE, |
|||
route: "functions", |
|||
order: 4, |
|||
children: [ |
|||
{ |
|||
id: "3667930780705750", |
|||
parentId: "8132044808088488", |
|||
label: "sys.menu.clipboard", |
|||
name: "Clipboard", |
|||
type: PermissionType.MENU, |
|||
route: "clipboard", |
|||
component: "/functions/clipboard/index.tsx", |
|||
}, |
|||
{ |
|||
id: "3667930780705751", |
|||
parentId: "8132044808088488", |
|||
label: "sys.menu.token_expired", |
|||
name: "Token Expired", |
|||
type: PermissionType.MENU, |
|||
route: "token-expired", |
|||
component: "/functions/token-expired/index.tsx", |
|||
}, |
|||
], |
|||
}; |
|||
const MENU_LEVEL_PERMISSION = { |
|||
id: "0194818428516575", |
|||
parentId: "", |
|||
label: "sys.menu.menulevel.index", |
|||
name: "Menu Level", |
|||
icon: "ic-menulevel", |
|||
type: PermissionType.CATALOGUE, |
|||
route: "menu-level", |
|||
order: 5, |
|||
children: [ |
|||
{ |
|||
id: "0144431332471389", |
|||
parentId: "0194818428516575", |
|||
label: "sys.menu.menulevel.1a", |
|||
name: "Menu Level 1a", |
|||
type: PermissionType.MENU, |
|||
route: "menu-level-1a", |
|||
component: "/menu-level/menu-level-1a/index.tsx", |
|||
}, |
|||
{ |
|||
id: "7572529636800586", |
|||
parentId: "0194818428516575", |
|||
label: "sys.menu.menulevel.1b.index", |
|||
name: "Menu Level 1b", |
|||
type: PermissionType.CATALOGUE, |
|||
route: "menu-level-1b", |
|||
children: [ |
|||
{ |
|||
id: "3653745576583237", |
|||
parentId: "7572529636800586", |
|||
label: "sys.menu.menulevel.1b.2a", |
|||
name: "Menu Level 2a", |
|||
type: PermissionType.MENU, |
|||
route: "menu-level-2a", |
|||
component: "/menu-level/menu-level-1b/menu-level-2a/index.tsx", |
|||
}, |
|||
{ |
|||
id: "4873136353891364", |
|||
parentId: "7572529636800586", |
|||
label: "sys.menu.menulevel.1b.2b.index", |
|||
name: "Menu Level 2b", |
|||
type: PermissionType.CATALOGUE, |
|||
route: "menu-level-2b", |
|||
children: [ |
|||
{ |
|||
id: "4233029726998055", |
|||
parentId: "4873136353891364", |
|||
label: "sys.menu.menulevel.1b.2b.3a", |
|||
name: "Menu Level 3a", |
|||
type: PermissionType.MENU, |
|||
route: "menu-level-3a", |
|||
component: "/menu-level/menu-level-1b/menu-level-2b/menu-level-3a/index.tsx", |
|||
}, |
|||
{ |
|||
id: "3298034742548454", |
|||
parentId: "4873136353891364", |
|||
label: "sys.menu.menulevel.1b.2b.3b", |
|||
name: "Menu Level 3b", |
|||
type: PermissionType.MENU, |
|||
route: "menu-level-3b", |
|||
component: "/menu-level/menu-level-1b/menu-level-2b/menu-level-3b/index.tsx", |
|||
}, |
|||
], |
|||
}, |
|||
], |
|||
}, |
|||
], |
|||
}; |
|||
const ERRORS_PERMISSION = { |
|||
id: "9406067785553476", |
|||
parentId: "", |
|||
label: "sys.menu.error.index", |
|||
name: "Error", |
|||
icon: "bxs:error-alt", |
|||
type: PermissionType.CATALOGUE, |
|||
route: "error", |
|||
order: 6, |
|||
children: [ |
|||
{ |
|||
id: "8557056851997154", |
|||
parentId: "9406067785553476", |
|||
label: "sys.menu.error.403", |
|||
name: "403", |
|||
type: PermissionType.MENU, |
|||
route: "403", |
|||
component: "/sys/error/Page403.tsx", |
|||
}, |
|||
{ |
|||
id: "5095669208159005", |
|||
parentId: "9406067785553476", |
|||
label: "sys.menu.error.404", |
|||
name: "404", |
|||
type: PermissionType.MENU, |
|||
route: "404", |
|||
component: "/sys/error/Page404.tsx", |
|||
}, |
|||
{ |
|||
id: "0225992135973772", |
|||
parentId: "9406067785553476", |
|||
label: "sys.menu.error.500", |
|||
name: "500", |
|||
type: PermissionType.MENU, |
|||
route: "500", |
|||
component: "/sys/error/Page500.tsx", |
|||
}, |
|||
], |
|||
}; |
|||
const OTHERS_PERMISSION = [ |
|||
{ |
|||
id: "3981225257359246", |
|||
parentId: "", |
|||
label: "sys.menu.calendar", |
|||
name: "Calendar", |
|||
icon: "solar:calendar-bold-duotone", |
|||
type: PermissionType.MENU, |
|||
route: "calendar", |
|||
component: "/sys/others/calendar/index.tsx", |
|||
}, |
|||
{ |
|||
id: "3513985683886393", |
|||
parentId: "", |
|||
label: "sys.menu.kanban", |
|||
name: "kanban", |
|||
icon: "solar:clipboard-bold-duotone", |
|||
type: PermissionType.MENU, |
|||
route: "kanban", |
|||
component: "/sys/others/kanban/index.tsx", |
|||
}, |
|||
{ |
|||
id: "5455837930804461", |
|||
parentId: "", |
|||
label: "sys.menu.disabled", |
|||
name: "Disabled", |
|||
icon: "ic_disabled", |
|||
type: PermissionType.MENU, |
|||
route: "disabled", |
|||
status: BasicStatus.DISABLE, |
|||
component: "/sys/others/calendar/index.tsx", |
|||
}, |
|||
{ |
|||
id: "7728048658221587", |
|||
parentId: "", |
|||
label: "sys.menu.label", |
|||
name: "Label", |
|||
icon: "ic_label", |
|||
type: PermissionType.MENU, |
|||
route: "label", |
|||
newFeature: true, |
|||
component: "/sys/others/blank.tsx", |
|||
}, |
|||
{ |
|||
id: "5733704222120995", |
|||
parentId: "", |
|||
label: "sys.menu.frame", |
|||
name: "Frame", |
|||
icon: "ic_external", |
|||
type: PermissionType.CATALOGUE, |
|||
route: "frame", |
|||
children: [ |
|||
{ |
|||
id: "9884486809510480", |
|||
parentId: "5733704222120995", |
|||
label: "sys.menu.external_link", |
|||
name: "External Link", |
|||
type: PermissionType.MENU, |
|||
route: "external_link", |
|||
hideTab: true, |
|||
component: "/sys/others/iframe/external-link.tsx", |
|||
frameSrc: "https://ant.design/", |
|||
}, |
|||
{ |
|||
id: "9299640886731819", |
|||
parentId: "5733704222120995", |
|||
label: "sys.menu.iframe", |
|||
name: "Iframe", |
|||
type: PermissionType.MENU, |
|||
route: "frame", |
|||
component: "/sys/others/iframe/index.tsx", |
|||
frameSrc: "https://ant.design/", |
|||
}, |
|||
], |
|||
}, |
|||
{ |
|||
id: "0941594969900756", |
|||
parentId: "", |
|||
label: "sys.menu.blank", |
|||
name: "Disabled", |
|||
icon: "ic_blank", |
|||
type: PermissionType.MENU, |
|||
route: "blank", |
|||
component: "/sys/others/blank.tsx", |
|||
}, |
|||
]; |
|||
|
|||
export const PERMISSION_LIST = [ |
|||
DASHBOARD_PERMISSION, |
|||
MANAGEMENT_PERMISSION, |
|||
COMPONENTS_PERMISSION, |
|||
FUNCTIONS_PERMISSION, |
|||
MENU_LEVEL_PERMISSION, |
|||
ERRORS_PERMISSION, |
|||
...OTHERS_PERMISSION, |
|||
]; |
|||
|
|||
/** |
|||
* User role mock |
|||
*/ |
|||
const ADMIN_ROLE = { |
|||
id: "4281707933534332", |
|||
name: "Admin", |
|||
label: "admin", |
|||
status: BasicStatus.ENABLE, |
|||
order: 1, |
|||
desc: "Super Admin", |
|||
permission: PERMISSION_LIST, |
|||
}; |
|||
const TEST_ROLE = { |
|||
id: "9931665660771476", |
|||
name: "Test", |
|||
label: "test", |
|||
status: BasicStatus.ENABLE, |
|||
order: 2, |
|||
desc: "test", |
|||
permission: [DASHBOARD_PERMISSION, COMPONENTS_PERMISSION, FUNCTIONS_PERMISSION], |
|||
}; |
|||
export const ROLE_LIST = [ADMIN_ROLE, TEST_ROLE]; |
|||
|
|||
/** |
|||
* User data mock |
|||
*/ |
|||
export const DEFAULT_USER = { |
|||
id: "b34719e1-ce46-457e-9575-99505ecee828", |
|||
username: "admin", |
|||
email: faker.internet.email(), |
|||
avatar: faker.image.avatarGitHub(), |
|||
createdAt: faker.date.anytime(), |
|||
updatedAt: faker.date.recent(), |
|||
password: "1q2w3E*", |
|||
role: ADMIN_ROLE, |
|||
permissions: ADMIN_ROLE.permission, |
|||
desc: "", |
|||
homePath: "/", |
|||
token: "/", |
|||
realName: "", |
|||
userId: "", |
|||
}; |
|||
export const TEST_USER = { |
|||
id: "efaa20ea-4dc5-47ee-a200-8a899be29494", |
|||
username: "test", |
|||
password: "1q2w3E*", |
|||
email: faker.internet.email(), |
|||
avatar: faker.image.avatarGitHub(), |
|||
createdAt: faker.date.anytime(), |
|||
updatedAt: faker.date.recent(), |
|||
role: TEST_ROLE, |
|||
permissions: TEST_ROLE.permission, |
|||
desc: "", |
|||
homePath: "/", |
|||
token: "/", |
|||
realName: "", |
|||
userId: "", |
|||
}; |
|||
export const USER_LIST = [DEFAULT_USER, TEST_USER]; |
|||
|
|||
// * Hot update, updating user permissions, only effective in the development environment
|
|||
if (import.meta.hot) { |
|||
import.meta.hot.accept((newModule) => { |
|||
if (!newModule) return; |
|||
|
|||
const { DEFAULT_USER, TEST_USER, PERMISSION_LIST } = newModule; |
|||
|
|||
const { |
|||
userInfo, |
|||
actions: { setUserInfo }, |
|||
} = useUserStore.getState(); |
|||
|
|||
if (!userInfo?.username) return; |
|||
|
|||
const newUserInfo = userInfo.username === DEFAULT_USER.username ? DEFAULT_USER : TEST_USER; |
|||
|
|||
setUserInfo(newUserInfo); |
|||
|
|||
console.log("[HMR] User permissions updated:", { |
|||
username: newUserInfo.username, |
|||
permissions: newUserInfo.permissions, |
|||
}); |
|||
}); |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
import { http, HttpResponse } from "msw"; |
|||
|
|||
import { DemoApi } from "@/api/services/demoService"; |
|||
|
|||
const mockTokenExpired = http.post(`/api${DemoApi.TOKEN_EXPIRED}`, () => { |
|||
return new HttpResponse(null, { status: 401 }); |
|||
}); |
|||
|
|||
export default [mockTokenExpired]; |
|||
@ -0,0 +1,14 @@ |
|||
import { http, HttpResponse } from "msw"; |
|||
|
|||
import { ORG_LIST } from "@/_mock/assets"; |
|||
import { OrgApi } from "@/api/services/orgService"; |
|||
|
|||
const orgList = http.get(`/api${OrgApi.Org}`, () => { |
|||
return HttpResponse.json({ |
|||
status: 0, |
|||
message: "", |
|||
data: ORG_LIST, |
|||
}); |
|||
}); |
|||
|
|||
export default [orgList]; |
|||
@ -0,0 +1,46 @@ |
|||
import { faker } from "@faker-js/faker"; |
|||
import { http, HttpResponse, delay } from "msw"; |
|||
|
|||
import { UserApi } from "@/api/services/userService"; |
|||
|
|||
import { USER_LIST } from "../assets"; |
|||
|
|||
const signIn = http.post(`/api${UserApi.SignIn}`, async ({ request }) => { |
|||
const { username, password } = await request.json(); |
|||
|
|||
const user = USER_LIST.find((item) => item.username === username); |
|||
|
|||
if (!user || user.password !== password) { |
|||
return HttpResponse.json({ |
|||
status: 10001, |
|||
message: "Incorrect username or password.", |
|||
}); |
|||
} |
|||
|
|||
return HttpResponse.json({ |
|||
status: 0, |
|||
message: "", |
|||
data: { |
|||
user, |
|||
accessToken: faker.string.uuid(), |
|||
refreshToken: faker.string.uuid(), |
|||
}, |
|||
}); |
|||
}); |
|||
|
|||
const userList = http.get("/api/user", async () => { |
|||
await delay(1000); |
|||
return HttpResponse.json( |
|||
Array.from({ length: 10 }).map(() => ({ |
|||
fullname: faker.person.fullName(), |
|||
email: faker.internet.email(), |
|||
avatar: faker.image.avatarGitHub(), |
|||
address: faker.location.streetAddress(), |
|||
})), |
|||
{ |
|||
status: 200, |
|||
}, |
|||
); |
|||
}); |
|||
|
|||
export default [signIn, userList]; |
|||
@ -0,0 +1,10 @@ |
|||
import { setupWorker } from "msw/browser"; |
|||
|
|||
import demoMockApi from "./handlers/_demo"; |
|||
import orgMockApi from "./handlers/_org"; |
|||
import userMockApi from "./handlers/_user"; |
|||
|
|||
const handlers = [...userMockApi, ...orgMockApi, ...demoMockApi]; |
|||
const worker = setupWorker(...handlers); |
|||
|
|||
export default worker; |
|||
@ -0,0 +1,9 @@ |
|||
import { faker } from "@faker-js/faker"; |
|||
|
|||
export const fakeAvatars = (count) => { |
|||
const result = []; |
|||
for (let index = 0; index < count; index += 1) { |
|||
result.push(faker.image.avatarGitHub()); |
|||
} |
|||
return result; |
|||
}; |
|||
@ -0,0 +1,26 @@ |
|||
import type { ApplicationConfigurationDto, ApplicationLocalizationDto } from "#/abp-core"; |
|||
import requestClient from "../request"; |
|||
|
|||
/** |
|||
* 获取应用程序配置信息 |
|||
*/ |
|||
export function getConfigApi(options?: { |
|||
includeLocalizationResources?: boolean; |
|||
}): Promise<ApplicationConfigurationDto> { |
|||
return requestClient.get<ApplicationConfigurationDto>("/api/abp/application-configuration", { |
|||
params: options, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 获取应用程序语言 |
|||
* @returns 本地化配置 |
|||
*/ |
|||
export function getLocalizationApi(options: { |
|||
cultureName: string; |
|||
onlyDynamics?: boolean; |
|||
}): Promise<ApplicationLocalizationDto> { |
|||
return requestClient.get<ApplicationLocalizationDto>("/api/abp/application-localization", { |
|||
params: options, |
|||
}); |
|||
} |
|||
@ -0,0 +1,2 @@ |
|||
export * from "./abp"; |
|||
// export * from './menu';
|
|||
@ -0,0 +1,9 @@ |
|||
// import type { RouteRecordStringComponent } from '@vben/types';
|
|||
// import requestClient from '../request';
|
|||
|
|||
/** |
|||
* 获取用户所有菜单 |
|||
*/ |
|||
// export async function getAllMenusApi() {
|
|||
// return requestClient.get<RouteRecordStringComponent[]>('/menu/all');
|
|||
// }
|
|||
@ -0,0 +1,28 @@ |
|||
import type { ListResultDto } from "#/abp-core"; |
|||
import type { |
|||
GetTwoFactorProvidersInput, |
|||
TwoFactorProvider, |
|||
SendEmailSigninCodeDto, |
|||
SendPhoneSigninCodeDto, |
|||
} from "#/account/account"; |
|||
import requestClient from "@/api/request"; |
|||
|
|||
/** |
|||
* Get available two-factor authentication providers |
|||
*/ |
|||
export const getTwoFactorProvidersApi = (input: GetTwoFactorProvidersInput) => |
|||
requestClient.get<ListResultDto<TwoFactorProvider>>("/api/account/two-factor-providers", { |
|||
params: input, |
|||
}); |
|||
|
|||
/** |
|||
* Send sign-in verification email |
|||
*/ |
|||
export const sendEmailSigninCodeApi = (input: SendEmailSigninCodeDto) => |
|||
requestClient.post("/api/account/email/send-signin-code", input); |
|||
|
|||
/** |
|||
* Send sign-in verification SMS |
|||
*/ |
|||
export const sendPhoneSigninCodeApi = (input: SendPhoneSigninCodeDto) => |
|||
requestClient.post("/api/account/phone/send-signin-code", input); |
|||
@ -0,0 +1,4 @@ |
|||
export * from "./token"; |
|||
export * from "./user"; |
|||
export * from "./my-session"; |
|||
export * from "./account"; |
|||
@ -0,0 +1,23 @@ |
|||
import type { IdentitySessionDto } from "#/management/identity/sessions"; |
|||
import type { PagedResultDto } from "#/abp-core"; |
|||
import requestClient from "@/api/request"; |
|||
|
|||
export interface GetMySessionsInput { |
|||
filter?: string; |
|||
maxResultCount?: number; |
|||
skipCount?: number; |
|||
} |
|||
|
|||
/** |
|||
* Get current user's sessions |
|||
*/ |
|||
export const getSessionsApi = (input?: GetMySessionsInput) => |
|||
requestClient.get<PagedResultDto<IdentitySessionDto>>("/api/account/my-profile/sessions", { |
|||
params: input, |
|||
}); |
|||
|
|||
/** |
|||
* Revoke a session |
|||
*/ |
|||
export const revokeSessionApi = (sessionId: string) => |
|||
requestClient.delete(`/api/account/my-profile/sessions/${sessionId}/revoke`); |
|||
@ -0,0 +1,68 @@ |
|||
import type { |
|||
ProfileDto, |
|||
UpdateProfileDto, |
|||
ChangePasswordInput, |
|||
TwoFactorEnabledDto, |
|||
AuthenticatorDto, |
|||
VerifyAuthenticatorCodeInput, |
|||
AuthenticatorRecoveryCodeDto, |
|||
SendEmailConfirmCodeDto, |
|||
ConfirmEmailInput, |
|||
} from "#/account/profile"; |
|||
import requestClient from "@/api/request"; |
|||
|
|||
/** |
|||
* Get profile information |
|||
*/ |
|||
export const getApi = () => requestClient.get<ProfileDto>("/api/account/my-profile"); |
|||
|
|||
/** |
|||
* Update profile information |
|||
*/ |
|||
export const updateApi = (input: UpdateProfileDto) => requestClient.put<ProfileDto>("/api/account/my-profile", input); |
|||
|
|||
/** |
|||
* Change password |
|||
*/ |
|||
export const changePasswordApi = (input: ChangePasswordInput) => |
|||
requestClient.post("/api/account/my-profile/change-password", input); |
|||
|
|||
/** |
|||
* Get two-factor authentication status |
|||
*/ |
|||
export const getTwoFactorEnabledApi = () => |
|||
requestClient.get<TwoFactorEnabledDto>("/api/account/my-profile/two-factor"); |
|||
|
|||
/** |
|||
* Set two-factor authentication status |
|||
*/ |
|||
export const changeTwoFactorEnabledApi = (input: TwoFactorEnabledDto) => |
|||
requestClient.put("/api/account/my-profile/change-two-factor", input); |
|||
|
|||
/** |
|||
* Get authenticator configuration |
|||
*/ |
|||
export const getAuthenticatorApi = () => requestClient.get<AuthenticatorDto>("/api/account/my-profile/authenticator"); |
|||
|
|||
/** |
|||
* Verify authenticator code |
|||
*/ |
|||
export const verifyAuthenticatorCodeApi = (input: VerifyAuthenticatorCodeInput) => |
|||
requestClient.post<AuthenticatorRecoveryCodeDto>("/api/account/my-profile/verify-authenticator-code", input); |
|||
|
|||
/** |
|||
* Reset authenticator |
|||
*/ |
|||
export const resetAuthenticatorApi = () => requestClient.post("/api/account/my-profile/reset-authenticator"); |
|||
|
|||
/** |
|||
* Send email confirmation link |
|||
*/ |
|||
export const sendEmailConfirmLinkApi = (input: SendEmailConfirmCodeDto) => |
|||
requestClient.post("/api/account/my-profile/send-email-confirm-link", input); |
|||
|
|||
/** |
|||
* Confirm email |
|||
*/ |
|||
export const confirmEmailApi = (input: ConfirmEmailInput) => |
|||
requestClient.put("/api/account/my-profile/confirm-email", input); |
|||
@ -0,0 +1,63 @@ |
|||
import type { OAuthTokenResult, PasswordTokenRequestModel, RefreshTokenRequestModel, TokenResult } from "#/account"; |
|||
import requestClient from "../request"; |
|||
|
|||
/** |
|||
* 用户登录 |
|||
* @param request 参数 |
|||
* @returns 用户token |
|||
*/ |
|||
export async function loginApi(request: PasswordTokenRequestModel): Promise<TokenResult> { |
|||
const clientId = import.meta.env.VITE_GLOB_CLIENT_ID; |
|||
const clientSecret = import.meta.env.VITE_GLOB_CLIENT_SECRET; |
|||
const scope = import.meta.env.VITE_GLOB_SCOPE; |
|||
const result = await requestClient.post<OAuthTokenResult>( |
|||
"/connect/token", |
|||
{ |
|||
client_id: clientId, |
|||
client_secret: clientSecret, |
|||
grant_type: "password", |
|||
password: request.password, |
|||
scope: scope, |
|||
username: request.username, |
|||
}, |
|||
{ |
|||
headers: { |
|||
"Content-Type": "application/x-www-form-urlencoded", |
|||
}, |
|||
timeout: 30_000, |
|||
}, |
|||
); |
|||
return { |
|||
accessToken: result.access_token, |
|||
expiresIn: result.expires_in, |
|||
refreshToken: result.refresh_token, |
|||
tokenType: result.token_type, |
|||
}; |
|||
} |
|||
|
|||
export async function refreshToken(request: RefreshTokenRequestModel): Promise<TokenResult> { |
|||
const clientId = import.meta.env.VITE_GLOB_CLIENT_ID; |
|||
const clientSecret = import.meta.env.VITE_GLOB_CLIENT_SECRET; |
|||
const scope = import.meta.env.VITE_GLOB_SCOPE; |
|||
const result = await requestClient.post<OAuthTokenResult>( |
|||
"/connect/token", |
|||
{ |
|||
client_id: clientId, |
|||
client_secret: clientSecret, |
|||
grant_type: "refresh_token", |
|||
refresh_token: request.refreshToken, |
|||
scope: scope, |
|||
}, |
|||
{ |
|||
headers: { |
|||
"Content-Type": "application/x-www-form-urlencoded", |
|||
}, |
|||
}, |
|||
); |
|||
return { |
|||
accessToken: result.access_token, |
|||
expiresIn: result.expires_in, |
|||
refreshToken: result.refresh_token, |
|||
tokenType: result.token_type, |
|||
}; |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
import type { OAuthUserInfo, UserInfo } from "#/account"; |
|||
import requestClient from "../request"; |
|||
|
|||
/** |
|||
* 获取用户信息 |
|||
*/ |
|||
export async function getUserInfoApi(): Promise<UserInfo> { |
|||
const result = await requestClient.get<OAuthUserInfo>("/connect/userinfo"); |
|||
return { |
|||
...result, |
|||
emailVerified: result.email_verified, |
|||
givenName: result.given_name, |
|||
phoneNumberVerified: result.phone_number_verified, |
|||
preferredUsername: result.preferred_username, |
|||
uniqueName: result.unique_name, |
|||
}; |
|||
} |
|||
@ -0,0 +1,98 @@ |
|||
import axios, { type AxiosRequestConfig, type AxiosError, type AxiosResponse } from "axios"; |
|||
|
|||
import { t } from "@/locales/i18n"; |
|||
import userStore, { useUserToken } from "@/store/userStore"; |
|||
|
|||
import { toast } from "sonner"; |
|||
//TODO rm
|
|||
// 创建 axios 实例
|
|||
const axiosInstance = axios.create({ |
|||
baseURL: import.meta.env.VITE_APP_BASE_API, |
|||
timeout: 50000, |
|||
headers: { "Content-Type": "application/json;charset=utf-8" }, |
|||
}); |
|||
|
|||
// 请求拦截
|
|||
axiosInstance.interceptors.request.use( |
|||
(config) => { |
|||
// 在请求被发送之前做些什么
|
|||
const { accessToken } = useUserToken(); |
|||
config.headers.Authorization = `${accessToken}`; |
|||
return config; |
|||
}, |
|||
(error) => { |
|||
// 请求错误时做些什么
|
|||
return Promise.reject(error); |
|||
}, |
|||
); |
|||
|
|||
// 响应拦截
|
|||
axiosInstance.interceptors.response.use( |
|||
(res: AxiosResponse<any>) => { |
|||
const { data, status, headers } = res; |
|||
|
|||
if (headers._abpwrapresult === "true") { |
|||
const { code, result, message, details } = data; |
|||
const hasSuccess = data && Reflect.has(data, "code") && code === "0"; |
|||
if (hasSuccess) { |
|||
return result; |
|||
} |
|||
const content = details || message; |
|||
|
|||
throw new Error(content); |
|||
} |
|||
|
|||
if (status >= 200 && status < 400) { |
|||
return data; |
|||
} |
|||
|
|||
// 业务请求错误
|
|||
throw new Error(t("sys.api.apiRequestFailed")); |
|||
}, |
|||
(error: AxiosError<any>) => { |
|||
const { response, message } = error || {}; |
|||
|
|||
const errMsg = response?.data?.message || message || t("sys.api.errorMessage"); |
|||
toast.error(errMsg, { |
|||
position: "top-center", |
|||
}); |
|||
|
|||
const status = response?.status; |
|||
if (status === 401) { |
|||
userStore.getState().actions.clearUserInfoAndToken(); |
|||
} |
|||
return Promise.reject(error); |
|||
}, |
|||
); |
|||
|
|||
class APIClient { |
|||
get<T = any>(config: AxiosRequestConfig): Promise<T> { |
|||
return this.request({ ...config, method: "GET" }); |
|||
} |
|||
|
|||
post<T = any>(config: AxiosRequestConfig): Promise<T> { |
|||
return this.request({ ...config, method: "POST" }); |
|||
} |
|||
|
|||
put<T = any>(config: AxiosRequestConfig): Promise<T> { |
|||
return this.request({ ...config, method: "PUT" }); |
|||
} |
|||
|
|||
delete<T = any>(config: AxiosRequestConfig): Promise<T> { |
|||
return this.request({ ...config, method: "DELETE" }); |
|||
} |
|||
|
|||
request<T = any>(config: AxiosRequestConfig): Promise<T> { |
|||
return new Promise((resolve, reject) => { |
|||
axiosInstance |
|||
.request<any, AxiosResponse<any>>(config) |
|||
.then((res: AxiosResponse<any>) => { |
|||
resolve(res as unknown as Promise<T>); |
|||
}) |
|||
.catch((e: Error | AxiosError) => { |
|||
reject(e); |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
export default new APIClient(); |
|||
@ -0,0 +1,3 @@ |
|||
// This file is auto-generated by @hey-api/openapi-ts
|
|||
export * from "./sdk.gen"; |
|||
export * from "./types.gen"; |
|||
@ -0,0 +1,30 @@ |
|||
import type { PagedResultDto } from "#/abp-core"; |
|||
|
|||
import type { AuditLogDto, AuditLogGetListInput } from "#/management/auditing"; |
|||
import requestClient from "../../request"; |
|||
|
|||
/** |
|||
* 获取审计日志 |
|||
* @param id 日志id |
|||
*/ |
|||
export function getApi(id: string): Promise<AuditLogDto> { |
|||
return requestClient.get<AuditLogDto>(`/api/auditing/audit-log/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 获取审计日志分页列表 |
|||
* @param input 参数 |
|||
*/ |
|||
export function getPagedListApi(input: AuditLogGetListInput): Promise<PagedResultDto<AuditLogDto>> { |
|||
return requestClient.get<PagedResultDto<AuditLogDto>>("/api/auditing/audit-log", { |
|||
params: input, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 删除审计日志 |
|||
* @param id 日志id |
|||
*/ |
|||
export function deleteApi(id: string): Promise<void> { |
|||
return requestClient.delete(`/api/auditing/audit-log/${id}`); |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
import type { ListResultDto } from "#/abp-core"; |
|||
|
|||
import type { EntityChangeGetWithUsernameInput, EntityChangeWithUsernameDto } from "#/management/auditing"; |
|||
import requestClient from "../../request"; |
|||
|
|||
/** |
|||
* 获取包含用户名称的实体变更列表 |
|||
* @param input 参数 |
|||
*/ |
|||
export function getListWithUsernameApi( |
|||
input: EntityChangeGetWithUsernameInput, |
|||
): Promise<ListResultDto<EntityChangeWithUsernameDto>> { |
|||
return requestClient.get<ListResultDto<EntityChangeWithUsernameDto>>("/api/auditing/entity-changes/with-username", { |
|||
params: input, |
|||
}); |
|||
} |
|||
@ -0,0 +1,2 @@ |
|||
export * as auditLogsApi from "./audit-logs"; |
|||
export * as entityChangesApi from "./entity-changes"; |
|||
@ -0,0 +1,64 @@ |
|||
import type { ListResultDto, PagedResultDto } from "#/abp-core"; |
|||
|
|||
import type { |
|||
GetIdentityClaimTypePagedListInput, |
|||
IdentityClaimTypeCreateDto, |
|||
IdentityClaimTypeDto, |
|||
IdentityClaimTypeUpdateDto, |
|||
} from "#/management/identity"; |
|||
import requestClient from "../../request"; |
|||
|
|||
/** |
|||
* 新增用户声明 |
|||
* @param input 参数 |
|||
* @returns 用户声明实体数据传输对象 |
|||
*/ |
|||
export function createApi(input: IdentityClaimTypeCreateDto): Promise<IdentityClaimTypeDto> { |
|||
return requestClient.post<IdentityClaimTypeDto>("/api/identity/claim-types", input); |
|||
} |
|||
|
|||
/** |
|||
* 删除用户声明 |
|||
* @param id 用户声明id |
|||
*/ |
|||
export function deleteApi(id: string): Promise<void> { |
|||
return requestClient.delete(`/api/identity/claim-types/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 查询用户声明 |
|||
* @param id 用户声明id |
|||
* @returns 用户声明实体数据传输对象 |
|||
*/ |
|||
export function getApi(id: string): Promise<IdentityClaimTypeDto> { |
|||
return requestClient.get<IdentityClaimTypeDto>(`/api/identity/claim-types/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 更新用户声明 |
|||
* @param id 用户声明id |
|||
* @returns 用户声明实体数据传输对象 |
|||
*/ |
|||
export function updateApi(id: string, input: IdentityClaimTypeUpdateDto): Promise<IdentityClaimTypeDto> { |
|||
return requestClient.put<IdentityClaimTypeDto>(`/api/identity/claim-types/${id}`, input); |
|||
} |
|||
|
|||
/** |
|||
* 查询用户声明分页列表 |
|||
* @param input 过滤参数 |
|||
* @returns 用户声明实体数据传输对象分页列表 |
|||
*/ |
|||
export function getPagedListApi( |
|||
input?: GetIdentityClaimTypePagedListInput, |
|||
): Promise<PagedResultDto<IdentityClaimTypeDto>> { |
|||
return requestClient.get<PagedResultDto<IdentityClaimTypeDto>>("/api/identity/claim-types", { |
|||
params: input, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 获取可用的声明类型列表 |
|||
*/ |
|||
export function getAssignableClaimsApi(): Promise<ListResultDto<IdentityClaimTypeDto>> { |
|||
return requestClient.get<ListResultDto<IdentityClaimTypeDto>>("/api/identity/claim-types/actived-list"); |
|||
} |
|||
@ -0,0 +1,173 @@ |
|||
import type { ListResultDto, PagedResultDto } from "#/abp-core"; |
|||
|
|||
import type { IdentityRoleDto, IdentityUserDto } from "#/management/identity"; |
|||
import type { |
|||
GetIdentityRolesInput, |
|||
GetIdentityUsersInput, |
|||
GetOrganizationUnitPagedListInput, |
|||
GetUnaddedRoleListInput, |
|||
GetUnaddedUserListInput, |
|||
OrganizationUnitAddRoleDto, |
|||
OrganizationUnitAddUserDto, |
|||
OrganizationUnitCreateDto, |
|||
OrganizationUnitDto, |
|||
OrganizationUnitGetChildrenDto, |
|||
OrganizationUnitUpdateDto, |
|||
} from "#/management/identity/organization-units"; |
|||
|
|||
import requestClient from "../../request"; |
|||
|
|||
/** |
|||
* 新增组织机构 |
|||
* @param input 参数 |
|||
* @returns 组织机构实体数据传输对象 |
|||
*/ |
|||
export function createApi(input: OrganizationUnitCreateDto): Promise<OrganizationUnitDto> { |
|||
return requestClient.post<OrganizationUnitDto>("/api/identity/organization-units", input); |
|||
} |
|||
|
|||
/** |
|||
* 删除组织机构 |
|||
* @param id 组织机构id |
|||
*/ |
|||
export function deleteApi(id: string): Promise<void> { |
|||
return requestClient.delete(`/api/identity/organization-units/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 查询组织机构 |
|||
* @param id 组织机构id |
|||
* @returns 组织机构实体数据传输对象 |
|||
*/ |
|||
export function getApi(id: string): Promise<OrganizationUnitDto> { |
|||
return requestClient.get<OrganizationUnitDto>(`/api/identity/organization-units/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 更新组织机构 |
|||
* @param id 组织机构id |
|||
* @returns 组织机构实体数据传输对象 |
|||
*/ |
|||
|
|||
export function updateApi(id: string, input: OrganizationUnitUpdateDto): Promise<OrganizationUnitDto> { |
|||
return requestClient.put<OrganizationUnitDto>(`/api/identity/organization-units/${id}`, input); |
|||
} |
|||
|
|||
/** |
|||
* 查询组织机构分页列表 |
|||
* @param input 过滤参数 |
|||
* @returns 组织机构实体数据传输对象分页列表 |
|||
*/ |
|||
export function getPagedListApi( |
|||
input?: GetOrganizationUnitPagedListInput, |
|||
): Promise<PagedResultDto<OrganizationUnitDto>> { |
|||
return requestClient.get<PagedResultDto<OrganizationUnitDto>>("/api/identity/organization-units", { |
|||
params: input, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 查询根组织机构列表 |
|||
* @returns 组织机构实体数据传输对象列表 |
|||
*/ |
|||
export function getRootListApi(): Promise<ListResultDto<OrganizationUnitDto>> { |
|||
return requestClient.get<ListResultDto<OrganizationUnitDto>>("/api/identity/organization-units/root-node"); |
|||
} |
|||
|
|||
/** |
|||
* 查询组织机构列表 |
|||
* @returns 组织机构实体数据传输对象列表 |
|||
*/ |
|||
export function getAllListApi(): Promise<ListResultDto<OrganizationUnitDto>> { |
|||
return requestClient.get<ListResultDto<OrganizationUnitDto>>("/api/identity/organization-units/all"); |
|||
} |
|||
|
|||
/** |
|||
* 查询下级组织机构列表 |
|||
* @param input 查询参数 |
|||
* @returns 组织机构实体数据传输对象列表 |
|||
*/ |
|||
export function getChildrenApi(input: OrganizationUnitGetChildrenDto): Promise<ListResultDto<OrganizationUnitDto>> { |
|||
return requestClient.get<ListResultDto<OrganizationUnitDto>>("/api/identity/organization-units/find-children", { |
|||
params: input, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 查询组织机构用户列表 |
|||
* @param id 组织机构id |
|||
* @param input 查询过滤参数 |
|||
* @returns 用户实体数据传输对象分页列表 |
|||
*/ |
|||
export function getUserListApi(id: string, input?: GetIdentityUsersInput): Promise<PagedResultDto<IdentityUserDto>> { |
|||
return requestClient.get<PagedResultDto<IdentityUserDto>>(`/api/identity/organization-units/${id}/users`, { |
|||
params: input, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 查询未加入组织机构的用户列表 |
|||
* @param input 查询过滤参数 |
|||
* @returns 用户实体数据传输对象分页列表 |
|||
*/ |
|||
export function getUnaddedUserListApi(input: GetUnaddedUserListInput): Promise<PagedResultDto<IdentityUserDto>> { |
|||
return requestClient.get<PagedResultDto<IdentityUserDto>>( |
|||
`/api/identity/organization-units/${input.id}/unadded-users`, |
|||
{ |
|||
params: input, |
|||
}, |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* 用户添加到组织机构 |
|||
* @param id 组织机构id |
|||
* @param input 用户id列表 |
|||
*/ |
|||
export function addMembers(id: string, input: OrganizationUnitAddUserDto): Promise<void> { |
|||
return requestClient.post(`/api/identity/organization-units/${id}/users`, input); |
|||
} |
|||
|
|||
/** |
|||
* 查询组织机构角色列表 |
|||
* @param id 组织机构id |
|||
* @param input 查询过滤参数 |
|||
* @returns 角色实体数据传输对象分页列表 |
|||
*/ |
|||
export function getRoleListApi(id: string, input?: GetIdentityRolesInput): Promise<PagedResultDto<IdentityRoleDto>> { |
|||
return requestClient.get<PagedResultDto<IdentityRoleDto>>(`/api/identity/organization-units/${id}/roles`, { |
|||
params: input, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 查询未加入组织机构的角色列表 |
|||
* @param input 查询过滤参数 |
|||
* @returns 角色实体数据传输对象分页列表 |
|||
*/ |
|||
export function getUnaddedRoleListApi(input: GetUnaddedRoleListInput): Promise<PagedResultDto<IdentityRoleDto>> { |
|||
return requestClient.get<PagedResultDto<IdentityRoleDto>>( |
|||
`/api/identity/organization-units/${input.id}/unadded-roles`, |
|||
{ |
|||
params: input, |
|||
}, |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* 角色添加到组织机构 |
|||
* @param id 组织机构id |
|||
* @param input 角色id列表 |
|||
*/ |
|||
export function addRoles(id: string, input: OrganizationUnitAddRoleDto): Promise<void> { |
|||
return requestClient.post(`/api/identity/organization-units/${id}/roles`, input); |
|||
} |
|||
|
|||
/** |
|||
* 移动组织机构 |
|||
* @param id 组织机构id |
|||
* @param parentId 父级组织机构id |
|||
*/ |
|||
export function moveTo(id: string, parentId?: string): Promise<void> { |
|||
return requestClient.put(`api/identity/organization-units/${id}/move`, { parentId }); |
|||
} |
|||
@ -0,0 +1,109 @@ |
|||
import type { PagedResultDto, ListResultDto } from "#/abp-core"; |
|||
|
|||
import type { |
|||
IdentityClaimCreateDto, |
|||
IdentityClaimDeleteDto, |
|||
IdentityClaimDto, |
|||
IdentityClaimUpdateDto, |
|||
} from "#/management/identity/claims"; |
|||
|
|||
import type { |
|||
GetRolePagedListInput, |
|||
IdentityRoleCreateDto, |
|||
IdentityRoleDto, |
|||
IdentityRoleUpdateDto, |
|||
} from "#/management/identity"; |
|||
|
|||
import requestClient from "../../request"; |
|||
|
|||
/** |
|||
* 新增角色 |
|||
* @param input 参数 |
|||
* @returns 角色实体数据传输对象 |
|||
*/ |
|||
export function createApi(input: IdentityRoleCreateDto): Promise<IdentityRoleDto> { |
|||
return requestClient.post<IdentityRoleDto>("/api/identity/roles", input); |
|||
} |
|||
|
|||
/** |
|||
* 删除角色 |
|||
* @param id 角色id |
|||
*/ |
|||
export function deleteApi(id: string): Promise<void> { |
|||
return requestClient.delete(`/api/identity/roles/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 查询角色 |
|||
* @param id 角色id |
|||
* @returns 角色实体数据传输对象 |
|||
*/ |
|||
export function getApi(id: string): Promise<IdentityRoleDto> { |
|||
return requestClient.get<IdentityRoleDto>(`/api/identity/roles/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 更新角色 |
|||
* @param id 角色id |
|||
* @returns 角色实体数据传输对象 |
|||
*/ |
|||
export function updateApi(id: string, input: IdentityRoleUpdateDto): Promise<IdentityRoleDto> { |
|||
return requestClient.put<IdentityRoleDto>(`/api/identity/roles/${id}`, input); |
|||
} |
|||
|
|||
/** |
|||
* 查询角色分页列表 |
|||
* @param input 过滤参数 |
|||
* @returns 角色实体数据传输对象分页列表 |
|||
*/ |
|||
export function getPagedListApi(input?: GetRolePagedListInput): Promise<PagedResultDto<IdentityRoleDto>> { |
|||
return requestClient.get<PagedResultDto<IdentityRoleDto>>("/api/identity/roles", { |
|||
params: input, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 从组织机构中移除角色 |
|||
* @param id 角色id |
|||
* @param ouId 组织机构id |
|||
*/ |
|||
export function removeOrganizationUnitApi(id: string, ouId: string): Promise<void> { |
|||
return requestClient.delete(`/api/identity/roles/${id}/organization-units/${ouId}`); |
|||
} |
|||
|
|||
/** |
|||
* 获取角色声明列表 |
|||
* @param id 角色id |
|||
*/ |
|||
export function getClaimsApi(id: string): Promise<ListResultDto<IdentityClaimDto>> { |
|||
return requestClient.get<ListResultDto<IdentityClaimDto>>(`/api/identity/roles/${id}/claims`); |
|||
} |
|||
|
|||
/** |
|||
* 删除角色声明 |
|||
* @param id 角色id |
|||
* @param input 角色声明dto |
|||
*/ |
|||
export function deleteClaimApi(id: string, input: IdentityClaimDeleteDto): Promise<void> { |
|||
return requestClient.delete(`/api/identity/roles/${id}/claims`, { |
|||
params: input, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 创建角色声明 |
|||
* @param id 角色id |
|||
* @param input 角色声明dto |
|||
*/ |
|||
export function createClaimApi(id: string, input: IdentityClaimCreateDto): Promise<void> { |
|||
return requestClient.post(`/api/identity/roles/${id}/claims`, input); |
|||
} |
|||
|
|||
/** |
|||
* 更新角色声明 |
|||
* @param id 角色id |
|||
* @param input 用户角色dto |
|||
*/ |
|||
export function updateClaimApi(id: string, input: IdentityClaimUpdateDto): Promise<void> { |
|||
return requestClient.put(`/api/identity/roles/${id}/claims`, input); |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
import type { GetSecurityLogPagedRequest, SecurityLogDto } from "#/management/identity"; |
|||
import type { PagedResultDto } from "#/abp-core"; |
|||
import requestClient from "../../request"; |
|||
|
|||
/** |
|||
* 删除安全日志 |
|||
* @param id 安全日志id |
|||
*/ |
|||
export function deleteApi(id: string): Promise<void> { |
|||
return requestClient.delete(`/api/auditing/security-log/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 查询安全日志 |
|||
* @param id 安全日志id |
|||
* @returns 安全日志实体数据传输对象 |
|||
*/ |
|||
export function getApi(id: string): Promise<SecurityLogDto> { |
|||
return requestClient.get<SecurityLogDto>(`/api/auditing/security-log/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 查询安全日志分页列表 |
|||
* @param input 过滤参数 |
|||
* @returns 安全日志实体数据传输对象分页列表 |
|||
*/ |
|||
export function getPagedListApi(input?: GetSecurityLogPagedRequest): Promise<PagedResultDto<SecurityLogDto>> { |
|||
return requestClient.get<PagedResultDto<SecurityLogDto>>("/api/auditing/security-log", { |
|||
params: input, |
|||
}); |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
import type { ListResultDto } from "#/abp-core"; |
|||
|
|||
import type { IdentityUserDto, UserLookupCountInput, UserLookupSearchInput } from "#/management/identity/user"; |
|||
|
|||
import requestClient from "../../request"; |
|||
|
|||
/** |
|||
* 通过id查询用户 |
|||
* @param id 用户id |
|||
* @returns 用户实体数据传输对象 |
|||
*/ |
|||
export function findByIdApi(id: string): Promise<IdentityUserDto> { |
|||
return requestClient.get<IdentityUserDto>(`/api/identity/users/lookup/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 通过用户名查询用户 |
|||
* @param userName 用户名 |
|||
* @returns 用户实体数据传输对象 |
|||
*/ |
|||
export function findByUserNameApi(userName: string): Promise<IdentityUserDto> { |
|||
return requestClient.get<IdentityUserDto>(`/api/identity/users/lookup/by-username/${userName}`); |
|||
} |
|||
|
|||
/** |
|||
* 搜索用户列表 |
|||
* @param input 搜索过滤条件 |
|||
* @returns 用户实体数据传输对象列表 |
|||
*/ |
|||
export function searchApi(input?: UserLookupSearchInput): Promise<ListResultDto<IdentityUserDto>> { |
|||
return requestClient.get<ListResultDto<IdentityUserDto>>("/api/identity/users/lookup/search", { |
|||
params: input, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 搜索用户数量 |
|||
* @param input 搜索过滤条件 |
|||
*/ |
|||
export function countApi(input?: UserLookupCountInput): Promise<number> { |
|||
return requestClient.get<number>("/api/identity/users/lookup/count", { |
|||
params: input, |
|||
}); |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
import type { PagedResultDto } from "#/abp-core"; |
|||
import type { GetUserSessionsInput, IdentitySessionDto } from "#/management/identity/sessions"; |
|||
import requestClient from "@/api/request"; |
|||
|
|||
/** |
|||
* 查询会话列表 |
|||
* @param { GetUserSessionsInput } input 查询参数 |
|||
* @returns { Promise<PagedResultDto<IdentitySessionDto>> } 用户会话列表 |
|||
*/ |
|||
export function getSessionsApi(input?: GetUserSessionsInput): Promise<PagedResultDto<IdentitySessionDto>> { |
|||
return requestClient.get<PagedResultDto<IdentitySessionDto>>("/api/identity/sessions", { |
|||
params: input, |
|||
}); |
|||
} |
|||
/** |
|||
* 撤销会话 |
|||
* @param { string } sessionId 会话id |
|||
* @returns { Promise<void> } |
|||
*/ |
|||
export function revokeSessionApi(sessionId: string): Promise<void> { |
|||
return requestClient.delete(`/api/identity/sessions/${sessionId}/revoke`); |
|||
} |
|||
@ -0,0 +1,155 @@ |
|||
import type { ListResultDto, PagedResultDto } from "#/abp-core"; |
|||
import type { IdentityRoleDto, OrganizationUnitDto } from "#/management/identity"; |
|||
import type { |
|||
IdentityClaimCreateDto, |
|||
IdentityClaimDeleteDto, |
|||
IdentityClaimDto, |
|||
IdentityClaimUpdateDto, |
|||
} from "#/management/identity/claims"; |
|||
import type { |
|||
ChangeUserPasswordInput, |
|||
GetUserPagedListInput, |
|||
IdentityUserCreateDto, |
|||
IdentityUserDto, |
|||
IdentityUserUpdateDto, |
|||
} from "#/management/identity"; |
|||
import requestClient from "../../request"; |
|||
|
|||
/** |
|||
* 新增用户 |
|||
* @param input 参数 |
|||
* @returns 用户实体数据传输对象 |
|||
*/ |
|||
export function createApi(input: IdentityUserCreateDto): Promise<IdentityUserDto> { |
|||
return requestClient.post<IdentityUserDto>("/api/identity/users", input); |
|||
} |
|||
|
|||
/** |
|||
* 删除用户 |
|||
* @param id 用户id |
|||
*/ |
|||
export function deleteApi(id: string): Promise<void> { |
|||
return requestClient.delete(`/api/identity/users/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 查询用户 |
|||
* @param id 用户id |
|||
* @returns 用户实体数据传输对象 |
|||
*/ |
|||
export function getApi(id: string): Promise<IdentityUserDto> { |
|||
return requestClient.get<IdentityUserDto>(`/api/identity/users/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 更新用户 |
|||
* @param id 用户id |
|||
* @returns 用户实体数据传输对象 |
|||
*/ |
|||
export function updateApi(id: string, input: IdentityUserUpdateDto): Promise<IdentityUserDto> { |
|||
return requestClient.put<IdentityUserDto>(`/api/identity/users/${id}`, input); |
|||
} |
|||
|
|||
/** |
|||
* 查询用户分页列表 |
|||
* @param input 过滤参数 |
|||
* @returns 用户实体数据传输对象分页列表 |
|||
*/ |
|||
export function getPagedListApi(input?: GetUserPagedListInput): Promise<PagedResultDto<IdentityUserDto>> { |
|||
return requestClient.get<PagedResultDto<IdentityUserDto>>("/api/identity/users", { |
|||
params: input, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 从组织机构中移除用户 |
|||
* @param id 用户id |
|||
* @param ouId 组织机构id |
|||
*/ |
|||
export function removeOrganizationUnitApi(id: string, ouId: string): Promise<void> { |
|||
return requestClient.delete(`/api/identity/users/${id}/organization-units/${ouId}`); |
|||
} |
|||
|
|||
/** |
|||
* 获取用户组织机构列表 |
|||
* @param id 用户id |
|||
*/ |
|||
export function getOrganizationUnitsApi(id: string): Promise<ListResultDto<OrganizationUnitDto>> { |
|||
return requestClient.get<ListResultDto<OrganizationUnitDto>>(`/api/identity/users/${id}/organization-units`); |
|||
} |
|||
|
|||
/** |
|||
* 锁定用户 |
|||
* @param id 用户id |
|||
* @param seconds 锁定时长(秒) |
|||
*/ |
|||
export function lockApi(id: string, seconds: number): Promise<void> { |
|||
return requestClient.put(`/api/identity/users/${id}/lock/${seconds}`); |
|||
} |
|||
|
|||
/** |
|||
* 解锁用户 |
|||
* @param id 用户id |
|||
*/ |
|||
export function unLockApi(id: string): Promise<void> { |
|||
return requestClient.put(`/api/identity/users/${id}/unlock`); |
|||
} |
|||
|
|||
/** |
|||
* 更改用户密码 |
|||
* @param id 用户id |
|||
* @param input 密码变更dto |
|||
*/ |
|||
export function changePasswordApi(id: string, input: ChangeUserPasswordInput): Promise<void> { |
|||
return requestClient.put(`/api/identity/users/change-password?id=${id}`, input); |
|||
} |
|||
|
|||
/** |
|||
* 获取可用的角色列表 |
|||
*/ |
|||
export function getAssignableRolesApi(): Promise<ListResultDto<IdentityRoleDto>> { |
|||
return requestClient.get<ListResultDto<IdentityRoleDto>>("/api/identity/users/assignable-roles"); |
|||
} |
|||
|
|||
/** |
|||
* 获取用户角色列表 |
|||
* @param id 用户id |
|||
*/ |
|||
export function getRolesApi(id: string): Promise<ListResultDto<IdentityRoleDto>> { |
|||
return requestClient.get<ListResultDto<IdentityRoleDto>>(`/api/identity/users/${id}/roles`); |
|||
} |
|||
|
|||
/** |
|||
* 获取用户声明列表 |
|||
* @param id 用户id |
|||
*/ |
|||
export function getClaimsApi(id: string): Promise<ListResultDto<IdentityClaimDto>> { |
|||
return requestClient.get<ListResultDto<IdentityClaimDto>>(`/api/identity/users/${id}/claims`); |
|||
} |
|||
|
|||
/** |
|||
* 删除用户声明 |
|||
* @param id 用户id |
|||
* @param input 用户声明dto |
|||
*/ |
|||
export function deleteClaimApi(id: string, input: IdentityClaimDeleteDto): Promise<void> { |
|||
return requestClient.delete(`/api/identity/users/${id}/claims`, { params: input }); |
|||
} |
|||
|
|||
/** |
|||
* 创建用户声明 |
|||
* @param id 用户id |
|||
* @param input 用户声明dto |
|||
*/ |
|||
export function createClaimApi(id: string, input: IdentityClaimCreateDto): Promise<void> { |
|||
return requestClient.post(`/api/identity/users/${id}/claims`, input); |
|||
} |
|||
|
|||
/** |
|||
* 更新用户声明 |
|||
* @param id 用户id |
|||
* @param input 用户声明dto |
|||
*/ |
|||
export function updateClaimApi(id: string, input: IdentityClaimUpdateDto): Promise<void> { |
|||
return requestClient.put(`/api/identity/users/${id}/claims`, input); |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
import type { PagedResultDto } from "#/abp-core"; |
|||
|
|||
import type { |
|||
GetMyNotifilerPagedListInput, |
|||
MarkReadStateInput, |
|||
UserNotificationDto, |
|||
} from "#/notifications/my-notifilers"; |
|||
|
|||
import requestClient from "@/api/request"; |
|||
/** |
|||
* 获取我的通知列表 |
|||
* @param {GetMyNotifilerPagedListInput} input 参数 |
|||
* @returns {Promise<PagedResultDto<UserNotificationDto>>} 通知分页列表 |
|||
*/ |
|||
export function getMyNotifilersApi(input?: GetMyNotifilerPagedListInput): Promise<PagedResultDto<UserNotificationDto>> { |
|||
return requestClient.get<PagedResultDto<UserNotificationDto>>("/api/notifications/my-notifilers", { |
|||
params: input, |
|||
}); |
|||
} |
|||
/** |
|||
* 删除我的通知 |
|||
* @param {string} id 通知id |
|||
* @returns {void} |
|||
*/ |
|||
export function deleteMyNotifilerApi(id: string): Promise<void> { |
|||
return requestClient.delete(`/api/notifications/my-notifilers/${id}`); |
|||
} |
|||
/** |
|||
* 设置通知已读状态 |
|||
* @param {MarkReadStateInput} input 参数 |
|||
* @returns {void} |
|||
*/ |
|||
export function markReadStateApi(input: MarkReadStateInput): Promise<void> { |
|||
return requestClient.put("/api/notifications/my-notifilers/mark-read-state", input); |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
import type { ListResultDto } from "#/abp-core"; |
|||
|
|||
import type { NotificationGroupDto, NotificationTemplateDto } from "#/notifications/definitions"; |
|||
import type { NotificationSendInput, NotificationTemplateSendInput } from "#/notifications/notifications"; |
|||
|
|||
import requestClient from "@/api/request"; |
|||
|
|||
/** |
|||
* 获取可用通知列表 |
|||
* @returns {Promise<ListResultDto<NotificationGroupDto>>} 可用通知列表 |
|||
*/ |
|||
export function getAssignableNotifiersApi(): Promise<ListResultDto<NotificationGroupDto>> { |
|||
return requestClient.get<ListResultDto<NotificationGroupDto>>("/api/notifications/assignables"); |
|||
} |
|||
/** |
|||
* 获取可用通知模板列表 |
|||
* @returns {Promise<ListResultDto<NotificationTemplateDto>>} 可用通知模板列表 |
|||
*/ |
|||
export function getAssignableTemplatesApi(): Promise<ListResultDto<NotificationTemplateDto>> { |
|||
return requestClient.get<ListResultDto<NotificationTemplateDto>>("/api/notifications/assignable-templates", { |
|||
method: "GET", |
|||
}); |
|||
} |
|||
/** |
|||
* 发送通知 |
|||
* @param input 参数 |
|||
* @returns {Promise<void>} |
|||
*/ |
|||
export function sendNotiferApi(input: NotificationSendInput): Promise<void> { |
|||
return requestClient.post("/api/notifications/send", input); |
|||
} |
|||
/** |
|||
* 发送模板通知 |
|||
* @param input 参数 |
|||
* @returns {Promise<void>} |
|||
*/ |
|||
export function sendTemplateNotiferApi(input: NotificationTemplateSendInput): Promise<void> { |
|||
return requestClient.post("/api/notifications/send/template", input); |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
import type { ListResultDto } from "#/abp-core"; |
|||
|
|||
import type { |
|||
PermissionDefinitionCreateDto, |
|||
PermissionDefinitionDto, |
|||
PermissionDefinitionGetListInput, |
|||
PermissionDefinitionUpdateDto, |
|||
} from "#/management/permissions/definitions"; |
|||
|
|||
import requestClient from "../../request"; |
|||
|
|||
/** |
|||
* 删除权限定义 |
|||
* @param name 权限名称 |
|||
*/ |
|||
export function deleteApi(name: string): Promise<void> { |
|||
return requestClient.delete(`/api/permission-management/definitions/${name}`); |
|||
} |
|||
|
|||
/** |
|||
* 查询权限定义 |
|||
* @param name 权限名称 |
|||
* @returns 权限定义数据传输对象 |
|||
*/ |
|||
export function getApi(name: string): Promise<PermissionDefinitionDto> { |
|||
return requestClient.get<PermissionDefinitionDto>(`/api/permission-management/definitions/${name}`); |
|||
} |
|||
|
|||
/** |
|||
* 查询权限定义列表 |
|||
* @param input 权限过滤条件 |
|||
* @returns 权限定义数据传输对象列表 |
|||
*/ |
|||
export function getListApi(input?: PermissionDefinitionGetListInput): Promise<ListResultDto<PermissionDefinitionDto>> { |
|||
return requestClient.get<ListResultDto<PermissionDefinitionDto>>("/api/permission-management/definitions", { |
|||
params: input, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 创建权限定义 |
|||
* @param input 权限定义参数 |
|||
* @returns 权限定义数据传输对象 |
|||
*/ |
|||
export function createApi(input: PermissionDefinitionCreateDto): Promise<PermissionDefinitionDto> { |
|||
return requestClient.post<PermissionDefinitionDto>("/api/permission-management/definitions", input); |
|||
} |
|||
|
|||
/** |
|||
* 更新权限定义 |
|||
* @param name 权限名称 |
|||
* @param input 权限定义参数 |
|||
* @returns 权限定义数据传输对象 |
|||
*/ |
|||
export function updateApi(name: string, input: PermissionDefinitionUpdateDto): Promise<PermissionDefinitionDto> { |
|||
return requestClient.put<PermissionDefinitionDto>(`/api/permission-management/definitions/${name}`, input); |
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
import type { ListResultDto } from "#/abp-core"; |
|||
|
|||
import type { |
|||
PermissionGroupDefinitionCreateDto, |
|||
PermissionGroupDefinitionDto, |
|||
PermissionGroupDefinitionGetListInput, |
|||
PermissionGroupDefinitionUpdateDto, |
|||
} from "#/management/permissions/groups"; |
|||
|
|||
import requestClient from "../../request"; |
|||
|
|||
/** |
|||
* 删除权限定义 |
|||
* @param name 权限名称 |
|||
*/ |
|||
export function deleteApi(name: string): Promise<void> { |
|||
return requestClient.delete(`/api/permission-management/definitions/groups/${name}`); |
|||
} |
|||
|
|||
/** |
|||
* 查询权限定义 |
|||
* @param name 权限名称 |
|||
* @returns 权限定义数据传输对象 |
|||
*/ |
|||
export function getApi(name: string): Promise<PermissionGroupDefinitionDto> { |
|||
return requestClient.get<PermissionGroupDefinitionDto>(`/api/permission-management/definitions/groups/${name}`); |
|||
} |
|||
|
|||
/** |
|||
* 查询权限定义列表 |
|||
* @param input 权限过滤条件 |
|||
* @returns 权限定义数据传输对象列表 |
|||
*/ |
|||
export function getListApi( |
|||
input?: PermissionGroupDefinitionGetListInput, |
|||
): Promise<ListResultDto<PermissionGroupDefinitionDto>> { |
|||
return requestClient.get<ListResultDto<PermissionGroupDefinitionDto>>( |
|||
"/api/permission-management/definitions/groups", |
|||
{ |
|||
params: input, |
|||
}, |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* 创建权限定义 |
|||
* @param input 权限定义参数 |
|||
* @returns 权限定义数据传输对象 |
|||
*/ |
|||
export function createApi(input: PermissionGroupDefinitionCreateDto): Promise<PermissionGroupDefinitionDto> { |
|||
return requestClient.post<PermissionGroupDefinitionDto>("/api/permission-management/definitions/groups", input); |
|||
} |
|||
|
|||
/** |
|||
* 更新权限定义 |
|||
* @param name 权限名称 |
|||
* @param input 权限定义参数 |
|||
* @returns 权限定义数据传输对象 |
|||
*/ |
|||
export function updateApi( |
|||
name: string, |
|||
input: PermissionGroupDefinitionUpdateDto, |
|||
): Promise<PermissionGroupDefinitionDto> { |
|||
return requestClient.put<PermissionGroupDefinitionDto>( |
|||
`/api/permission-management/definitions/groups/${name}`, |
|||
input, |
|||
); |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
import type { PermissionProvider, PermissionResultDto, PermissionsUpdateDto } from "#/management/permissions"; |
|||
|
|||
import requestClient from "../../request"; |
|||
|
|||
/** |
|||
* 查询权限 |
|||
* @param provider |
|||
* @returns 权限实体数据传输对象 |
|||
*/ |
|||
export function getApi(provider: PermissionProvider): Promise<PermissionResultDto> { |
|||
return requestClient.get<PermissionResultDto>("/api/permission-management/permissions", { |
|||
params: provider, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 更新权限 |
|||
* @param provider |
|||
* @param input |
|||
*/ |
|||
export function updateApi(provider: PermissionProvider, input: PermissionsUpdateDto): Promise<void> { |
|||
return requestClient.put("/api/permission-management/permissions", input, { |
|||
params: provider, |
|||
}); |
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
import type { ListResultDto } from "#/abp-core"; |
|||
|
|||
import type { |
|||
SettingDefinitionCreateDto, |
|||
SettingDefinitionDto, |
|||
SettingDefinitionGetListInput, |
|||
SettingDefinitionUpdateDto, |
|||
} from "#/management/settings/definitions"; |
|||
import requestClient from "@/api/request"; |
|||
|
|||
/** |
|||
* 删除设置定义 |
|||
* @param name 设置名称 |
|||
*/ |
|||
export function deleteApi(name: string): Promise<void> { |
|||
return requestClient.delete(`/api/setting-management/settings/definitions/${name}`); |
|||
} |
|||
|
|||
/** |
|||
* 查询设置定义 |
|||
* @param name 设置名称 |
|||
* @returns 设置定义数据传输对象 |
|||
*/ |
|||
export function getApi(name: string): Promise<SettingDefinitionDto> { |
|||
return requestClient.get<SettingDefinitionDto>(`/api/setting-management/settings/definitions/${name}`); |
|||
} |
|||
|
|||
/** |
|||
* 查询设置定义列表 |
|||
* @param input 设置过滤条件 |
|||
* @returns 设置定义数据传输对象列表 |
|||
*/ |
|||
export function getListApi(input?: SettingDefinitionGetListInput): Promise<ListResultDto<SettingDefinitionDto>> { |
|||
return requestClient.get<ListResultDto<SettingDefinitionDto>>("/api/setting-management/settings/definitions", { |
|||
params: input, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 创建设置定义 |
|||
* @param input 设置定义参数 |
|||
* @returns 设置定义数据传输对象 |
|||
*/ |
|||
export function createApi(input: SettingDefinitionCreateDto): Promise<SettingDefinitionDto> { |
|||
return requestClient.post<SettingDefinitionDto>("/api/setting-management/settings/definitions", input); |
|||
} |
|||
|
|||
/** |
|||
* 更新设置定义 |
|||
* @param name 设置名称 |
|||
* @param input 设置定义参数 |
|||
* @returns 设置定义数据传输对象 |
|||
*/ |
|||
export function updateApi(name: string, input: SettingDefinitionUpdateDto): Promise<SettingDefinitionDto> { |
|||
return requestClient.put<SettingDefinitionDto>(`/api/setting-management/settings/definitions/${name}`, input); |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
import type { ListResultDto } from "#/abp-core"; |
|||
|
|||
import type { SettingGroup, SettingsUpdateInput } from "#/management/settings"; |
|||
|
|||
import requestClient from "@/api/request"; |
|||
|
|||
/** |
|||
* 获取全局设置 |
|||
* @returns 设置数据传输对象列表 |
|||
*/ |
|||
export function getGlobalSettingsApi(): Promise<ListResultDto<SettingGroup>> { |
|||
return requestClient.get<ListResultDto<SettingGroup>>("/api/setting-management/settings/by-global"); |
|||
} |
|||
|
|||
/** |
|||
* 设置全局设置 |
|||
* @returns 设置数据传输对象列表 |
|||
*/ |
|||
export function setGlobalSettingsApi(input: SettingsUpdateInput): Promise<void> { |
|||
return requestClient.put("/api/setting-management/settings/change-global", input); |
|||
} |
|||
|
|||
/** |
|||
* 获取租户设置 |
|||
* @returns 设置数据传输对象列表 |
|||
*/ |
|||
export function getTenantSettingsApi(): Promise<ListResultDto<SettingGroup>> { |
|||
return requestClient.get<ListResultDto<SettingGroup>>("api/setting-management/settings/by-current-tenant"); |
|||
} |
|||
|
|||
/** |
|||
* 设置租户设置 |
|||
* @returns 设置数据传输对象列表 |
|||
*/ |
|||
export function setTenantSettingsApi(input: SettingsUpdateInput): Promise<void> { |
|||
return requestClient.put("/api/setting-management/settings/change-current-tenant", input); |
|||
} |
|||
/** |
|||
* 获取用户设置 |
|||
* @returns 设置数据传输对象列表 |
|||
*/ |
|||
export function getUserSettingsApi(): Promise<ListResultDto<SettingGroup>> { |
|||
return requestClient.get<ListResultDto<SettingGroup>>("/api/setting-management/settings/by-current-user"); |
|||
} |
|||
|
|||
/** |
|||
* 设置用户设置 |
|||
* @returns 设置数据传输对象列表 |
|||
*/ |
|||
export function setUserSettingsApi(input: SettingsUpdateInput): Promise<void> { |
|||
return requestClient.put("/api/setting-management/settings/change-current-user", input); |
|||
} |
|||
|
|||
/** |
|||
* 发送测试邮件 |
|||
* @param emailAddress 邮件接收方地址 |
|||
*/ |
|||
export const sendTestEmailApi = (emailAddress: string) => { |
|||
return requestClient.post("/api/setting-management/settings/send-test-email", { |
|||
emailAddress, |
|||
}); |
|||
}; |
|||
@ -0,0 +1,58 @@ |
|||
import type { PagedResultDto } from "#/abp-core"; |
|||
import type { |
|||
OpenIddictApplicationCreateDto, |
|||
OpenIddictApplicationDto, |
|||
OpenIddictApplicationGetListInput, |
|||
OpenIddictApplicationUpdateDto, |
|||
} from "#/openiddict/applications"; |
|||
|
|||
import requestClient from "../request"; |
|||
|
|||
/** |
|||
* 创建应用 |
|||
* @param input 参数 |
|||
* @returns 应用实体数据传输对象 |
|||
*/ |
|||
export function createApi(input: OpenIddictApplicationCreateDto): Promise<OpenIddictApplicationDto> { |
|||
return requestClient.post<OpenIddictApplicationDto>("/api/openiddict/applications", input); |
|||
} |
|||
|
|||
/** |
|||
* 删除应用 |
|||
* @param id 应用id |
|||
*/ |
|||
export function deleteApi(id: string): Promise<void> { |
|||
return requestClient.delete(`/api/openiddict/applications/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 查询应用 |
|||
* @param id 应用id |
|||
* @returns 应用实体数据传输对象 |
|||
*/ |
|||
export function getApi(id: string): Promise<OpenIddictApplicationDto> { |
|||
return requestClient.get<OpenIddictApplicationDto>(`/api/openiddict/applications/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 更新应用 |
|||
* @param id 应用id |
|||
* @param input 更新参数 |
|||
* @returns 应用实体数据传输对象 |
|||
*/ |
|||
export function updateApi(id: string, input: OpenIddictApplicationUpdateDto): Promise<OpenIddictApplicationDto> { |
|||
return requestClient.put<OpenIddictApplicationDto>(`/api/openiddict/applications/${id}`, input); |
|||
} |
|||
|
|||
/** |
|||
* 查询应用分页列表 |
|||
* @param input 过滤参数 |
|||
* @returns 应用实体数据传输对象分页列表 |
|||
*/ |
|||
export function getPagedListApi( |
|||
input?: OpenIddictApplicationGetListInput, |
|||
): Promise<PagedResultDto<OpenIddictApplicationDto>> { |
|||
return requestClient.get<PagedResultDto<OpenIddictApplicationDto>>("/api/openiddict/applications", { |
|||
params: input, |
|||
}); |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
import type { PagedResultDto } from "#/abp-core"; |
|||
import type { OpenIddictAuthorizationDto, OpenIddictAuthorizationGetListInput } from "#/openiddict/authorizations"; |
|||
|
|||
import requestClient from "../request"; |
|||
|
|||
/** |
|||
* 删除授权 |
|||
* @param id 授权id |
|||
*/ |
|||
export function deleteApi(id: string): Promise<void> { |
|||
return requestClient.delete(`/api/openiddict/authorizations/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 查询授权 |
|||
* @param id 授权id |
|||
* @returns 授权实体数据传输对象 |
|||
*/ |
|||
export function getApi(id: string): Promise<OpenIddictAuthorizationDto> { |
|||
return requestClient.get<OpenIddictAuthorizationDto>(`/api/openiddict/authorizations/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 查询授权分页列表 |
|||
* @param input 过滤参数 |
|||
* @returns 授权实体数据传输对象分页列表 |
|||
*/ |
|||
export function getPagedListApi( |
|||
input?: OpenIddictAuthorizationGetListInput, |
|||
): Promise<PagedResultDto<OpenIddictAuthorizationDto>> { |
|||
return requestClient.get<PagedResultDto<OpenIddictAuthorizationDto>>("/api/openiddict/authorizations", { |
|||
params: input, |
|||
}); |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
import type { OpenIdConfiguration } from "#/abp-core/openid"; |
|||
|
|||
import requestClient from "../request"; |
|||
|
|||
/** |
|||
* openid发现端点 |
|||
* @returns OpenId配置数据 |
|||
*/ |
|||
export function discoveryApi(): Promise<OpenIdConfiguration> { |
|||
return requestClient.get<OpenIdConfiguration>("/.well-known/openid-configuration"); |
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
import type { PagedResultDto } from "#/abp-core"; |
|||
import type { |
|||
OpenIddictScopeCreateDto, |
|||
OpenIddictScopeDto, |
|||
OpenIddictScopeGetListInput, |
|||
OpenIddictScopeUpdateDto, |
|||
} from "#/openiddict/scopes"; |
|||
|
|||
import requestClient from "../request"; |
|||
|
|||
/** |
|||
* 创建范围 |
|||
* @param input 参数 |
|||
* @returns 范围实体数据传输对象 |
|||
*/ |
|||
export function createApi(input: OpenIddictScopeCreateDto): Promise<OpenIddictScopeDto> { |
|||
return requestClient.post<OpenIddictScopeDto>("/api/openiddict/scopes", input); |
|||
} |
|||
|
|||
/** |
|||
* 删除范围 |
|||
* @param id 范围id |
|||
*/ |
|||
export function deleteApi(id: string): Promise<void> { |
|||
return requestClient.delete(`/api/openiddict/scopes/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 获取范围 |
|||
* @param id 范围id |
|||
* @returns 范围实体数据传输对象 |
|||
*/ |
|||
export function getApi(id: string): Promise<OpenIddictScopeDto> { |
|||
return requestClient.get<OpenIddictScopeDto>(`/api/openiddict/scopes/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 更新范围 |
|||
* @param id 范围id |
|||
* @param input 更新参数 |
|||
* @returns 范围实体数据传输对象 |
|||
*/ |
|||
export function updateApi(id: string, input: OpenIddictScopeUpdateDto): Promise<OpenIddictScopeDto> { |
|||
return requestClient.put<OpenIddictScopeDto>(`/api/openiddict/scopes/${id}`, input); |
|||
} |
|||
|
|||
/** |
|||
* 获取范围分页列表 |
|||
* @param input 过滤参数 |
|||
* @returns 范围实体数据传输对象分页列表 |
|||
*/ |
|||
export function getPagedListApi(input?: OpenIddictScopeGetListInput): Promise<PagedResultDto<OpenIddictScopeDto>> { |
|||
return requestClient.get<PagedResultDto<OpenIddictScopeDto>>("/api/openiddict/scopes", { |
|||
params: input, |
|||
}); |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
import type { PagedResultDto } from "#/abp-core"; |
|||
import type { OpenIddictTokenDto, OpenIddictTokenGetListInput } from "#/openiddict/tokens"; |
|||
import requestClient from "../request"; |
|||
|
|||
/** |
|||
* 删除令牌 |
|||
* @param id 令牌id |
|||
*/ |
|||
export function deleteApi(id: string): Promise<void> { |
|||
return requestClient.delete(`/api/openiddict/tokens/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 获取令牌 |
|||
* @param id 令牌id |
|||
* @returns 令牌实体数据传输对象 |
|||
*/ |
|||
export function getApi(id: string): Promise<OpenIddictTokenDto> { |
|||
return requestClient.get<OpenIddictTokenDto>(`/api/openiddict/tokens/${id}`); |
|||
} |
|||
|
|||
/** |
|||
* 获取令牌分页列表 |
|||
* @param input 过滤参数 |
|||
* @returns 令牌实体数据传输对象分页列表 |
|||
*/ |
|||
export function getPagedListApi(input?: OpenIddictTokenGetListInput): Promise<PagedResultDto<OpenIddictTokenDto>> { |
|||
return requestClient.get<PagedResultDto<OpenIddictTokenDto>>("/api/openiddict/tokens", { |
|||
params: input, |
|||
}); |
|||
} |
|||
@ -0,0 +1,127 @@ |
|||
import { authenticateResponseInterceptor, errorMessageResponseInterceptor, RequestClient } from "@/request-client"; |
|||
import useLocaleStore from "@/store/localeI18nStore"; |
|||
import useUserStore from "@/store/userStore"; |
|||
import userStore from "@/store/userStore"; |
|||
import { mapLocaleToAbpLanguageFormat } from "@/utils"; |
|||
import { toast } from "sonner"; |
|||
import { refreshToken } from "./account/token"; |
|||
import { wrapperResult } from "@/utils/abp/request"; |
|||
import { handleOAuthError } from "@/utils/abp/handleOAuthError"; |
|||
|
|||
const requestClient = new RequestClient({ |
|||
baseURL: import.meta.env.VITE_APP_BASE_API, |
|||
}); |
|||
|
|||
/** |
|||
* 重新认证逻辑 |
|||
*/ |
|||
async function doReAuthenticate() { |
|||
console.warn("Access token or refresh token is invalid or expired. "); |
|||
//直接登出
|
|||
userStore.getState().actions.clearUserInfoAndToken(); |
|||
} |
|||
|
|||
/** |
|||
* 刷新token逻辑 |
|||
*/ |
|||
async function doRefreshToken() { |
|||
console.debug("try -> Refresh token"); |
|||
|
|||
const { userToken } = useUserStore.getState(); |
|||
if (!userToken.refreshToken) { |
|||
console.warn("No refresh token available."); |
|||
return ""; |
|||
} |
|||
|
|||
try { |
|||
const res = await refreshToken({ refreshToken: userToken.refreshToken }); |
|||
|
|||
const { tokenType, accessToken, refreshToken: newRefreshToken } = res; |
|||
|
|||
if (accessToken) { |
|||
// 更新 userStore,保存新 token
|
|||
useUserStore.getState().actions.setUserToken({ |
|||
accessToken: `${tokenType} ${accessToken}`, |
|||
refreshToken: newRefreshToken, |
|||
}); |
|||
console.debug("Token refreshed successfully."); |
|||
return `${tokenType} ${accessToken}`; // 返回新 token 供拦截器使用
|
|||
} |
|||
|
|||
console.error("Failed to refresh token: No access token returned."); |
|||
return ""; |
|||
} catch (error) { |
|||
console.error("Error refreshing token:", error); |
|||
return ""; // 返回空字符串,触发重登录逻辑
|
|||
} |
|||
} |
|||
|
|||
function formatToken(token: null | string) { |
|||
return token ? token : null; //有个tokenType的获取值
|
|||
} |
|||
|
|||
// 请求头处理
|
|||
requestClient.addRequestInterceptor({ |
|||
fulfilled: async (config) => { |
|||
const { userToken } = useUserStore.getState(); |
|||
if (userToken.accessToken) { |
|||
config.headers.Authorization = `${userToken.accessToken}`; |
|||
} |
|||
const { locale } = useLocaleStore.getState(); |
|||
config.headers["Accept-Language"] = mapLocaleToAbpLanguageFormat(locale); |
|||
config.headers["X-Request-From"] = "slash-admin"; |
|||
return config; |
|||
}, |
|||
}); |
|||
|
|||
// response数据解构
|
|||
requestClient.addResponseInterceptor<any>({ |
|||
fulfilled: (response) => { |
|||
const { data, status } = response; |
|||
const { hasWrapResult, getData } = wrapperResult(response); |
|||
|
|||
if (hasWrapResult()) { |
|||
return getData(); |
|||
} |
|||
|
|||
if (status >= 200 && status < 400) { |
|||
return data; |
|||
} |
|||
|
|||
throw Object.assign({}, response, { response }); |
|||
}, |
|||
}); |
|||
|
|||
// token过期的处理
|
|||
requestClient.addResponseInterceptor( |
|||
authenticateResponseInterceptor({ |
|||
client: requestClient, |
|||
doReAuthenticate, |
|||
doRefreshToken, |
|||
enableRefreshToken: true, |
|||
formatToken, |
|||
}), |
|||
); |
|||
|
|||
// 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里
|
|||
requestClient.addResponseInterceptor( |
|||
errorMessageResponseInterceptor((msg: string, error) => { |
|||
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
|
|||
// 当前mock接口返回的错误字段是 error 或者 message
|
|||
const responseData = error?.response?.data ?? {}; |
|||
if (responseData?.error_description) { |
|||
const { formatError } = handleOAuthError(); |
|||
toast.error(formatError(responseData) || msg, { |
|||
position: "top-center", |
|||
}); |
|||
return; |
|||
} |
|||
const errorMessage = responseData?.error ?? responseData?.message ?? ""; |
|||
// 如果没有错误信息,则会根据状态码进行提示
|
|||
toast.error(errorMessage || msg, { |
|||
position: "top-center", |
|||
}); |
|||
}), |
|||
); |
|||
|
|||
export default requestClient; |
|||
@ -0,0 +1,11 @@ |
|||
import apiClient from "../apiClient"; |
|||
|
|||
export enum DemoApi { |
|||
TOKEN_EXPIRED = "/user/tokenExpired", |
|||
} |
|||
|
|||
const mockTokenExpired = () => apiClient.post({ url: DemoApi.TOKEN_EXPIRED }); |
|||
|
|||
export default { |
|||
mockTokenExpired, |
|||
}; |
|||
@ -0,0 +1,13 @@ |
|||
import apiClient from "../apiClient"; |
|||
|
|||
import type { Organization } from "#/entity"; |
|||
|
|||
export enum OrgApi { |
|||
Org = "/org", |
|||
} |
|||
|
|||
const getOrgList = () => apiClient.get<Organization[]>({ url: OrgApi.Org }); |
|||
|
|||
export default { |
|||
getOrgList, |
|||
}; |
|||
@ -0,0 +1,33 @@ |
|||
import apiClient from "../apiClient"; |
|||
|
|||
import type { UserInfo, UserToken } from "#/entity"; |
|||
|
|||
export interface SignInReq { |
|||
username: string; |
|||
password: string; |
|||
} |
|||
|
|||
export interface SignUpReq extends SignInReq { |
|||
email: string; |
|||
} |
|||
export type SignInRes = UserToken & { user: UserInfo }; |
|||
|
|||
export enum UserApi { |
|||
SignIn = "/auth/signin", |
|||
SignUp = "/auth/signup", |
|||
Logout = "/auth/logout", |
|||
Refresh = "/auth/refresh", |
|||
User = "/user", |
|||
} |
|||
|
|||
const signin = (data: SignInReq) => apiClient.post<SignInRes>({ url: UserApi.SignIn, data }); |
|||
const signup = (data: SignUpReq) => apiClient.post<SignInRes>({ url: UserApi.SignUp, data }); |
|||
const logout = () => apiClient.get({ url: UserApi.Logout }); |
|||
const findById = (id: string) => apiClient.get<UserInfo[]>({ url: `${UserApi.User}/${id}` }); |
|||
|
|||
export default { |
|||
signin, |
|||
signup, |
|||
findById, |
|||
logout, |
|||
}; |
|||
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 418 B |
|
After Width: | Height: | Size: 351 B |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 767 B |
|
After Width: | Height: | Size: 710 B |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 346 B |
|
After Width: | Height: | Size: 356 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 509 B |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 735 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 1.6 KiB |