feat: 初始化前端项目基础结构

- 添加项目配置文件(tsconfig, eslint, prettier等)
- 实现基础路由和页面布局
- 添加全局状态管理和API请求封装
- 集成UI组件库和主题系统
- 添加文档网站和示例页面
- 配置CI/CD和工作流
This commit is contained in:
zhangtao
2026-05-01 00:47:48 +08:00
parent ff738007cd
commit 5c29d22aa5
256 changed files with 45257 additions and 2 deletions
+46
View File
@@ -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&#x27;ve switched to the design first approach!
You can now help us improve the API whether it&#x27;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}']
};
+84
View File
@@ -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
}
+106
View File
@@ -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
}
+55
View File
@@ -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
+92
View File
@@ -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
+101
View File
@@ -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&#x27;ve switched to the design first approach!
You can now help us improve the API whether it&#x27;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;
+1058
View File
File diff suppressed because it is too large Load Diff
+18
View File
@@ -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 }
+107
View File
@@ -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. 模拟数据应包含各种场景,包括成功和失败的情况
+436
View File
@@ -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.* - 用户模块演示')
}
+47
View File
@@ -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,
})
},
})
+239
View File
@@ -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)
+173
View File
@@ -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)
+304
View File
@@ -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)]
},
}
+277
View File
@@ -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
}