fix: 修复前端界面边界条件问题 #1

Merged
xiongyuxing merged 1 commits from wangziqi/tiku-backend.net:fix/frontend-boundary-conditions into main 2026-08-01 00:59:40 +00:00
5 changed files with 25 additions and 14 deletions

View File

@@ -64,7 +64,11 @@ export async function apiRequest<T = unknown>(
signal?: AbortSignal,
): Promise<T> {
const pathValues = (input.path || {}) as Record<string, unknown>;
let route = operation.path.replace(/\{([^}]+)\}/g, (_, name: string) => encodeURIComponent(String(pathValues[name] ?? '')));
let route = operation.path.replace(/\{([^}]+)\}/g, (_, name: string) => {
const value = pathValues[name];
if (value === undefined || value === null) throw new Error(`缺少必填路径参数:${name}`);
return encodeURIComponent(String(value));
});
const url = new URL(route, window.location.origin);
appendQuery(url, ((input.query || {}) as Record<string, unknown>));
route = `${url.pathname}${url.search}`;

View File

@@ -21,8 +21,11 @@ export const tokenStore = {
get: () => currentTokens,
set(tokens: TokenPair | null) {
currentTokens = tokens;
if (tokens) localStorage.setItem(storageKey, JSON.stringify(tokens));
else localStorage.removeItem(storageKey);
if (tokens) {
try { localStorage.setItem(storageKey, JSON.stringify(tokens)); } catch { /* quota exceeded — in-memory copy still valid */ }
} else {
localStorage.removeItem(storageKey);
}
window.dispatchEvent(new CustomEvent('platform-auth-change'));
},
};

View File

@@ -34,7 +34,7 @@ export function BusinessTable({ payload, loading, onSelect }: { payload: unknown
<Table
loading={loading}
dataSource={rows}
rowKey={(row, index) => String(row.id || row.tenantId || row.code || index)}
rowKey={(row, index) => String(row.id ?? row.tenantId ?? row.code ?? index)}
rowSelection={{ type: 'radio', onChange: (_, selected) => onSelect(selected[0] || null) }}
scroll={{ x: 'max-content' }}
pagination={{ pageSize: 20, showSizeChanger: true, showTotal: (total) => `${total}` }}

View File

@@ -27,7 +27,7 @@ export function ResponseView({ payload }: { payload: unknown }) {
return (
<Table
size="small"
rowKey={(row, index) => String(row.id || row.code || row.userId || index)}
rowKey={(row, index) => String(row.id ?? row.code ?? row.userId ?? index)}
dataSource={rows}
scroll={{ x: 'max-content' }}
pagination={{ pageSize: 20, showSizeChanger: true }}

View File

@@ -75,18 +75,21 @@ function toTree(nodes: BankNode[]): DataNode[] {
const key = node.parentId || null;
children.set(key, [...(children.get(key) || []), node]);
}
const build = (parentId: string | null): DataNode[] => (children.get(parentId) || [])
.sort((a, b) => Number(a.sortOrder) - Number(b.sortOrder))
.map((node) => ({
key: node.id,
title: <Flex justify="space-between" gap={8}><span>{node.name}</span><Badge count={Number(node.questionCount)} showZero color="#b9c4cf" /></Flex>,
children: build(node.id),
}));
const build = (parentId: string | null, depth = 0): DataNode[] => {
if (depth > 50) return [];
return (children.get(parentId) || [])
.sort((a, b) => Number(a.sortOrder) - Number(b.sortOrder))
.map((node) => ({
key: node.id,
title: <Flex justify="space-between" gap={8}><span>{node.name}</span><Badge count={Number(node.questionCount)} showZero color="#b9c4cf" /></Flex>,
children: build(node.id, depth + 1),
}));
};
return build(null);
}
function parseJson(value: string | undefined, fallback: unknown) {
if (!value?.trim()) return fallback;
function parseJson(value: unknown, fallback: unknown) {
if (typeof value !== 'string' || !value.trim()) return fallback;
return JSON.parse(value);
}
@@ -197,6 +200,7 @@ export function QuestionBankPage() {
const saveBatchNodes = async () => {
const values = await batchForm.validateFields();
const names = String(values.names).split(/\n|,/).map((item) => item.trim()).filter(Boolean);
if (!names.length) return message.error('请输入至少一个节点名称');
if (names.length > 100) return message.error('一次最多创建 100 个节点');
await platformRequest('POST', '/api/platform-admin/question-banks/nodes/batch', { body: { questionBankId: bankId, parentId: values.parentId || null, nodeType: values.nodeType, names } });
message.success(`已创建 ${names.length} 个节点`); setBatchNodeOpen(false); batchForm.resetFields(); await loadNodes();