mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-26 14:23:48 +00:00
feat: 初始化前端项目基础结构
- 添加项目配置文件(tsconfig, eslint, prettier等) - 实现基础路由和页面布局 - 添加全局状态管理和API请求封装 - 集成UI组件库和主题系统 - 添加文档网站和示例页面 - 配置CI/CD和工作流
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
/// <reference types='./globals.d.ts' />
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Swagger Petstore - OpenAPI 3.0 - version 1.0.27
|
||||
*
|
||||
* This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about
|
||||
Swagger at [https://swagger.io](https://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!
|
||||
You can now help us improve the API whether it's by making changes to the definition itself or to the code.
|
||||
That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
|
||||
|
||||
Some useful links:
|
||||
- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)
|
||||
- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)
|
||||
*
|
||||
* OpenAPI version: 3.0.4
|
||||
*
|
||||
* Contact:
|
||||
*
|
||||
* NOTE: This file is auto generated by the alova's vscode plugin.
|
||||
*
|
||||
* https://alova.js.org/devtools/vscode
|
||||
*
|
||||
* **Do not edit the file manually.**
|
||||
*/
|
||||
export default {
|
||||
'pet.updatePet': ['PUT', '/pet'],
|
||||
'pet.addPet': ['POST', '/pet'],
|
||||
'pet.findPetsByStatus': ['GET', '/pet/findByStatus'],
|
||||
'pet.findPetsByTags': ['GET', '/pet/findByTags'],
|
||||
'pet.getPetById': ['GET', '/pet/{petId}'],
|
||||
'pet.updatePetWithForm': ['POST', '/pet/{petId}'],
|
||||
'pet.deletePet': ['DELETE', '/pet/{petId}'],
|
||||
'pet.uploadFile': ['POST', '/pet/{petId}/uploadImage'],
|
||||
'store.getInventory': ['GET', '/store/inventory'],
|
||||
'store.placeOrder': ['POST', '/store/order'],
|
||||
'store.getOrderById': ['GET', '/store/order/{orderId}'],
|
||||
'store.deleteOrder': ['DELETE', '/store/order/{orderId}'],
|
||||
'user.createUser': ['POST', '/user'],
|
||||
'user.createUsersWithListInput': ['POST', '/user/createWithList'],
|
||||
'user.loginUser': ['GET', '/user/login'],
|
||||
'user.logoutUser': ['GET', '/user/logout'],
|
||||
'user.getUserByName': ['GET', '/user/{username}'],
|
||||
'user.updateUser': ['PUT', '/user/{username}'],
|
||||
'user.deleteUser': ['DELETE', '/user/{username}']
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
import { ApiHeader } from '@/enums/api-header.enum'
|
||||
import { http } from '@/http'
|
||||
|
||||
const AUTH_BASE_URL = '/system/auth'
|
||||
|
||||
const AuthAPI = {
|
||||
/**
|
||||
* 登录
|
||||
* @param body 登录表单数据
|
||||
* @returns 登录结果
|
||||
*/
|
||||
login(body: LoginFormData): Promise<LoginResult> {
|
||||
return http.Post(`${AUTH_BASE_URL}/login`, body, {
|
||||
headers: {
|
||||
[ApiHeader.KEY]: ApiHeader.FORM,
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新令牌
|
||||
* @param body 刷新令牌请求体
|
||||
* @returns 新的访问令牌
|
||||
*/
|
||||
refreshToken(body: RefreshToekenBody): Promise<any> {
|
||||
return http.Post(`${AUTH_BASE_URL}/token/refresh`, body)
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取验证码
|
||||
* @returns 验证码信息
|
||||
*/
|
||||
getCaptcha(): Promise<any> {
|
||||
// 添加随机参数防止缓存
|
||||
const timestamp = new Date().getTime()
|
||||
return http.Get(`${AUTH_BASE_URL}/captcha/get?timestamp=${timestamp}`)
|
||||
},
|
||||
|
||||
/**
|
||||
* 登出
|
||||
* @param body 登出请求体
|
||||
* @returns 登出结果
|
||||
*/
|
||||
logout(body: LogoutBody): Promise<any> {
|
||||
return http.Post(`${AUTH_BASE_URL}/logout`, body)
|
||||
},
|
||||
}
|
||||
|
||||
export default AuthAPI
|
||||
|
||||
/** 登录表单数据 */
|
||||
export interface LoginFormData {
|
||||
username: string
|
||||
password: string
|
||||
captcha_key: string
|
||||
captcha: string
|
||||
remember: boolean
|
||||
login_type: string
|
||||
}
|
||||
|
||||
// 刷新令牌
|
||||
export interface RefreshToekenBody {
|
||||
refresh_token: string
|
||||
}
|
||||
|
||||
/** 登录响应 */
|
||||
export interface LoginResult {
|
||||
access_token: string
|
||||
refresh_token: string
|
||||
token_type: string
|
||||
expires_in: number
|
||||
}
|
||||
|
||||
/** 验证码信息 */
|
||||
export interface CaptchaInfo {
|
||||
enable: boolean
|
||||
key: string
|
||||
img_base: string
|
||||
}
|
||||
|
||||
/** 退出登录操作 */
|
||||
export interface LogoutBody {
|
||||
token: string
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2025-04-17 15:58:11
|
||||
* @LastEditTime: 2025-06-15 21:47:22
|
||||
* @LastEditors: weisheng
|
||||
* @Description: Alova response and error handlers
|
||||
* @FilePath: /wot-starter/src/api/core/handlers.ts
|
||||
*/
|
||||
import type { Method } from 'alova'
|
||||
import router from '@/router'
|
||||
|
||||
// Custom error class for API errors
|
||||
export class ApiError extends Error {
|
||||
code: number
|
||||
data?: any
|
||||
|
||||
constructor(message: string, code: number, data?: any) {
|
||||
super(message)
|
||||
this.name = 'ApiError'
|
||||
this.code = code
|
||||
this.data = data
|
||||
}
|
||||
}
|
||||
|
||||
// Define a type for the expected API response structure
|
||||
interface ApiResponse {
|
||||
code: number
|
||||
msg?: string
|
||||
data?: any
|
||||
success?: boolean
|
||||
total?: number
|
||||
more?: boolean
|
||||
}
|
||||
|
||||
// Handle successful responses
|
||||
export async function handleAlovaResponse(
|
||||
response: UniApp.RequestSuccessCallbackResult | UniApp.UploadFileSuccessCallbackResult | UniApp.DownloadSuccessData,
|
||||
) {
|
||||
const globalToast = useGlobalToast()
|
||||
// Extract status code and data from UniApp response
|
||||
const { statusCode, data } = response as UniNamespace.RequestSuccessCallbackResult
|
||||
|
||||
// 处理401/403错误(如果不是在handleAlovaResponse中处理的)
|
||||
if ((statusCode === 401 || statusCode === 403)) {
|
||||
// 如果是未授权错误,清除用户信息并跳转到登录页
|
||||
globalToast.error({ msg: '登录已过期,请重新登录!', duration: 500 })
|
||||
const timer = setTimeout(() => {
|
||||
clearTimeout(timer)
|
||||
router.replaceAll({ name: 'login' })
|
||||
}, 500)
|
||||
|
||||
throw new ApiError('登录已过期,请重新登录!', statusCode, data)
|
||||
}
|
||||
|
||||
// Handle HTTP error status codes
|
||||
if (statusCode >= 400) {
|
||||
globalToast.error(`Request failed with status: ${statusCode}`)
|
||||
throw new ApiError(`Request failed with status: ${statusCode}`, statusCode, data)
|
||||
}
|
||||
|
||||
// The data is already parsed by UniApp adapter
|
||||
const json = data as ApiResponse
|
||||
// Log response in development
|
||||
if (import.meta.env.MODE === 'development') {
|
||||
console.log('[Alova Response]', json)
|
||||
}
|
||||
|
||||
// Return data for successful responses
|
||||
return json
|
||||
}
|
||||
|
||||
// Handle request errors
|
||||
export function handleAlovaError(error: any, method: Method) {
|
||||
const globalToast = useGlobalToast()
|
||||
// Log error in development
|
||||
if (import.meta.env.MODE === 'development') {
|
||||
console.error('[Alova Error]', error, method)
|
||||
}
|
||||
|
||||
// 处理401/403错误(如果不是在handleAlovaResponse中处理的)
|
||||
if (error instanceof ApiError && (error.code === 401 || error.code === 403)) {
|
||||
// 如果是未授权错误,清除用户信息并跳转到登录页
|
||||
globalToast.error({ msg: '登录已过期,请重新登录!', duration: 500 })
|
||||
const timer = setTimeout(() => {
|
||||
clearTimeout(timer)
|
||||
router.replaceAll({ name: 'login' })
|
||||
}, 500)
|
||||
throw new ApiError('登录已过期,请重新登录!', error.code, error.data)
|
||||
}
|
||||
|
||||
// Handle different types of errors
|
||||
if (error.name === 'NetworkError') {
|
||||
globalToast.error('网络错误,请检查您的网络连接')
|
||||
}
|
||||
else if (error.name === 'TimeoutError') {
|
||||
globalToast.error('请求超时,请重试')
|
||||
}
|
||||
else if (error instanceof ApiError) {
|
||||
globalToast.error(error.message || '请求失败')
|
||||
}
|
||||
else {
|
||||
globalToast.error('发生意外错误')
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import AdapterUniapp from '@alova/adapter-uniapp'
|
||||
import { createAlova } from 'alova'
|
||||
import vueHook from 'alova/vue'
|
||||
import mockAdapter from '../mock/mockAdapter'
|
||||
import { handleAlovaError, handleAlovaResponse } from './handlers'
|
||||
|
||||
export const alovaInstance = createAlova({
|
||||
baseURL: import.meta.env.VITE_API_BASE_URL || 'https://petstore3.swagger.io/api/v3',
|
||||
...AdapterUniapp({
|
||||
mockRequest: mockAdapter,
|
||||
}),
|
||||
statesHook: vueHook,
|
||||
beforeRequest: (method) => {
|
||||
// Add content type for POST/PUT/PATCH requests
|
||||
if (['POST', 'PUT', 'PATCH'].includes(method.type)) {
|
||||
method.config.headers['Content-Type'] = 'application/json'
|
||||
}
|
||||
|
||||
// Add timestamp to prevent caching for GET requests
|
||||
if (method.type === 'GET' && CommonUtil.isObj(method.config.params)) {
|
||||
method.config.params._t = Date.now()
|
||||
}
|
||||
|
||||
// Log request in development
|
||||
if (import.meta.env.MODE === 'development') {
|
||||
console.log(`[Alova Request] ${method.type} ${method.url}`, method.data || method.config.params)
|
||||
console.log(`[API Base URL] ${import.meta.env.VITE_API_BASE_URL}`)
|
||||
console.log(`[Environment] ${import.meta.env.VITE_ENV_NAME}`)
|
||||
}
|
||||
},
|
||||
|
||||
// Response handlers
|
||||
responded: {
|
||||
// Success handler
|
||||
onSuccess: handleAlovaResponse,
|
||||
|
||||
// Error handler
|
||||
onError: handleAlovaError,
|
||||
|
||||
// Complete handler - runs after success or error
|
||||
onComplete: async () => {
|
||||
// Any cleanup or logging can be done here
|
||||
},
|
||||
},
|
||||
|
||||
// We'll use the middleware in the hooks
|
||||
// middleware is not directly supported in createAlova options
|
||||
|
||||
// Default request timeout (10 seconds)
|
||||
timeout: 60000,
|
||||
// 设置为null即可全局关闭全部请求缓存
|
||||
cacheFor: null,
|
||||
})
|
||||
|
||||
export default alovaInstance
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* 延迟加载中间件
|
||||
* 延迟显示加载状态,防止快速请求导致的闪烁
|
||||
* @param delay 显示加载状态前的延迟时间(毫秒)
|
||||
* @returns Alova 中间件
|
||||
*/
|
||||
export function createDelayLoadingMiddleware(delay = 300) {
|
||||
return async (context: any, next: any) => {
|
||||
context.controlLoading()
|
||||
|
||||
const { loading } = context.proxyStates
|
||||
|
||||
const timer = setTimeout(() => {
|
||||
loading.v = true
|
||||
}, delay)
|
||||
|
||||
await next()
|
||||
|
||||
loading.v = false
|
||||
clearTimeout(timer)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局加载中间件
|
||||
* 为所有请求显示全局加载指示器,支持延迟显示
|
||||
*
|
||||
* 使用示例:
|
||||
* ```typescript
|
||||
* // 1. 基本用法
|
||||
* const { send: submit } = useRequest(method, {
|
||||
* middleware: createGlobalLoadingMiddleware()
|
||||
* });
|
||||
*
|
||||
* // 2. 自定义延迟时间和加载文本
|
||||
* const { send: submit } = useRequest(method, {
|
||||
* middleware: createGlobalLoadingMiddleware({
|
||||
* delay: 500, // 延迟 500ms 显示加载指示器,防止闪烁
|
||||
* loadingText: '正在提交...', // 自定义加载文本
|
||||
* })
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @param options 加载选项
|
||||
* @param options.delay 显示加载指示器前的延迟时间(毫秒),默认 300ms
|
||||
* @param options.loadingText 加载指示器显示的文本,默认为 'Loading...'
|
||||
* @returns Alova 中间件
|
||||
*/
|
||||
export function createGlobalLoadingMiddleware(options: {
|
||||
delay?: number
|
||||
loadingText?: string
|
||||
} = {}) {
|
||||
const {
|
||||
delay = 0,
|
||||
loadingText = 'Loading...',
|
||||
} = options
|
||||
|
||||
return async (ctx: any, next: any) => {
|
||||
// 自行控制loading
|
||||
ctx.controlLoading()
|
||||
|
||||
const globalLoading = useGlobalLoading()
|
||||
let timer: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
// 如果delay为0或未设置,直接显示loading
|
||||
if (delay <= 0) {
|
||||
globalLoading.loading(loadingText)
|
||||
}
|
||||
else {
|
||||
// 延迟特定时间显示全局loading
|
||||
timer = setTimeout(() => {
|
||||
globalLoading.loading(loadingText)
|
||||
}, delay)
|
||||
}
|
||||
|
||||
try {
|
||||
await next()
|
||||
}
|
||||
finally {
|
||||
// 清除定时器并关闭loading
|
||||
if (timer) {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
globalLoading.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 导出延迟加载中间件作为默认中间件
|
||||
export const defaultMiddleware = createDelayLoadingMiddleware()
|
||||
|
||||
export default defaultMiddleware
|
||||
@@ -0,0 +1,101 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Swagger Petstore - OpenAPI 3.0 - version 1.0.27
|
||||
*
|
||||
* This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about
|
||||
Swagger at [https://swagger.io](https://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!
|
||||
You can now help us improve the API whether it's by making changes to the definition itself or to the code.
|
||||
That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
|
||||
|
||||
Some useful links:
|
||||
- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)
|
||||
- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)
|
||||
*
|
||||
* OpenAPI version: 3.0.4
|
||||
*
|
||||
* Contact:
|
||||
*
|
||||
* NOTE: This file is auto generated by the alova's vscode plugin.
|
||||
*
|
||||
* https://alova.js.org/devtools/vscode
|
||||
*
|
||||
* **Do not edit the file manually.**
|
||||
*/
|
||||
import type { Alova, MethodType, AlovaGenerics, AlovaMethodCreateConfig } from 'alova';
|
||||
import { Method } from 'alova';
|
||||
import apiDefinitions from './apiDefinitions';
|
||||
|
||||
const createFunctionalProxy = (array: (string | symbol)[], alovaInstance: Alova<AlovaGenerics>, configMap: any) => {
|
||||
// create a new proxy instance
|
||||
return new Proxy(function () {}, {
|
||||
get(_, property) {
|
||||
// record the target property, so that it can get the completed accessing paths
|
||||
const newArray = [...array, property];
|
||||
// always return a new proxy to continue recording accessing paths.
|
||||
return createFunctionalProxy(newArray, alovaInstance, configMap);
|
||||
},
|
||||
apply(_, __, [config]) {
|
||||
const apiPathKey = array.join('.') as keyof typeof apiDefinitions;
|
||||
const apiItem = apiDefinitions[apiPathKey];
|
||||
if (!apiItem) {
|
||||
throw new Error(`the api path of \`${apiPathKey}\` is not found`);
|
||||
}
|
||||
const mergedConfig = {
|
||||
...configMap[apiPathKey],
|
||||
...config
|
||||
};
|
||||
const [method, url] = apiItem;
|
||||
const pathParams = mergedConfig.pathParams;
|
||||
const urlReplaced = url.replace(/\{([^}]+)\}/g, (_, key) => {
|
||||
const pathParam = pathParams[key];
|
||||
return pathParam;
|
||||
});
|
||||
delete mergedConfig.pathParams;
|
||||
let data = mergedConfig.data;
|
||||
if (Object.prototype.toString.call(data) === '[object Object]' && typeof FormData !== 'undefined') {
|
||||
let hasBlobData = false;
|
||||
const formData = new FormData();
|
||||
for (const key in data) {
|
||||
formData.append(key, data[key]);
|
||||
if (data[key] instanceof Blob) {
|
||||
hasBlobData = true;
|
||||
}
|
||||
}
|
||||
data = hasBlobData ? formData : data;
|
||||
}
|
||||
return new Method(method.toUpperCase() as MethodType, alovaInstance, urlReplaced, mergedConfig, data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const createApis = (alovaInstance: Alova<AlovaGenerics>, configMap: any) => {
|
||||
const Apis = new Proxy({} as Apis, {
|
||||
get(_, property) {
|
||||
return createFunctionalProxy([property], alovaInstance, configMap);
|
||||
}
|
||||
});
|
||||
return Apis;
|
||||
};
|
||||
export const mountApis = (Apis: Apis) => {
|
||||
// define global variable `Apis`
|
||||
(globalThis as any).Apis = Apis;
|
||||
};
|
||||
type MethodConfig<T> = AlovaMethodCreateConfig<
|
||||
(typeof import('./index'))['alovaInstance'] extends Alova<infer AG> ? AG : any,
|
||||
any,
|
||||
T
|
||||
>;
|
||||
type APISofParameters<Tag extends string, Url extends string> = Tag extends keyof Apis
|
||||
? Url extends keyof Apis[Tag]
|
||||
? Apis[Tag][Url] extends (...args: any) => any
|
||||
? Parameters<Apis[Tag][Url]>
|
||||
: any
|
||||
: any
|
||||
: any;
|
||||
type MethodsConfigMap = {
|
||||
[P in keyof typeof import('./apiDefinitions').default]?: MethodConfig<
|
||||
P extends `${infer Tag}.${infer Url}` ? Parameters<NonNullable<APISofParameters<Tag, Url>[0]>['transform']>[0] : any
|
||||
>;
|
||||
};
|
||||
export const withConfigType = <Config extends MethodsConfigMap>(config: Config) => config;
|
||||
Vendored
+1058
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
||||
// Import the core alova instance
|
||||
import alovaInstance from './core/instance'
|
||||
|
||||
// Export the global Apis object from the generated code
|
||||
import { createApis, withConfigType } from './createApis'
|
||||
|
||||
// Export the alova instance for direct use if needed
|
||||
export { alovaInstance }
|
||||
|
||||
// Configure method options for specific APIs
|
||||
export const $$userConfigMap = withConfigType({})
|
||||
|
||||
// Create the global Apis object
|
||||
const Apis = createApis(alovaInstance, $$userConfigMap)
|
||||
|
||||
// Export both default and named export for AutoImport
|
||||
export default Apis
|
||||
export { Apis }
|
||||
@@ -0,0 +1,107 @@
|
||||
# API Mock 数据
|
||||
|
||||
本目录包含了项目中使用的 API 模拟数据,用于开发和测试环境。
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
mock/
|
||||
├── modules/ # 按模块分类的模拟数据
|
||||
│ ├── common.ts # 通用模拟处理
|
||||
│ ├── loginInterface.ts # 登录相关接口的模拟数据
|
||||
│ ├── mdataInterface.ts # 主数据相关接口的模拟数据
|
||||
│ ├── vehsaleusesignInterface.ts # 车销使用签收相关接口的模拟数据
|
||||
│ ├── vehsaleusesignarvInterface.ts # 车销使用签收到货相关接口的模拟数据
|
||||
│ ├── user.ts # 用户相关的模拟数据
|
||||
│ ├── university.ts # 大学相关的模拟数据
|
||||
│ └── feedback.ts # 反馈相关的模拟数据
|
||||
├── utils/ # 工具目录
|
||||
│ ├── index.ts # 工具导出文件
|
||||
│ └── generators.ts # 模拟数据生成工具
|
||||
└── mockAdapter.ts # 模拟适配器配置
|
||||
```
|
||||
|
||||
## 使用方法
|
||||
|
||||
模拟数据已经通过 `@alova/mock` 和 `@alova/adapter-uniapp` 集成到项目中。在开发环境中,API 请求会自动使用模拟数据进行响应。
|
||||
|
||||
### 启用/禁用模拟
|
||||
|
||||
在 `mockAdapter.ts` 中,可以通过修改 `enable` 选项来启用或禁用模拟:
|
||||
|
||||
```typescript
|
||||
const mockAdapter = createAlovaMockAdapter(allMocks, {
|
||||
// ...
|
||||
enable: true, // 设置为 false 可禁用模拟
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
### 添加新的模拟数据
|
||||
|
||||
1. 在 `modules` 目录下创建新的模块文件或在现有文件中添加
|
||||
2. 使用 `defineMock` 函数定义模拟数据
|
||||
3. 在 `mockAdapter.ts` 中导入并添加到 `allMocks` 数组中
|
||||
|
||||
示例:
|
||||
|
||||
```typescript
|
||||
// modules/example.ts
|
||||
import { defineMock } from '@alova/mock'
|
||||
|
||||
// mockAdapter.ts
|
||||
import exampleMocks from './modules/example'
|
||||
|
||||
export default defineMock({
|
||||
'[GET]/api/example': () => {
|
||||
return {
|
||||
code: 200,
|
||||
data: { /* 模拟数据 */ },
|
||||
message: 'success'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const allMocks = [
|
||||
// ...
|
||||
exampleMocks
|
||||
]
|
||||
```
|
||||
|
||||
## 模拟数据生成工具
|
||||
|
||||
在 `utils/generators.ts` 中提供了一系列用于生成模拟数据的工具函数,可以在各个模块中复用:
|
||||
|
||||
```typescript
|
||||
import { generateMockData } from '../utils'
|
||||
|
||||
// 生成随机ID
|
||||
const id = generateMockData.id()
|
||||
|
||||
// 生成随机名称
|
||||
const name = generateMockData.name('前缀')
|
||||
|
||||
// 生成随机数组
|
||||
const array = generateMockData.array(index => ({
|
||||
id: generateMockData.id(),
|
||||
name: generateMockData.name(`项目${index}`)
|
||||
}), 10)
|
||||
|
||||
// 生成基础响应对象
|
||||
const response = generateMockData.baseResponse(data)
|
||||
|
||||
// 生成列表响应对象
|
||||
const listResponse = generateMockData.listResponse(items, total, more)
|
||||
|
||||
// 生成业务对象
|
||||
const user = generateMockData.user()
|
||||
const goods = generateMockData.goods(0)
|
||||
const vehSaleEmp = generateMockData.vehSaleEmp(0)
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 模拟数据应尽量接近真实数据结构,以便于开发和测试
|
||||
2. 对于需要保持一致性的数据(如ID引用),可以使用固定值而非随机生成
|
||||
3. 可以使用请求参数来定制模拟响应,例如分页、筛选等
|
||||
4. 模拟数据应包含各种场景,包括成功和失败的情况
|
||||
@@ -0,0 +1,436 @@
|
||||
import Apis from '@/api'
|
||||
|
||||
/**
|
||||
* Pet模块演示
|
||||
* 演示宠物相关API的使用
|
||||
*/
|
||||
export class PetDemo {
|
||||
// 获取所有可用的宠物
|
||||
static async getAvailablePets() {
|
||||
console.log('=== 获取可用宠物 ===')
|
||||
try {
|
||||
const pets = await Apis.pet.findPetsByStatus({
|
||||
params: { status: 'available' },
|
||||
}).send()
|
||||
console.log('可用宠物列表:', pets)
|
||||
return pets
|
||||
}
|
||||
catch (error) {
|
||||
console.error('获取宠物失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取特定宠物信息
|
||||
static async getPetById(petId: number) {
|
||||
console.log(`=== 获取宠物 ${petId} 的信息 ===`)
|
||||
try {
|
||||
const pet = await Apis.pet.getPetById({
|
||||
pathParams: { petId },
|
||||
}).send()
|
||||
console.log('宠物信息:', pet)
|
||||
return pet
|
||||
}
|
||||
catch (error) {
|
||||
console.error('获取宠物信息失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 添加新宠物
|
||||
static async addNewPet() {
|
||||
console.log('=== 添加新宠物 ===')
|
||||
try {
|
||||
const newPet = await Apis.pet.addPet({
|
||||
data: {
|
||||
name: 'Buddy',
|
||||
category: { id: 1, name: 'Dogs' },
|
||||
status: 'available',
|
||||
photoUrls: ['https://example.com/buddy.jpg'],
|
||||
tags: [
|
||||
{ id: 1, name: 'friendly' },
|
||||
{ id: 2, name: 'trained' },
|
||||
],
|
||||
},
|
||||
}).send()
|
||||
console.log('新添加的宠物:', newPet)
|
||||
return newPet
|
||||
}
|
||||
catch (error) {
|
||||
console.error('添加宠物失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 测试宠物不存在的情况
|
||||
static async testPetNotFound() {
|
||||
console.log('=== 测试宠物不存在的情况 ===')
|
||||
try {
|
||||
await Apis.pet.getPetById({
|
||||
pathParams: { petId: 404 },
|
||||
}).send()
|
||||
}
|
||||
catch (error) {
|
||||
console.log('预期的404错误:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 删除宠物(需要API密钥)
|
||||
static async deletePet(petId: number, apiKey: string = 'special-key') {
|
||||
console.log(`=== 删除宠物 ${petId} ===`)
|
||||
try {
|
||||
const result = await Apis.pet.deletePet({
|
||||
pathParams: { petId },
|
||||
headers: { api_key: apiKey },
|
||||
}).send()
|
||||
console.log('删除结果:', result)
|
||||
return result
|
||||
}
|
||||
catch (error) {
|
||||
console.error('删除宠物失败:', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store模块演示
|
||||
* 演示商店相关API的使用
|
||||
*/
|
||||
export class StoreDemo {
|
||||
// 获取库存信息
|
||||
static async getInventory() {
|
||||
console.log('=== 获取库存信息 ===')
|
||||
try {
|
||||
const inventory = await Apis.store.getInventory().send()
|
||||
console.log('库存信息:', inventory)
|
||||
return inventory
|
||||
}
|
||||
catch (error) {
|
||||
console.error('获取库存失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 下单购买宠物
|
||||
static async placeOrder(petId: number, quantity: number = 1) {
|
||||
console.log('=== 下单购买宠物 ===')
|
||||
try {
|
||||
const order = await Apis.store.placeOrder({
|
||||
data: {
|
||||
petId,
|
||||
quantity,
|
||||
shipDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(), // 7天后发货
|
||||
status: 'placed',
|
||||
complete: false,
|
||||
},
|
||||
}).send()
|
||||
console.log('订单信息:', order)
|
||||
return order
|
||||
}
|
||||
catch (error) {
|
||||
console.error('下单失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取订单信息
|
||||
static async getOrderById(orderId: number) {
|
||||
console.log(`=== 获取订单 ${orderId} 信息 ===`)
|
||||
try {
|
||||
const order = await Apis.store.getOrderById({
|
||||
pathParams: { orderId },
|
||||
}).send()
|
||||
console.log('订单详情:', order)
|
||||
return order
|
||||
}
|
||||
catch (error) {
|
||||
console.error('获取订单失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 测试无效订单ID
|
||||
static async testInvalidOrderId() {
|
||||
console.log('=== 测试无效订单ID ===')
|
||||
try {
|
||||
await Apis.store.getOrderById({
|
||||
pathParams: { orderId: 999 },
|
||||
}).send()
|
||||
}
|
||||
catch (error) {
|
||||
console.log('预期的400错误:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 删除订单
|
||||
static async deleteOrder(orderId: number) {
|
||||
console.log(`=== 删除订单 ${orderId} ===`)
|
||||
try {
|
||||
const result = await Apis.store.deleteOrder({
|
||||
pathParams: { orderId },
|
||||
}).send()
|
||||
console.log('删除结果:', result)
|
||||
return result
|
||||
}
|
||||
catch (error) {
|
||||
console.error('删除订单失败:', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* User模块演示
|
||||
* 演示用户相关API的使用
|
||||
*/
|
||||
export class UserDemo {
|
||||
// 用户登录
|
||||
static async login(username: string = 'admin', password: string = 'admin') {
|
||||
console.log('=== 用户登录 ===')
|
||||
try {
|
||||
const loginResult = await Apis.user.loginUser({
|
||||
params: { username, password },
|
||||
}).send()
|
||||
console.log('登录结果:', loginResult)
|
||||
return loginResult
|
||||
}
|
||||
catch (error) {
|
||||
console.error('登录失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
static async getUserInfo(username: string) {
|
||||
console.log(`=== 获取用户 ${username} 信息 ===`)
|
||||
try {
|
||||
const user = await Apis.user.getUserByName({
|
||||
pathParams: { username },
|
||||
}).send()
|
||||
console.log('用户信息:', user)
|
||||
return user
|
||||
}
|
||||
catch (error) {
|
||||
console.error('获取用户信息失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 创建新用户
|
||||
static async createUser(userData: any = {}) {
|
||||
console.log('=== 创建新用户 ===')
|
||||
try {
|
||||
const newUser = await Apis.user.createUser({
|
||||
data: {
|
||||
username: 'newuser',
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
email: 'john@example.com',
|
||||
password: 'password123',
|
||||
phone: '1234567890',
|
||||
userStatus: 1,
|
||||
...userData,
|
||||
},
|
||||
}).send()
|
||||
console.log('新用户:', newUser)
|
||||
return newUser
|
||||
}
|
||||
catch (error) {
|
||||
console.error('创建用户失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 更新用户信息
|
||||
static async updateUser(username: string, updateData: any) {
|
||||
console.log(`=== 更新用户 ${username} 信息 ===`)
|
||||
try {
|
||||
const updatedUser = await Apis.user.updateUser({
|
||||
pathParams: { username },
|
||||
data: updateData,
|
||||
}).send()
|
||||
console.log('更新后的用户:', updatedUser)
|
||||
return updatedUser
|
||||
}
|
||||
catch (error) {
|
||||
console.error('更新用户失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 测试用户不存在的情况
|
||||
static async testUserNotFound() {
|
||||
console.log('=== 测试用户不存在的情况 ===')
|
||||
try {
|
||||
await Apis.user.getUserByName({
|
||||
pathParams: { username: 'notfound' },
|
||||
}).send()
|
||||
}
|
||||
catch (error) {
|
||||
console.log('预期的404错误:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 批量创建用户
|
||||
static async createUsersWithArray() {
|
||||
console.log('=== 批量创建用户(数组) ===')
|
||||
try {
|
||||
const result = await Apis.user.createUsersWithListInput({
|
||||
data: [
|
||||
{
|
||||
username: 'user1',
|
||||
firstName: 'User',
|
||||
lastName: 'One',
|
||||
email: 'user1@example.com',
|
||||
password: 'password',
|
||||
phone: '1111111111',
|
||||
userStatus: 1,
|
||||
},
|
||||
{
|
||||
username: 'user2',
|
||||
firstName: 'User',
|
||||
lastName: 'Two',
|
||||
email: 'user2@example.com',
|
||||
password: 'password',
|
||||
phone: '2222222222',
|
||||
userStatus: 1,
|
||||
},
|
||||
],
|
||||
}).send()
|
||||
console.log('批量创建结果:', result)
|
||||
return result
|
||||
}
|
||||
catch (error) {
|
||||
console.error('批量创建用户失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 用户登出
|
||||
static async logout() {
|
||||
console.log('=== 用户登出 ===')
|
||||
try {
|
||||
const result = await Apis.user.logoutUser().send()
|
||||
console.log('登出结果:', result)
|
||||
return result
|
||||
}
|
||||
catch (error) {
|
||||
console.error('登出失败:', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 综合演示
|
||||
* 演示完整的业务流程
|
||||
*/
|
||||
export class FullDemo {
|
||||
// 完整的宠物商店购买流程
|
||||
static async completePetStorePurchaseFlow() {
|
||||
console.log('\n🎯 开始完整的宠物商店购买流程演示\n')
|
||||
|
||||
// 1. 用户登录
|
||||
const loginResult = await UserDemo.login('admin', 'admin')
|
||||
if (!loginResult)
|
||||
return
|
||||
|
||||
// 2. 查看库存
|
||||
const inventory = await StoreDemo.getInventory()
|
||||
console.log('\n📦 当前库存状态:', inventory)
|
||||
|
||||
// 3. 浏览可用宠物
|
||||
const availablePets = await PetDemo.getAvailablePets()
|
||||
if (!availablePets || availablePets.length === 0) {
|
||||
console.log('❌ 没有可用的宠物')
|
||||
return
|
||||
}
|
||||
|
||||
// 4. 选择第一个宠物
|
||||
const selectedPet = availablePets[0]
|
||||
console.log('\n🐕 选择的宠物:', selectedPet)
|
||||
|
||||
// 5. 查看宠物详情
|
||||
if (selectedPet?.id) {
|
||||
await PetDemo.getPetById(selectedPet.id)
|
||||
}
|
||||
|
||||
// 6. 下单购买
|
||||
const order = selectedPet?.id ? await StoreDemo.placeOrder(selectedPet.id, 1) : null
|
||||
if (!order)
|
||||
return
|
||||
|
||||
// 7. 查看订单详情
|
||||
if (order?.id) {
|
||||
await StoreDemo.getOrderById(order.id)
|
||||
}
|
||||
|
||||
// 8. 获取用户信息
|
||||
await UserDemo.getUserInfo('admin')
|
||||
|
||||
console.log('\n✅ 完整流程演示结束')
|
||||
}
|
||||
|
||||
// 错误处理演示
|
||||
static async errorHandlingDemo() {
|
||||
console.log('\n⚠️ 开始错误处理演示\n')
|
||||
|
||||
// 测试各种错误情况
|
||||
await PetDemo.testPetNotFound()
|
||||
await StoreDemo.testInvalidOrderId()
|
||||
await UserDemo.testUserNotFound()
|
||||
|
||||
console.log('\n✅ 错误处理演示结束')
|
||||
}
|
||||
|
||||
// CRUD操作演示
|
||||
static async crudDemo() {
|
||||
console.log('\n🔄 开始CRUD操作演示\n')
|
||||
|
||||
// 创建
|
||||
const newPet = await PetDemo.addNewPet()
|
||||
const newUser = await UserDemo.createUser({ username: 'testuser' })
|
||||
|
||||
// 读取
|
||||
if (newPet?.id)
|
||||
await PetDemo.getPetById(newPet.id)
|
||||
if (newUser)
|
||||
await UserDemo.getUserInfo('testuser')
|
||||
|
||||
// 更新
|
||||
if (newUser) {
|
||||
await UserDemo.updateUser('testuser', {
|
||||
firstName: 'Updated',
|
||||
lastName: 'User',
|
||||
})
|
||||
}
|
||||
|
||||
// 删除
|
||||
if (newPet?.id)
|
||||
await PetDemo.deletePet(newPet.id)
|
||||
|
||||
console.log('\n✅ CRUD操作演示结束')
|
||||
}
|
||||
}
|
||||
|
||||
// 导出演示运行器
|
||||
export async function runMockDemo() {
|
||||
console.log('🚀 开始Mock数据演示\n')
|
||||
|
||||
try {
|
||||
// 运行完整流程演示
|
||||
await FullDemo.completePetStorePurchaseFlow()
|
||||
|
||||
// 运行错误处理演示
|
||||
await FullDemo.errorHandlingDemo()
|
||||
|
||||
// 运行CRUD演示
|
||||
await FullDemo.crudDemo()
|
||||
|
||||
console.log('\n🎉 所有演示完成!')
|
||||
}
|
||||
catch (error) {
|
||||
console.error('演示过程中发生错误:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 如果直接运行此文件,执行演示
|
||||
if (typeof window !== 'undefined') {
|
||||
// 在浏览器环境中,可以在控制台调用
|
||||
(window as any).runMockDemo = runMockDemo;
|
||||
(window as any).PetDemo = PetDemo;
|
||||
(window as any).StoreDemo = StoreDemo;
|
||||
(window as any).UserDemo = UserDemo
|
||||
console.log('Mock演示函数已加载到全局对象,可在控制台调用:')
|
||||
console.log('- runMockDemo() - 运行完整演示')
|
||||
console.log('- PetDemo.* - 宠物模块演示')
|
||||
console.log('- StoreDemo.* - 商店模块演示')
|
||||
console.log('- UserDemo.* - 用户模块演示')
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2025-04-17 16:21:36
|
||||
* @LastEditTime: 2025-06-15 22:48:04
|
||||
* @LastEditors: weisheng
|
||||
* @Description: Mock适配器配置 - 集成所有模块的mock数据
|
||||
* @FilePath: /wot-starter/src/api/mock/mockAdapter.ts
|
||||
* 记得注释
|
||||
*/
|
||||
import { uniappMockResponse, uniappRequestAdapter } from '@alova/adapter-uniapp'
|
||||
import { createAlovaMockAdapter } from '@alova/mock'
|
||||
|
||||
// 导入所有mock模块
|
||||
import commonMocks from './modules/common'
|
||||
import petMocks from './modules/pet'
|
||||
import storeMocks from './modules/store'
|
||||
import userMocks from './modules/user'
|
||||
|
||||
// 合并所有mock定义
|
||||
const allMocks = [
|
||||
commonMocks,
|
||||
petMocks,
|
||||
storeMocks,
|
||||
userMocks,
|
||||
]
|
||||
|
||||
// 创建mock适配器
|
||||
const mockAdapter = createAlovaMockAdapter(allMocks, {
|
||||
// 使用uniapp请求适配器处理非mock请求
|
||||
httpAdapter: uniappRequestAdapter,
|
||||
|
||||
// 使用uniapp mock响应适配器
|
||||
onMockResponse: uniappMockResponse,
|
||||
|
||||
// 根据环境变量启用/禁用mock
|
||||
enable: true,
|
||||
|
||||
// 添加延迟以模拟网络延迟 (200-600ms)
|
||||
delay: Math.random() * 400 + 200,
|
||||
|
||||
// 在开发环境下打印mock请求日志
|
||||
mockRequestLogger: import.meta.env.MODE === 'development',
|
||||
// 路径匹配模式 - 使用完整路径匹配
|
||||
matchMode: 'pathname',
|
||||
})
|
||||
|
||||
export default mockAdapter
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-05-20 10:00:00
|
||||
* @LastEditTime: 2025-06-26 21:59:35
|
||||
* @LastEditors: weisheng
|
||||
* @Description: 通用mock处理
|
||||
* @FilePath: /wot-starter/src/api/mock/modules/common.ts
|
||||
*/
|
||||
import { defineMock } from '@alova/mock'
|
||||
import { generateMockData } from '../utils/generators'
|
||||
|
||||
export default defineMock({
|
||||
// 通用GET请求处理
|
||||
'[GET]/*': (_params: any, matchedUrl: string) => {
|
||||
console.log(`[Mock] GET ${matchedUrl}`, _params)
|
||||
return generateMockData.baseResponse({
|
||||
message: `Mock response for GET ${matchedUrl}`,
|
||||
params: _params,
|
||||
})
|
||||
},
|
||||
|
||||
// 通用POST请求处理
|
||||
'[POST]/*': (_params: any, matchedUrl: string) => {
|
||||
console.log(`[Mock] POST ${matchedUrl}`, _params)
|
||||
return generateMockData.baseResponse({
|
||||
message: `Mock response for POST ${matchedUrl}`,
|
||||
params: _params,
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2025-06-15 14:25:00
|
||||
* @LastEditTime: 2025-06-26 21:59:38
|
||||
* @LastEditors: weisheng
|
||||
* @Description: Pet Store - Pet相关接口的mock数据
|
||||
* @FilePath: /wot-starter/src/api/mock/modules/pet.ts
|
||||
*/
|
||||
import { defineMock } from '@alova/mock'
|
||||
import { generateMockData } from '../utils/generators'
|
||||
|
||||
// 宠物状态枚举
|
||||
const PET_STATUS = ['available', 'pending', 'sold'] as const
|
||||
type PetStatus = typeof PET_STATUS[number]
|
||||
|
||||
// 宠物类别
|
||||
const PET_CATEGORIES = [
|
||||
{ id: 1, name: 'Dogs' },
|
||||
{ id: 2, name: 'Cats' },
|
||||
{ id: 3, name: 'Birds' },
|
||||
{ id: 4, name: 'Fish' },
|
||||
{ id: 5, name: 'Reptiles' },
|
||||
]
|
||||
|
||||
// 宠物标签
|
||||
const PET_TAGS = [
|
||||
{ id: 1, name: 'friendly' },
|
||||
{ id: 2, name: 'playful' },
|
||||
{ id: 3, name: 'calm' },
|
||||
{ id: 4, name: 'energetic' },
|
||||
{ id: 5, name: 'trained' },
|
||||
{ id: 6, name: 'house-trained' },
|
||||
]
|
||||
|
||||
// 生成宠物对象
|
||||
function generatePet(id?: number, status?: PetStatus) {
|
||||
const petId = id || generateMockData.number(1, 10000)
|
||||
const category = PET_CATEGORIES[generateMockData.number(0, PET_CATEGORIES.length - 1)]
|
||||
const tags = generateMockData.array(() => PET_TAGS[generateMockData.number(0, PET_TAGS.length - 1)], generateMockData.number(1, 3))
|
||||
|
||||
return {
|
||||
id: petId,
|
||||
category,
|
||||
name: generateMockData.name('Pet'),
|
||||
photoUrls: generateMockData.array(
|
||||
index => `https://example.com/pet/${petId}/photo${index + 1}.jpg`,
|
||||
generateMockData.number(1, 3),
|
||||
),
|
||||
tags,
|
||||
status: status || PET_STATUS[generateMockData.number(0, PET_STATUS.length - 1)],
|
||||
}
|
||||
}
|
||||
|
||||
export default defineMock({
|
||||
// 上传宠物图片
|
||||
'[POST]/pet/{petId}/uploadImage': ({ params, data }) => {
|
||||
console.log(`[Mock] POST /pet/${params.petId}/uploadImage`, data)
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
type: 'success',
|
||||
message: `Image uploaded successfully for pet ${params.petId}`,
|
||||
data: {
|
||||
petId: params.petId,
|
||||
imageUrl: `https://example.com/pet/${params.petId}/uploaded-${Date.now()}.jpg`,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
// 添加新宠物
|
||||
'[POST]/pet': ({ data }) => {
|
||||
console.log('[Mock] POST /pet', data)
|
||||
|
||||
const newPet = {
|
||||
...data,
|
||||
id: generateMockData.number(10001, 20000),
|
||||
}
|
||||
|
||||
return newPet
|
||||
},
|
||||
|
||||
// 更新宠物信息
|
||||
'[PUT]/pet': ({ data }) => {
|
||||
console.log('[Mock] PUT /pet', data)
|
||||
|
||||
if (!data.id) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Pet ID is required',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...data,
|
||||
updatedAt: generateMockData.datetime(),
|
||||
}
|
||||
},
|
||||
|
||||
// 根据状态查找宠物
|
||||
'[GET]/pet/findByStatus': ({ query }) => {
|
||||
console.log('[Mock] GET /pet/findByStatus', query)
|
||||
|
||||
const status = query.status as PetStatus
|
||||
const validStatuses = Array.isArray(status) ? status : [status]
|
||||
|
||||
// 验证状态
|
||||
const invalidStatuses = validStatuses.filter(s => !PET_STATUS.includes(s as PetStatus))
|
||||
if (invalidStatuses.length > 0) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: `Invalid status value: ${invalidStatuses.join(', ')}`,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 生成符合状态的宠物列表
|
||||
const pets = generateMockData.array(
|
||||
index => generatePet(undefined, validStatuses[index % validStatuses.length] as PetStatus),
|
||||
generateMockData.number(5, 15),
|
||||
)
|
||||
|
||||
return pets
|
||||
},
|
||||
|
||||
// 根据ID获取宠物
|
||||
'[GET]/pet/{petId}': ({ params }) => {
|
||||
console.log(`[Mock] GET /pet/${params.petId}`)
|
||||
|
||||
const petId = Number.parseInt(params.petId)
|
||||
|
||||
if (Number.isNaN(petId)) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Invalid pet ID',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟宠物不存在的情况
|
||||
if (petId === 404) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
code: 404,
|
||||
message: 'Pet not found',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return generatePet(petId)
|
||||
},
|
||||
|
||||
// 使用表单数据更新宠物
|
||||
'[POST]/pet/{petId}': ({ params, data }) => {
|
||||
console.log(`[Mock] POST /pet/${params.petId}`, data)
|
||||
|
||||
const petId = Number.parseInt(params.petId)
|
||||
|
||||
if (Number.isNaN(petId)) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Invalid pet ID',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟宠物不存在的情况
|
||||
if (petId === 404) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
code: 404,
|
||||
message: 'Pet not found',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const updatedPet = {
|
||||
...generatePet(petId),
|
||||
...data,
|
||||
updatedAt: generateMockData.datetime(),
|
||||
}
|
||||
|
||||
return updatedPet
|
||||
},
|
||||
|
||||
// 删除宠物
|
||||
'[DELETE]/pet/{petId}': ({ params, headers }) => {
|
||||
console.log(`[Mock] DELETE /pet/${params.petId}`, headers)
|
||||
|
||||
const petId = Number.parseInt(params.petId)
|
||||
|
||||
if (Number.isNaN(petId)) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Invalid pet ID',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 检查API密钥
|
||||
if (!headers.api_key) {
|
||||
return {
|
||||
status: 401,
|
||||
body: {
|
||||
code: 401,
|
||||
message: 'API key is required',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟宠物不存在的情况
|
||||
if (petId === 404) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
code: 404,
|
||||
message: 'Pet not found',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
message: `Pet ${petId} deleted successfully`,
|
||||
}
|
||||
},
|
||||
}, true)
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2025-06-15 14:30:00
|
||||
* @LastEditTime: 2025-06-15 14:30:00
|
||||
* @LastEditors: weisheng
|
||||
* @Description: Pet Store - Store相关接口的mock数据
|
||||
* @FilePath: /wot-starter/src/api/mock/modules/store.ts
|
||||
*/
|
||||
import { defineMock } from '@alova/mock'
|
||||
import { generateMockData } from '../utils/generators'
|
||||
|
||||
// 订单状态枚举
|
||||
const ORDER_STATUS = ['placed', 'approved', 'delivered'] as const
|
||||
type OrderStatus = typeof ORDER_STATUS[number]
|
||||
|
||||
// 生成订单对象
|
||||
function generateOrder(id?: number, status?: OrderStatus) {
|
||||
const orderId = id || generateMockData.number(1, 10000)
|
||||
|
||||
return {
|
||||
id: orderId,
|
||||
petId: generateMockData.number(1, 1000),
|
||||
quantity: generateMockData.number(1, 10),
|
||||
shipDate: generateMockData.datetime(generateMockData.number(1, 30)), // 1-30天后发货
|
||||
status: status || ORDER_STATUS[generateMockData.number(0, ORDER_STATUS.length - 1)],
|
||||
complete: generateMockData.boolean(),
|
||||
}
|
||||
}
|
||||
|
||||
export default defineMock({
|
||||
// 获取库存
|
||||
'[GET]/store/inventory': () => {
|
||||
console.log('[Mock] GET /store/inventory')
|
||||
|
||||
// 生成随机库存数据
|
||||
const inventory: Record<string, number> = {}
|
||||
|
||||
// 为不同状态生成库存数量
|
||||
ORDER_STATUS.forEach((status) => {
|
||||
inventory[status] = generateMockData.number(0, 100)
|
||||
})
|
||||
|
||||
// 添加一些额外的状态
|
||||
inventory.pending = generateMockData.number(0, 50)
|
||||
inventory.sold = generateMockData.number(0, 200)
|
||||
inventory.available = generateMockData.number(10, 300)
|
||||
|
||||
return inventory
|
||||
},
|
||||
|
||||
// 下单购买宠物
|
||||
'[POST]/store/order': ({ data }) => {
|
||||
console.log('[Mock] POST /store/order', data)
|
||||
|
||||
// 验证必填字段
|
||||
if (!data.petId) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Pet ID is required',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (!data.quantity || data.quantity <= 0) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Quantity must be greater than 0',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 创建新订单
|
||||
const newOrder = {
|
||||
id: generateMockData.number(10001, 20000),
|
||||
petId: data.petId,
|
||||
quantity: data.quantity,
|
||||
shipDate: data.shipDate || generateMockData.datetime(generateMockData.number(1, 7)), // 默认7天内发货
|
||||
status: 'placed' as OrderStatus,
|
||||
complete: false,
|
||||
}
|
||||
|
||||
return newOrder
|
||||
},
|
||||
|
||||
// 根据ID获取订单
|
||||
'[GET]/store/order/{orderId}': ({ params }) => {
|
||||
console.log(`[Mock] GET /store/order/${params.orderId}`)
|
||||
|
||||
const orderId = Number.parseInt(params.orderId)
|
||||
|
||||
if (Number.isNaN(orderId)) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Invalid order ID',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟订单不存在的情况
|
||||
if (orderId === 404) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
code: 404,
|
||||
message: 'Order not found',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟无效订单ID的情况(订单ID必须在1-10之间)
|
||||
if (orderId < 1 || orderId > 10) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Invalid ID supplied',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return generateOrder(orderId)
|
||||
},
|
||||
|
||||
// 删除订单
|
||||
'[DELETE]/store/order/{orderId}': ({ params }) => {
|
||||
console.log(`[Mock] DELETE /store/order/${params.orderId}`)
|
||||
|
||||
const orderId = Number.parseInt(params.orderId)
|
||||
|
||||
if (Number.isNaN(orderId)) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Invalid order ID',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟订单不存在的情况
|
||||
if (orderId === 404) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
code: 404,
|
||||
message: 'Order not found',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟无效订单ID的情况
|
||||
if (orderId < 1) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Invalid ID supplied',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
message: `Order ${orderId} deleted successfully`,
|
||||
}
|
||||
},
|
||||
}, true)
|
||||
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2025-06-15 14:35:00
|
||||
* @LastEditTime: 2025-06-27 09:43:25
|
||||
* @LastEditors: weisheng
|
||||
* @Description: Pet Store - User相关接口的mock数据
|
||||
* @FilePath: /wot-starter/src/api/mock/modules/user.ts
|
||||
*/
|
||||
import { defineMock } from '@alova/mock'
|
||||
import { generateMockData } from '../utils/generators'
|
||||
|
||||
// 用户状态枚举
|
||||
const USER_STATUS = [0, 1, 2] // 0: 离线, 1: 在线, 2: 忙碌
|
||||
type UserStatus = typeof USER_STATUS[number]
|
||||
|
||||
// 生成用户对象
|
||||
function generateUser(username?: string, status?: UserStatus) {
|
||||
const baseUsername = username || generateMockData.name('user').toLowerCase()
|
||||
|
||||
return {
|
||||
id: generateMockData.number(1, 10000),
|
||||
username: baseUsername,
|
||||
firstName: generateMockData.name('First'),
|
||||
lastName: generateMockData.name('Last'),
|
||||
email: `${baseUsername}@example.com`,
|
||||
password: 'password123', // 在实际应用中不应该返回密码
|
||||
phone: `1${generateMockData.number(1000000000, 9999999999)}`,
|
||||
userStatus: CommonUtil.isDef(status) ? status : USER_STATUS[generateMockData.number(0, USER_STATUS.length - 1)],
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟用户数据库
|
||||
const mockUsers = generateMockData.array(index => generateUser(`user${index + 1}`), 10)
|
||||
|
||||
export default defineMock({
|
||||
// 批量创建用户(数组输入)
|
||||
'[POST]/user/createWithArray': ({ data }) => {
|
||||
console.log('[Mock] POST /user/createWithArray', data)
|
||||
|
||||
if (!Array.isArray(data)) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Input should be an array of users',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 验证每个用户对象
|
||||
for (const user of data) {
|
||||
if (!user.username) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Username is required for all users',
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
message: `Successfully created ${data.length} users`,
|
||||
}
|
||||
},
|
||||
|
||||
// 批量创建用户(列表输入)
|
||||
'[POST]/user/createWithList': ({ data }) => {
|
||||
console.log('[Mock] POST /user/createWithList', data)
|
||||
|
||||
if (!Array.isArray(data)) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Input should be a list of users',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 验证每个用户对象
|
||||
for (const user of data) {
|
||||
if (!user.username) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Username is required for all users',
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
message: `Successfully created ${data.length} users from list`,
|
||||
}
|
||||
},
|
||||
|
||||
// 用户登录
|
||||
'[GET]/user/login': ({ query }) => {
|
||||
console.log('[Mock] GET /user/login', query)
|
||||
|
||||
const { username, password } = query
|
||||
|
||||
if (!username || !password) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Username and password are required',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟登录验证
|
||||
if (username === 'admin' && password === 'admin') {
|
||||
return {
|
||||
code: 200,
|
||||
message: 'logged in user session',
|
||||
token: `mock_token_${Date.now()}`,
|
||||
expiresIn: 3600, // 1小时
|
||||
user: generateUser('admin', 1),
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟用户名密码错误
|
||||
if (username === 'invalid' || password === 'invalid') {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Invalid username/password supplied',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 默认成功登录
|
||||
return {
|
||||
code: 200,
|
||||
message: 'logged in user session',
|
||||
token: `mock_token_${Date.now()}`,
|
||||
expiresIn: 3600,
|
||||
user: generateUser(username as string, 1),
|
||||
}
|
||||
},
|
||||
|
||||
// 用户登出
|
||||
'[GET]/user/logout': () => {
|
||||
console.log('[Mock] GET /user/logout')
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
message: 'ok',
|
||||
}
|
||||
},
|
||||
|
||||
// 根据用户名获取用户
|
||||
'[GET]/user/{username}': ({ params }) => {
|
||||
console.log(`[Mock] GET /user/${params.username}`)
|
||||
|
||||
const username = params.username
|
||||
|
||||
if (!username) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Username is required',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟用户不存在的情况
|
||||
if (username === 'notfound') {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
code: 404,
|
||||
message: 'User not found',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 从模拟数据库中查找用户
|
||||
const existingUser = mockUsers.find(user => user.username === username)
|
||||
if (existingUser) {
|
||||
return existingUser
|
||||
}
|
||||
|
||||
// 生成新用户
|
||||
return generateUser(username)
|
||||
},
|
||||
|
||||
// 更新用户信息
|
||||
'[PUT]/user/{username}': ({ params, data }) => {
|
||||
console.log(`[Mock] PUT /user/${params.username}`, data)
|
||||
|
||||
const username = params.username
|
||||
|
||||
if (!username) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Username is required',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟用户不存在的情况
|
||||
if (username === 'notfound') {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
code: 404,
|
||||
message: 'User not found',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 更新用户信息
|
||||
const updatedUser = {
|
||||
...generateUser(username),
|
||||
...data,
|
||||
username, // 确保用户名不被修改
|
||||
updatedAt: generateMockData.datetime(),
|
||||
}
|
||||
|
||||
return updatedUser
|
||||
},
|
||||
|
||||
// 删除用户
|
||||
'[DELETE]/user/{username}': ({ params }) => {
|
||||
console.log(`[Mock] DELETE /user/${params.username}`)
|
||||
|
||||
const username = params.username
|
||||
|
||||
if (!username) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Username is required',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟用户不存在的情况
|
||||
if (username === 'notfound') {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
code: 404,
|
||||
message: 'User not found',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
message: `User ${username} deleted successfully`,
|
||||
}
|
||||
},
|
||||
|
||||
// 创建用户
|
||||
'[POST]/user': ({ data }) => {
|
||||
console.log('[Mock] POST /user', data)
|
||||
|
||||
if (!data.username) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: 'Username is required',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 检查用户名是否已存在
|
||||
const existingUser = mockUsers.find(user => user.username === data.username)
|
||||
if (existingUser) {
|
||||
return {
|
||||
status: 409,
|
||||
body: {
|
||||
code: 409,
|
||||
message: 'Username already exists',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 创建新用户
|
||||
const newUser = {
|
||||
...generateUser(),
|
||||
...data,
|
||||
id: generateMockData.number(20001, 30000),
|
||||
createdAt: generateMockData.datetime(),
|
||||
}
|
||||
|
||||
return newUser
|
||||
},
|
||||
}, true)
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-05-20 10:00:00
|
||||
* @LastEditTime: 2025-05-21 15:46:14
|
||||
* @LastEditors: weisheng
|
||||
* @Description: Mock数据生成工具
|
||||
* @FilePath: /lsym-cx-mini/src/api/mock/utils/generators.ts
|
||||
*/
|
||||
|
||||
// 模拟数据生成工具函数
|
||||
export const generateMockData = {
|
||||
// 生成随机ID
|
||||
id: (): number => Math.floor(Math.random() * 10000),
|
||||
|
||||
// 生成随机名称
|
||||
name: (prefix = '名称'): string => `${prefix}_${Math.floor(Math.random() * 1000)}`,
|
||||
|
||||
// 生成随机代码
|
||||
code: (prefix = 'CODE'): string => `${prefix}_${Math.floor(Math.random() * 1000)}`,
|
||||
|
||||
// 生成随机日期
|
||||
// 可以传入天数偏移,负数表示过去的日期,正数表示未来的日期
|
||||
date: (dayOffset = 0): string => {
|
||||
const date = new Date()
|
||||
if (dayOffset !== 0) {
|
||||
date.setDate(date.getDate() + dayOffset)
|
||||
}
|
||||
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`
|
||||
},
|
||||
|
||||
// 生成随机时间
|
||||
// 可以传入天数偏移,负数表示过去的日期,正数表示未来的日期
|
||||
datetime: (dayOffset = 0): string => {
|
||||
const date = new Date()
|
||||
if (dayOffset !== 0) {
|
||||
date.setDate(date.getDate() + dayOffset)
|
||||
}
|
||||
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}:${String(date.getSeconds()).padStart(2, '0')}`
|
||||
},
|
||||
|
||||
// 生成随机布尔值
|
||||
boolean: (): boolean => Math.random() > 0.5,
|
||||
|
||||
// 生成随机数字
|
||||
number: (min = 0, max = 100): number => Math.floor(Math.random() * (max - min)) + min,
|
||||
|
||||
// 生成随机数组
|
||||
array: <T>(generator: (index: number) => T, length = 10): T[] => {
|
||||
const result: T[] = []
|
||||
for (let i = 0; i < length; i++) {
|
||||
result.push(generator(i))
|
||||
}
|
||||
return result
|
||||
},
|
||||
|
||||
// 生成基础响应对象
|
||||
baseResponse: <T>(data: T = null as unknown as T, code = 2000, msg = '操作成功') => ({
|
||||
code,
|
||||
data,
|
||||
msg,
|
||||
}),
|
||||
|
||||
// 生成列表响应对象
|
||||
listResponse: <T>(data: T[] = [], total = data.length, more = false, code = 2000, msg = '操作成功') => ({
|
||||
code,
|
||||
data,
|
||||
total,
|
||||
more,
|
||||
msg,
|
||||
}),
|
||||
|
||||
// 生成GCN对象
|
||||
gcn: (_index?: number) => ({
|
||||
gid: generateMockData.id(),
|
||||
code: generateMockData.code('ORG'),
|
||||
name: generateMockData.name('组织'),
|
||||
}),
|
||||
|
||||
// 生成员工对象
|
||||
faEmp: (index: number) => ({
|
||||
gid: generateMockData.id(),
|
||||
code: generateMockData.code('EMP'),
|
||||
name: generateMockData.name('员工'),
|
||||
org: generateMockData.gcn(index),
|
||||
}),
|
||||
|
||||
// 生成车销业务员对象
|
||||
vehSaleEmp: (index: number) => ({
|
||||
gid: generateMockData.id(),
|
||||
code: generateMockData.code('VSE'),
|
||||
name: generateMockData.name('车销业务员'),
|
||||
faEmp: generateMockData.faEmp(index),
|
||||
org: generateMockData.gcn(index),
|
||||
wms: generateMockData.gcn(index),
|
||||
}),
|
||||
|
||||
// 生成权限对象
|
||||
permission: (index: number) => ({
|
||||
module: `module_${index}`,
|
||||
moduleName: `模块${index}`,
|
||||
roleId: `role_${index}`,
|
||||
state: 1,
|
||||
}),
|
||||
|
||||
// 生成代码名称对象
|
||||
codeName: (index: number, prefix = '线路') => ({
|
||||
code: generateMockData.code(`LINE_${index}`),
|
||||
name: `${prefix}${index}`,
|
||||
}),
|
||||
|
||||
// 生成用户对象
|
||||
user: (roleCode = '01') => ({
|
||||
permissions: generateMockData.array(generateMockData.permission, 5),
|
||||
sortLines: generateMockData.array(generateMockData.codeName, 3),
|
||||
token: `mock_token_${Date.now()}`,
|
||||
roleCode, // 添加roleCode字段:01-车销业务员,02-仓管
|
||||
vehSaleEmp: generateMockData.vehSaleEmp(0),
|
||||
}),
|
||||
|
||||
// 生成商品对象
|
||||
goods: (index: number) => ({
|
||||
gid: generateMockData.id(),
|
||||
code: generateMockData.code('GOODS'),
|
||||
name: generateMockData.name('商品'),
|
||||
gdCode: generateMockData.code('GDCODE'),
|
||||
spec: `规格${index}`,
|
||||
munit: '个',
|
||||
price: generateMockData.number(1, 1000) / 100,
|
||||
qpc: generateMockData.number(1, 10),
|
||||
qpcStr: `${generateMockData.number(1, 10)}个/箱`,
|
||||
qty: generateMockData.number(1, 100),
|
||||
qtyStr: `${generateMockData.number(1, 100)}个`,
|
||||
busInvQty: generateMockData.number(1, 100),
|
||||
advUseSignQty: generateMockData.number(1, 100),
|
||||
version: 1,
|
||||
}),
|
||||
// 单据状态,可选值为:0 | 100 | 1300 | 300 | 110 | 1310
|
||||
stat: (): number => {
|
||||
const stats = [100, 1300, 300, 110, 1310]
|
||||
return stats[generateMockData.number(0, stats.length - 1)]
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
import { ApiHeader } from '@/enums/api-header.enum'
|
||||
import { http } from '@/http'
|
||||
|
||||
const USER_BASE_URL = '/system/user'
|
||||
|
||||
const UserAPI = {
|
||||
/**
|
||||
* 个人中心用户信息
|
||||
*
|
||||
* @returns 登录用户昵称、头像信息,包括角色和权限
|
||||
*/
|
||||
getCurrentUserInfo(): Promise<UserInfo> {
|
||||
return http.Get(`${USER_BASE_URL}/current/info`)
|
||||
},
|
||||
|
||||
/**
|
||||
* 当前用户头像上传
|
||||
*
|
||||
* @param body
|
||||
* @returns 上传后的文件路径
|
||||
*/
|
||||
uploadCurrentUserAvatar(body: any): Promise<UploadFileResult> {
|
||||
return http.Post(`${USER_BASE_URL}/current/avatar/upload`, body, {
|
||||
headers: {
|
||||
[ApiHeader.KEY]: ApiHeader.MULTIPART,
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 修改个人中心用户信息
|
||||
*
|
||||
* @param body
|
||||
* @returns 修改后的用户信息
|
||||
*/
|
||||
updateCurrentUserInfo(body: UserProfileForm): Promise<UserInfo> {
|
||||
return http.Put(`${USER_BASE_URL}/current/info/update`, body)
|
||||
},
|
||||
|
||||
/**
|
||||
* 修改个人中心用户密码
|
||||
*
|
||||
* @param body
|
||||
* @returns 修改后的用户信息
|
||||
*/
|
||||
changeCurrentUserPassword(body: PasswordChangeForm): Promise<ApiResponse> {
|
||||
return http.Put(`${USER_BASE_URL}/current/password/change`, body)
|
||||
},
|
||||
|
||||
/**
|
||||
* 注册用户
|
||||
*
|
||||
* @param body
|
||||
* @returns 忘记密码结果
|
||||
*/
|
||||
registerUser(body: RegisterForm): Promise<ApiResponse> {
|
||||
return http.Post(`${USER_BASE_URL}/register`, body)
|
||||
},
|
||||
|
||||
/**
|
||||
* 忘记密码
|
||||
*
|
||||
* @param body
|
||||
* @returns 忘记密码结果
|
||||
*/
|
||||
forgetPassword(body: ForgetPasswordForm): Promise<ApiResponse> {
|
||||
return http.Post(`${USER_BASE_URL}/forget/password`, body)
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取用户分页列表
|
||||
*POST
|
||||
* @param queryParams 查询参数
|
||||
*/
|
||||
getUserPage(queryParams: UserPageQuery): Promise<PageResult<UserInfo[]>> {
|
||||
return http.Get(`${USER_BASE_URL}/list`, queryParams)
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取用户表单详情
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @returns 用户表单详情
|
||||
*/
|
||||
getUserDetail(userId: number): Promise<UserForm> {
|
||||
return http.Get(`${USER_BASE_URL}/detail/${userId}`)
|
||||
},
|
||||
|
||||
/**
|
||||
* 添加用户
|
||||
*
|
||||
* @param body 用户表单数据
|
||||
*/
|
||||
addUser(body: UserForm): Promise<ApiResponse> {
|
||||
return http.Post(`${USER_BASE_URL}/create`, body)
|
||||
},
|
||||
|
||||
/**
|
||||
* 修改用户
|
||||
*
|
||||
* @param body 用户表单数据
|
||||
*/
|
||||
updateUser(body: UserForm): Promise<ApiResponse> {
|
||||
return http.Put(`${USER_BASE_URL}/update`, body)
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
*
|
||||
* @param ids 用户ID数组
|
||||
*/
|
||||
deleteUser(ids: number[]): Promise<ApiResponse> {
|
||||
return http.Delete(`${USER_BASE_URL}/delete`, ids)
|
||||
},
|
||||
}
|
||||
|
||||
export default UserAPI
|
||||
|
||||
/* 忘记密码表单 */
|
||||
export interface ForgetPasswordForm {
|
||||
username: string
|
||||
new_password: string
|
||||
confirmPassword: string
|
||||
}
|
||||
|
||||
/* 注册表单 */
|
||||
export interface RegisterForm {
|
||||
username: string
|
||||
password: string
|
||||
confirmPassword: string
|
||||
}
|
||||
|
||||
/* 分页查询表单 */
|
||||
export interface UserPageQuery extends PageQuery {
|
||||
username?: string
|
||||
name?: string
|
||||
status?: boolean
|
||||
dept_id?: number
|
||||
start_time?: string
|
||||
end_time?: string
|
||||
}
|
||||
|
||||
/* 搜索选择器数据类型 */
|
||||
export interface searchSelectDataType {
|
||||
name?: string
|
||||
status?: string
|
||||
}
|
||||
|
||||
/* 用户表单 */
|
||||
export interface UserForm {
|
||||
id?: number
|
||||
username?: string
|
||||
name?: string
|
||||
dept_id?: number
|
||||
dept_name?: string
|
||||
role_ids?: number[]
|
||||
roleNames?: string[]
|
||||
position_ids?: number[]
|
||||
positionNames?: string[]
|
||||
password?: string
|
||||
gender?: number
|
||||
email?: string
|
||||
mobile?: string
|
||||
is_superuser?: boolean
|
||||
status?: boolean
|
||||
description?: string
|
||||
}
|
||||
|
||||
/* 登录用户信息 */
|
||||
export interface UserInfo {
|
||||
index?: number
|
||||
id?: number
|
||||
username?: string
|
||||
name?: string
|
||||
avatar?: string
|
||||
email?: string
|
||||
mobile?: string
|
||||
gender?: string
|
||||
password?: string
|
||||
menus?: MenuTable[]
|
||||
dept?: deptTreeType
|
||||
dept_id?: deptTreeType['id']
|
||||
dept_name?: deptTreeType['name']
|
||||
roles?: roleSelectorType[]
|
||||
roleNames?: roleSelectorType['name'][]
|
||||
role_ids?: roleSelectorType['id'][]
|
||||
positions?: positionSelectorType[]
|
||||
positionNames?: positionSelectorType['name'][]
|
||||
position_ids?: positionSelectorType['id'][]
|
||||
is_superuser?: boolean
|
||||
status?: boolean
|
||||
description?: string
|
||||
last_login?: string
|
||||
created_at?: string
|
||||
updated_at?: string
|
||||
creator?: creatorType
|
||||
}
|
||||
|
||||
/* 菜单表 */
|
||||
export interface MenuTable {
|
||||
index?: number
|
||||
id?: number
|
||||
name?: string
|
||||
type?: number
|
||||
icon?: string
|
||||
order?: number
|
||||
permission?: string
|
||||
route_name?: string
|
||||
route_path?: string
|
||||
component_path?: string
|
||||
redirect?: string
|
||||
parent_id?: number
|
||||
parent_name?: string
|
||||
keep_alive?: boolean
|
||||
hidden?: boolean
|
||||
always_show?: boolean
|
||||
title?: string
|
||||
params?: { key: string, value: string }[]
|
||||
affix?: boolean
|
||||
status?: boolean
|
||||
description?: string
|
||||
created_at?: string
|
||||
updated_at?: string
|
||||
children?: MenuTable[]
|
||||
}
|
||||
|
||||
/* 部门树 */
|
||||
export interface deptTreeType {
|
||||
id?: number
|
||||
name?: string
|
||||
parent_id?: number
|
||||
children?: deptTreeType[]
|
||||
}
|
||||
|
||||
/* 角色选择器 */
|
||||
export interface roleSelectorType {
|
||||
id?: number
|
||||
name?: string
|
||||
status?: boolean
|
||||
description?: string
|
||||
}
|
||||
|
||||
/* 职位选择器 */
|
||||
export interface positionSelectorType {
|
||||
id?: number
|
||||
name?: string
|
||||
status?: boolean
|
||||
description?: string
|
||||
}
|
||||
|
||||
/* 个人中心用户信息表单 */
|
||||
export interface UserProfileForm {
|
||||
id?: number
|
||||
name?: string
|
||||
gender?: string
|
||||
mobile?: string
|
||||
email?: string
|
||||
username?: string
|
||||
dept_name?: string
|
||||
positions?: positionSelectorType[]
|
||||
roles?: roleSelectorType[]
|
||||
avatar?: string
|
||||
created_at?: string
|
||||
}
|
||||
|
||||
/* 修改密码表单 */
|
||||
export interface PasswordChangeForm {
|
||||
old_password: string
|
||||
new_password: string
|
||||
confirm_password: string
|
||||
}
|
||||
|
||||
/* 重置密码表单 */
|
||||
export interface ResetPasswordForm {
|
||||
id: number
|
||||
password: string
|
||||
}
|
||||
Reference in New Issue
Block a user