fix(admin): improve promo layout and system settings save UX
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:
2026-07-23 13:54:10 +08:00
parent 479de04f7c
commit d11757c854
5 changed files with 206 additions and 288 deletions
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useState, type CSSProperties } from 'react';
import { useOutletContext } from 'react-router-dom';
import {
Button,
@@ -25,6 +25,15 @@ import { request } from '../../lib/api';
import { fmtTime } from '../../lib/constants';
import type { PromoCodeDetailContext } from './PromoCodeDetailLayout';
const descLabelStyle: CSSProperties = {
whiteSpace: 'nowrap',
width: 108,
};
const descContentStyle: CSSProperties = {
wordBreak: 'break-all',
};
async function downloadQrcode(url: string, filename: string) {
try {
const res = await fetch(url);
@@ -72,49 +81,25 @@ export default function PromoCodeDetailPage() {
return (
<>
<Row gutter={[16, 16]}>
<Col xs={24} lg={8}>
<Card title="小程序码" size="small">
{detail.qrcodeUrl ? (
<div style={{ textAlign: 'center' }}>
<img
src={detail.qrcodeUrl}
alt="推广小程序码"
style={{ width: 200, height: 200, marginBottom: 12 }}
/>
<Typography.Paragraph type="secondary" style={{ marginBottom: 12, fontSize: 12 }}>
scene= ID {detail.id}
</Typography.Paragraph>
<Space direction="vertical" style={{ width: '100%' }}>
<Button
block
onClick={() => void downloadQrcode(detail.qrcodeUrl!, `${detail.code}-wxacode.png`)}
>
</Button>
</Space>
</div>
) : (
<Typography.Text type="secondary"></Typography.Text>
)}
</Card>
</Col>
<Col xs={24} lg={16}>
<Row gutter={[16, 16]} align="top">
<Col flex="1 1 480px" style={{ minWidth: 0 }}>
<Card
title="基础信息"
size="small"
styles={{ body: { paddingTop: 12 } }}
extra={(
<Space>
<Button size="small" onClick={() => {
editForm.setFieldsValue({
name: detail.name,
scene: detail.scene,
remark: detail.remark,
ownerUserId: detail.ownerUser?.id,
});
setEditOpen(true);
}}
<Button
size="small"
onClick={() => {
editForm.setFieldsValue({
name: detail.name,
scene: detail.scene,
remark: detail.remark,
ownerUserId: detail.ownerUser?.id,
});
setEditOpen(true);
}}
>
</Button>
@@ -138,7 +123,18 @@ export default function PromoCodeDetailPage() {
</Space>
)}
>
<Descriptions column={{ xs: 1, sm: 2 }} bordered size="small">
<Descriptions
column={2}
bordered
size="small"
layout="horizontal"
labelStyle={descLabelStyle}
contentStyle={descContentStyle}
styles={{
label: descLabelStyle,
content: descContentStyle,
}}
>
<Descriptions.Item label="名称">{detail.name}</Descriptions.Item>
<Descriptions.Item label="码值">{detail.code}</Descriptions.Item>
<Descriptions.Item label="场景">
@@ -147,30 +143,67 @@ export default function PromoCodeDetailPage() {
<Descriptions.Item label="状态">
{PROMO_CODE_STATUS_LABELS[detail.status] || detail.status}
</Descriptions.Item>
<Descriptions.Item label="活动 ID" span={2}>
<Typography.Text copyable={{ text: String(detail.id) }}>
{detail.id} scene
<Descriptions.Item label="活动 ID">
<Typography.Text copyable={{ text: String(detail.id) }} style={{ whiteSpace: 'nowrap' }}>
{detail.id}
</Typography.Text>
</Descriptions.Item>
<Descriptions.Item label="二维码 ID" span={2}>
<Typography.Text copyable={{ text: detail.qrcodeId }}>{detail.qrcodeId}</Typography.Text>
<Descriptions.Item label="二维码 ID">
<Typography.Text copyable={{ text: detail.qrcodeId }} style={{ whiteSpace: 'nowrap' }}>
{detail.qrcodeId}
</Typography.Text>
</Descriptions.Item>
<Descriptions.Item label="小程序码 OSS" span={2}>
{detail.qrcodeUrl ? (
<Typography.Text copyable={{ text: detail.qrcodeUrl }} ellipsis>
<Typography.Text copyable={{ text: detail.qrcodeUrl }} ellipsis style={{ maxWidth: '100%' }}>
{detail.qrcodeUrl}
</Typography.Text>
) : '—'}
</Descriptions.Item>
<Descriptions.Item label="渠道负责人">
{detail.ownerUser?.userNo || detail.ownerUser?.phone || '—'}
<span style={{ whiteSpace: 'nowrap' }}>
{detail.ownerUser?.userNo || detail.ownerUser?.phone || '—'}
</span>
</Descriptions.Item>
<Descriptions.Item label="备注">{detail.remark || '—'}</Descriptions.Item>
<Descriptions.Item label="创建时间">{fmtTime(detail.createdAt)}</Descriptions.Item>
<Descriptions.Item label="更新时间">{fmtTime(detail.updatedAt)}</Descriptions.Item>
<Descriptions.Item label="创建时间">
<span style={{ whiteSpace: 'nowrap' }}>{fmtTime(detail.createdAt)}</span>
</Descriptions.Item>
<Descriptions.Item label="更新时间">
<span style={{ whiteSpace: 'nowrap' }}>{fmtTime(detail.updatedAt)}</span>
</Descriptions.Item>
</Descriptions>
</Card>
</Col>
<Col flex="0 0 220px">
<Card title="小程序码" size="small" styles={{ body: { textAlign: 'center', padding: 12 } }}>
{detail.qrcodeUrl ? (
<>
<img
src={detail.qrcodeUrl}
alt="推广小程序码"
style={{ width: 168, height: 168, display: 'block', margin: '0 auto 8px' }}
/>
<Typography.Paragraph
type="secondary"
style={{ marginBottom: 8, fontSize: 12, whiteSpace: 'nowrap' }}
>
scene={detail.id}
</Typography.Paragraph>
<Button
block
size="small"
onClick={() => void downloadQrcode(detail.qrcodeUrl!, `${detail.code}-wxacode.png`)}
>
</Button>
</>
) : (
<Typography.Text type="secondary"></Typography.Text>
)}
</Card>
</Col>
</Row>
<Row gutter={16} style={{ marginTop: 16 }}>