fix: 1. 接入入口模块的管理接口,优化样式。

2. 将查看文档评查结果详情对接接口,采用接口的方式进行查询。
This commit is contained in:
2025-11-26 23:37:14 +08:00
parent ae24b82384
commit d5827a2146
13 changed files with 563 additions and 673 deletions
+217 -102
View File
@@ -1,9 +1,19 @@
/**
* 入口模块管理 API 客户端
* 提供入口模块的增删改查功能
* API 文档: auth_doc/ENTRY_MODULE_API.md
*/
import { postgrestGet, postgrestPost, postgrestPut, postgrestDelete } from "../postgrest-client";
import { get, post, put, del } from "../axios-client";
/**
* 地区配置接口
*/
export interface AreaConfig {
area: string; // 地区名称(如:梅州、云浮、揭阳、潮州)
enabled: boolean; // 是否启用(默认 true
sort_order: number; // 排序号(默认 0
}
/**
* 入口模块数据接口
@@ -11,9 +21,9 @@ import { postgrestGet, postgrestPost, postgrestPut, postgrestDelete } from "../p
export interface EntryModule {
id?: number;
name: string;
description?: string;
path?: string; // logo图片路径
areas?: string[]; // 地区数组
description?: string | null;
path?: string | null; // logo图片路径
areas?: AreaConfig[] | null; // 地区配置列表
created_at?: string;
updated_at?: string;
}
@@ -25,7 +35,7 @@ export interface EntryModuleSearchParams {
name?: string;
area?: string;
page?: number;
pageSize?: number;
page_size?: number; // 注意:API使用page_size而不是pageSize
}
/**
@@ -36,83 +46,94 @@ export interface EntryModulesResponse {
total: number;
}
/**
* API统一响应格式
* 注意:后端返回的字段是 msg 而不是 messagecode 为 0 表示成功
*/
interface ApiResponse<T> {
code: number; // 0 表示成功
msg: string; // 消息(不是 message
data: T;
}
/**
* 列表数据响应格式
*/
interface ListResponse<T> {
total: number;
page: number;
page_size: number;
items: T[];
}
/**
* 获取入口模块列表
* @param searchParams 搜索参数
* @param jwtToken JWT令牌
* @returns 入口模块列表和总数
*
* 注意:不需要传递 JWTaxios-client 会自动从 localStorage 读取并添加
*/
export async function getEntryModules(
searchParams: EntryModuleSearchParams = {},
jwtToken?: string | null
searchParams: EntryModuleSearchParams = {}
): Promise<{ data?: EntryModulesResponse; error?: string }> {
try {
const { name, area, page = 1, pageSize = 10 } = searchParams;
const { name, area, page = 1, page_size = 10 } = searchParams;
// 构建过滤条件
const filter: Record<string, string> = {};
// 构建查询参数
const queryParams: Record<string, any> = {
page,
page_size
};
if (name) {
filter.name = `ilike.*${name}*`;
queryParams.name = name;
}
// 如果有地区筛选,使用 JSONB 查询
if (area) {
filter.areas = `cs.{"${area}"}`; // cs = contains (JSONB数组包含)
queryParams.area = area;
}
// 计算分页
const offset = (page - 1) * pageSize;
// 调用 API
const response = await get<ApiResponse<ListResponse<EntryModule>>>(
'/api/v3/entry-modules',
queryParams
);
// 构建查询参数(一次请求获取数据和总数)
const queryParams: any = {
select: "*",
order: "created_at.desc",
limit: pageSize,
offset: offset,
headers: {
'Prefer': 'count=exact'
},
token: jwtToken
};
// 只在有过滤条件时添加 filter
if (Object.keys(filter).length > 0) {
queryParams.filter = filter;
if (response.error) {
console.error('❌ [getEntryModules] API错误:', response.error);
return { error: response.error };
}
// 获取分页数据
const result = await postgrestGet<EntryModule[]>("entry_modules", queryParams);
// 🔑 解析响应数据
// axios-client 返回: { data: {后端JSON}, status: 200 }
// 后端返回: { code: 0, msg: "成功", data: { total, items } }
const backendResponse = response.data;
if (result.error) {
return { error: result.error };
if (!backendResponse) {
console.error('❌ [getEntryModules] 响应为空');
return { error: '响应为空' };
}
// 从 Content-Range 头获取总数
let totalCount = 0;
const responseWithHeaders = result as {
data: unknown;
headers?: Record<string, string>;
};
// 检查后端返回的 code(0 表示成功)
if (backendResponse.code !== 0) {
console.error('❌ [getEntryModules] 后端返回错误:', backendResponse.msg);
return { error: backendResponse.msg || '请求失败' };
}
if (responseWithHeaders.headers) {
const rangeHeader = responseWithHeaders.headers['content-range'];
if (rangeHeader) {
const total = rangeHeader.split('/')[1];
if (total !== '*') {
totalCount = parseInt(total, 10);
}
}
const apiData = backendResponse.data;
if (!apiData) {
console.error('❌ [getEntryModules] data 字段为空');
return { error: '数据为空' };
}
return {
data: {
modules: result.data || [],
total: totalCount || (result.data?.length || 0)
modules: apiData.items || [],
total: apiData.total || 0
}
};
} catch (error) {
console.error("获取入口模块列表失败:", error);
console.error("❌ [getEntryModules] 获取入口模块列表失败:", error);
return { error: error instanceof Error ? error.message : "获取入口模块列表失败" };
}
}
@@ -120,31 +141,39 @@ export async function getEntryModules(
/**
* 根据ID获取入口模块
* @param id 入口模块ID
* @param jwtToken JWT令牌
* @returns 入口模块数据
*
* 注意:不需要传递 JWTaxios-client 会自动从 localStorage 读取并添加
*/
export async function getEntryModuleById(
id: number,
jwtToken?: string | null
id: number
): Promise<{ data?: EntryModule; error?: string }> {
try {
const result = await postgrestGet<EntryModule[]>("entry_modules", {
filter: { id: `eq.${id}` },
token: jwtToken
});
// 调用 API
const response = await get<ApiResponse<EntryModule>>(
`/api/v3/entry-modules/${id}`
);
if (result.error) {
return { error: result.error };
if (response.error) {
console.error('❌ [getEntryModuleById] API错误:', response.error);
return { error: response.error };
}
const module = result.data?.[0];
const backendResponse = response.data;
if (!backendResponse || backendResponse.code !== 0) {
console.error('❌ [getEntryModuleById] 后端返回错误:', backendResponse?.msg);
return { error: backendResponse?.msg || '获取失败' };
}
const module = backendResponse.data;
if (!module) {
console.error('❌ [getEntryModuleById] 入口模块不存在');
return { error: "入口模块不存在" };
}
return { data: module };
} catch (error) {
console.error("获取入口模块失败:", error);
console.error("❌ [getEntryModuleById] 获取入口模块失败:", error);
return { error: error instanceof Error ? error.message : "获取入口模块失败" };
}
}
@@ -152,28 +181,69 @@ export async function getEntryModuleById(
/**
* 创建入口模块
* @param module 入口模块数据
* @param jwtToken JWT令牌
* @returns 创建的入口模块
*
* 注意:不需要传递 JWTaxios-client 会自动从 localStorage 读取并添加
*/
export async function createEntryModule(
module: Omit<EntryModule, "id" | "created_at" | "updated_at">,
jwtToken?: string | null
module: {
name: string;
description?: string;
path?: string | null;
areas?: string[] | AreaConfig[]; // 兼容两种格式
}
): Promise<{ data?: EntryModule; error?: string }> {
try {
const result = await postgrestPost<EntryModule[], EntryModule>(
"entry_modules",
module as EntryModule,
jwtToken
);
if (result.error) {
return { error: result.error };
// 转换 areas 格式(如果是字符串数组,转换为 AreaConfig 数组)
let areasConfig: AreaConfig[] | undefined;
if (module.areas && Array.isArray(module.areas)) {
if (typeof module.areas[0] === 'string') {
// 字符串数组转换为 AreaConfig 数组
areasConfig = (module.areas as string[]).map((area, index) => ({
area,
enabled: true,
sort_order: index + 1
}));
} else {
// 已经是 AreaConfig 数组
areasConfig = module.areas as AreaConfig[];
}
}
const createdModule = Array.isArray(result.data) ? result.data[0] : result.data;
return { data: createdModule as EntryModule };
// 构建请求体
const requestBody = {
name: module.name,
description: module.description || undefined,
path: module.path || undefined,
areas: areasConfig
};
// 调用 API
const response = await post<ApiResponse<EntryModule>>(
'/api/v3/entry-modules',
requestBody
);
if (response.error) {
console.error('❌ [createEntryModule] API错误:', response.error);
return { error: response.error };
}
const backendResponse = response.data;
if (!backendResponse || backendResponse.code !== 0) {
console.error('❌ [createEntryModule] 后端返回错误:', backendResponse?.msg);
return { error: backendResponse?.msg || '创建失败' };
}
const createdModule = backendResponse.data;
if (!createdModule) {
console.error('❌ [createEntryModule] 响应数据格式错误');
return { error: '创建失败:响应数据格式错误' };
}
return { data: createdModule };
} catch (error) {
console.error("创建入口模块失败:", error);
console.error("❌ [createEntryModule] 创建入口模块失败:", error);
return { error: error instanceof Error ? error.message : "创建入口模块失败" };
}
}
@@ -182,30 +252,69 @@ export async function createEntryModule(
* 更新入口模块
* @param id 入口模块ID
* @param module 更新的入口模块数据
* @param jwtToken JWT令牌
* @returns 更新的入口模块
*
* 注意:不需要传递 JWTaxios-client 会自动从 localStorage 读取并添加
*/
export async function updateEntryModule(
id: number,
module: Partial<Omit<EntryModule, "id" | "created_at" | "updated_at">>,
jwtToken?: string | null
module: {
name?: string;
description?: string;
path?: string | null;
areas?: string[] | AreaConfig[]; // 兼容两种格式
}
): Promise<{ data?: EntryModule; error?: string }> {
try {
const result = await postgrestPut<EntryModule[], Partial<EntryModule>>(
"entry_modules",
module,
{ id: `eq.${id}` },
jwtToken
);
if (result.error) {
return { error: result.error };
// 转换 areas 格式(如果是字符串数组,转换为 AreaConfig 数组)
let areasConfig: AreaConfig[] | undefined;
if (module.areas && Array.isArray(module.areas)) {
if (typeof module.areas[0] === 'string') {
// 字符串数组转换为 AreaConfig 数组
areasConfig = (module.areas as string[]).map((area, index) => ({
area,
enabled: true,
sort_order: index + 1
}));
} else {
// 已经是 AreaConfig 数组
areasConfig = module.areas as AreaConfig[];
}
}
const updatedModule = Array.isArray(result.data) ? result.data[0] : result.data;
return { data: updatedModule as EntryModule };
// 构建请求体(只包含需要更新的字段)
const requestBody: any = {};
if (module.name !== undefined) requestBody.name = module.name;
if (module.description !== undefined) requestBody.description = module.description;
if (module.path !== undefined) requestBody.path = module.path;
if (areasConfig !== undefined) requestBody.areas = areasConfig;
// 调用 API
const response = await put<ApiResponse<EntryModule>>(
`/api/v3/entry-modules/${id}`,
requestBody
);
if (response.error) {
console.error('❌ [updateEntryModule] API错误:', response.error);
return { error: response.error };
}
const backendResponse = response.data;
if (!backendResponse || backendResponse.code !== 0) {
console.error('❌ [updateEntryModule] 后端返回错误:', backendResponse?.msg);
return { error: backendResponse?.msg || '更新失败' };
}
const updatedModule = backendResponse.data;
if (!updatedModule) {
console.error('❌ [updateEntryModule] 响应数据格式错误');
return { error: '更新失败:响应数据格式错误' };
}
return { data: updatedModule };
} catch (error) {
console.error("更新入口模块失败:", error);
console.error("❌ [updateEntryModule] 更新入口模块失败:", error);
return { error: error instanceof Error ? error.message : "更新入口模块失败" };
}
}
@@ -213,27 +322,33 @@ export async function updateEntryModule(
/**
* 删除入口模块
* @param id 入口模块ID
* @param jwtToken JWT令牌
* @returns 是否成功
*
* 注意:不需要传递 JWTaxios-client 会自动从 localStorage 读取并添加
*/
export async function deleteEntryModule(
id: number,
jwtToken?: string | null
id: number
): Promise<{ success: boolean; error?: string }> {
try {
const result = await postgrestDelete(
"entry_modules",
{ id: `eq.${id}` },
jwtToken
// 调用 API
const response = await del<ApiResponse<{ id: number; deleted: boolean }>>(
`/api/v3/entry-modules/${id}`
);
if (result.error) {
return { success: false, error: result.error };
if (response.error) {
console.error('❌ [deleteEntryModule] API错误:', response.error);
return { success: false, error: response.error };
}
const backendResponse = response.data;
if (!backendResponse || backendResponse.code !== 0) {
console.error('❌ [deleteEntryModule] 删除失败:', backendResponse?.msg);
return { success: false, error: backendResponse?.msg || '删除失败' };
}
return { success: true };
} catch (error) {
console.error("删除入口模块失败:", error);
console.error("❌ [deleteEntryModule] 删除入口模块失败:", error);
return {
success: false,
error: error instanceof Error ? error.message : "删除入口模块失败"