fix(admin): improve promo layout and system settings save UX
CI / verify (pull_request) Has been cancelled
CI / verify (pull_request) Has been cancelled
Fix mini home media form persistence; float save with unsaved leave prompt; promo detail QR on the right. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Button, Space } from 'antd';
|
||||
import { ArrowDownOutlined, ArrowUpOutlined, DeleteOutlined, PlusOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
@@ -8,6 +9,21 @@ import OssUpload from './OssUpload';
|
||||
|
||||
const MAX_BANNERS = 8;
|
||||
|
||||
/** 编辑态保留空位;下发/入库仍用 parseMiniHomeBanners 过滤空串 */
|
||||
function parseBannersForEdit(raw?: string | null): string[] {
|
||||
if (!raw?.trim()) return [];
|
||||
try {
|
||||
const parsed = JSON.parse(raw.trim()) as unknown;
|
||||
if (!Array.isArray(parsed)) return parseMiniHomeBanners(raw);
|
||||
return parsed
|
||||
.filter((u): u is string => typeof u === 'string')
|
||||
.map((u) => u.trim())
|
||||
.slice(0, MAX_BANNERS);
|
||||
} catch {
|
||||
return parseMiniHomeBanners(raw);
|
||||
}
|
||||
}
|
||||
|
||||
/** Ant Form 控件:单图 URL 字符串(默认 OSS 路径 footer) */
|
||||
export function ConfigImageField({
|
||||
value,
|
||||
@@ -22,8 +38,8 @@ export function ConfigImageField({
|
||||
<OssUpload
|
||||
bizType={bizType}
|
||||
mediaType="IMAGE"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
value={value ?? ''}
|
||||
onChange={(url) => onChange?.(url ?? '')}
|
||||
placeholder="上传或粘贴图片 URL"
|
||||
/>
|
||||
);
|
||||
@@ -39,10 +55,17 @@ export function ConfigImageListField({
|
||||
onChange?: (json: string) => void;
|
||||
bizType?: string;
|
||||
}) {
|
||||
const urls = parseMiniHomeBanners(value);
|
||||
const [urls, setUrls] = useState<string[]>(() => parseBannersForEdit(value));
|
||||
|
||||
useEffect(() => {
|
||||
setUrls(parseBannersForEdit(value));
|
||||
}, [value]);
|
||||
|
||||
/** 本地可含空位;写入 Form 时去掉空串 */
|
||||
function commit(next: string[]) {
|
||||
onChange?.(serializeMiniHomeBanners(next));
|
||||
const clipped = next.slice(0, MAX_BANNERS);
|
||||
setUrls(clipped);
|
||||
onChange?.(serializeMiniHomeBanners(clipped));
|
||||
}
|
||||
|
||||
function updateAt(index: number, url: string) {
|
||||
@@ -67,13 +90,14 @@ export function ConfigImageListField({
|
||||
|
||||
function add() {
|
||||
if (urls.length >= MAX_BANNERS) return;
|
||||
commit([...urls, '']);
|
||||
// 只加本地空位,避免 serialize 过滤空串导致「点击无反应」
|
||||
setUrls((prev) => [...prev, '']);
|
||||
}
|
||||
|
||||
return (
|
||||
<Space direction="vertical" style={{ width: '100%' }} size="middle">
|
||||
{urls.map((url, index) => (
|
||||
<Space key={`${index}-${url || 'empty'}`} align="start" style={{ width: '100%' }} wrap>
|
||||
<Space key={`banner-${index}`} align="start" style={{ width: '100%' }} wrap>
|
||||
<div style={{ flex: 1, minWidth: 240 }}>
|
||||
<OssUpload
|
||||
bizType={bizType}
|
||||
|
||||
Reference in New Issue
Block a user