feat:为webui配置名提供中文翻译,并修改优化布局

This commit is contained in:
SengokuCola
2026-05-06 15:45:50 +08:00
parent b3d16a5705
commit 8c73424583
24 changed files with 538 additions and 132 deletions

View File

@@ -1,6 +1,7 @@
import { useEffect, useMemo, useState } from 'react'
import { Textarea } from '@/components/ui/textarea'
import { resolveLocalizedText } from '@/lib/config-label'
import type { FieldHookComponent } from '@/lib/field-hooks'
import type { ConfigSchema, FieldSchema } from '@/types/config-schema'
@@ -15,7 +16,7 @@ function resolveLabel(schema?: ConfigSchema | FieldSchema, fieldPath?: string):
return fieldPath?.split('.').at(-1) || 'JSON 配置'
}
if ('label' in schema && schema.label) {
return schema.label
return resolveLocalizedText(schema.label, undefined, fieldPath?.split('.').at(-1) || 'JSON 配置')
}
if ('uiLabel' in schema && schema.uiLabel) {
return schema.uiLabel

View File

@@ -11,6 +11,7 @@ import {
CardTitle,
} from '@/components/ui/card'
import { DynamicConfigForm } from '@/components/dynamic-form/DynamicConfigForm'
import { resolveLocalizedText } from '@/lib/config-label'
import type { FieldHookComponent } from '@/lib/field-hooks'
import type { ConfigSchema, FieldSchema } from '@/types/config-schema'
@@ -49,7 +50,7 @@ function resolveLabel(schema?: ConfigSchema | FieldSchema, fieldPath?: string):
return fieldPath?.split('.').at(-1) ?? '列表配置'
}
if ('label' in schema && schema.label) {
return schema.label
return resolveLocalizedText(schema.label, undefined, fieldPath?.split('.').at(-1) ?? '列表配置')
}
if ('uiLabel' in schema && schema.uiLabel) {
return schema.uiLabel

View File

@@ -294,6 +294,120 @@ export const BotPlatformsHook: FieldHookComponent = ({ onChange, value }) => {
)
}
export const HiddenFieldHook: FieldHookComponent = () => null
export const BotPlatformAccountsHook: FieldHookComponent = ({
onChange,
onParentChange,
parentValues,
value,
}) => {
const primaryPlatform = typeof value === 'string' ? value : ''
const qqAccountValue = parentValues?.qq_account
const qqAccount =
typeof qqAccountValue === 'string' || typeof qqAccountValue === 'number'
? String(qqAccountValue)
: ''
const platforms = normalizePlatformAccounts(parentValues?.platforms)
const rows = platforms.map(parsePlatformAccount)
const updateRows = (nextRows: PlatformAccountRow[]) => {
onParentChange?.('platforms', nextRows.map(formatPlatformAccount))
}
const addRow = () => {
updateRows([...rows, { platform: '', account: '' }])
}
const removeRow = (rowIndex: number) => {
updateRows(rows.filter((_, index) => index !== rowIndex))
}
const updateRow = (rowIndex: number, patch: Partial<PlatformAccountRow>) => {
updateRows(rows.map((row, index) => (index === rowIndex ? { ...row, ...patch } : row)))
}
return (
<div className="space-y-3">
<div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
<div className="space-y-1">
<Label className="text-[15px] font-semibold leading-6"></Label>
<p className="text-xs text-muted-foreground">
platform qq_account platforms
</p>
</div>
<Button type="button" size="sm" variant="outline" onClick={addRow}>
<Plus className="mr-2 h-4 w-4" />
</Button>
</div>
<div className="space-y-2">
<div className="grid gap-2 rounded-md border bg-muted/20 p-3 sm:grid-cols-[minmax(7rem,0.6fr)_minmax(10rem,1fr)_2.5rem]">
<div className="space-y-1">
<Label className="text-xs"></Label>
<Input
value={primaryPlatform}
placeholder="qq"
onChange={(event) => onChange?.(event.target.value)}
/>
</div>
<div className="space-y-1">
<Label className="text-xs"></Label>
<Input
className="font-mono"
value={qqAccount}
placeholder="2814567326"
onChange={(event) => onParentChange?.('qq_account', event.target.value)}
/>
</div>
<div className="flex items-end justify-end">
<span className="rounded-md bg-primary/10 px-2 py-1 text-xs font-medium text-primary">
</span>
</div>
</div>
{rows.map((row, rowIndex) => (
<div
key={rowIndex}
className="grid gap-2 rounded-md border bg-muted/20 p-3 sm:grid-cols-[minmax(7rem,0.6fr)_minmax(10rem,1fr)_2.5rem]"
>
<div className="space-y-1">
<Label className="text-xs"></Label>
<Input
value={row.platform}
placeholder="wx"
onChange={(event) => updateRow(rowIndex, { platform: event.target.value })}
/>
</div>
<div className="space-y-1">
<Label className="text-xs"></Label>
<Input
className="font-mono"
value={row.account}
placeholder="114514"
onChange={(event) => updateRow(rowIndex, { account: event.target.value })}
/>
</div>
<div className="flex items-end justify-end">
<Button
type="button"
size="icon"
variant="ghost"
aria-label={`删除其他平台 ${rowIndex + 1}`}
onClick={() => removeRow(rowIndex)}
>
<Trash2 className="h-4 w-4" />
</Button>
</div>
</div>
))}
</div>
</div>
)
}
export const KeywordRulesHook = createListItemEditorHook({
addLabel: '添加关键词规则',
helperText: '匹配命中后会用 reaction 内容作为额外上下文。keywords 至少填一条,或使用正则模式。',

View File

@@ -12,11 +12,13 @@ export type {
} from './useAutoSave'
export {
BotPlatformsHook,
BotPlatformAccountsHook,
ChatPromptsHook,
ChatTalkValueRulesHook,
ExpressionGroupsHook,
ExpressionLearningListHook,
KeywordRulesHook,
HiddenFieldHook,
MCPRootItemsHook,
MCPServersHook,
RegexRulesHook,