feat: login

This commit is contained in:
2025-09-09 16:58:30 +08:00
parent d6457f59f7
commit f33f597a9a
41 changed files with 10998 additions and 3594 deletions

View File

@@ -1,20 +1,20 @@
// https://umijs.org/config/ // https://umijs.org/config/
import { join } from 'node:path'; import { join } from "node:path";
import { defineConfig } from '@umijs/max'; import { defineConfig } from "@umijs/max";
import defaultSettings from './defaultSettings'; import defaultSettings from "./defaultSettings";
import proxy from './proxy'; import proxy from "./proxy";
import routes from './routes'; import routes from "./routes";
const { UMI_ENV = 'dev' } = process.env; const { UMI_ENV = "dev" } = process.env;
/** /**
* @name 使用公共路径 * @name 使用公共路径
* @description 部署时的路径,如果部署在非根目录下,需要配置这个变量 * @description 部署时的路径,如果部署在非根目录下,需要配置这个变量
* @doc https://umijs.org/docs/api/config#publicpath * @doc https://umijs.org/docs/api/config#publicpath
*/ */
const PUBLIC_PATH: string = '/'; const PUBLIC_PATH: string = "/";
export default defineConfig({ export default defineConfig({
/** /**
@@ -83,7 +83,7 @@ export default defineConfig({
* @name layout 插件 * @name layout 插件
* @doc https://umijs.org/docs/max/layout-menu * @doc https://umijs.org/docs/max/layout-menu
*/ */
title: 'Ant Design Pro', title: "Ant Design Pro",
layout: { layout: {
locale: true, locale: true,
...defaultSettings, ...defaultSettings,
@@ -94,8 +94,8 @@ export default defineConfig({
* @doc https://umijs.org/docs/max/moment2dayjs * @doc https://umijs.org/docs/max/moment2dayjs
*/ */
moment2dayjs: { moment2dayjs: {
preset: 'antd', preset: "antd",
plugins: ['duration'], plugins: ["duration"],
}, },
/** /**
* @name 国际化插件 * @name 国际化插件
@@ -103,7 +103,7 @@ export default defineConfig({
*/ */
locale: { locale: {
// default zh-CN // default zh-CN
default: 'zh-CN', default: "zh-CN",
antd: true, antd: true,
// default true, when it is true, will use `navigator.language` overwrite default // default true, when it is true, will use `navigator.language` overwrite default
baseNavigator: true, baseNavigator: true,
@@ -119,7 +119,7 @@ export default defineConfig({
theme: { theme: {
cssVar: true, cssVar: true,
token: { token: {
fontFamily: 'AlibabaSans, sans-serif', fontFamily: "AlibabaSans, sans-serif",
}, },
}, },
}, },
@@ -142,10 +142,10 @@ export default defineConfig({
*/ */
headScripts: [ headScripts: [
// 解决首次加载时白屏的问题 // 解决首次加载时白屏的问题
{ src: join(PUBLIC_PATH, 'scripts/loading.js'), async: true }, { src: join(PUBLIC_PATH, "scripts/loading.js"), async: true },
], ],
//================ pro 插件配置 ================= //================ pro 插件配置 =================
presets: ['umi-presets-pro'], presets: ["umi-presets-pro"],
/** /**
* @name openAPI 插件的配置 * @name openAPI 插件的配置
* @description 基于 openapi 的规范生成serve 和mock能减少很多样板代码 * @description 基于 openapi 的规范生成serve 和mock能减少很多样板代码
@@ -154,20 +154,19 @@ export default defineConfig({
openAPI: [ openAPI: [
{ {
requestLibPath: "import { request } from '@umijs/max'", requestLibPath: "import { request } from '@umijs/max'",
// 或者使用在线的版本
// schemaPath: "https://gw.alipayobjects.com/os/antfincdn/M%24jrzTTYJN/oneapi.json" schemaPath: join(__dirname, "oneapi/prodapi.json"),
schemaPath: join(__dirname, 'oneapi.json'),
mock: false, mock: false,
projectName: "prodApi",
}, },
{ // {schemaPath: "./docs/apifox-api.json",
requestLibPath: "import { request } from '@umijs/max'", // requestLibPath: "import { request } from '@umijs/max'",
schemaPath: // schemaPath: join(__dirname, "oneapi.json"),
'https://gw.alipayobjects.com/os/antfincdn/CA1dOm%2631B/openapi.json', // projectName: "login",
projectName: 'swagger', // },
},
], ],
mock: { mock: {
include: ['mock/**/*', 'src/pages/**/_mock.ts'], include: ["mock/**/*", "src/pages/**/_mock.ts"],
}, },
/** /**
* @name 是否开启 mako * @name 是否开启 mako
@@ -179,6 +178,6 @@ export default defineConfig({
requestRecord: {}, requestRecord: {},
exportStatic: {}, exportStatic: {},
define: { define: {
'process.env.CI': process.env.CI, "process.env.CI": process.env.CI,
}, },
}); });

View File

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

View File

@@ -1,593 +0,0 @@
{
"openapi": "3.0.1",
"info": {
"title": "Ant Design Pro",
"version": "1.0.0"
},
"servers": [
{
"url": "http://localhost:8000/"
},
{
"url": "https://localhost:8000/"
}
],
"paths": {
"/api/currentUser": {
"get": {
"tags": ["api"],
"description": "获取当前的用户",
"operationId": "currentUser",
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CurrentUser"
}
}
}
},
"401": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
},
"x-swagger-router-controller": "api"
},
"/api/login/captcha": {
"post": {
"description": "发送验证码",
"operationId": "getFakeCaptcha",
"tags": ["login"],
"parameters": [
{
"name": "phone",
"in": "query",
"description": "手机号",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/FakeCaptcha"
}
}
}
}
}
}
},
"/api/login/outLogin": {
"post": {
"description": "登录接口",
"operationId": "outLogin",
"tags": ["login"],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
},
"401": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
},
"x-swagger-router-controller": "api"
},
"/api/login/account": {
"post": {
"tags": ["login"],
"description": "登录接口",
"operationId": "login",
"requestBody": {
"description": "登录系统",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginParams"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginResult"
}
}
}
},
"401": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
},
"x-codegen-request-body-name": "body"
},
"x-swagger-router-controller": "api"
},
"/api/notices": {
"summary": "getNotices",
"description": "NoticeIconItem",
"get": {
"tags": ["api"],
"operationId": "getNotices",
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NoticeIconList"
}
}
}
}
}
}
},
"/api/rule": {
"get": {
"tags": ["rule"],
"description": "获取规则列表",
"operationId": "rule",
"parameters": [
{
"name": "current",
"in": "query",
"description": "当前的页码",
"schema": {
"type": "number"
}
},
{
"name": "pageSize",
"in": "query",
"description": "页面的容量",
"schema": {
"type": "number"
}
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RuleList"
}
}
}
},
"401": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
},
"post": {
"tags": ["rule"],
"description": "新建规则",
"operationId": "addRule",
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RuleListItem"
}
}
}
},
"401": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
},
"put": {
"tags": ["rule"],
"description": "新建规则",
"operationId": "updateRule",
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RuleListItem"
}
}
}
},
"401": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
},
"delete": {
"tags": ["rule"],
"description": "删除规则",
"operationId": "removeRule",
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
},
"401": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
},
"x-swagger-router-controller": "api"
},
"/swagger": {
"x-swagger-pipe": "swagger_raw"
}
},
"components": {
"schemas": {
"CurrentUser": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"avatar": {
"type": "string"
},
"userid": {
"type": "string"
},
"email": {
"type": "string"
},
"signature": {
"type": "string"
},
"title": {
"type": "string"
},
"group": {
"type": "string"
},
"tags": {
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string"
},
"label": {
"type": "string"
}
}
}
},
"notifyCount": {
"type": "integer",
"format": "int32"
},
"unreadCount": {
"type": "integer",
"format": "int32"
},
"country": {
"type": "string"
},
"access": {
"type": "string"
},
"geographic": {
"type": "object",
"properties": {
"province": {
"type": "object",
"properties": {
"label": {
"type": "string"
},
"key": {
"type": "string"
}
}
},
"city": {
"type": "object",
"properties": {
"label": {
"type": "string"
},
"key": {
"type": "string"
}
}
}
}
},
"address": {
"type": "string"
},
"phone": {
"type": "string"
}
}
},
"LoginResult": {
"type": "object",
"properties": {
"status": {
"type": "string"
},
"type": {
"type": "string"
},
"currentAuthority": {
"type": "string"
}
}
},
"PageParams": {
"type": "object",
"properties": {
"current": {
"type": "number"
},
"pageSize": {
"type": "number"
}
}
},
"RuleListItem": {
"type": "object",
"properties": {
"key": {
"type": "integer",
"format": "int32"
},
"disabled": {
"type": "boolean"
},
"href": {
"type": "string"
},
"avatar": {
"type": "string"
},
"name": {
"type": "string"
},
"owner": {
"type": "string"
},
"desc": {
"type": "string"
},
"callNo": {
"type": "integer",
"format": "int32"
},
"status": {
"type": "integer",
"format": "int32"
},
"updatedAt": {
"type": "string",
"format": "datetime"
},
"createdAt": {
"type": "string",
"format": "datetime"
},
"progress": {
"type": "integer",
"format": "int32"
}
}
},
"RuleList": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/RuleListItem"
}
},
"total": {
"type": "integer",
"description": "列表的内容总数",
"format": "int32"
},
"success": {
"type": "boolean"
}
}
},
"FakeCaptcha": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"status": {
"type": "string"
}
}
},
"LoginParams": {
"type": "object",
"properties": {
"username": {
"type": "string"
},
"password": {
"type": "string"
},
"autoLogin": {
"type": "boolean"
},
"type": {
"type": "string"
}
}
},
"ErrorResponse": {
"required": ["errorCode"],
"type": "object",
"properties": {
"errorCode": {
"type": "string",
"description": "业务约定的错误码"
},
"errorMessage": {
"type": "string",
"description": "业务上的错误信息"
},
"success": {
"type": "boolean",
"description": "业务上的请求是否成功"
}
}
},
"NoticeIconList": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/NoticeIconItem"
}
},
"total": {
"type": "integer",
"description": "列表的内容总数",
"format": "int32"
},
"success": {
"type": "boolean"
}
}
},
"NoticeIconItemType": {
"title": "NoticeIconItemType",
"description": "已读未读列表的枚举",
"type": "string",
"properties": {},
"enum": ["notification", "message", "event"]
},
"NoticeIconItem": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"extra": {
"type": "string",
"format": "any"
},
"key": { "type": "string" },
"read": {
"type": "boolean"
},
"avatar": {
"type": "string"
},
"title": {
"type": "string"
},
"status": {
"type": "string"
},
"datetime": {
"type": "string",
"format": "date"
},
"description": {
"type": "string"
},
"type": {
"extensions": {
"x-is-enum": true
},
"$ref": "#/components/schemas/NoticeIconItemType"
}
}
}
}
}
}

View File

6627
config/oneapi/prodapi.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -11,33 +11,33 @@
*/ */
export default { export default {
// 如果需要自定义本地开发服务器 请取消注释按需调整 // 如果需要自定义本地开发服务器 请取消注释按需调整
// dev: { dev: {
// // localhost:8000/api/** -> https://preview.pro.ant.design/api/** // localhost:8000/api/** -> https://preview.pro.ant.design/api/**
// '/api/': { "/admin-api/": {
// // 要代理的地址 // 要代理的地址
// target: 'https://preview.pro.ant.design', target: "http://192.168.1.114:48080",
// // 配置了这个可以从 http 代理到 https // 配置了这个可以从 http 代理到 https
// // 依赖 origin 的功能可能需要这个,比如 cookie // 依赖 origin 的功能可能需要这个,比如 cookie
// changeOrigin: true, changeOrigin: true,
// }, },
// }, },
/** /**
* @name 详细的代理配置 * @name 详细的代理配置
* @doc https://github.com/chimurai/http-proxy-middleware * @doc https://github.com/chimurai/http-proxy-middleware
*/ */
test: { test: {
// localhost:8000/api/** -> https://preview.pro.ant.design/api/** // localhost:8000/api/** -> https://preview.pro.ant.design/api/**
'/api/': { "/api/": {
target: 'https://proapi.azurewebsites.net', target: "https://proapi.azurewebsites.net",
changeOrigin: true, changeOrigin: true,
pathRewrite: { '^': '' }, pathRewrite: { "^": "" },
}, },
}, },
pre: { pre: {
'/api/': { "/api/": {
target: 'your pre url', target: "your pre url",
changeOrigin: true, changeOrigin: true,
pathRewrite: { '^': '' }, pathRewrite: { "^": "" },
}, },
}, },
}; };

View File

@@ -12,52 +12,52 @@
*/ */
export default [ export default [
{ {
path: '/user', path: "/user",
layout: false, layout: false,
routes: [ routes: [
{ {
name: 'login', name: "login",
path: '/user/login', path: "/user/login",
component: './user/login', component: "./user/login",
}, },
], ],
}, },
{ {
path: '/welcome', path: "/welcome",
name: 'welcome', name: "welcome",
icon: 'smile', icon: "smile",
component: './Welcome', component: "./Welcome",
}, },
{ {
path: '/admin', path: "/admin",
name: 'admin', name: "admin",
icon: 'crown', icon: "crown",
access: 'canAdmin', access: "canAdmin",
routes: [ routes: [
{ {
path: '/admin', path: "/admin",
redirect: '/admin/sub-page', redirect: "/admin/sub-page",
}, },
{ {
path: '/admin/sub-page', path: "/admin/sub-page",
name: 'sub-page', name: "sub-page",
component: './Admin', component: "./Admin",
}, },
], ],
}, },
// {
// name: 'list.table-list',
// icon: 'table',
// path: '/list',
// component: './table-list',
// },
{ {
name: 'list.table-list', path: "/",
icon: 'table', redirect: "/welcome",
path: '/list',
component: './table-list',
}, },
{ {
path: '/', component: "404",
redirect: '/welcome',
},
{
component: '404',
layout: false, layout: false,
path: './*', path: "./*",
}, },
]; ];

View File

@@ -37,22 +37,26 @@
"dependencies": { "dependencies": {
"@ant-design/icons": "^5.6.1", "@ant-design/icons": "^5.6.1",
"@ant-design/pro-components": "^2.8.9", "@ant-design/pro-components": "^2.8.9",
"antd": "^5.26.4",
"@ant-design/v5-patch-for-react-19": "^1.0.3", "@ant-design/v5-patch-for-react-19": "^1.0.3",
"antd": "^5.26.4",
"antd-style": "^3.7.0", "antd-style": "^3.7.0",
"classnames": "^2.5.1", "classnames": "^2.5.1",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"jsencrypt": "^3.5.4",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0" "react-dom": "^19.1.0",
"web-storage-cache": "^1.1.1"
}, },
"devDependencies": { "devDependencies": {
"@ant-design/pro-cli": "^3.3.0", "@ant-design/pro-cli": "^3.3.0",
"@biomejs/biome": "^2.1.1",
"@commitlint/cli": "^19.8.1", "@commitlint/cli": "^19.8.1",
"@commitlint/config-conventional": "^19.8.1", "@commitlint/config-conventional": "^19.8.1",
"@testing-library/dom": "^10.4.0", "@testing-library/dom": "^10.4.0",
"@testing-library/react": "^16.3.0", "@testing-library/react": "^16.3.0",
"@types/express": "^5.0.3", "@types/express": "^5.0.3",
"@types/jest": "^30.0.0", "@types/jest": "^30.0.0",
"@types/node": "^24.0.13",
"@types/react": "^19.1.8", "@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6", "@types/react-dom": "^19.1.6",
"@types/react-helmet": "^6.1.11", "@types/react-helmet": "^6.1.11",
@@ -68,9 +72,7 @@
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^5.6.3", "typescript": "^5.6.3",
"umi-presets-pro": "^2.0.3", "umi-presets-pro": "^2.0.3",
"umi-serve": "^1.9.11", "umi-serve": "^1.9.11"
"@biomejs/biome": "^2.1.1",
"@types/node": "^24.0.13"
}, },
"engines": { "engines": {
"node": ">=20.0.0" "node": ">=20.0.0"

39
pnpm-lock.yaml generated
View File

@@ -29,12 +29,18 @@ importers:
dayjs: dayjs:
specifier: ^1.11.13 specifier: ^1.11.13
version: 1.11.18 version: 1.11.18
jsencrypt:
specifier: ^3.5.4
version: 3.5.4
react: react:
specifier: ^19.1.0 specifier: ^19.1.0
version: 19.1.1 version: 19.1.1
react-dom: react-dom:
specifier: ^19.1.0 specifier: ^19.1.0
version: 19.1.1(react@19.1.1) version: 19.1.1(react@19.1.1)
web-storage-cache:
specifier: ^1.1.1
version: 1.1.1
devDependencies: devDependencies:
'@ant-design/pro-cli': '@ant-design/pro-cli':
specifier: ^3.3.0 specifier: ^3.3.0
@@ -6624,6 +6630,9 @@ packages:
canvas: canvas:
optional: true optional: true
jsencrypt@3.5.4:
resolution: {integrity: sha512-kNjfYEMNASxrDGsmcSQh/rUTmcoRfSUkxnAz+MMywM8jtGu+fFEZ3nJjHM58zscVnwR0fYmG9sGkTDjqUdpiwA==}
jsesc@2.5.2: jsesc@2.5.2:
resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
engines: {node: '>=4'} engines: {node: '>=4'}
@@ -10737,6 +10746,9 @@ packages:
wcwidth@1.0.1: wcwidth@1.0.1:
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
web-storage-cache@1.1.1:
resolution: {integrity: sha512-D0MieGooOs8RpsrK+vnejXnvh4OOv/+lTFB35JRkJJQt+uOjPE08XpaE0QBLMTRu47B1KGT/Nq3Gbag3Orinzw==}
web-streams-polyfill@3.3.3: web-streams-polyfill@3.3.3:
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
@@ -14812,7 +14824,7 @@ snapshots:
'@types/history@5.0.0': '@types/history@5.0.0':
dependencies: dependencies:
history: 4.10.1 history: 5.3.0
'@types/hoist-non-react-statics@3.3.7(@types/react@19.1.12)': '@types/hoist-non-react-statics@3.3.7(@types/react@19.1.12)':
dependencies: dependencies:
@@ -14917,7 +14929,7 @@ snapshots:
'@types/history': 4.7.11 '@types/history': 4.7.11
'@types/react': 19.1.12 '@types/react': 19.1.12
'@types/react-router': 5.1.20 '@types/react-router': 5.1.20
redux: 3.7.2 redux: 4.2.1
'@types/react-router@5.1.20': '@types/react-router@5.1.20':
dependencies: dependencies:
@@ -15247,7 +15259,7 @@ snapshots:
'@svgr/core': 6.5.1 '@svgr/core': 6.5.1
'@umijs/bundler-utils': 4.4.12 '@umijs/bundler-utils': 4.4.12
'@umijs/utils': 4.4.12 '@umijs/utils': 4.4.12
'@vitejs/plugin-react': 4.0.0(vite@4.5.2(@types/node@24.3.1)(less@4.4.1)(lightningcss@1.22.1)(sugarss@2.0.0)(terser@5.44.0)) '@vitejs/plugin-react': 4.0.0(vite@4.5.2(@types/node@24.3.1)(less@4.1.3)(lightningcss@1.22.1)(sugarss@2.0.0)(terser@5.44.0))
core-js: 3.34.0 core-js: 3.34.0
less: 4.1.3 less: 4.1.3
postcss-preset-env: 7.5.0(postcss@8.5.6) postcss-preset-env: 7.5.0(postcss@8.5.6)
@@ -15934,13 +15946,13 @@ snapshots:
'@unrs/resolver-binding-win32-x64-msvc@1.11.1': '@unrs/resolver-binding-win32-x64-msvc@1.11.1':
optional: true optional: true
'@vitejs/plugin-react@4.0.0(vite@4.5.2(@types/node@24.3.1)(less@4.4.1)(lightningcss@1.22.1)(sugarss@2.0.0)(terser@5.44.0))': '@vitejs/plugin-react@4.0.0(vite@4.5.2(@types/node@24.3.1)(less@4.1.3)(lightningcss@1.22.1)(sugarss@2.0.0)(terser@5.44.0))':
dependencies: dependencies:
'@babel/core': 7.28.4 '@babel/core': 7.28.4
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4)
'@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.4)
react-refresh: 0.14.2 react-refresh: 0.14.2
vite: 4.5.2(@types/node@24.3.1)(less@4.4.1)(lightningcss@1.22.1)(sugarss@2.0.0)(terser@5.44.0) vite: 4.5.2(@types/node@24.3.1)(less@4.1.3)(lightningcss@1.22.1)(sugarss@2.0.0)(terser@5.44.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -20412,6 +20424,8 @@ snapshots:
- supports-color - supports-color
- utf-8-validate - utf-8-validate
jsencrypt@3.5.4: {}
jsesc@2.5.2: {} jsesc@2.5.2: {}
jsesc@3.0.2: {} jsesc@3.0.2: {}
@@ -25430,19 +25444,6 @@ snapshots:
sugarss: 2.0.0 sugarss: 2.0.0
terser: 5.44.0 terser: 5.44.0
vite@4.5.2(@types/node@24.3.1)(less@4.4.1)(lightningcss@1.22.1)(sugarss@2.0.0)(terser@5.44.0):
dependencies:
esbuild: 0.18.20
postcss: 8.5.6
rollup: 3.29.5
optionalDependencies:
'@types/node': 24.3.1
fsevents: 2.3.3
less: 4.4.1
lightningcss: 1.22.1
sugarss: 2.0.0
terser: 5.44.0
vm-browserify@1.1.2: {} vm-browserify@1.1.2: {}
w3c-xmlserializer@5.0.0: w3c-xmlserializer@5.0.0:
@@ -25476,6 +25477,8 @@ snapshots:
dependencies: dependencies:
defaults: 1.0.4 defaults: 1.0.4
web-storage-cache@1.1.1: {}
web-streams-polyfill@3.3.3: {} web-streams-polyfill@3.3.3: {}
webidl-conversions@3.0.1: {} webidl-conversions@3.0.1: {}

View File

@@ -1,11 +1,13 @@
import { UserVO } from "./services/login/types";
/** /**
* @see https://umijs.org/docs/max/access#access * @see https://umijs.org/docs/max/access#access
* */ * */
export default function access( export default function access(
initialState: { currentUser?: API.CurrentUser } | undefined, initialState: { currentUser?: UserVO } | undefined
) { ) {
const { currentUser } = initialState ?? {}; const { currentUser } = initialState ?? {};
return { return {
canAdmin: currentUser && currentUser.access === 'admin', canAdmin: currentUser && currentUser.username === "admin",
}; };
} }

View File

@@ -1,39 +1,39 @@
import { LinkOutlined } from '@ant-design/icons'; import { LinkOutlined } from "@ant-design/icons";
import type { Settings as LayoutSettings } from '@ant-design/pro-components'; import type { Settings as LayoutSettings } from "@ant-design/pro-components";
import { SettingDrawer } from '@ant-design/pro-components'; import { SettingDrawer } from "@ant-design/pro-components";
import type { RequestConfig, RunTimeLayoutConfig } from '@umijs/max'; import type { RequestConfig, RunTimeLayoutConfig } from "@umijs/max";
import { history, Link } from '@umijs/max'; import { history, Link } from "@umijs/max";
import React from 'react'; import React from "react";
import { import {
AvatarDropdown, AvatarDropdown,
AvatarName, AvatarName,
Footer, Footer,
Question, Question,
SelectLang, SelectLang,
} from '@/components'; } from "@/components";
import { currentUser as queryCurrentUser } from '@/services/ant-design-pro/api'; import { getInfo } from "@/services/login";
import defaultSettings from '../config/defaultSettings'; import type { UserVO, TokenType } from "@/services/login/types";
import { errorConfig } from './requestErrorConfig'; import defaultSettings from "../config/defaultSettings";
import '@ant-design/v5-patch-for-react-19'; import { errorConfig } from "./requestErrorConfig";
import "@ant-design/v5-patch-for-react-19";
const isDev = process.env.NODE_ENV === 'development'; const isDev = process.env.NODE_ENV === "development";
const isDevOrTest = isDev || process.env.CI; const isDevOrTest = isDev || process.env.CI;
const loginPath = '/user/login'; const loginPath = "/user/login";
/** /**
* @see https://umijs.org/docs/api/runtime-config#getinitialstate * @see https://umijs.org/docs/api/runtime-config#getinitialstate
* */ * */
export async function getInitialState(): Promise<{ export async function getInitialState(): Promise<{
settings?: Partial<LayoutSettings>; settings?: Partial<LayoutSettings>;
currentUser?: API.CurrentUser; currentUser?: { user: UserVO };
loading?: boolean; loading?: boolean;
fetchUserInfo?: () => Promise<API.CurrentUser | undefined>; fetchUserInfo?: () => Promise<{ user: UserVO } | undefined>;
}> { }> {
const fetchUserInfo = async () => { const fetchUserInfo = async () => {
// history.push(loginPath);
try { try {
const msg = await queryCurrentUser({ const msg = await getInfo();
skipErrorHandler: true,
});
return msg.data; return msg.data;
} catch (_error) { } catch (_error) {
history.push(loginPath); history.push(loginPath);
@@ -43,8 +43,8 @@ export async function getInitialState(): Promise<{
// 如果不是登录页面,执行 // 如果不是登录页面,执行
const { location } = history; const { location } = history;
if ( if (
![loginPath, '/user/register', '/user/register-result'].includes( ![loginPath, "/user/register", "/user/register-result"].includes(
location.pathname, location.pathname
) )
) { ) {
const currentUser = await fetchUserInfo(); const currentUser = await fetchUserInfo();
@@ -71,14 +71,14 @@ export const layout: RunTimeLayoutConfig = ({
<SelectLang key="SelectLang" />, <SelectLang key="SelectLang" />,
], ],
avatarProps: { avatarProps: {
src: initialState?.currentUser?.avatar, src: initialState?.currentUser?.user.avatar,
title: <AvatarName />, title: <AvatarName />,
render: (_, avatarChildren) => ( render: (_, avatarChildren) => (
<AvatarDropdown>{avatarChildren}</AvatarDropdown> <AvatarDropdown>{avatarChildren}</AvatarDropdown>
), ),
}, },
waterMarkProps: { waterMarkProps: {
content: initialState?.currentUser?.name, content: initialState?.currentUser?.user.nickname,
}, },
footerRender: () => <Footer />, footerRender: () => <Footer />,
onPageChange: () => { onPageChange: () => {
@@ -90,22 +90,22 @@ export const layout: RunTimeLayoutConfig = ({
}, },
bgLayoutImgList: [ bgLayoutImgList: [
{ {
src: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/D2LWSqNny4sAAAAAAAAAAAAAFl94AQBr', src: "https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/D2LWSqNny4sAAAAAAAAAAAAAFl94AQBr",
left: 85, left: 85,
bottom: 100, bottom: 100,
height: '303px', height: "303px",
}, },
{ {
src: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/C2TWRpJpiC0AAAAAAAAAAAAAFl94AQBr', src: "https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/C2TWRpJpiC0AAAAAAAAAAAAAFl94AQBr",
bottom: -68, bottom: -68,
right: -45, right: -45,
height: '303px', height: "303px",
}, },
{ {
src: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/F6vSTbj8KpYAAAAAAAAAAAAAFl94AQBr', src: "https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/F6vSTbj8KpYAAAAAAAAAAAAAFl94AQBr",
bottom: 0, bottom: 0,
left: 0, left: 0,
width: '331px', width: "331px",
}, },
], ],
links: isDevOrTest links: isDevOrTest
@@ -151,6 +151,6 @@ export const layout: RunTimeLayoutConfig = ({
* @doc https://umijs.org/docs/max/request#配置 * @doc https://umijs.org/docs/max/request#配置
*/ */
export const request: RequestConfig = { export const request: RequestConfig = {
baseURL: isDev ? '' : 'https://proapi.azurewebsites.net', baseURL: isDev ? "" : "https://proapi.azurewebsites.net",
...errorConfig, ...errorConfig,
}; };

View File

@@ -2,15 +2,15 @@ import {
LogoutOutlined, LogoutOutlined,
SettingOutlined, SettingOutlined,
UserOutlined, UserOutlined,
} from '@ant-design/icons'; } from "@ant-design/icons";
import { history, useModel } from '@umijs/max'; import { history, useModel } from "@umijs/max";
import type { MenuProps } from 'antd'; import type { MenuProps } from "antd";
import { Spin } from 'antd'; import { Spin } from "antd";
import { createStyles } from 'antd-style'; import { createStyles } from "antd-style";
import React from 'react'; import React from "react";
import { flushSync } from 'react-dom'; import { flushSync } from "react-dom";
import { outLogin } from '@/services/ant-design-pro/api'; import { loginOut } from "@/services/login";
import HeaderDropdown from '../HeaderDropdown'; import HeaderDropdown from "../HeaderDropdown";
export type GlobalHeaderRightProps = { export type GlobalHeaderRightProps = {
menu?: boolean; menu?: boolean;
@@ -18,23 +18,23 @@ export type GlobalHeaderRightProps = {
}; };
export const AvatarName = () => { export const AvatarName = () => {
const { initialState } = useModel('@@initialState'); const { initialState } = useModel("@@initialState");
const { currentUser } = initialState || {}; const { currentUser } = initialState || {};
return <span className="anticon">{currentUser?.name}</span>; return <span className="anticon">{currentUser?.user.nickname}</span>;
}; };
const useStyles = createStyles(({ token }) => { const useStyles = createStyles(({ token }) => {
return { return {
action: { action: {
display: 'flex', display: "flex",
height: '48px', height: "48px",
marginLeft: 'auto', marginLeft: "auto",
overflow: 'hidden', overflow: "hidden",
alignItems: 'center', alignItems: "center",
padding: '0 8px', padding: "0 8px",
cursor: 'pointer', cursor: "pointer",
borderRadius: token.borderRadius, borderRadius: token.borderRadius,
'&:hover': { "&:hover": {
backgroundColor: token.colorBgTextHover, backgroundColor: token.colorBgTextHover,
}, },
}, },
@@ -49,29 +49,29 @@ export const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({
* 退出登录,并且将当前的 url 保存 * 退出登录,并且将当前的 url 保存
*/ */
const loginOut = async () => { const loginOut = async () => {
await outLogin(); await loginOut();
const { search, pathname } = window.location; const { search, pathname } = window.location;
const urlParams = new URL(window.location.href).searchParams; const urlParams = new URL(window.location.href).searchParams;
const searchParams = new URLSearchParams({ const searchParams = new URLSearchParams({
redirect: pathname + search, redirect: pathname + search,
}); });
/** 此方法会跳转到 redirect 参数所在的位置 */ /** 此方法会跳转到 redirect 参数所在的位置 */
const redirect = urlParams.get('redirect'); const redirect = urlParams.get("redirect");
// Note: There may be security issues, please note // Note: There may be security issues, please note
if (window.location.pathname !== '/user/login' && !redirect) { if (window.location.pathname !== "/user/login" && !redirect) {
history.replace({ history.replace({
pathname: '/user/login', pathname: "/user/login",
search: searchParams.toString(), search: searchParams.toString(),
}); });
} }
}; };
const { styles } = useStyles(); const { styles } = useStyles();
const { initialState, setInitialState } = useModel('@@initialState'); const { initialState, setInitialState } = useModel("@@initialState");
const onMenuClick: MenuProps['onClick'] = (event) => { const onMenuClick: MenuProps["onClick"] = (event) => {
const { key } = event; const { key } = event;
if (key === 'logout') { if (key === "logout") {
flushSync(() => { flushSync(() => {
setInitialState((s) => ({ ...s, currentUser: undefined })); setInitialState((s) => ({ ...s, currentUser: undefined }));
}); });
@@ -99,7 +99,7 @@ export const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({
const { currentUser } = initialState; const { currentUser } = initialState;
if (!currentUser || !currentUser.name) { if (!currentUser || !currentUser.user.nickname) {
return loading; return loading;
} }
@@ -107,24 +107,24 @@ export const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({
...(menu ...(menu
? [ ? [
{ {
key: 'center', key: "center",
icon: <UserOutlined />, icon: <UserOutlined />,
label: '个人中心', label: "个人中心",
}, },
{ {
key: 'settings', key: "settings",
icon: <SettingOutlined />, icon: <SettingOutlined />,
label: '个人设置', label: "个人设置",
}, },
{ {
type: 'divider' as const, type: "divider" as const,
}, },
] ]
: []), : []),
{ {
key: 'logout', key: "logout",
icon: <LogoutOutlined />, icon: <LogoutOutlined />,
label: '退出登录', label: "退出登录",
}, },
]; ];

39
src/hooks/web/useCache.ts Normal file
View File

@@ -0,0 +1,39 @@
/**
* 配置浏览器本地存储的方式,可直接存储对象数组。
*/
import WebStorageCache from "web-storage-cache";
type CacheType = "localStorage" | "sessionStorage";
export const CACHE_KEY = {
// 用户相关
ROLE_ROUTERS: "roleRouters",
USER: "user",
// 系统设置
IS_DARK: "isDark",
LANG: "lang",
THEME: "theme",
LAYOUT: "layout",
DICT_CACHE: "dictCache",
// 登录表单
LoginForm: "loginForm",
TenantId: "tenantId",
};
export const useCache = (type: CacheType = "localStorage") => {
const wsCache: WebStorageCache = new WebStorageCache({
storage: type,
});
return {
wsCache,
};
};
export const deleteUserCache = () => {
const { wsCache } = useCache();
wsCache.delete(CACHE_KEY.USER);
wsCache.delete(CACHE_KEY.ROLE_ROUTERS);
// 注意,不要清理 LoginForm 登录表单
};

View File

@@ -1,80 +1,80 @@
import { PlusOutlined } from '@ant-design/icons'; // import { PlusOutlined } from '@ant-design/icons';
import { // import {
type ActionType, // type ActionType,
ModalForm, // ModalForm,
ProFormText, // ProFormText,
ProFormTextArea, // ProFormTextArea,
} from '@ant-design/pro-components'; // } from '@ant-design/pro-components';
import { FormattedMessage, useIntl, useRequest } from '@umijs/max'; // import { FormattedMessage, useIntl, useRequest } from '@umijs/max';
import { Button, message } from 'antd'; // import { Button, message } from 'antd';
import type { FC } from 'react'; // import type { FC } from 'react';
import { addRule } from '@/services/ant-design-pro/api'; // import { addRule } from '@/services/ant-design-pro/api';
interface CreateFormProps { // interface CreateFormProps {
reload?: ActionType['reload']; // reload?: ActionType['reload'];
} // }
const CreateForm: FC<CreateFormProps> = (props) => { // const CreateForm: FC<CreateFormProps> = (props) => {
const { reload } = props; // const { reload } = props;
const [messageApi, contextHolder] = message.useMessage(); // const [messageApi, contextHolder] = message.useMessage();
/** // /**
* @en-US International configuration // * @en-US International configuration
* @zh-CN 国际化配置 // * @zh-CN 国际化配置
* */ // * */
const intl = useIntl(); // const intl = useIntl();
const { run, loading } = useRequest(addRule, { // const { run, loading } = useRequest(addRule, {
manual: true, // manual: true,
onSuccess: () => { // onSuccess: () => {
messageApi.success('Added successfully'); // messageApi.success('Added successfully');
reload?.(); // reload?.();
}, // },
onError: () => { // onError: () => {
messageApi.error('Adding failed, please try again!'); // messageApi.error('Adding failed, please try again!');
}, // },
}); // });
return ( // return (
<> // <>
{contextHolder} // {contextHolder}
<ModalForm // <ModalForm
title={intl.formatMessage({ // title={intl.formatMessage({
id: 'pages.searchTable.createForm.newRule', // id: 'pages.searchTable.createForm.newRule',
defaultMessage: 'New rule', // defaultMessage: 'New rule',
})} // })}
trigger={ // trigger={
<Button type="primary" icon={<PlusOutlined />}> // <Button type="primary" icon={<PlusOutlined />}>
<FormattedMessage id="pages.searchTable.new" defaultMessage="New" /> // <FormattedMessage id="pages.searchTable.new" defaultMessage="New" />
</Button> // </Button>
} // }
width="400px" // width="400px"
modalProps={{ okButtonProps: { loading } }} // modalProps={{ okButtonProps: { loading } }}
onFinish={async (value) => { // onFinish={async (value) => {
await run({ data: value as API.RuleListItem }); // await run({ data: value as API.RuleListItem });
return true; // return true;
}} // }}
> // >
<ProFormText // <ProFormText
rules={[ // rules={[
{ // {
required: true, // required: true,
message: ( // message: (
<FormattedMessage // <FormattedMessage
id="pages.searchTable.ruleName" // id="pages.searchTable.ruleName"
defaultMessage="Rule name is required" // defaultMessage="Rule name is required"
/> // />
), // ),
}, // },
]} // ]}
width="md" // width="md"
name="name" // name="name"
/> // />
<ProFormTextArea width="md" name="desc" /> // <ProFormTextArea width="md" name="desc" />
</ModalForm> // </ModalForm>
</> // </>
); // );
}; // };
export default CreateForm; // export default CreateForm;

View File

@@ -1,251 +1,251 @@
import { // import {
ProFormDateTimePicker, // ProFormDateTimePicker,
ProFormRadio, // ProFormRadio,
ProFormSelect, // ProFormSelect,
ProFormText, // ProFormText,
ProFormTextArea, // ProFormTextArea,
StepsForm, // StepsForm,
} from '@ant-design/pro-components'; // } from '@ant-design/pro-components';
import { FormattedMessage, useIntl, useRequest } from '@umijs/max'; // import { FormattedMessage, useIntl, useRequest } from '@umijs/max';
import { Modal, message } from 'antd'; // import { Modal, message } from 'antd';
import React, { cloneElement, useCallback, useState } from 'react'; // import React, { cloneElement, useCallback, useState } from 'react';
import { updateRule } from '@/services/ant-design-pro/api'; // import { updateRule } from '@/services/ant-design-pro/api';
export type FormValueType = { // export type FormValueType = {
target?: string; // target?: string;
template?: string; // template?: string;
type?: string; // type?: string;
time?: string; // time?: string;
frequency?: string; // frequency?: string;
} & Partial<API.RuleListItem>; // } & Partial<API.RuleListItem>;
export type UpdateFormProps = { // export type UpdateFormProps = {
trigger?: React.ReactElement<any>; // trigger?: React.ReactElement<any>;
onOk?: () => void; // onOk?: () => void;
values: Partial<API.RuleListItem>; // values: Partial<API.RuleListItem>;
}; // };
const UpdateForm: React.FC<UpdateFormProps> = (props) => { // const UpdateForm: React.FC<UpdateFormProps> = (props) => {
const { onOk, values, trigger } = props; // const { onOk, values, trigger } = props;
const intl = useIntl(); // const intl = useIntl();
const [open, setOpen] = useState(false); // const [open, setOpen] = useState(false);
const [messageApi, contextHolder] = message.useMessage(); // const [messageApi, contextHolder] = message.useMessage();
const { run } = useRequest(updateRule, { // const { run } = useRequest(updateRule, {
manual: true, // manual: true,
onSuccess: () => { // onSuccess: () => {
messageApi.success('Configuration is successful'); // messageApi.success('Configuration is successful');
onOk?.(); // onOk?.();
}, // },
onError: () => { // onError: () => {
messageApi.error('Configuration failed, please try again!'); // messageApi.error('Configuration failed, please try again!');
}, // },
}); // });
const onCancel = useCallback(() => { // const onCancel = useCallback(() => {
setOpen(false); // setOpen(false);
}, []); // }, []);
const onOpen = useCallback(() => { // const onOpen = useCallback(() => {
setOpen(true); // setOpen(true);
}, []); // }, []);
const onFinish = useCallback( // const onFinish = useCallback(
async (values?: any) => { // async (values?: any) => {
await run({ data: values }); // await run({ data: values });
onCancel(); // onCancel();
}, // },
[onCancel, run], // [onCancel, run],
); // );
return ( // return (
<> // <>
{contextHolder} // {contextHolder}
{trigger // {trigger
? cloneElement(trigger, { // ? cloneElement(trigger, {
onClick: onOpen, // onClick: onOpen,
}) // })
: null} // : null}
<StepsForm // <StepsForm
stepsProps={{ // stepsProps={{
size: 'small', // size: 'small',
}} // }}
stepsFormRender={(dom, submitter) => { // stepsFormRender={(dom, submitter) => {
return ( // return (
<Modal // <Modal
width={640} // width={640}
styles={{ // styles={{
body: { // body: {
padding: '32px 40px 48px', // padding: '32px 40px 48px',
}, // },
}} // }}
destroyOnHidden // destroyOnHidden
title={intl.formatMessage({ // title={intl.formatMessage({
id: 'pages.searchTable.updateForm.ruleConfig', // id: 'pages.searchTable.updateForm.ruleConfig',
defaultMessage: '规则配置', // defaultMessage: '规则配置',
})} // })}
open={open} // open={open}
footer={submitter} // footer={submitter}
onCancel={onCancel} // onCancel={onCancel}
> // >
{dom} // {dom}
</Modal> // </Modal>
); // );
}} // }}
onFinish={onFinish} // onFinish={onFinish}
> // >
<StepsForm.StepForm // <StepsForm.StepForm
initialValues={values} // initialValues={values}
title={intl.formatMessage({ // title={intl.formatMessage({
id: 'pages.searchTable.updateForm.basicConfig', // id: 'pages.searchTable.updateForm.basicConfig',
defaultMessage: '基本信息', // defaultMessage: '基本信息',
})} // })}
> // >
<ProFormText // <ProFormText
name="name" // name="name"
label={intl.formatMessage({ // label={intl.formatMessage({
id: 'pages.searchTable.updateForm.ruleName.nameLabel', // id: 'pages.searchTable.updateForm.ruleName.nameLabel',
defaultMessage: '规则名称', // defaultMessage: '规则名称',
})} // })}
width="md" // width="md"
rules={[ // rules={[
{ // {
required: true, // required: true,
message: ( // message: (
<FormattedMessage // <FormattedMessage
id="pages.searchTable.updateForm.ruleName.nameRules" // id="pages.searchTable.updateForm.ruleName.nameRules"
defaultMessage="请输入规则名称!" // defaultMessage="请输入规则名称!"
/> // />
), // ),
}, // },
]} // ]}
/> // />
<ProFormTextArea // <ProFormTextArea
name="desc" // name="desc"
width="md" // width="md"
label={intl.formatMessage({ // label={intl.formatMessage({
id: 'pages.searchTable.updateForm.ruleDesc.descLabel', // id: 'pages.searchTable.updateForm.ruleDesc.descLabel',
defaultMessage: '规则描述', // defaultMessage: '规则描述',
})} // })}
placeholder={intl.formatMessage({ // placeholder={intl.formatMessage({
id: 'pages.searchTable.updateForm.ruleDesc.descPlaceholder', // id: 'pages.searchTable.updateForm.ruleDesc.descPlaceholder',
defaultMessage: '请输入至少五个字符', // defaultMessage: '请输入至少五个字符',
})} // })}
rules={[ // rules={[
{ // {
required: true, // required: true,
message: ( // message: (
<FormattedMessage // <FormattedMessage
id="pages.searchTable.updateForm.ruleDesc.descRules" // id="pages.searchTable.updateForm.ruleDesc.descRules"
defaultMessage="请输入至少五个字符的规则描述!" // defaultMessage="请输入至少五个字符的规则描述!"
/> // />
), // ),
min: 5, // min: 5,
}, // },
]} // ]}
/> // />
</StepsForm.StepForm> // </StepsForm.StepForm>
<StepsForm.StepForm // <StepsForm.StepForm
initialValues={{ // initialValues={{
target: '0', // target: '0',
template: '0', // template: '0',
}} // }}
title={intl.formatMessage({ // title={intl.formatMessage({
id: 'pages.searchTable.updateForm.ruleProps.title', // id: 'pages.searchTable.updateForm.ruleProps.title',
defaultMessage: '配置规则属性', // defaultMessage: '配置规则属性',
})} // })}
> // >
<ProFormSelect // <ProFormSelect
name="target" // name="target"
width="md" // width="md"
label={intl.formatMessage({ // label={intl.formatMessage({
id: 'pages.searchTable.updateForm.object', // id: 'pages.searchTable.updateForm.object',
defaultMessage: '监控对象', // defaultMessage: '监控对象',
})} // })}
valueEnum={{ // valueEnum={{
0: '表一', // 0: '表一',
1: '表二', // 1: '表二',
}} // }}
/> // />
<ProFormSelect // <ProFormSelect
name="template" // name="template"
width="md" // width="md"
label={intl.formatMessage({ // label={intl.formatMessage({
id: 'pages.searchTable.updateForm.ruleProps.templateLabel', // id: 'pages.searchTable.updateForm.ruleProps.templateLabel',
defaultMessage: '规则模板', // defaultMessage: '规则模板',
})} // })}
valueEnum={{ // valueEnum={{
0: '规则模板一', // 0: '规则模板一',
1: '规则模板二', // 1: '规则模板二',
}} // }}
/> // />
<ProFormRadio.Group // <ProFormRadio.Group
name="type" // name="type"
label={intl.formatMessage({ // label={intl.formatMessage({
id: 'pages.searchTable.updateForm.ruleProps.typeLabel', // id: 'pages.searchTable.updateForm.ruleProps.typeLabel',
defaultMessage: '规则类型', // defaultMessage: '规则类型',
})} // })}
options={[ // options={[
{ // {
value: '0', // value: '0',
label: '强', // label: '强',
}, // },
{ // {
value: '1', // value: '1',
label: '弱', // label: '弱',
}, // },
]} // ]}
/> // />
</StepsForm.StepForm> // </StepsForm.StepForm>
<StepsForm.StepForm // <StepsForm.StepForm
initialValues={{ // initialValues={{
type: '1', // type: '1',
frequency: 'month', // frequency: 'month',
}} // }}
title={intl.formatMessage({ // title={intl.formatMessage({
id: 'pages.searchTable.updateForm.schedulingPeriod.title', // id: 'pages.searchTable.updateForm.schedulingPeriod.title',
defaultMessage: '设定调度周期', // defaultMessage: '设定调度周期',
})} // })}
> // >
<ProFormDateTimePicker // <ProFormDateTimePicker
name="time" // name="time"
width="md" // width="md"
label={intl.formatMessage({ // label={intl.formatMessage({
id: 'pages.searchTable.updateForm.schedulingPeriod.timeLabel', // id: 'pages.searchTable.updateForm.schedulingPeriod.timeLabel',
defaultMessage: '开始时间', // defaultMessage: '开始时间',
})} // })}
rules={[ // rules={[
{ // {
required: true, // required: true,
message: ( // message: (
<FormattedMessage // <FormattedMessage
id="pages.searchTable.updateForm.schedulingPeriod.timeRules" // id="pages.searchTable.updateForm.schedulingPeriod.timeRules"
defaultMessage="请选择开始时间!" // defaultMessage="请选择开始时间!"
/> // />
), // ),
}, // },
]} // ]}
/> // />
<ProFormSelect // <ProFormSelect
name="frequency" // name="frequency"
label={intl.formatMessage({ // label={intl.formatMessage({
id: 'pages.searchTable.updateForm.object', // id: 'pages.searchTable.updateForm.object',
defaultMessage: '监控对象', // defaultMessage: '监控对象',
})} // })}
width="md" // width="md"
valueEnum={{ // valueEnum={{
month: '月', // month: '月',
week: '周', // week: '周',
}} // }}
/> // />
</StepsForm.StepForm> // </StepsForm.StepForm>
</StepsForm> // </StepsForm>
</> // </>
); // );
}; // };
export default UpdateForm; // export default UpdateForm;

View File

@@ -1,330 +1,330 @@
import type { // import type {
ActionType, // ActionType,
ProColumns, // ProColumns,
ProDescriptionsItemProps, // ProDescriptionsItemProps,
} from '@ant-design/pro-components'; // } from '@ant-design/pro-components';
import { // import {
FooterToolbar, // FooterToolbar,
PageContainer, // PageContainer,
ProDescriptions, // ProDescriptions,
ProTable, // ProTable,
} from '@ant-design/pro-components'; // } from '@ant-design/pro-components';
import { FormattedMessage, useIntl, useRequest } from '@umijs/max'; // import { FormattedMessage, useIntl, useRequest } from '@umijs/max';
import { Button, Drawer, Input, message } from 'antd'; // import { Button, Drawer, Input, message } from 'antd';
import React, { useCallback, useRef, useState } from 'react'; // import React, { useCallback, useRef, useState } from 'react';
import { removeRule, rule } from '@/services/ant-design-pro/api'; // import { removeRule, rule } from '@/services/ant-design-pro/api';
import CreateForm from './components/CreateForm'; // import CreateForm from './components/CreateForm';
import UpdateForm from './components/UpdateForm'; // import UpdateForm from './components/UpdateForm';
const TableList: React.FC = () => { // const TableList: React.FC = () => {
const actionRef = useRef<ActionType | null>(null); // const actionRef = useRef<ActionType | null>(null);
const [showDetail, setShowDetail] = useState<boolean>(false); // const [showDetail, setShowDetail] = useState<boolean>(false);
const [currentRow, setCurrentRow] = useState<API.RuleListItem>(); // const [currentRow, setCurrentRow] = useState<API.RuleListItem>();
const [selectedRowsState, setSelectedRows] = useState<API.RuleListItem[]>([]); // const [selectedRowsState, setSelectedRows] = useState<API.RuleListItem[]>([]);
/** // /**
* @en-US International configuration // * @en-US International configuration
* @zh-CN 国际化配置 // * @zh-CN 国际化配置
* */ // * */
const intl = useIntl(); // const intl = useIntl();
const [messageApi, contextHolder] = message.useMessage(); // const [messageApi, contextHolder] = message.useMessage();
const { run: delRun, loading } = useRequest(removeRule, { // const { run: delRun, loading } = useRequest(removeRule, {
manual: true, // manual: true,
onSuccess: () => { // onSuccess: () => {
setSelectedRows([]); // setSelectedRows([]);
actionRef.current?.reloadAndRest?.(); // actionRef.current?.reloadAndRest?.();
messageApi.success('Deleted successfully and will refresh soon'); // messageApi.success('Deleted successfully and will refresh soon');
}, // },
onError: () => { // onError: () => {
messageApi.error('Delete failed, please try again'); // messageApi.error('Delete failed, please try again');
}, // },
}); // });
const columns: ProColumns<API.RuleListItem>[] = [ // const columns: ProColumns<API.RuleListItem>[] = [
{ // {
title: ( // title: (
<FormattedMessage // <FormattedMessage
id="pages.searchTable.updateForm.ruleName.nameLabel" // id="pages.searchTable.updateForm.ruleName.nameLabel"
defaultMessage="Rule name" // defaultMessage="Rule name"
/> // />
), // ),
dataIndex: 'name', // dataIndex: 'name',
render: (dom, entity) => { // render: (dom, entity) => {
return ( // return (
<a // <a
onClick={() => { // onClick={() => {
setCurrentRow(entity); // setCurrentRow(entity);
setShowDetail(true); // setShowDetail(true);
}} // }}
> // >
{dom} // {dom}
</a> // </a>
); // );
}, // },
}, // },
{ // {
title: ( // title: (
<FormattedMessage // <FormattedMessage
id="pages.searchTable.titleDesc" // id="pages.searchTable.titleDesc"
defaultMessage="Description" // defaultMessage="Description"
/> // />
), // ),
dataIndex: 'desc', // dataIndex: 'desc',
valueType: 'textarea', // valueType: 'textarea',
}, // },
{ // {
title: ( // title: (
<FormattedMessage // <FormattedMessage
id="pages.searchTable.titleCallNo" // id="pages.searchTable.titleCallNo"
defaultMessage="Number of service calls" // defaultMessage="Number of service calls"
/> // />
), // ),
dataIndex: 'callNo', // dataIndex: 'callNo',
sorter: true, // sorter: true,
hideInForm: true, // hideInForm: true,
renderText: (val: string) => // renderText: (val: string) =>
`${val}${intl.formatMessage({ // `${val}${intl.formatMessage({
id: 'pages.searchTable.tenThousand', // id: 'pages.searchTable.tenThousand',
defaultMessage: ' 万 ', // defaultMessage: ' 万 ',
})}`, // })}`,
}, // },
{ // {
title: ( // title: (
<FormattedMessage // <FormattedMessage
id="pages.searchTable.titleStatus" // id="pages.searchTable.titleStatus"
defaultMessage="Status" // defaultMessage="Status"
/> // />
), // ),
dataIndex: 'status', // dataIndex: 'status',
hideInForm: true, // hideInForm: true,
valueEnum: { // valueEnum: {
0: { // 0: {
text: ( // text: (
<FormattedMessage // <FormattedMessage
id="pages.searchTable.nameStatus.default" // id="pages.searchTable.nameStatus.default"
defaultMessage="Shut down" // defaultMessage="Shut down"
/> // />
), // ),
status: 'Default', // status: 'Default',
}, // },
1: { // 1: {
text: ( // text: (
<FormattedMessage // <FormattedMessage
id="pages.searchTable.nameStatus.running" // id="pages.searchTable.nameStatus.running"
defaultMessage="Running" // defaultMessage="Running"
/> // />
), // ),
status: 'Processing', // status: 'Processing',
}, // },
2: { // 2: {
text: ( // text: (
<FormattedMessage // <FormattedMessage
id="pages.searchTable.nameStatus.online" // id="pages.searchTable.nameStatus.online"
defaultMessage="Online" // defaultMessage="Online"
/> // />
), // ),
status: 'Success', // status: 'Success',
}, // },
3: { // 3: {
text: ( // text: (
<FormattedMessage // <FormattedMessage
id="pages.searchTable.nameStatus.abnormal" // id="pages.searchTable.nameStatus.abnormal"
defaultMessage="Abnormal" // defaultMessage="Abnormal"
/> // />
), // ),
status: 'Error', // status: 'Error',
}, // },
}, // },
}, // },
{ // {
title: ( // title: (
<FormattedMessage // <FormattedMessage
id="pages.searchTable.titleUpdatedAt" // id="pages.searchTable.titleUpdatedAt"
defaultMessage="Last scheduled time" // defaultMessage="Last scheduled time"
/> // />
), // ),
sorter: true, // sorter: true,
dataIndex: 'updatedAt', // dataIndex: 'updatedAt',
valueType: 'dateTime', // valueType: 'dateTime',
renderFormItem: (item, { defaultRender, ...rest }, form) => { // renderFormItem: (item, { defaultRender, ...rest }, form) => {
const status = form.getFieldValue('status'); // const status = form.getFieldValue('status');
if (`${status}` === '0') { // if (`${status}` === '0') {
return false; // return false;
} // }
if (`${status}` === '3') { // if (`${status}` === '3') {
return ( // return (
<Input // <Input
{...rest} // {...rest}
placeholder={intl.formatMessage({ // placeholder={intl.formatMessage({
id: 'pages.searchTable.exception', // id: 'pages.searchTable.exception',
defaultMessage: 'Please enter the reason for the exception!', // defaultMessage: 'Please enter the reason for the exception!',
})} // })}
/> // />
); // );
} // }
return defaultRender(item); // return defaultRender(item);
}, // },
}, // },
{ // {
title: ( // title: (
<FormattedMessage // <FormattedMessage
id="pages.searchTable.titleOption" // id="pages.searchTable.titleOption"
defaultMessage="Operating" // defaultMessage="Operating"
/> // />
), // ),
dataIndex: 'option', // dataIndex: 'option',
valueType: 'option', // valueType: 'option',
render: (_, record) => [ // render: (_, record) => [
<UpdateForm // <UpdateForm
trigger={ // trigger={
<a> // <a>
<FormattedMessage // <FormattedMessage
id="pages.searchTable.config" // id="pages.searchTable.config"
defaultMessage="Configuration" // defaultMessage="Configuration"
/> // />
</a> // </a>
} // }
key="config" // key="config"
onOk={actionRef.current?.reload} // onOk={actionRef.current?.reload}
values={record} // values={record}
/>, // />,
<a key="subscribeAlert" href="https://procomponents.ant.design/"> // <a key="subscribeAlert" href="https://procomponents.ant.design/">
<FormattedMessage // <FormattedMessage
id="pages.searchTable.subscribeAlert" // id="pages.searchTable.subscribeAlert"
defaultMessage="Subscribe to alerts" // defaultMessage="Subscribe to alerts"
/> // />
</a>, // </a>,
], // ],
}, // },
]; // ];
/** // /**
* Delete node // * Delete node
* @zh-CN 删除节点 // * @zh-CN 删除节点
* // *
* @param selectedRows // * @param selectedRows
*/ // */
const handleRemove = useCallback( // const handleRemove = useCallback(
async (selectedRows: API.RuleListItem[]) => { // async (selectedRows: API.RuleListItem[]) => {
if (!selectedRows?.length) { // if (!selectedRows?.length) {
messageApi.warning('请选择删除项'); // messageApi.warning('请选择删除项');
return; // return;
} // }
await delRun({ // await delRun({
data: { // data: {
key: selectedRows.map((row) => row.key), // key: selectedRows.map((row) => row.key),
}, // },
}); // });
}, // },
[delRun, messageApi.warning], // [delRun, messageApi.warning],
); // );
return ( // return (
<PageContainer> // <PageContainer>
{contextHolder} // {contextHolder}
<ProTable<API.RuleListItem, API.PageParams> // <ProTable<API.RuleListItem, API.PageParams>
headerTitle={intl.formatMessage({ // headerTitle={intl.formatMessage({
id: 'pages.searchTable.title', // id: 'pages.searchTable.title',
defaultMessage: 'Enquiry form', // defaultMessage: 'Enquiry form',
})} // })}
actionRef={actionRef} // actionRef={actionRef}
rowKey="key" // rowKey="key"
search={{ // search={{
labelWidth: 120, // labelWidth: 120,
}} // }}
toolBarRender={() => [ // toolBarRender={() => [
<CreateForm key="create" reload={actionRef.current?.reload} />, // <CreateForm key="create" reload={actionRef.current?.reload} />,
]} // ]}
request={rule} // request={rule}
columns={columns} // columns={columns}
rowSelection={{ // rowSelection={{
onChange: (_, selectedRows) => { // onChange: (_, selectedRows) => {
setSelectedRows(selectedRows); // setSelectedRows(selectedRows);
}, // },
}} // }}
/> // />
{selectedRowsState?.length > 0 && ( // {selectedRowsState?.length > 0 && (
<FooterToolbar // <FooterToolbar
extra={ // extra={
<div> // <div>
<FormattedMessage // <FormattedMessage
id="pages.searchTable.chosen" // id="pages.searchTable.chosen"
defaultMessage="Chosen" // defaultMessage="Chosen"
/>{' '} // />{' '}
<a style={{ fontWeight: 600 }}>{selectedRowsState.length}</a>{' '} // <a style={{ fontWeight: 600 }}>{selectedRowsState.length}</a>{' '}
<FormattedMessage // <FormattedMessage
id="pages.searchTable.item" // id="pages.searchTable.item"
defaultMessage="项" // defaultMessage="项"
/> // />
&nbsp;&nbsp; // &nbsp;&nbsp;
<span> // <span>
<FormattedMessage // <FormattedMessage
id="pages.searchTable.totalServiceCalls" // id="pages.searchTable.totalServiceCalls"
defaultMessage="Total number of service calls" // defaultMessage="Total number of service calls"
/>{' '} // />{' '}
{selectedRowsState.reduce( // {selectedRowsState.reduce(
(pre, item) => pre + (item.callNo ?? 0), // (pre, item) => pre + (item.callNo ?? 0),
0, // 0,
)}{' '} // )}{' '}
<FormattedMessage // <FormattedMessage
id="pages.searchTable.tenThousand" // id="pages.searchTable.tenThousand"
defaultMessage="万" // defaultMessage="万"
/> // />
</span> // </span>
</div> // </div>
} // }
> // >
<Button // <Button
loading={loading} // loading={loading}
onClick={() => { // onClick={() => {
handleRemove(selectedRowsState); // handleRemove(selectedRowsState);
}} // }}
> // >
<FormattedMessage // <FormattedMessage
id="pages.searchTable.batchDeletion" // id="pages.searchTable.batchDeletion"
defaultMessage="Batch deletion" // defaultMessage="Batch deletion"
/> // />
</Button> // </Button>
<Button type="primary"> // <Button type="primary">
<FormattedMessage // <FormattedMessage
id="pages.searchTable.batchApproval" // id="pages.searchTable.batchApproval"
defaultMessage="Batch approval" // defaultMessage="Batch approval"
/> // />
</Button> // </Button>
</FooterToolbar> // </FooterToolbar>
)} // )}
<Drawer // <Drawer
width={600} // width={600}
open={showDetail} // open={showDetail}
onClose={() => { // onClose={() => {
setCurrentRow(undefined); // setCurrentRow(undefined);
setShowDetail(false); // setShowDetail(false);
}} // }}
closable={false} // closable={false}
> // >
{currentRow?.name && ( // {currentRow?.name && (
<ProDescriptions<API.RuleListItem> // <ProDescriptions<API.RuleListItem>
column={2} // column={2}
title={currentRow?.name} // title={currentRow?.name}
request={async () => ({ // request={async () => ({
data: currentRow || {}, // data: currentRow || {},
})} // })}
params={{ // params={{
id: currentRow?.name, // id: currentRow?.name,
}} // }}
columns={columns as ProDescriptionsItemProps<API.RuleListItem>[]} // columns={columns as ProDescriptionsItemProps<API.RuleListItem>[]}
/> // />
)} // )}
</Drawer> // </Drawer>
</PageContainer> // </PageContainer>
); // );
}; // };
export default TableList; // export default TableList;

File diff suppressed because it is too large Load Diff

View File

@@ -1,397 +1,283 @@
import { import {
AlipayCircleOutlined, AlipayOutlined,
LockOutlined, LockOutlined,
MobileOutlined, MobileOutlined,
TaobaoCircleOutlined, TaobaoOutlined,
UserOutlined, UserOutlined,
WeiboCircleOutlined, WeiboOutlined,
} from '@ant-design/icons'; } from "@ant-design/icons";
import { import {
LoginForm, LoginFormPage,
ProConfigProvider,
ProFormCaptcha, ProFormCaptcha,
ProFormCheckbox, ProFormCheckbox,
ProFormText, ProFormText,
} from '@ant-design/pro-components'; } from "@ant-design/pro-components";
import { import { Button, Divider, Space, Tabs, message, theme } from "antd";
FormattedMessage, import type { CSSProperties } from "react";
Helmet, import { useState } from "react";
SelectLang,
useIntl,
useModel,
} from '@umijs/max';
import { Alert, App, Tabs } from 'antd';
import { createStyles } from 'antd-style';
import React, { useState } from 'react';
import { flushSync } from 'react-dom';
import { Footer } from '@/components';
import { login } from '@/services/ant-design-pro/api';
import { getFakeCaptcha } from '@/services/ant-design-pro/login';
import Settings from '../../../../config/defaultSettings';
const useStyles = createStyles(({ token }) => { type LoginType = "phone" | "account";
return {
action: {
marginLeft: '8px',
color: 'rgba(0, 0, 0, 0.2)',
fontSize: '24px',
verticalAlign: 'middle',
cursor: 'pointer',
transition: 'color 0.3s',
'&:hover': {
color: token.colorPrimaryActive,
},
},
lang: {
width: 42,
height: 42,
lineHeight: '42px',
position: 'fixed',
right: 16,
borderRadius: token.borderRadius,
':hover': {
backgroundColor: token.colorBgTextHover,
},
},
container: {
display: 'flex',
flexDirection: 'column',
height: '100vh',
overflow: 'auto',
backgroundImage:
"url('https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/V-_oS6r-i7wAAAAAAAAAAAAAFl94AQBr')",
backgroundSize: '100% 100%',
},
};
});
const ActionIcons = () => { const iconStyles: CSSProperties = {
const { styles } = useStyles(); color: "rgba(0, 0, 0, 0.2)",
fontSize: "18px",
return ( verticalAlign: "middle",
<> cursor: "pointer",
<AlipayCircleOutlined
key="AlipayCircleOutlined"
className={styles.action}
/>
<TaobaoCircleOutlined
key="TaobaoCircleOutlined"
className={styles.action}
/>
<WeiboCircleOutlined
key="WeiboCircleOutlined"
className={styles.action}
/>
</>
);
}; };
const Lang = () => { const Page = () => {
const { styles } = useStyles(); const [loginType, setLoginType] = useState<LoginType>("phone");
const { token } = theme.useToken();
return ( return (
<div className={styles.lang} data-lang> <div
{SelectLang && <SelectLang />}
</div>
);
};
const LoginMessage: React.FC<{
content: string;
}> = ({ content }) => {
return (
<Alert
style={{ style={{
marginBottom: 24, backgroundColor: "white",
height: "100vh",
}} }}
message={content} >
type="error" <LoginFormPage
showIcon backgroundImageUrl="https://mdn.alipayobjects.com/huamei_gcee1x/afts/img/A*y0ZTS6WLwvgAAAAAAAAAAAAADml6AQ/fmt.webp"
/> logo="https://github.githubassets.com/favicons/favicon.png"
); backgroundVideoUrl="https://gw.alipayobjects.com/v/huamei_gcee1x/afts/video/jXRBRK_VAwoAAAAAAAAAAAAAK4eUAQBr"
}; title="Github"
containerStyle={{
const Login: React.FC = () => { backgroundColor: "rgba(0, 0, 0,0.65)",
const [userLoginState, setUserLoginState] = useState<API.LoginResult>({}); backdropFilter: "blur(4px)",
const [type, setType] = useState<string>('account');
const { initialState, setInitialState } = useModel('@@initialState');
const { styles } = useStyles();
const { message } = App.useApp();
const intl = useIntl();
const fetchUserInfo = async () => {
const userInfo = await initialState?.fetchUserInfo?.();
if (userInfo) {
flushSync(() => {
setInitialState((s) => ({
...s,
currentUser: userInfo,
}));
});
}
};
const handleSubmit = async (values: API.LoginParams) => {
try {
// 登录
const msg = await login({ ...values, type });
if (msg.status === 'ok') {
const defaultLoginSuccessMessage = intl.formatMessage({
id: 'pages.login.success',
defaultMessage: '登录成功!',
});
message.success(defaultLoginSuccessMessage);
await fetchUserInfo();
const urlParams = new URL(window.location.href).searchParams;
window.location.href = urlParams.get('redirect') || '/';
return;
}
console.log(msg);
// 如果失败去设置用户错误信息
setUserLoginState(msg);
} catch (error) {
const defaultLoginFailureMessage = intl.formatMessage({
id: 'pages.login.failure',
defaultMessage: '登录失败,请重试!',
});
console.log(error);
message.error(defaultLoginFailureMessage);
}
};
const { status, type: loginType } = userLoginState;
return (
<div className={styles.container}>
<Helmet>
<title>
{intl.formatMessage({
id: 'menu.login',
defaultMessage: '登录页',
})}
{Settings.title && ` - ${Settings.title}`}
</title>
</Helmet>
<Lang />
<div
style={{
flex: '1',
padding: '32px 0',
}} }}
> subTitle="全球最大的代码托管平台"
<LoginForm activityConfig={{
contentStyle={{ style: {
minWidth: 280, boxShadow: "0px 0px 8px rgba(0, 0, 0, 0.2)",
maxWidth: '75vw', color: token.colorTextHeading,
}} borderRadius: 8,
logo={<img alt="logo" src="/logo.svg" />} backgroundColor: "rgba(255,255,255,0.25)",
title="Ant Design" backdropFilter: "blur(4px)",
subTitle={intl.formatMessage({ },
id: 'pages.layouts.userLayout.title', title: "活动标题,可配置图片",
})} subTitle: "活动介绍说明文字",
initialValues={{ action: (
autoLogin: true, <Button
}} size="large"
actions={[
<FormattedMessage
key="loginWith"
id="pages.login.loginWith"
defaultMessage="其他登录方式"
/>,
<ActionIcons key="icons" />,
]}
onFinish={async (values) => {
await handleSubmit(values as API.LoginParams);
}}
>
<Tabs
activeKey={type}
onChange={setType}
centered
items={[
{
key: 'account',
label: intl.formatMessage({
id: 'pages.login.accountLogin.tab',
defaultMessage: '账户密码登录',
}),
},
{
key: 'mobile',
label: intl.formatMessage({
id: 'pages.login.phoneLogin.tab',
defaultMessage: '手机号登录',
}),
},
]}
/>
{status === 'error' && loginType === 'account' && (
<LoginMessage
content={intl.formatMessage({
id: 'pages.login.accountLogin.errorMessage',
defaultMessage: '账户或密码错误(admin/ant.design)',
})}
/>
)}
{type === 'account' && (
<>
<ProFormText
name="username"
fieldProps={{
size: 'large',
prefix: <UserOutlined />,
}}
placeholder={intl.formatMessage({
id: 'pages.login.username.placeholder',
defaultMessage: '用户名: admin or user',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.username.required"
defaultMessage="请输入用户名!"
/>
),
},
]}
/>
<ProFormText.Password
name="password"
fieldProps={{
size: 'large',
prefix: <LockOutlined />,
}}
placeholder={intl.formatMessage({
id: 'pages.login.password.placeholder',
defaultMessage: '密码: ant.design',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.password.required"
defaultMessage="请输入密码!"
/>
),
},
]}
/>
</>
)}
{status === 'error' && loginType === 'mobile' && (
<LoginMessage content="验证码错误" />
)}
{type === 'mobile' && (
<>
<ProFormText
fieldProps={{
size: 'large',
prefix: <MobileOutlined />,
}}
name="mobile"
placeholder={intl.formatMessage({
id: 'pages.login.phoneNumber.placeholder',
defaultMessage: '手机号',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.phoneNumber.required"
defaultMessage="请输入手机号!"
/>
),
},
{
pattern: /^1\d{10}$/,
message: (
<FormattedMessage
id="pages.login.phoneNumber.invalid"
defaultMessage="手机号格式错误!"
/>
),
},
]}
/>
<ProFormCaptcha
fieldProps={{
size: 'large',
prefix: <LockOutlined />,
}}
captchaProps={{
size: 'large',
}}
placeholder={intl.formatMessage({
id: 'pages.login.captcha.placeholder',
defaultMessage: '请输入验证码',
})}
captchaTextRender={(timing, count) => {
if (timing) {
return `${count} ${intl.formatMessage({
id: 'pages.getCaptchaSecondText',
defaultMessage: '获取验证码',
})}`;
}
return intl.formatMessage({
id: 'pages.login.phoneLogin.getVerificationCode',
defaultMessage: '获取验证码',
});
}}
name="captcha"
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.captcha.required"
defaultMessage="请输入验证码!"
/>
),
},
]}
onGetCaptcha={async (phone) => {
const result = await getFakeCaptcha({
phone,
});
if (!result) {
return;
}
message.success('获取验证码成功验证码为1234');
}}
/>
</>
)}
<div
style={{
marginBottom: 24,
}}
>
<ProFormCheckbox noStyle name="autoLogin">
<FormattedMessage
id="pages.login.rememberMe"
defaultMessage="自动登录"
/>
</ProFormCheckbox>
<a
style={{ style={{
float: 'right', borderRadius: 20,
background: token.colorBgElevated,
color: token.colorPrimary,
width: 120,
}} }}
> >
<FormattedMessage
id="pages.login.forgotPassword" </Button>
defaultMessage="忘记密码" ),
/> }}
</a> actions={
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
flexDirection: "column",
}}
>
<Divider plain>
<span
style={{
color: token.colorTextPlaceholder,
fontWeight: "normal",
fontSize: 14,
}}
>
</span>
</Divider>
<Space align="center" size={24}>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
flexDirection: "column",
height: 40,
width: 40,
border: "1px solid " + token.colorPrimaryBorder,
borderRadius: "50%",
}}
>
<AlipayOutlined style={{ ...iconStyles, color: "#1677FF" }} />
</div>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
flexDirection: "column",
height: 40,
width: 40,
border: "1px solid " + token.colorPrimaryBorder,
borderRadius: "50%",
}}
>
<TaobaoOutlined style={{ ...iconStyles, color: "#FF6A10" }} />
</div>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
flexDirection: "column",
height: 40,
width: 40,
border: "1px solid " + token.colorPrimaryBorder,
borderRadius: "50%",
}}
>
<WeiboOutlined style={{ ...iconStyles, color: "#1890ff" }} />
</div>
</Space>
</div> </div>
</LoginForm> }
</div> >
<Footer /> <Tabs
centered
activeKey={loginType}
onChange={(activeKey) => setLoginType(activeKey as LoginType)}
>
<Tabs.TabPane key={"account"} tab={"账号密码登录"} />
<Tabs.TabPane key={"phone"} tab={"手机号登录"} />
</Tabs>
{loginType === "account" && (
<>
<ProFormText
name="username"
fieldProps={{
size: "large",
prefix: (
<UserOutlined
style={{
color: token.colorText,
}}
className={"prefixIcon"}
/>
),
}}
placeholder={"用户名: admin or user"}
rules={[
{
required: true,
message: "请输入用户名!",
},
]}
/>
<ProFormText.Password
name="password"
fieldProps={{
size: "large",
prefix: (
<LockOutlined
style={{
color: token.colorText,
}}
className={"prefixIcon"}
/>
),
}}
placeholder={"密码: ant.design"}
rules={[
{
required: true,
message: "请输入密码!",
},
]}
/>
</>
)}
{loginType === "phone" && (
<>
<ProFormText
fieldProps={{
size: "large",
prefix: (
<MobileOutlined
style={{
color: token.colorText,
}}
className={"prefixIcon"}
/>
),
}}
name="mobile"
placeholder={"手机号"}
rules={[
{
required: true,
message: "请输入手机号!",
},
{
pattern: /^1\d{10}$/,
message: "手机号格式错误!",
},
]}
/>
<ProFormCaptcha
fieldProps={{
size: "large",
prefix: (
<LockOutlined
style={{
color: token.colorText,
}}
className={"prefixIcon"}
/>
),
}}
captchaProps={{
size: "large",
}}
placeholder={"请输入验证码"}
captchaTextRender={(timing, count) => {
if (timing) {
return `${count} ${"获取验证码"}`;
}
return "获取验证码";
}}
name="captcha"
rules={[
{
required: true,
message: "请输入验证码!",
},
]}
onGetCaptcha={async () => {
message.success("获取验证码成功验证码为1234");
}}
/>
</>
)}
<div
style={{
marginBlockEnd: 24,
}}
>
<ProFormCheckbox noStyle name="autoLogin">
</ProFormCheckbox>
<a
style={{
float: "right",
}}
>
</a>
</div>
</LoginFormPage>
</div> </div>
); );
}; };
export default Login; export default () => {
return (
<ProConfigProvider dark>
<Page />
</ProConfigProvider>
);
};

View File

@@ -1,102 +0,0 @@
// @ts-ignore
import { startMock } from '@@/requestRecordMock';
import { TestBrowser } from '@@/testBrowser';
import { fireEvent, render } from '@testing-library/react';
import React, { act } from 'react';
const waitTime = (time: number = 100) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, time);
});
};
let server: {
close: () => void;
};
describe('Login Page', () => {
beforeAll(async () => {
server = await startMock({
port: 8000,
scene: 'login',
});
});
afterAll(() => {
server?.close();
});
it('should show login form', async () => {
const historyRef = React.createRef<any>();
const rootContainer = render(
<TestBrowser
historyRef={historyRef}
location={{
pathname: '/user/login',
}}
/>,
);
await rootContainer.findAllByText('Ant Design');
act(() => {
historyRef.current?.push('/user/login');
});
expect(
rootContainer.baseElement?.querySelector('.ant-pro-form-login-desc')
?.textContent,
).toBe(
'Ant Design is the most influential web design specification in Xihu district',
);
expect(rootContainer.asFragment()).toMatchSnapshot();
rootContainer.unmount();
});
it('should login success', async () => {
const historyRef = React.createRef<any>();
const rootContainer = render(
<TestBrowser
historyRef={historyRef}
location={{
pathname: '/user/login',
}}
/>,
);
await rootContainer.findAllByText('Ant Design');
const userNameInput = await rootContainer.findByPlaceholderText(
'Username: admin or user',
);
act(() => {
fireEvent.change(userNameInput, { target: { value: 'admin' } });
});
const passwordInput = await rootContainer.findByPlaceholderText(
'Password: ant.design',
);
act(() => {
fireEvent.change(passwordInput, { target: { value: 'ant.design' } });
});
await (await rootContainer.findByText('Login')).click();
// 等待接口返回结果
await waitTime(5000);
await rootContainer.findAllByText('Ant Design Pro');
expect(rootContainer.asFragment()).toMatchSnapshot();
await waitTime(2000);
rootContainer.unmount();
});
});

View File

@@ -1,94 +0,0 @@
// @ts-ignore
/* eslint-disable */
import { request } from '@umijs/max';
/** 获取当前的用户 GET /api/currentUser */
export async function currentUser(options?: { [key: string]: any }) {
return request<{
data: API.CurrentUser;
}>('/api/currentUser', {
method: 'GET',
...(options || {}),
});
}
/** 退出登录接口 POST /api/login/outLogin */
export async function outLogin(options?: { [key: string]: any }) {
return request<Record<string, any>>('/api/login/outLogin', {
method: 'POST',
...(options || {}),
});
}
/** 登录接口 POST /api/login/account */
export async function login(body: API.LoginParams, options?: { [key: string]: any }) {
return request<API.LoginResult>('/api/login/account', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 此处后端没有提供注释 GET /api/notices */
export async function getNotices(options?: { [key: string]: any }) {
return request<API.NoticeIconList>('/api/notices', {
method: 'GET',
...(options || {}),
});
}
/** 获取规则列表 GET /api/rule */
export async function rule(
params: {
// query
/** 当前的页码 */
current?: number;
/** 页面的容量 */
pageSize?: number;
},
options?: { [key: string]: any },
) {
return request<API.RuleList>('/api/rule', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** 更新规则 PUT /api/rule */
export async function updateRule(options?: { [key: string]: any }) {
return request<API.RuleListItem>('/api/rule', {
method: 'POST',
data: {
method: 'update',
...(options || {}),
},
});
}
/** 新建规则 POST /api/rule */
export async function addRule(options?: { [key: string]: any }) {
return request<API.RuleListItem>('/api/rule', {
method: 'POST',
data: {
method: 'post',
...(options || {}),
},
});
}
/** 删除规则 DELETE /api/rule */
export async function removeRule(options?: { [key: string]: any }) {
return request<Record<string, any>>('/api/rule', {
method: 'POST',
data: {
method: 'delete',
...(options || {}),
},
});
}

View File

@@ -1,21 +0,0 @@
// @ts-ignore
/* eslint-disable */
import { request } from '@umijs/max';
/** 发送验证码 POST /api/login/captcha */
export async function getFakeCaptcha(
params: {
// query
/** 手机号 */
phone?: string;
},
options?: { [key: string]: any },
) {
return request<API.FakeCaptcha>('/api/login/captcha', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}

View File

@@ -1,101 +0,0 @@
// @ts-ignore
/* eslint-disable */
declare namespace API {
type CurrentUser = {
name?: string;
avatar?: string;
userid?: string;
email?: string;
signature?: string;
title?: string;
group?: string;
tags?: { key?: string; label?: string }[];
notifyCount?: number;
unreadCount?: number;
country?: string;
access?: string;
geographic?: {
province?: { label?: string; key?: string };
city?: { label?: string; key?: string };
};
address?: string;
phone?: string;
};
type LoginResult = {
status?: string;
type?: string;
currentAuthority?: string;
};
type PageParams = {
current?: number;
pageSize?: number;
};
type RuleListItem = {
key?: number;
disabled?: boolean;
href?: string;
avatar?: string;
name?: string;
owner?: string;
desc?: string;
callNo?: number;
status?: number;
updatedAt?: string;
createdAt?: string;
progress?: number;
};
type RuleList = {
data?: RuleListItem[];
/** 列表的内容总数 */
total?: number;
success?: boolean;
};
type FakeCaptcha = {
code?: number;
status?: string;
};
type LoginParams = {
username?: string;
password?: string;
autoLogin?: boolean;
type?: string;
};
type ErrorResponse = {
/** 业务约定的错误码 */
errorCode: string;
/** 业务上的错误信息 */
errorMessage?: string;
/** 业务上的请求是否成功 */
success?: boolean;
};
type NoticeIconList = {
data?: NoticeIconItem[];
/** 列表的内容总数 */
total?: number;
success?: boolean;
};
type NoticeIconItemType = 'notification' | 'message' | 'event';
type NoticeIconItem = {
id?: string;
extra?: string;
key?: string;
read?: boolean;
avatar?: string;
title?: string;
status?: string;
datetime?: string;
description?: string;
type?: NoticeIconItemType;
};
}

153
src/services/login/index.ts Normal file
View File

@@ -0,0 +1,153 @@
import { request } from "@umijs/max";
import * as API from "./types";
export interface SmsCodeVO {
mobile: string;
scene: number;
}
export interface SmsLoginVO {
mobile: string;
code: string;
}
// 登录
// export const login = (data: UserLoginVO) => {
// return request.post({ url: '/system/auth/login', data })
// }
export async function login(
body: API.UserLoginVO,
options?: { [key: string]: any }
) {
return request<API.TokenType>("/system/auth/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
data: body,
...(options || {}),
});
}
// 注册
// export const register = (data: RegisterVO) => {
// return request.post({ url: "/system/auth/register", data });
// };
// 使用租户名,获得租户编号
// export const getTenantIdByName = (name: string) => {
// return request.get({ url: "/system/tenant/get-id-by-name?name=" + name });
// };
export async function getTenantIdByName(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: { name: string },
options?: { [key: string]: any }
) {
return request("/system/tenant/get-id-by-name", {
method: "GET",
params: {
...params,
},
...(options || {}),
});
}
// 使用租户域名,获得租户信息
// export const getTenantByWebsite = (website: string) => {
// return request.get({
// url: "/system/tenant/get-by-website?website=" + website,
// });
// };
export async function getTenantByWebsite(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: { website: string },
options?: { [key: string]: any }
) {
return request("/system/tenant/get-by-website", {
method: "GET",
params: {
...params,
},
...(options || {}),
});
}
// 登出
// export const loginOut = () => {
// return request.post({ url: "/system/auth/logout" });
// };
export async function loginOut(
body: API.UserLoginVO,
options?: { [key: string]: any }
) {
return request("/system/auth/logout", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
data: body,
...(options || {}),
});
}
// 获取用户权限信息
// export const getInfo = () => {
// return request.get({ url: "/system/auth/get-permission-info" });
// };
export async function getInfo(options?: { [key: string]: any }) {
return request<IResponse<{ user: API.UserVO }>>(
"/system/auth/get-permission-info",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
...(options || {}),
}
);
}
//获取登录验证码
// export const sendSmsCode = (data: SmsCodeVO) => {
// return request.post({ url: "/system/auth/send-sms-code", data });
// };
// // 短信验证码登录
// export const smsLogin = (data: SmsLoginVO) => {
// return request.post({ url: "/system/auth/sms-login", data });
// };
// 社交快捷登录,使用 code 授权码
// export function socialLogin(type: string, code: string, state: string) {
// return request.post({
// url: "/system/auth/social-login",
// data: {
// type,
// code,
// state,
// },
// });
// }
// 社交授权的跳转
// export const socialAuthRedirect = (type: number, redirectUri: string) => {
// return request.get({
// url:
// "/system/auth/social-auth-redirect?type=" +
// type +
// "&redirectUri=" +
// redirectUri,
// });
// };
// 获取验证图片以及 token
// export const getCode = (data: any) => {
// debugger;
// return request.postOriginal({ url: "system/captcha/get", data });
// };
// 滑动或者点选验证
// export const reqCheck = (data: any) => {
// return request.postOriginal({ url: "system/captcha/check", data });
// };
// 通过短信重置密码
// export const smsResetPassword = (data: any) => {
// return request.post({ url: "/system/auth/reset-password", data });
// };

View File

@@ -0,0 +1,41 @@
import request from '@/config/axios'
// 获得授权信息
export const getAuthorize = (clientId: string) => {
return request.get({ url: '/system/oauth2/authorize?clientId=' + clientId })
}
// 发起授权
export const authorize = (
responseType: string,
clientId: string,
redirectUri: string,
state: string,
autoApprove: boolean,
checkedScopes: string[],
uncheckedScopes: string[]
) => {
// 构建 scopes
const scopes = {}
for (const scope of checkedScopes) {
scopes[scope] = true
}
for (const scope of uncheckedScopes) {
scopes[scope] = false
}
// 发起请求
return request.post({
url: '/system/oauth2/authorize',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
params: {
response_type: responseType,
client_id: clientId,
redirect_uri: redirectUri,
state: state,
auto_approve: autoApprove,
scope: JSON.stringify(scopes)
}
})
}

View File

@@ -0,0 +1,38 @@
export type UserLoginVO = {
username: string
password: string
captchaVerification: string
socialType?: string
socialCode?: string
socialState?: string
}
export type TokenType = {
id: number // 编号
accessToken: string // 访问令牌
refreshToken: string // 刷新令牌
userId: number // 用户编号
userType: number //用户类型
clientId: string //客户端编号
expiresTime: number //过期时间
}
export type UserVO = {
id: number
username: string
nickname: string
deptId: number
email: string
mobile: string
sex: number
avatar: string
loginIp: string
loginDate: string
}
export type RegisterVO = {
tenantName: string
username: string
password: string
captchaVerification: string
}

View File

@@ -0,0 +1,51 @@
// @ts-ignore
/* eslint-disable */
import { request } from "@umijs/max";
/** 获取菜单页面的表 GET /product/category/categoryList */
export async function getProductCategoryCategoryList(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.getProductCategoryCategoryListParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultListCategoryDto>(
"/product/category/categoryList",
{
method: "GET",
params: {
...params,
},
...(options || {}),
}
);
}
/** 创建产品类目 创建产品类目 POST /product/category/create */
export async function postProductCategoryCreate(
body: API.CategorySaveReqVO,
options?: { [key: string]: any }
) {
return request<API.CommonResultLong>("/product/category/create", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
data: body,
...(options || {}),
});
}
/** 更新产品类目 更新产品类目 PUT /product/category/update */
export async function putProductCategoryUpdate(
body: API.CategorySaveReqVO,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/category/update", {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
data: body,
...(options || {}),
});
}

View File

@@ -2,9 +2,9 @@
/* eslint-disable */ /* eslint-disable */
// API 更新时间: // API 更新时间:
// API 唯一标识: // API 唯一标识:
import * as api from './api'; import * as product from "./product";
import * as login from './login'; import * as category from "./category";
export default { export default {
api, product,
login, category,
}; };

View File

@@ -0,0 +1,601 @@
// @ts-ignore
/* eslint-disable */
import { request } from "@umijs/max";
/** 创建商品 创建商品 POST /prod/create */
export async function postProdCreate(
body: API.ProdSaveReqVO,
options?: { [key: string]: any }
) {
return request<API.CommonResultLong>("/prod/create", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
data: body,
...(options || {}),
});
}
/** 创建商品 创建商品 POST /product/prod/create */
export async function postProductProdCreate(
body: API.ProdSaveReqVO,
options?: { [key: string]: any }
) {
return request<API.CommonResultLong>("/product/prod/create", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
data: body,
...(options || {}),
});
}
/** 创建商品服务配置 创建商品服务配置 POST /product/prod/createProdService */
export async function postProductProdCreateProdService(
body: API.ProdServiceVO,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/prod/createProdService", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
data: body,
...(options || {}),
});
}
/** 删除商品 删除商品 DELETE /product/prod/delete */
export async function deleteProductProdOpenApiDelete(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.deleteProductProd_openAPI_deleteParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/prod/delete", {
method: "DELETE",
params: {
...params,
},
...(options || {}),
});
}
/** 批量删除商品 批量删除商品 DELETE /product/prod/deleteSkuList */
export async function deleteProductProdDeleteSkuList(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.deleteProductProdDeleteSkuListParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/prod/deleteSkuList", {
method: "DELETE",
params: {
...params,
},
...(options || {}),
});
}
/** 获得商品回收站分页列表 获得商品回收站分页列表 GET /product/prod/getProdRecycleBinPageList */
export async function getProductProdGetProdRecycleBinPageList(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.getProductProdGetProdRecycleBinPageListParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultPageResultProdRestoreListVO>(
"/product/prod/getProdRecycleBinPageList",
{
method: "GET",
params: {
// pageNo has a default value: 1
pageNo: "1",
// pageSize has a default value: 10
pageSize: "10",
...params,
},
...(options || {}),
}
);
}
/** 获得商品服务信息 获得商品服务信息 GET /product/prod/getProdService */
export async function getProductProdGetProdService(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.getProductProdGetProdServiceParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultProdServiceVO>(
"/product/prod/getProdService",
{
method: "GET",
params: {
...params,
},
...(options || {}),
}
);
}
/** 获得商品分页 获得商品分页 GET /product/prod/page */
export async function getProductProdPage(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.getProductProdPageParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultPageResultProdListVO>("/product/prod/page", {
method: "GET",
params: {
// pageNo has a default value: 1
pageNo: "1",
// pageSize has a default value: 10
pageSize: "10",
...params,
},
...(options || {}),
});
}
/** 恢复商品 恢复商品 POST /product/prod/restoreProdList */
export async function postProductProdRestoreProdList(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.postProductProdRestoreProdListParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/prod/restoreProdList", {
method: "POST",
params: {
...params,
},
...(options || {}),
});
}
/** 更新商品 更新商品 PUT /product/prod/update */
export async function putProductProdUpdate(
body: API.ProdSaveReqVO,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/prod/update", {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
data: body,
...(options || {}),
});
}
/** 批量上下架 批量上下架 DELETE /product/prod/updateSkuShelfList */
export async function deleteProductProdUpdateSkuShelfList(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.deleteProductProdUpdateSkuShelfListParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/prod/updateSkuShelfList", {
method: "DELETE",
params: {
...params,
},
...(options || {}),
});
}
/** 修改商品服务配置 修改商品服务配置 POST /product/prod/uptateProdService */
export async function postProductProdUptateProdService(
body: API.ProdServiceInfoVO,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/prod/uptateProdService", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
data: body,
...(options || {}),
});
}
/** 创建sku扩展服务配置 创建sku扩展服务配置 POST /product/sku/createSkuExtend */
export async function postProductSkuCreateSkuExtend(
body: API.SkuExtendVO,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/sku/createSkuExtend", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
data: body,
...(options || {}),
});
}
/** 删除单品SKU 删除单品SKU DELETE /product/sku/delete */
export async function deleteProductSkuOpenApiDelete(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.deleteProductSku_openAPI_deleteParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/sku/delete", {
method: "DELETE",
params: {
...params,
},
...(options || {}),
});
}
/** 删除规格值 删除规格值 PUT /product/sku/deleteProp */
export async function putProductSkuDeleteProp(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.putProductSkuDeletePropParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/sku/deleteProp", {
method: "PUT",
params: {
...params,
},
...(options || {}),
});
}
/** 批量删除SKU 批量删除SKU DELETE /product/sku/deleteSkuList */
export async function deleteProductSkuDeleteSkuList(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.deleteProductSkuDeleteSkuListParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/sku/deleteSkuList", {
method: "DELETE",
params: {
...params,
},
...(options || {}),
});
}
/** 禁用或者启用规格值 禁用规格值 PUT /product/sku/disableProp */
export async function putProductSkuDisableProp(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.putProductSkuDisablePropParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/sku/disableProp", {
method: "PUT",
params: {
...params,
},
...(options || {}),
});
}
/** 获得单品SKU 获得单品SKU GET /product/sku/get */
export async function getProductSkuGet(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.getProductSkuGetParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultSkuRespVO>("/product/sku/get", {
method: "GET",
params: {
...params,
},
...(options || {}),
});
}
/** 获取规格回收站 获取规格回收站 GET /product/sku/getPropRecycleBinList */
export async function getProductSkuGetPropRecycleBinList(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.getProductSkuGetPropRecycleBinListParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultPageResultProPropRecycleBinVO>(
"/product/sku/getPropRecycleBinList",
{
method: "GET",
params: {
// pageNo has a default value: 1
pageNo: "1",
// pageSize has a default value: 10
pageSize: "10",
...params,
},
...(options || {}),
}
);
}
/** 获取sku扩展服务配置信息 获取sku扩展服务配置信息 POST /product/sku/getSkuExtend */
export async function postProductSkuGetSkuExtend(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.postProductSkuGetSkuExtendParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultSkuExtendVO>("/product/sku/getSkuExtend", {
method: "POST",
params: {
...params,
},
...(options || {}),
});
}
/** 获得SKU分页列表 获得SKU分页列表 GET /product/sku/getSkuPageList */
export async function getProductSkuGetSkuPageList(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.getProductSkuGetSkuPageListParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultPageResultSkuDO>(
"/product/sku/getSkuPageList",
{
method: "GET",
params: {
// pageNo has a default value: 1
pageNo: "1",
// pageSize has a default value: 10
pageSize: "10",
...params,
},
...(options || {}),
}
);
}
/** 获取sku规格 获取sku规格 GET /product/sku/getSKuPropList */
export async function getProductSkuGetSKuPropList(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.getProductSkuGetSKuPropListParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultSkuPropInfoVO>("/product/sku/getSKuPropList", {
method: "GET",
params: {
...params,
},
...(options || {}),
});
}
/** 获得SKU回收站分页列表 获得SKU回收站分页列表 GET /product/sku/getSkuRecycleBinPageList */
export async function getProductSkuGetSkuRecycleBinPageList(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.getProductSkuGetSkuRecycleBinPageListParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultPageResultSkuRecycleBinVO>(
"/product/sku/getSkuRecycleBinPageList",
{
method: "GET",
params: {
// pageNo has a default value: 1
pageNo: "1",
// pageSize has a default value: 10
pageSize: "10",
...params,
},
...(options || {}),
}
);
}
/** 恢复规格 恢复规格 POST /product/sku/restorePropList */
export async function postProductSkuRestorePropList(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.postProductSkuRestorePropListParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/sku/restorePropList", {
method: "POST",
params: {
...params,
},
...(options || {}),
});
}
/** 恢复SKU 恢复SKU POST /product/sku/restoreSkuList */
export async function postProductSkuRestoreSkuList(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.postProductSkuRestoreSkuListParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/sku/restoreSkuList", {
method: "POST",
params: {
...params,
},
...(options || {}),
});
}
/** 更新单品SKU 更新单品SKU PUT /product/sku/update */
export async function putProductSkuUpdate(
body: API.SkuSaveReqVO,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/sku/update", {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
data: body,
...(options || {}),
});
}
/** 修改配送方式 修改配送方式 POST /product/sku/updateDeliver */
export async function postProductSkuUpdateDeliver(
body: API.SkuServiceDeliverDO[],
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/sku/updateDeliver", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
data: body,
...(options || {}),
});
}
/** 修物料配置 修物料配置 POST /product/sku/updateMaterial */
export async function postProductSkuUpdateMaterial(
body: API.SkuServiceMaterialDO[],
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/sku/updateMaterial", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
data: body,
...(options || {}),
});
}
/** 修改属性规格值 修改属性规格值 PUT /product/sku/updateProdProp */
export async function putProductSkuUpdateProdProp(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.putProductSkuUpdateProdPropParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/sku/updateProdProp", {
method: "PUT",
params: {
...params,
},
...(options || {}),
});
}
/** 新增统一保存sku规格 更新sku规格 PUT /product/sku/updateProp */
export async function putProductSkuUpdateProp(
body: API.SkuPropVO,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/sku/updateProp", {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
data: body,
...(options || {}),
});
}
/** 修改属性下面规格值 修改属性下面规格值 PUT /product/sku/updatePropValue */
export async function putProductSkuUpdatePropValue(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.putProductSkuUpdatePropValueParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/sku/updatePropValue", {
method: "PUT",
params: {
...params,
},
...(options || {}),
});
}
/** 修改扩展服务信息配置(遗体接运扩展服务,遗体清洁配置,追思告别配置,骨灰处理配置...... 修改扩展服务信息配置(遗体接运扩展服务,遗体清洁配置,追思告别配置,骨灰处理配置...... POST /product/sku/updateServiceDetails */
export async function postProductSkuUpdateServiceDetails(
body: API.SkuServiceDetailsDO[],
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/sku/updateServiceDetails", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
data: body,
...(options || {}),
});
}
/** 修改单品上下架 修改单品上下架 PUT /product/sku/updateSkuShelf */
export async function putProductSkuUpdateSkuShelf(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.putProductSkuUpdateSkuShelfParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/sku/updateSkuShelf", {
method: "PUT",
params: {
...params,
},
...(options || {}),
});
}
/** 修改单品上下架 修改单品上下架 POST /product/sku/updateSkuShelf */
export async function postProductSkuUpdateSkuShelf(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.postProductSkuUpdateSkuShelfParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/sku/updateSkuShelf", {
method: "POST",
params: {
...params,
},
...(options || {}),
});
}
/** 批量上下架 批量上下架 PUT /product/sku/updateSkuShelfList */
export async function putProductSkuUpdateSkuShelfList(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.putProductSkuUpdateSkuShelfListParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/sku/updateSkuShelfList", {
method: "PUT",
params: {
...params,
},
...(options || {}),
});
}
/** 批量上下架 批量上下架 POST /product/sku/updateSkuShelfList */
export async function postProductSkuUpdateSkuShelfList(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.postProductSkuUpdateSkuShelfListParams,
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>("/product/sku/updateSkuShelfList", {
method: "POST",
params: {
...params,
},
...(options || {}),
});
}
/** 修改接运地址配置 修改接运地址配置 POST /product/sku/updateTransportAdress */
export async function postProductSkuUpdateTransportAdress(
body: API.SkuServiceTransportDO[],
options?: { [key: string]: any }
) {
return request<API.CommonResultBoolean>(
"/product/sku/updateTransportAdress",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
data: body,
...(options || {}),
}
);
}

2086
src/services/prodApi/typings.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +0,0 @@
// @ts-ignore
/* eslint-disable */
// API 更新时间:
// API 唯一标识:
import * as pet from './pet';
import * as store from './store';
import * as user from './user';
export default {
pet,
store,
user,
};

View File

@@ -1,153 +0,0 @@
// @ts-ignore
/* eslint-disable */
import { request } from '@umijs/max';
/** Update an existing pet PUT /pet */
export async function updatePet(body: API.Pet, options?: { [key: string]: any }) {
return request<any>('/pet', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** Add a new pet to the store POST /pet */
export async function addPet(body: API.Pet, options?: { [key: string]: any }) {
return request<any>('/pet', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** Find pet by ID Returns a single pet GET /pet/${param0} */
export async function getPetById(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.getPetByIdParams,
options?: { [key: string]: any },
) {
const { petId: param0, ...queryParams } = params;
return request<API.Pet>(`/pet/${param0}`, {
method: 'GET',
params: { ...queryParams },
...(options || {}),
});
}
/** Updates a pet in the store with form data POST /pet/${param0} */
export async function updatePetWithForm(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.updatePetWithFormParams,
body: { name?: string; status?: string },
options?: { [key: string]: any },
) {
const { petId: param0, ...queryParams } = params;
const formData = new FormData();
Object.keys(body).forEach((ele) => {
const item = (body as any)[ele];
if (item !== undefined && item !== null) {
formData.append(
ele,
typeof item === 'object' && !(item instanceof File) ? JSON.stringify(item) : item,
);
}
});
return request<any>(`/pet/${param0}`, {
method: 'POST',
params: { ...queryParams },
data: formData,
...(options || {}),
});
}
/** Deletes a pet DELETE /pet/${param0} */
export async function deletePet(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.deletePetParams & {
// header
api_key?: string;
},
options?: { [key: string]: any },
) {
const { petId: param0, ...queryParams } = params;
return request<any>(`/pet/${param0}`, {
method: 'DELETE',
headers: {},
params: { ...queryParams },
...(options || {}),
});
}
/** uploads an image POST /pet/${param0}/uploadImage */
export async function uploadFile(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.uploadFileParams,
body: { additionalMetadata?: string; file?: string },
file?: File,
options?: { [key: string]: any },
) {
const { petId: param0, ...queryParams } = params;
const formData = new FormData();
if (file) {
formData.append('file', file);
}
Object.keys(body).forEach((ele) => {
const item = (body as any)[ele];
if (item !== undefined && item !== null) {
formData.append(
ele,
typeof item === 'object' && !(item instanceof File) ? JSON.stringify(item) : item,
);
}
});
return request<API.ApiResponse>(`/pet/${param0}/uploadImage`, {
method: 'POST',
params: { ...queryParams },
data: formData,
requestType: 'form',
...(options || {}),
});
}
/** Finds Pets by status Multiple status values can be provided with comma separated strings GET /pet/findByStatus */
export async function findPetsByStatus(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.findPetsByStatusParams,
options?: { [key: string]: any },
) {
return request<API.Pet[]>('/pet/findByStatus', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** Finds Pets by tags Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. GET /pet/findByTags */
export async function findPetsByTags(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.findPetsByTagsParams,
options?: { [key: string]: any },
) {
return request<API.Pet[]>('/pet/findByTags', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}

View File

@@ -1,48 +0,0 @@
// @ts-ignore
/* eslint-disable */
import { request } from '@umijs/max';
/** Returns pet inventories by status Returns a map of status codes to quantities GET /store/inventory */
export async function getInventory(options?: { [key: string]: any }) {
return request<Record<string, any>>('/store/inventory', {
method: 'GET',
...(options || {}),
});
}
/** Place an order for a pet POST /store/order */
export async function placeOrder(body: API.Order, options?: { [key: string]: any }) {
return request<API.Order>('/store/order', {
method: 'POST',
data: body,
...(options || {}),
});
}
/** Find purchase order by ID For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions GET /store/order/${param0} */
export async function getOrderById(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.getOrderByIdParams,
options?: { [key: string]: any },
) {
const { orderId: param0, ...queryParams } = params;
return request<API.Order>(`/store/order/${param0}`, {
method: 'GET',
params: { ...queryParams },
...(options || {}),
});
}
/** Delete purchase order by ID For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors DELETE /store/order/${param0} */
export async function deleteOrder(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.deleteOrderParams,
options?: { [key: string]: any },
) {
const { orderId: param0, ...queryParams } = params;
return request<any>(`/store/order/${param0}`, {
method: 'DELETE',
params: { ...queryParams },
...(options || {}),
});
}

View File

@@ -1,112 +0,0 @@
declare namespace API {
type ApiResponse = {
code?: number;
type?: string;
message?: string;
};
type Category = {
id?: number;
name?: string;
};
type deleteOrderParams = {
/** ID of the order that needs to be deleted */
orderId: number;
};
type deletePetParams = {
api_key?: string;
/** Pet id to delete */
petId: number;
};
type deleteUserParams = {
/** The name that needs to be deleted */
username: string;
};
type findPetsByStatusParams = {
/** Status values that need to be considered for filter */
status: ('available' | 'pending' | 'sold')[];
};
type findPetsByTagsParams = {
/** Tags to filter by */
tags: string[];
};
type getOrderByIdParams = {
/** ID of pet that needs to be fetched */
orderId: number;
};
type getPetByIdParams = {
/** ID of pet to return */
petId: number;
};
type getUserByNameParams = {
/** The name that needs to be fetched. Use user1 for testing. */
username: string;
};
type loginUserParams = {
/** The user name for login */
username: string;
/** The password for login in clear text */
password: string;
};
type Order = {
id?: number;
petId?: number;
quantity?: number;
shipDate?: string;
/** Order Status */
status?: 'placed' | 'approved' | 'delivered';
complete?: boolean;
};
type Pet = {
id?: number;
category?: Category;
name: string;
photoUrls: string[];
tags?: Tag[];
/** pet status in the store */
status?: 'available' | 'pending' | 'sold';
};
type Tag = {
id?: number;
name?: string;
};
type updatePetWithFormParams = {
/** ID of pet that needs to be updated */
petId: number;
};
type updateUserParams = {
/** name that need to be updated */
username: string;
};
type uploadFileParams = {
/** ID of pet to update */
petId: number;
};
type User = {
id?: number;
username?: string;
firstName?: string;
lastName?: string;
email?: string;
password?: string;
phone?: string;
/** User Status */
userStatus?: number;
};
}

View File

@@ -1,100 +0,0 @@
// @ts-ignore
/* eslint-disable */
import { request } from '@umijs/max';
/** Create user This can only be done by the logged in user. POST /user */
export async function createUser(body: API.User, options?: { [key: string]: any }) {
return request<any>('/user', {
method: 'POST',
data: body,
...(options || {}),
});
}
/** Get user by user name GET /user/${param0} */
export async function getUserByName(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.getUserByNameParams,
options?: { [key: string]: any },
) {
const { username: param0, ...queryParams } = params;
return request<API.User>(`/user/${param0}`, {
method: 'GET',
params: { ...queryParams },
...(options || {}),
});
}
/** Updated user This can only be done by the logged in user. PUT /user/${param0} */
export async function updateUser(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.updateUserParams,
body: API.User,
options?: { [key: string]: any },
) {
const { username: param0, ...queryParams } = params;
return request<any>(`/user/${param0}`, {
method: 'PUT',
params: { ...queryParams },
data: body,
...(options || {}),
});
}
/** Delete user This can only be done by the logged in user. DELETE /user/${param0} */
export async function deleteUser(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.deleteUserParams,
options?: { [key: string]: any },
) {
const { username: param0, ...queryParams } = params;
return request<any>(`/user/${param0}`, {
method: 'DELETE',
params: { ...queryParams },
...(options || {}),
});
}
/** Creates list of users with given input array POST /user/createWithArray */
export async function createUsersWithArrayInput(
body: API.User[],
options?: { [key: string]: any },
) {
return request<any>('/user/createWithArray', {
method: 'POST',
data: body,
...(options || {}),
});
}
/** Creates list of users with given input array POST /user/createWithList */
export async function createUsersWithListInput(body: API.User[], options?: { [key: string]: any }) {
return request<any>('/user/createWithList', {
method: 'POST',
data: body,
...(options || {}),
});
}
/** Logs user into the system GET /user/login */
export async function loginUser(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.loginUserParams,
options?: { [key: string]: any },
) {
return request<string>('/user/login', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** Logs out current logged in user session GET /user/logout */
export async function logoutUser(options?: { [key: string]: any }) {
return request<any>('/user/logout', {
method: 'GET',
...(options || {}),
});
}

View File

View File

@@ -0,0 +1,119 @@
import { request } from "@umijs/max";
export interface PermissionAssignUserRoleReqVO {
userId: number;
roleIds: number[];
}
export interface PermissionAssignRoleMenuReqVO {
roleId: number;
menuIds: number[];
}
export interface PermissionAssignRoleDataScopeReqVO {
roleId: number;
dataScope: number;
dataScopeDeptIds: number[];
}
// export async function postProductProdRestoreProdList(
// // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
// params: API.postProductProdRestoreProdListParams,
// options?: { [key: string]: any }
// ) {
// return request<API.CommonResultBoolean>("/product/prod/restoreProdList", {
// method: "POST",
// params: {
// ...params,
// },
// ...(options || {}),
// });
// }
// export async function getRoleMenuList(
// // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
// params: API.getProductCategoryCategoryListParams,
// options?: { [key: string]: any }
// ) {
// return request<API.CommonResultListCategoryDto>(
// "/product/category/categoryList",
// {
// method: "GET",
// params: {
// ...params,
// },
// ...(options || {}),
// }
// );
// }
// 查询角色拥有的菜单权限
// export const getRoleMenuList = async (roleId: number) => {
// return await request.get({ url: '/system/permission/list-role-menus?roleId=' + roleId })
// }
export async function getRoleMenuList(roleId: number) {
return request("/system/permission/list-role-menus", {
method: "GET",
params: {
roleId,
},
});
}
// // 赋予角色菜单权限
// export const assignRoleMenu = async (data: PermissionAssignRoleMenuReqVO) => {
// return await request.post({ url: '/system/permission/assign-role-menu', data })
// }
export async function assignRoleMenu(
params: PermissionAssignRoleMenuReqVO,
options?: { [key: string]: any }
) {
return request("/system/permission/assign-role-menu", {
method: "POST",
params: {
...params,
},
...(options || {}),
});
}
// // 赋予角色数据权限
// export const assignRoleDataScope = async (data: PermissionAssignRoleDataScopeReqVO) => {
// return await request.post({ url: '/system/permission/assign-role-data-scope', data })
// }
export async function assignRoleDataScope(
params: PermissionAssignRoleDataScopeReqVO,
options?: { [key: string]: any }
) {
return request("/system/permission/assign-role-data-scope", {
method: "POST",
params: {
...params,
},
...(options || {}),
});
}
// // 查询用户拥有的角色数组
// export const getUserRoleList = async (userId: number) => {
// return await request.get({ url: '/system/permission/list-user-roles?userId=' + userId })
// }
export async function getUserRoleList(userId: number) {
return request("/system/permission/list-user-roles", {
method: "GET",
params: {
userId,
},
});
}
// // 赋予用户角色
// export const assignUserRole = async (data: PermissionAssignUserRoleReqVO) => {
// return await request.post({ url: '/system/permission/assign-user-role', data })
// }
export async function assignUserRole(
params: PermissionAssignUserRoleReqVO,
options?: { [key: string]: any }
) {
return request("/system/permission/assign-user-role", {
method: "POST",
params: {
...params,
},
...(options || {}),
});
}

0
src/services/system/typings.d.ts vendored Normal file
View File

78
src/types/global.d.ts vendored Normal file
View File

@@ -0,0 +1,78 @@
export {};
declare global {
interface Fn<T = any> {
(...arg: T[]): T;
}
type Nullable<T> = T | null;
type ElRef<T extends HTMLElement = HTMLDivElement> = Nullable<T>;
type Recordable<T = any, K = string> = Record<
K extends null | undefined ? string : K,
T
>;
type ComponentRef<T> = InstanceType<T>;
type LocaleType = "zh-CN" | "en";
declare type TimeoutHandle = ReturnType<typeof setTimeout>;
declare type IntervalHandle = ReturnType<typeof setInterval>;
type AxiosHeaders =
| "application/json"
| "application/x-www-form-urlencoded"
| "multipart/form-data";
type AxiosMethod =
| "get"
| "post"
| "delete"
| "put"
| "GET"
| "POST"
| "DELETE"
| "PUT";
type AxiosResponseType =
| "arraybuffer"
| "blob"
| "document"
| "json"
| "text"
| "stream";
interface AxiosConfig {
params?: any;
data?: any;
url?: string;
method?: AxiosMethod;
headersType?: string;
responseType?: AxiosResponseType;
}
interface IResponse<T> {
code: string;
data: T;
msg: string;
}
interface PageParam {
pageSize?: number;
pageNo?: number;
total?: number;
}
interface Tree {
id: number;
name: string;
children?: Tree[] | any[];
}
// 分页数据公共返回
interface PageResult<T> {
list: T; // 数据
total: number; // 总量
msg: string;
}
}

72
src/utils/auth.ts Normal file
View File

@@ -0,0 +1,72 @@
import { useCache, CACHE_KEY } from "@/hooks/web/useCache";
import type { TokenType } from "@/services/login/types";
import { decrypt, encrypt } from "@/utils/jsencrypt";
const { wsCache } = useCache();
const AccessTokenKey = "ACCESS_TOKEN";
const RefreshTokenKey = "REFRESH_TOKEN";
// 获取token
export const getAccessToken = () => {
// 此处与TokenKey相同此写法解决初始化时Cookies中不存在TokenKey报错
const accessToken = wsCache.get(AccessTokenKey);
return accessToken ? accessToken : wsCache.get("ACCESS_TOKEN");
};
// 刷新token
export const getRefreshToken = () => {
return wsCache.get(RefreshTokenKey);
};
// 设置token
export const setToken = (token: TokenType) => {
wsCache.set(RefreshTokenKey, token.refreshToken);
wsCache.set(AccessTokenKey, token.accessToken);
};
// 删除token
export const removeToken = () => {
wsCache.delete(AccessTokenKey);
wsCache.delete(RefreshTokenKey);
};
/** 格式化tokenjwt格式 */
export const formatToken = (token: string): string => {
return "Bearer " + token;
};
// ========== 账号相关 ==========
export type LoginFormType = {
tenantName: string;
username: string;
password: string;
rememberMe: boolean;
};
export const getLoginForm = () => {
const loginForm: LoginFormType = wsCache.get(CACHE_KEY.LoginForm);
if (loginForm) {
loginForm.password = decrypt(loginForm.password) as string;
}
return loginForm;
};
export const setLoginForm = (loginForm: LoginFormType) => {
loginForm.password = encrypt(loginForm.password) as string;
wsCache.set(CACHE_KEY.LoginForm, loginForm, { exp: 30 * 24 * 60 * 60 });
};
export const removeLoginForm = () => {
wsCache.delete(CACHE_KEY.LoginForm);
};
// ========== 租户相关 ==========
export const getTenantId = () => {
return wsCache.get(CACHE_KEY.TenantId);
};
export const setTenantId = (username: string) => {
wsCache.set(CACHE_KEY.TenantId, username);
};

31
src/utils/jsencrypt.ts Normal file
View File

@@ -0,0 +1,31 @@
import { JSEncrypt } from 'jsencrypt'
// 密钥对生成 http://web.chacuo.net/netrsakeypair
const publicKey =
'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdH\n' +
'nzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
const privateKey =
'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY\n' +
'7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKN\n' +
'PuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gA\n' +
'kM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWow\n' +
'cSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99Ecv\n' +
'DQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthh\n' +
'YhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3\n' +
'UP8iWi1Qw0Y='
// 加密
export const encrypt = (txt: string) => {
const encryptor = new JSEncrypt()
encryptor.setPublicKey(publicKey) // 设置公钥
return encryptor.encrypt(txt) // 对数据进行加密
}
// 解密
export const decrypt = (txt: string) => {
const encryptor = new JSEncrypt()
encryptor.setPrivateKey(privateKey) // 设置私钥
return encryptor.decrypt(txt) // 对数据进行解密
}

View File

@@ -19,5 +19,5 @@
} }
}, },
"include": ["./**/*.d.ts", "./**/*.ts", "./**/*.tsx"], "include": ["./**/*.d.ts", "./**/*.ts", "./**/*.tsx"],
"exclude": ["config"] "exclude": ["config", "src/services/*/*.ts"]
} }