From 589ecd06f053624273239d2c056a75b2c7717a3e Mon Sep 17 00:00:00 2001 From: wangziqi Date: Thu, 30 Jul 2026 17:08:03 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E7=95=8C=E9=9D=A2=E8=BE=B9=E7=95=8C=E6=9D=A1=E4=BB=B6=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - rowKey 使用 ?? 替代 ||,避免合法值 0 被当作 falsy - parseJson 增加非字符串类型防御检查 - toTree 增加递归深度限制防止循环引用栈溢出 - saveBatchNodes 增加空名称数组检查 - localStorage.setItem 捕获 QuotaExceededError - 路径参数缺失时显式抛出错误而非静默替换 --- Tiku.PlatformAdmin.Web/src/api/http.ts | 6 ++++- Tiku.PlatformAdmin.Web/src/api/token-store.ts | 7 ++++-- .../src/components/BusinessTable.tsx | 2 +- .../src/components/ResponseView.tsx | 2 +- .../src/pages/QuestionBankPage.tsx | 22 +++++++++++-------- 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/Tiku.PlatformAdmin.Web/src/api/http.ts b/Tiku.PlatformAdmin.Web/src/api/http.ts index 93c572e..983b811 100644 --- a/Tiku.PlatformAdmin.Web/src/api/http.ts +++ b/Tiku.PlatformAdmin.Web/src/api/http.ts @@ -64,7 +64,11 @@ export async function apiRequest( signal?: AbortSignal, ): Promise { const pathValues = (input.path || {}) as Record; - 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)); route = `${url.pathname}${url.search}`; diff --git a/Tiku.PlatformAdmin.Web/src/api/token-store.ts b/Tiku.PlatformAdmin.Web/src/api/token-store.ts index 4d85e9c..0991bb8 100644 --- a/Tiku.PlatformAdmin.Web/src/api/token-store.ts +++ b/Tiku.PlatformAdmin.Web/src/api/token-store.ts @@ -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')); }, }; diff --git a/Tiku.PlatformAdmin.Web/src/components/BusinessTable.tsx b/Tiku.PlatformAdmin.Web/src/components/BusinessTable.tsx index 3660823..a4b1af6 100644 --- a/Tiku.PlatformAdmin.Web/src/components/BusinessTable.tsx +++ b/Tiku.PlatformAdmin.Web/src/components/BusinessTable.tsx @@ -34,7 +34,7 @@ export function BusinessTable({ payload, loading, onSelect }: { payload: unknown 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} 条` }} diff --git a/Tiku.PlatformAdmin.Web/src/components/ResponseView.tsx b/Tiku.PlatformAdmin.Web/src/components/ResponseView.tsx index e45baed..42a778b 100644 --- a/Tiku.PlatformAdmin.Web/src/components/ResponseView.tsx +++ b/Tiku.PlatformAdmin.Web/src/components/ResponseView.tsx @@ -27,7 +27,7 @@ export function ResponseView({ payload }: { payload: unknown }) { return (
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 }} diff --git a/Tiku.PlatformAdmin.Web/src/pages/QuestionBankPage.tsx b/Tiku.PlatformAdmin.Web/src/pages/QuestionBankPage.tsx index dab191a..54b300f 100644 --- a/Tiku.PlatformAdmin.Web/src/pages/QuestionBankPage.tsx +++ b/Tiku.PlatformAdmin.Web/src/pages/QuestionBankPage.tsx @@ -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: {node.name}, - 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: {node.name}, + 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();