chore: 初始化项目基础结构与配置

添加了nvm配置、静态资源、项目配置文件、工具类、api模块、状态管理、国际化、路由配置等基础代码,搭建了uniapp前端项目的初始框架。
This commit is contained in:
zhangtao
2026-08-10 22:23:32 +08:00
parent 9e41358945
commit 50eac1872b
216 changed files with 44085 additions and 15 deletions
+92
View File
@@ -0,0 +1,92 @@
/**
* AI 聊天 API 模块(对应后端 module_ai 插件)
*/
import { http } from '@/http'
const AI_BASE = '/ai/chat'
export const ChatAPI = {
/** 获取会话列表 */
getSessions(params?: Record<string, any>): Promise<PageResult<ChatSession>> {
return http.Get(`${AI_BASE}/list`, params)
},
/** 创建会话 */
createSession(title?: string): Promise<ChatSession> {
return http.Post(`${AI_BASE}/create`, { title: title || '新对话' })
},
/** 获取会话详情(含消息列表) */
getDetail(sessionId: number): Promise<{ messages: ChatMessage[] }> {
return http.Get(`${AI_BASE}/detail/${sessionId}`)
},
/** 更新会话标题 */
updateSession(sessionId: number, data: Record<string, any>): Promise<void> {
return http.Put(`${AI_BASE}/update/${sessionId}`, data)
},
/** 删除会话 */
removeSession(ids: number[]): Promise<void> {
return http.Delete(`${AI_BASE}/delete`, { ids: JSON.stringify(ids) })
},
/** 发送消息 (非流式) */
sendMessage(sessionId: number, content: string): Promise<ChatMessage> {
// silent:聊天页将错误内联展示为 AI 消息,避免与全局 toast 重复提示
return http.Post(`${AI_BASE}/ai-chat`, { session_id: sessionId, content }, { meta: { silent: true } })
},
/** 获取 AI 模型配置列表 */
getModels(): Promise<AIModelList> {
return http.Get(`${AI_BASE}/model`)
},
/** 新增 AI 模型配置 */
createModel(data: AIModelForm): Promise<AIModelConfig> {
return http.Post(`${AI_BASE}/model`, data)
},
/** 更新 AI 模型配置 */
updateModel(configId: number, data: AIModelForm): Promise<AIModelConfig> {
return http.Put(`${AI_BASE}/model/${configId}`, data)
},
/** 删除 AI 模型配置 */
deleteModel(configId: number): Promise<void> {
return http.Delete(`${AI_BASE}/model/${configId}`)
},
/** 切换激活的 AI 模型配置 */
activateModel(configId: number): Promise<void> {
return http.Post(`${AI_BASE}/model/${configId}/activate`)
},
}
/* ==================== 类型定义 ==================== */
export interface ChatSession {
id: number
session_name?: string
title?: string
created_at?: number
}
export interface ChatMessage {
id?: string
role: string
content: string
created_at?: number
time?: string
}
export interface AIModelForm {
name: string
base_url: string
api_key: string
model_id: string
temperature?: number
}
export interface AIModelConfig extends AIModelForm {
config_id: number
is_active?: boolean
created_time?: string
updated_time?: string
}
/** 模型配置列表响应:items 为配置数组,active_id 为当前激活的配置 id */
export interface AIModelList {
items: AIModelConfig[]
active_id: number | null
}
@@ -0,0 +1,39 @@
import { http } from '@/http'
const MONITOR_BASE = '/monitor'
/**
* 运营大盘 API
* 与 web 端 module_monitor/dashboard.ts 对齐
*/
export const DashboardAPI = {
getStats(): Promise<DashboardStats> {
return http.Get(`${MONITOR_BASE}/online/stats`)
},
}
export interface RecentLoginItem {
username: string
status: number
login_time: string
login_ip?: string
login_location?: string
}
export interface DashboardStats {
online_users: number
total_users: number
today_login_count: number
today_unique_users: number
week_user_created: number
login_trend: LoginTrendItem[]
recent_logins: RecentLoginItem[]
}
/** 登录趋势(按天聚合,近7天) */
export interface LoginTrendItem {
day: string
logins: number
unique_users: number
new_users: number
}
@@ -0,0 +1,71 @@
import { http } from '@/http'
const MONITOR_BASE = '/monitor'
/**
* 服务器监控 API
* 与 web 端 module_monitor/server.ts 对齐(补全完整字段)
*/
export const ServerAPI = {
getInfo(): Promise<ServerInfo> {
return http.Get(`${MONITOR_BASE}/server/info`)
},
}
export interface CpuInfo {
/** 逻辑核心数 */
cpu_num: number
/** user 占用百分比 */
used: number
/** system 占用百分比 */
sys: number
/** idle 百分比 */
free: number
}
export interface MemoryInfo {
total: string
used: string
free: string
usage: number
}
export interface DiskInfo {
dir_name: string
sys_type_name: string
type_name: string
total: string
used: string
free: string
/** 使用率百分比 */
usage: number
}
export interface SysInfo {
computer_ip: string
computer_name: string
os_arch: string
os_name: string
user_dir: string
}
export interface PyInfo {
name: string
version: string
start_time: string
run_time: string
home: string
memory_total: string
memory_used: string
memory_free: string
/** 进程内存占用率百分比(rss / available) */
memory_usage: number
}
export interface ServerInfo {
cpu?: CpuInfo
mem?: MemoryInfo
sys?: SysInfo
py?: PyInfo
disks?: DiskInfo[]
}
+180
View File
@@ -0,0 +1,180 @@
import { http } from '@/http'
import { ContentTypeEnum } from '@/http/tools/enum'
const AUTH_BASE_URL = '/system/auth'
/** 方案提供方 */
export type OAuthProvider = 'wechat' | 'qq' | 'github' | 'gitee'
/**
* 认证 API
* 与 web 端 module_system/auth.ts 对齐(完整字段定义)
*/
const AuthAPI = {
/**
* 登录
* @param body 登录表单数据
* @returns 登录结果
*/
login(body: LoginFormData): Promise<LoginResult> {
return http.Post(`${AUTH_BASE_URL}/login`, body, {
headers: {
'Content-Type': ContentTypeEnum.FORM_URLENCODED,
},
// authRole: 'login':登录 401(密码错误)按普通错误处理,不触发 token 刷新逻辑
meta: { ignoreAuth: true, authRole: 'login' },
})
},
/**
* 刷新令牌
* @param body 刷新令牌请求体
* @returns 新的访问令牌
*/
refreshToken(body: RefreshToekenBody): Promise<LoginResult> {
// authRole: 'refreshToken':让 http 层 401 处理器识别刷新请求,自身 401 时不触发刷新逻辑(避免死循环)
// silent:刷新失败由 http 层统一跳转登录,无需全局 toast
return http.Post(`${AUTH_BASE_URL}/token/refresh`, body, {
meta: { ignoreAuth: true, silent: true, authRole: 'refreshToken' },
})
},
/**
* 获取验证码
* @returns 验证码信息
*/
getCaptcha(): Promise<CaptchaInfo> {
// 添加随机参数防止缓存
const timestamp = new Date().getTime()
return http.Get(`${AUTH_BASE_URL}/captcha/get?timestamp=${timestamp}`, { meta: { ignoreAuth: true, authRole: 'visitor' } })
},
/**
* 登出
* 后端 logout 接口 body 为纯字符串(JWT 原文,Annotated[str, Body]),
* 需显式 JSON.stringify 使请求体成为合法 JSON 字符串(uni.request 对字符串原样发送)
* @param token 访问令牌
*/
logout(token: string): Promise<void> {
return http.Post(`${AUTH_BASE_URL}/logout`, JSON.stringify(token))
},
/**
* 获取第三方 OAuth 登录跳转 URL
* @param provider oauth 提供商: wechat / qq / github / gitee
* @returns 跳转 URL
*/
getOAuthLoginUrl(provider: OAuthProvider): Promise<{ url: string }> {
return http.Get(`${AUTH_BASE_URL}/oauth/${provider}/login`, { meta: { ignoreAuth: true, authRole: 'visitor' } })
},
/**
* 滑块验证码完成
* 后端仅标记 captcha_key 状态为 verified,不校验 x 坐标值(x 为占位字段)
* @param data 验证数据
* @param data.captcha_key 验证码 key
* @param data.x 滑块 x 坐标(占位,后端未使用)
* @returns 验证结果 { captcha_key, verified }
*/
completeSliderCaptcha(data: { captcha_key: string, x: number }): Promise<{ captcha_key: string, verified: boolean }> {
return http.Post(`${AUTH_BASE_URL}/captcha/slider/complete`, data, { meta: { ignoreAuth: true, authRole: 'visitor' } })
},
/**
* 微信小程序登录
* 前端通过 uni.login 获取 code,后端调用 code2Session 换取 openid 后返回 JWT
* @param data 微信登录数据
* @param data.code uni.login 返回的 code
* @param data.nickname 用户昵称(可选,来自 getUserProfile)
* @param data.avatar 头像 URL(可选)
* @returns JWT 登录结果
*/
wxLogin(data: WxLoginData): Promise<LoginResult> {
return http.Post(`${AUTH_BASE_URL}/wx-login`, data, { meta: { ignoreAuth: true, authRole: 'visitor' } })
},
/**
* 微信小程序手机号快速登录
* 用户点击<button open-type="getPhoneNumber">后,回调 e.detail.code 发送给后端
* 后端通过 getuserphonenumber API 直接获取手机号(2023+ 新方案,无需 AES 解密)
* @param data 手机号登录数据
* @param data.code getPhoneNumber 回调返回的动态令牌 code
* @returns JWT 登录结果
*/
wxPhoneLogin(data: WxPhoneLoginData): Promise<LoginResult> {
return http.Post(`${AUTH_BASE_URL}/wx-phone-login`, data, { meta: { ignoreAuth: true, authRole: 'visitor' } })
},
/**
* 生成小程序码
* 调用后端接口,后端通过微信 getWXACodeUnlimit API 生成无限制小程序码
* @param data 生成参数
* @param data.scene 场景参数(最大32字符,如 invite_123)
* @param data.page 小程序页面路径(可选,默认主页)
* @param data.width 图片宽度(px,默认 430)
* @returns 包含 base64 图片 URL 的结果
*/
generateWxQrCode(data: WxQrCodeParams): Promise<WxQrCodeResult> {
return http.Post(`${AUTH_BASE_URL}/wx-qrcode/generate`, data)
},
}
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
}
/** JWT 响应 */
export interface LoginResult {
access_token: string
refresh_token: string
token_type: string
expires_in: number
}
/** 验证码信息(滑块模式:img_base 为空字符串) */
export interface CaptchaInfo {
enable: boolean
key: string
img_base: string
}
/** 微信小程序登录数据 */
export interface WxLoginData {
code: string
nickname?: string
avatar?: string
}
/** 微信手机号登录数据(2023+ 新方案:仅传 code) */
export interface WxPhoneLoginData {
code: string
}
/** 小程序码生成参数 */
export interface WxQrCodeParams {
/** 场景值(最大32字符,如 invite_123) */
scene: string
/** 目标页面路径(不带 /,如 pages/index/index),为空则默认主页 */
page?: string
/** 宽度(px),默认 430,范围 280-1280 */
width?: number
}
/** 小程序码生成结果 */
export interface WxQrCodeResult {
/** 小程序码图片 URL(data:image/png;base64,...) */
url: string
}
@@ -0,0 +1,42 @@
import type { BatchSetStatus } from './user'
import { http } from '@/http'
const SYSTEM_BASE = '/system'
/**
* 公告管理 API
* 与 web 端 module_system/notice.ts 对齐(完整字段定义)
*/
export const NoticeAPI = {
getPage(params?: Record<string, any>): Promise<PageResult<NoticeItem>> {
return http.Get(`${SYSTEM_BASE}/notice/list`, params)
},
getDetail(id: number): Promise<NoticeItem> {
return http.Get(`${SYSTEM_BASE}/notice/detail/${id}`)
},
create(data: NoticeForm): Promise<NoticeItem> {
return http.Post(`${SYSTEM_BASE}/notice/create`, data)
},
update(id: number, data: NoticeForm): Promise<NoticeItem> {
return http.Put(`${SYSTEM_BASE}/notice/update/${id}`, data)
},
remove(ids: number[]): Promise<void> {
return http.Delete(`${SYSTEM_BASE}/notice/delete`, { ids: JSON.stringify(ids) })
},
batchStatus(data: BatchSetStatus): Promise<void> {
return http.Patch(`${SYSTEM_BASE}/notice/status/batch`, data)
},
getAvailable(): Promise<NoticeItem[]> {
return http.Get(`${SYSTEM_BASE}/notice/available`)
},
}
export interface NoticeForm extends BaseFormType {
notice_title?: string
notice_type?: string
notice_content?: string
status?: number
description?: string
}
export interface NoticeItem extends BaseType, NoticeForm {}
@@ -0,0 +1,34 @@
import { http } from '@/http'
const PARAM_BASE_URL = '/system/param'
/** 系统参数项(与后端 ParamsOutSchema 对齐) */
export interface ParamsItem {
id: number
config_name: string
config_key: string
config_value: string | null
config_type: boolean
status: number
description?: string | null
created_time?: string
update_time?: string
}
/** 系统参数管理 API */
const ParamsAPI = {
/**
* 获取初始化缓存参数(系统配置列表)
*
* 免认证接口:登录页(无 token)也会调用,需标记 meta.ignoreAuth 跳过鉴权注入
*
* @returns 系统配置项列表,config_key 唯一标识
*/
getInitConfig(): Promise<ParamsItem[]> {
return http.Get(`${PARAM_BASE_URL}/info`, {
meta: { ignoreAuth: true },
})
},
}
export default ParamsAPI
@@ -0,0 +1,70 @@
import { http } from '@/http'
const SYSTEM_BASE = '/system'
/**
* 工单管理 API
* 与 web 端 module_system/ticket.ts 对齐(完整字段定义)
*/
export const TicketAPI = {
getPage(params?: Record<string, any>): Promise<PageResult<TicketItem>> {
return http.Get(`${SYSTEM_BASE}/ticket/list`, params)
},
getDetail(id: number): Promise<TicketItem> {
return http.Get(`${SYSTEM_BASE}/ticket/detail/${id}`)
},
create(data: TicketForm): Promise<TicketItem> {
return http.Post(`${SYSTEM_BASE}/ticket/create`, data)
},
update(id: number, data: Record<string, any>): Promise<TicketItem> {
return http.Put(`${SYSTEM_BASE}/ticket/update/${id}`, data)
},
remove(ids: number[]): Promise<void> {
return http.Delete(`${SYSTEM_BASE}/ticket/delete`, { ids: JSON.stringify(ids) })
},
batch(data: { ids: number[], status: number, assigned_id?: number }): Promise<void> {
return http.Put(`${SYSTEM_BASE}/ticket/batch`, data)
},
exportTickets(params?: Record<string, any>): Promise<unknown> {
return http.Post(`${SYSTEM_BASE}/ticket/export`, params)
},
getComments(ticketId: number, params?: Record<string, any>): Promise<PageResult<TicketComment>> {
return http.Get(`${SYSTEM_BASE}/ticket/${ticketId}/comments`, params)
},
createComment(ticketId: number, data: { content: string }): Promise<TicketComment> {
return http.Post(`${SYSTEM_BASE}/ticket/${ticketId}/comments`, data)
},
}
export interface TicketForm extends BaseFormType {
title: string
ticket_content?: string
summary?: string
ticket_type: string
images?: string
reply?: string
assigned_id?: number
status?: number
description?: string
}
export interface TicketItem extends BaseType {
title?: string
ticket_content?: string
summary?: string
ticket_type?: string
status?: string | number
assigned_id?: number
assigned_by?: CommonType
images?: string
reply?: string
description?: string
}
export interface TicketComment extends BaseType {
ticket_id?: number
user_id?: number
username?: string
content?: string
created_by_name?: string
}
+331
View File
@@ -0,0 +1,331 @@
import { http } from '@/http'
const USER_BASE_URL = '/system/user'
/**
* 用户管理 API
* 与 web 端 module_system/user.ts 对齐(完整字段定义)
*/
const UserAPI = {
/**
* 个人中心用户信息
*
* @returns 登录用户昵称、头像信息,包括角色和权限
*/
getCurrentUserInfo(): Promise<UserInfo> {
return http.Get(`${USER_BASE_URL}/current/info`)
},
/**
* 当前用户头像上传
*
* @param body 上传参数
* @param body.filePath 本地临时文件路径(uni.chooseImage 选择结果)
* @param body.name 上传字段名,后端约定为 file
* @returns uni.uploadFile 成功回调(statusCode + data 响应体字符串,需调用方解析)
*/
uploadCurrentUserAvatar(body: { filePath: string, name?: string }): Promise<{ statusCode: number, data: string }> {
return http.Post(`${USER_BASE_URL}/current/avatar/upload`, body, { requestType: 'upload' })
},
/**
* 修改个人中心用户信息
*
* @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<void> {
return http.Put(`${USER_BASE_URL}/current/password/change`, body)
},
/**
* 注册用户(公开接口)
*
* @param body 注册参数
* @param body.username 用户名(字母开头,3-32 位)
* @param body.password 密码(6-128 位)
* @param body.name 昵称(可选)
* @returns 注册结果
*/
registerUser(body: RegisterForm): Promise<void> {
return http.Post(`${USER_BASE_URL}/register`, body, { meta: { ignoreAuth: true } })
},
/**
* 忘记密码(公开接口)
*
* @param body 重置参数
* @param body.username 用户名(字母开头,3-32 位)
* @param body.new_password 新密码(6-128 位)
* @returns 重置结果
*/
forgetPassword(body: ForgetPasswordForm): Promise<void> {
return http.Post(`${USER_BASE_URL}/password/forget`, body, { meta: { ignoreAuth: true } })
},
/**
* 重置用户密码
*
* @param id 用户ID
* @param body 新密码
* @param body.password 新密码
*/
resetPassword(id: number, body: { password: string }): Promise<void> {
return http.Put(`${USER_BASE_URL}/password/reset/${id}`, body)
},
/**
* 批量修改用户状态
*
* @param body 批量操作参数
* @param body.ids 用户ID列表
* @param body.status 目标状态
*/
batchStatus(body: BatchSetStatus): Promise<void> {
return http.Patch(`${USER_BASE_URL}/status/batch`, body)
},
/**
* 导出用户
*
* @param params 导出参数
*/
exportUsers(params?: Record<string, any>): Promise<unknown> {
return http.Post(`${USER_BASE_URL}/export`, params)
},
/**
* 获取用户导入模板
*/
getImportTemplate(): Promise<unknown> {
return http.Get(`${USER_BASE_URL}/import/template`)
},
/**
* 导入用户数据
*
* @param body 导入数据
*/
importData(body: Record<string, any>): Promise<void> {
return http.Post(`${USER_BASE_URL}/import/data`, body)
},
/**
* 获取用户分页列表
*
* @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<void> {
return http.Post(`${USER_BASE_URL}/create`, body)
},
/**
* 修改用户
*
* @param body 用户表单数据
*/
updateUser(body: UserForm): Promise<void> {
return http.Put(`${USER_BASE_URL}/update`, body)
},
/**
* 删除用户
*
* @param ids 用户ID数组
*/
deleteUser(ids: number[]): Promise<void> {
return http.Delete(`${USER_BASE_URL}/delete`, ids)
},
}
export default UserAPI
/* 忘记密码表单(与后端 UserForgetPasswordSchema 一致,confirmPassword 为前端校验字段不提交) */
export interface ForgetPasswordForm {
username: string
new_password: string
}
/* 注册表单 */
export interface RegisterForm {
username: string
password: string
name?: string
}
/* 分页查询表单 */
export interface UserPageQuery extends PageQuery {
username?: string
name?: string
mobile?: string
email?: string
dept_id?: number
status?: number
start_time?: string
end_time?: string
}
/* 搜索选择器数据类型 */
export interface searchSelectDataType {
name?: string
status?: number
}
/* 用户表单 */
export interface UserForm extends BaseFormType {
username?: string
name?: string
dept_id?: number
dept_name?: string
role_ids?: number[]
role_names?: string[]
position_ids?: number[]
position_names?: string[]
password?: string
gender?: number
email?: string
mobile?: string
avatar?: string
is_superuser?: boolean
status?: number
description?: string
}
/* 登录用户信息 */
export interface UserInfo extends BaseType {
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[]
role_names?: roleSelectorType['name'][]
role_ids?: roleSelectorType['id'][]
positions?: positionSelectorType[]
position_names?: positionSelectorType['name'][]
position_ids?: positionSelectorType['id'][]
is_superuser?: boolean
last_login?: string
gitee_login?: string
github_login?: string
wx_login?: string
qq_login?: string
status?: number
description?: string
}
/* 菜单表 */
export interface MenuTable extends BaseType {
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?: number
description?: string
children?: MenuTable[]
}
/* 部门树 */
export interface deptTreeType {
id?: number
name?: string
parent_id?: number
children?: deptTreeType[]
}
/* 角色选择器 */
export interface roleSelectorType {
id?: number
name?: string
status?: number
description?: string
}
/* 职位选择器 */
export interface positionSelectorType {
id?: number
name?: string
status?: number
description?: string
}
/* 个人中心用户信息表单 */
export interface UserProfileForm extends BaseFormType {
name?: string
gender?: string
mobile?: string
email?: string
username?: string
dept_name?: string
positions?: positionSelectorType[]
roles?: roleSelectorType[]
avatar?: string
created_time?: string
}
/* 修改密码表单 */
export interface PasswordChangeForm {
old_password: string
new_password: string
confirm_password: string
}
/* 重置密码表单 */
export interface ResetPasswordForm {
id: number
password: string
}
/* 批量设置状态 */
export interface BatchSetStatus {
ids: number[]
status: number
}