feat: v3.4.12 ticket iteration
Refund rollback, winery T+3, multi withdraw, mini-user store detail, dev plan batch edit and WeCom dispatch, support ticket edit/attachments/batch status, package imageUrl. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Alert, Button, Form, Input, InputNumber, Space, Typography, message } from 'antd';
|
||||
import { Alert, Button, Form, Input, InputNumber, Modal, Space, Typography, message } from 'antd';
|
||||
import { DownOutlined, UpOutlined } from '@ant-design/icons';
|
||||
import type { StorePackageItemDto } from '@dukang/shared-types';
|
||||
import { STORE_PACKAGE_MAX_COUNT } from '@dukang/shared-types';
|
||||
import { request } from '../lib/api';
|
||||
|
||||
import OssUpload from './OssUpload';
|
||||
type PackageRow = StorePackageItemDto;
|
||||
|
||||
function emptyRow(index = 0): PackageRow {
|
||||
return { name: '', price: '0', dishes: '', usableTime: '', otherNotes: '', sortOrder: index };
|
||||
return { name: '', price: '0', dishes: '', usableTime: '', otherNotes: '', imageUrl: '', sortOrder: index };
|
||||
}
|
||||
|
||||
export default function AdminStorePackagesSection({ storeId }: { storeId: string }) {
|
||||
@@ -41,18 +41,33 @@ export default function AdminStorePackagesSection({ storeId }: { storeId: string
|
||||
}
|
||||
|
||||
function removeAt(index: number) {
|
||||
setItems((prev) => prev.filter((_, i) => i !== index).map((item, i) => ({ ...item, sortOrder: i })));
|
||||
setCollapsed((prev) => {
|
||||
const next: Record<number, boolean> = {};
|
||||
Object.entries(prev).forEach(([k, v]) => {
|
||||
const i = Number(k);
|
||||
if (i < index) next[i] = v;
|
||||
else if (i > index) next[i - 1] = v;
|
||||
const run = () => {
|
||||
setItems((prev) => {
|
||||
const next = prev.filter((_, i) => i !== index).map((item, i) => ({ ...item, sortOrder: i }));
|
||||
return next.length ? next : [];
|
||||
});
|
||||
return next;
|
||||
});
|
||||
setCollapsed((prev) => {
|
||||
const next: Record<number, boolean> = {};
|
||||
Object.entries(prev).forEach(([k, v]) => {
|
||||
const i = Number(k);
|
||||
if (i < index) next[i] = v;
|
||||
else if (i > index) next[i - 1] = v;
|
||||
});
|
||||
return next;
|
||||
});
|
||||
};
|
||||
if (items.length === 1) {
|
||||
Modal.confirm({
|
||||
title: '清空门店套餐',
|
||||
content: '删除最后一条套餐后,该门店将无展示套餐,确认继续?',
|
||||
okText: '确认删除',
|
||||
cancelText: '取消',
|
||||
onOk: run,
|
||||
});
|
||||
return;
|
||||
}
|
||||
run();
|
||||
}
|
||||
|
||||
function toggleCollapse(index: number) {
|
||||
setCollapsed((prev) => ({ ...prev, [index]: !prev[index] }));
|
||||
}
|
||||
@@ -65,6 +80,7 @@ export default function AdminStorePackagesSection({ storeId }: { storeId: string
|
||||
dishes: item.dishes.trim(),
|
||||
usableTime: item.usableTime?.trim() || null,
|
||||
otherNotes: item.otherNotes?.trim() || null,
|
||||
imageUrl: item.imageUrl?.trim() || null,
|
||||
sortOrder: index,
|
||||
}))
|
||||
.filter((item) => item.name || item.dishes || item.price);
|
||||
@@ -106,8 +122,21 @@ export default function AdminStorePackagesSection({ storeId }: { storeId: string
|
||||
return <Typography.Text type="secondary">加载套餐中…</Typography.Text>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Form layout="vertical" requiredMark={false}>
|
||||
if (!items.length) {
|
||||
return (
|
||||
<Form layout="vertical" requiredMark={false}>
|
||||
<Alert type="info" showIcon style={{ marginBottom: 16 }} message="该门店暂无套餐,可添加或保存为空。" />
|
||||
<Button onClick={addRow} style={{ marginBottom: 16 }}>
|
||||
添加套餐
|
||||
</Button>
|
||||
<Button type="primary" loading={saving} onClick={() => void save()}>
|
||||
保存套餐
|
||||
</Button>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
return ( <Form layout="vertical" requiredMark={false}>
|
||||
<Alert
|
||||
type="info"
|
||||
showIcon
|
||||
@@ -140,12 +169,11 @@ export default function AdminStorePackagesSection({ storeId }: { storeId: string
|
||||
{displayName}
|
||||
</Typography.Title>
|
||||
</Button>
|
||||
{items.length > 1 ? (
|
||||
{items.length > 0 ? (
|
||||
<Button type="link" danger onClick={() => removeAt(index)}>
|
||||
删除
|
||||
</Button>
|
||||
) : null}
|
||||
</Space>
|
||||
) : null} </Space>
|
||||
|
||||
{!isCollapsed ? (
|
||||
<>
|
||||
@@ -186,8 +214,16 @@ export default function AdminStorePackagesSection({ storeId }: { storeId: string
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="其他说明" style={{ marginBottom: 0 }}>
|
||||
<Input
|
||||
<Form.Item label="套餐图片" style={{ marginBottom: 12 }}>
|
||||
<OssUpload
|
||||
bizType="STORE_PACKAGE"
|
||||
mediaType="IMAGE"
|
||||
value={item.imageUrl || undefined}
|
||||
onChange={(url) => updateAt(index, { imageUrl: url })}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="其他说明" style={{ marginBottom: 0 }}> <Input
|
||||
placeholder="不可叠加"
|
||||
value={item.otherNotes || ''}
|
||||
onChange={(e) => updateAt(index, { otherNotes: e.target.value })}
|
||||
|
||||
Reference in New Issue
Block a user