fix(industry): 二次审计修复 — 2 CRITICAL + 4 HIGH + 2 MEDIUM
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
C-1: Industries.tsx 创建弹窗缺少 id 字段 → 添加 id 输入框 + 自动生成 C-2: Accounts.tsx handleSave 无 try/catch → 包装 + handleClose 统一关闭 V1: viking_commands Mutex 跨 await → 先 clone Arc 再释放 Mutex I1: intelligence_hooks 误导性"相关度" → 移除 access_count 伪分数 I2: pain point 摘要未 XML 转义 → xml_escape() 处理 S1: industry status 无枚举验证 → active/inactive 白名单 S2: create_industry id 无格式验证 → 正则 + 长度检查 H-3: Industries.tsx 编辑模态数据竞争 → data.id === industryId 守卫 H-4: Accounts.tsx useEffect 覆盖用户编辑 → editingId 守卫
This commit is contained in:
@@ -62,22 +62,21 @@ export default function Accounts() {
|
||||
enabled: !!editingId,
|
||||
})
|
||||
|
||||
// 当账户行业数据加载完,同步到表单
|
||||
// 当账户行业数据加载完且正在编辑时,同步到表单
|
||||
// Guard: only sync when editingId matches the query key
|
||||
useEffect(() => {
|
||||
if (accountIndustries) {
|
||||
if (accountIndustries && editingId) {
|
||||
const ids = accountIndustries.map((item) => item.industry_id)
|
||||
setEditingIndustries(ids)
|
||||
form.setFieldValue('industry_ids', ids)
|
||||
}
|
||||
}, [accountIndustries, form])
|
||||
}, [accountIndustries, editingId, form])
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: ({ id, data }: { id: string; data: Partial<AccountPublic> }) =>
|
||||
accountService.update(id, data),
|
||||
onSuccess: () => {
|
||||
message.success('更新成功')
|
||||
queryClient.invalidateQueries({ queryKey: ['accounts'] })
|
||||
setModalOpen(false)
|
||||
},
|
||||
onError: (err: Error) => message.error(err.message || '更新失败'),
|
||||
})
|
||||
@@ -185,7 +184,9 @@ export default function Accounts() {
|
||||
|
||||
const handleSave = async () => {
|
||||
const values = await form.validateFields()
|
||||
if (editingId) {
|
||||
if (!editingId) return
|
||||
|
||||
try {
|
||||
// 更新基础信息
|
||||
const { industry_ids, ...accountData } = values
|
||||
await updateMutation.mutateAsync({ id: editingId, data: accountData })
|
||||
@@ -201,6 +202,10 @@ export default function Accounts() {
|
||||
message.success('行业授权已更新')
|
||||
queryClient.invalidateQueries({ queryKey: ['account-industries'] })
|
||||
}
|
||||
|
||||
handleClose()
|
||||
} catch {
|
||||
// Errors handled by mutation onError callbacks
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ function IndustryEditModal({ open, industryId, onClose }: {
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (data && open) {
|
||||
if (data && open && data.id === industryId) {
|
||||
form.setFieldsValue({
|
||||
name: data.name,
|
||||
icon: data.icon,
|
||||
@@ -202,7 +202,7 @@ function IndustryEditModal({ open, industryId, onClose }: {
|
||||
pain_seed_categories: data.pain_seed_categories,
|
||||
})
|
||||
}
|
||||
}, [data, open, form])
|
||||
}, [data, open, industryId, form])
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: (body: UpdateIndustryRequest) =>
|
||||
@@ -306,11 +306,25 @@ function IndustryCreateModal({ open, onClose }: {
|
||||
layout="vertical"
|
||||
className="mt-4"
|
||||
initialValues={{ icon: '🏢' }}
|
||||
onFinish={(values) => createMutation.mutate(values)}
|
||||
onFinish={(values) => {
|
||||
// Auto-generate id from name if not provided
|
||||
if (!values.id && values.name) {
|
||||
values.id = values.name.toLowerCase()
|
||||
.replace(/[^a-z0-9\u4e00-\u9fff]+/g, '-')
|
||||
.replace(/^-|-$/g, '')
|
||||
}
|
||||
createMutation.mutate(values)
|
||||
}}
|
||||
>
|
||||
<Form.Item name="name" label="行业名称" rules={[{ required: true, message: '请输入行业名称' }]}>
|
||||
<Input placeholder="如:医疗健康、教育培训" />
|
||||
</Form.Item>
|
||||
<Form.Item name="id" label="行业标识" extra="唯一标识,留空则从名称自动生成。仅限小写字母、数字、连字符" rules={[
|
||||
{ pattern: /^[a-z0-9-]*$/, message: '仅限小写字母、数字、连字符' },
|
||||
{ max: 63, message: '最长 63 字符' },
|
||||
]}>
|
||||
<Input placeholder="如:healthcare、education" />
|
||||
</Form.Item>
|
||||
<Form.Item name="icon" label="图标">
|
||||
<Input placeholder="行业图标 emoji" className="w-32" />
|
||||
</Form.Item>
|
||||
|
||||
Reference in New Issue
Block a user