feat(settings): accept duration units while preserving seconds
douyin-release-gate / verify (push) Failing after 18m35s
douyin-release-gate / verify (push) Failing after 18m35s
This commit is contained in:
@@ -4,21 +4,50 @@ import { Alert, App, Button, Card, Flex, Form, Input, InputNumber, Select, Tabs,
|
||||
import { creatorAction, creatorGet, creatorUpdate } from '@/services/api';
|
||||
import { conflictMessage } from '@/utils/helpers';
|
||||
|
||||
const numericFields = new Set([
|
||||
'lookback_days',
|
||||
const durationFields = new Set([
|
||||
'new_work_interval_seconds',
|
||||
'metric_initial_interval_seconds',
|
||||
'metric_multiplier',
|
||||
'metric_max_interval_seconds',
|
||||
'metric_age_seconds',
|
||||
]);
|
||||
const numericFields = new Set(['lookback_days', 'metric_multiplier']);
|
||||
const editableFields = [
|
||||
...numericFields,
|
||||
...durationFields,
|
||||
'ai_base_url',
|
||||
'ai_api_key',
|
||||
'ai_model',
|
||||
];
|
||||
const editableSettings = (value: any) => Object.fromEntries(editableFields.map((field) => [field, value[field]]));
|
||||
// Match the backend's maximum whole-second Go time.Duration.
|
||||
const maxDurationSeconds = 9223372036;
|
||||
const durationHelp = '正整数 + 单位:s 秒、m 分钟、h 小时,例如 30s、5m、2h;数字与单位间可有空格。';
|
||||
|
||||
function parseDuration(value: unknown): number {
|
||||
const match = typeof value === 'string' && /^(\d+)\s*([smh])$/i.exec(value.trim());
|
||||
if (!match || Number(match[1]) <= 0) {
|
||||
throw new Error('请输入正整数和单位,例如 30s、5m 或 2h。');
|
||||
}
|
||||
const multiplier = { s: 1, m: 60, h: 3600 }[match[2].toLowerCase() as 's' | 'm' | 'h'];
|
||||
const seconds = Number(match[1]) * multiplier;
|
||||
if (!Number.isSafeInteger(seconds) || seconds > maxDurationSeconds) {
|
||||
throw new Error('时长过大,请缩短。');
|
||||
}
|
||||
return seconds;
|
||||
}
|
||||
|
||||
function formatDuration(seconds: number): string {
|
||||
if (!Number.isSafeInteger(seconds) || seconds <= 0 || seconds > maxDurationSeconds) {
|
||||
throw new Error('读取的采集时长无效,请检查已保存的设置。');
|
||||
}
|
||||
if (seconds % 3600 === 0) return `${seconds / 3600}h`;
|
||||
if (seconds % 60 === 0) return `${seconds / 60}m`;
|
||||
return `${seconds}s`;
|
||||
}
|
||||
|
||||
const durationRules = [{ validator: async (_: unknown, value: unknown) => { parseDuration(value); } }];
|
||||
const editableSettings = (value: any) => Object.fromEntries(editableFields.map((field) => [
|
||||
field, durationFields.has(field) ? formatDuration(value[field]) : value[field],
|
||||
]));
|
||||
|
||||
type ModelList = {
|
||||
baseURL: string;
|
||||
@@ -109,7 +138,9 @@ export default function Page() {
|
||||
}
|
||||
setBusy(true);
|
||||
try {
|
||||
const payload = Object.fromEntries(editableFields.map((field) => [field, numericFields.has(field) ? values[field] ?? 0 : String(values[field] ?? '').trim()]));
|
||||
const payload = Object.fromEntries(editableFields.map((field) => [
|
||||
field, durationFields.has(field) ? parseDuration(values[field]) : numericFields.has(field) ? values[field] ?? 0 : String(values[field] ?? '').trim(),
|
||||
]));
|
||||
const result = await creatorUpdate('/creator/settings', payload);
|
||||
form.setFieldsValue(editableSettings(result));
|
||||
messageApi.success('采集与 AI 配置已保存。');
|
||||
@@ -137,8 +168,8 @@ export default function Page() {
|
||||
<Form.Item name="lookback_days" label="竞品回溯天数" extra="首次回溯默认 30 天;不会猜测缺失发布时间。">
|
||||
<InputNumber min={1} style={{ width: 200 }} />
|
||||
</Form.Item>
|
||||
<Form.Item name="new_work_interval_seconds" label="新作品/一级评论间隔(秒)">
|
||||
<InputNumber min={1} style={{ width: 200 }} />
|
||||
<Form.Item name="new_work_interval_seconds" label="新作品/一级评论间隔" extra={durationHelp} rules={durationRules}>
|
||||
<Input placeholder="例如 30m" style={{ width: 200 }} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
),
|
||||
@@ -147,17 +178,17 @@ export default function Page() {
|
||||
key: 'metrics', label: '指标采集', forceRender: true,
|
||||
children: (
|
||||
<div style={{ maxWidth: 640 }}>
|
||||
<Form.Item name="metric_initial_interval_seconds" label="指标首次间隔(秒)">
|
||||
<InputNumber min={1} style={{ width: 200 }} />
|
||||
<Form.Item name="metric_initial_interval_seconds" label="指标首次间隔" extra={durationHelp} rules={durationRules}>
|
||||
<Input placeholder="例如 1h" style={{ width: 200 }} />
|
||||
</Form.Item>
|
||||
<Form.Item name="metric_multiplier" label="指标间隔倍数">
|
||||
<InputNumber min={1.01} step={0.01} style={{ width: 200 }} />
|
||||
</Form.Item>
|
||||
<Form.Item name="metric_max_interval_seconds" label="指标最大间隔(秒)">
|
||||
<InputNumber min={1} style={{ width: 200 }} />
|
||||
<Form.Item name="metric_max_interval_seconds" label="指标最大间隔" extra={durationHelp} rules={durationRules}>
|
||||
<Input placeholder="例如 24h" style={{ width: 200 }} />
|
||||
</Form.Item>
|
||||
<Form.Item name="metric_age_seconds" label="指标监测最长时长(秒)">
|
||||
<InputNumber min={1} style={{ width: 200 }} />
|
||||
<Form.Item name="metric_age_seconds" label="指标监测最长时长" extra={durationHelp} rules={durationRules}>
|
||||
<Input placeholder="例如 720h" style={{ width: 200 }} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user