diff --git a/apps/admin-web/src/components/ConfigMediaFields.tsx b/apps/admin-web/src/components/ConfigMediaFields.tsx new file mode 100644 index 0000000..33c67af --- /dev/null +++ b/apps/admin-web/src/components/ConfigMediaFields.tsx @@ -0,0 +1,114 @@ +import { Button, Space } from 'antd'; +import { ArrowDownOutlined, ArrowUpOutlined, DeleteOutlined, PlusOutlined } from '@ant-design/icons'; +import { + parseMiniHomeBanners, + serializeMiniHomeBanners, +} from '@dukang/shared-types'; +import OssUpload from './OssUpload'; + +const MAX_BANNERS = 8; + +/** Ant Form 控件:单图 URL 字符串(默认 OSS 路径 footer) */ +export function ConfigImageField({ + value, + onChange, + bizType = 'footer', +}: { + value?: string; + onChange?: (url: string) => void; + bizType?: string; +}) { + return ( + + ); +} + +/** Ant Form 控件:多图 JSON 字符串(默认 OSS 路径 swiper) */ +export function ConfigImageListField({ + value, + onChange, + bizType = 'swiper', +}: { + value?: string; + onChange?: (json: string) => void; + bizType?: string; +}) { + const urls = parseMiniHomeBanners(value); + + function commit(next: string[]) { + onChange?.(serializeMiniHomeBanners(next)); + } + + function updateAt(index: number, url: string) { + const next = [...urls]; + next[index] = url; + commit(next); + } + + function removeAt(index: number) { + commit(urls.filter((_, i) => i !== index)); + } + + function move(index: number, delta: number) { + const target = index + delta; + if (target < 0 || target >= urls.length) return; + const next = [...urls]; + const tmp = next[index]; + next[index] = next[target]; + next[target] = tmp; + commit(next); + } + + function add() { + if (urls.length >= MAX_BANNERS) return; + commit([...urls, '']); + } + + return ( + + {urls.map((url, index) => ( + +
+ updateAt(index, u)} + placeholder="上传或粘贴图片 URL" + /> +
+ + + + ); +} diff --git a/apps/admin-web/src/pages/SystemSettingsPage.tsx b/apps/admin-web/src/pages/SystemSettingsPage.tsx index 4b27e1d..b9e1fab 100644 --- a/apps/admin-web/src/pages/SystemSettingsPage.tsx +++ b/apps/admin-web/src/pages/SystemSettingsPage.tsx @@ -31,10 +31,8 @@ import { } from 'antd'; import type { MockSmsCodeItem, SystemConfigFieldMeta, SystemConfigFormResponse } from '@dukang/shared-types'; - import { request } from '../lib/api'; - - +import { ConfigImageField, ConfigImageListField } from '../components/ConfigMediaFields'; const { TextArea } = Input; @@ -131,123 +129,89 @@ function renderField( const isConfiguredSecret = field.secret && configuredSecrets.includes(field.key); if (field.type === 'boolean') { - return ( -
- - {field.label} - - {field.key} - - {field.requiresRestart ? 需重启 : 即时} - - } - tooltip={field.description} - valuePropName="checked" - getValueFromEvent={(checked: boolean) => (checked ? 'true' : 'false')} - getValueProps={(v: string) => ({ checked: v === 'true' || v === '1' })} - > - - - {extra} -
- ); - } - + if (field.type === 'image' || field.type === 'imageList') { + return ( + + {field.label} + + {field.key} + + {field.requiresRestart ? 需重启 : 即时} +
+ } + tooltip={field.description} + > + {field.type === 'image' ? ( + + ) : ( + + )} + + ); + } const input = - field.type === 'textarea' ? ( -