feat(store): add store sortOrder and swipeable package gallery
Enable HQ-controlled store list ordering and horizontal multi-image browsing on package detail. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -27,6 +27,7 @@ export type StoreCreateForm = {
|
||||
bankAccountNo: string;
|
||||
bankBranch: string;
|
||||
settlementRate?: number;
|
||||
sortOrder?: number;
|
||||
visibilityWhitelistEnabled?: boolean;
|
||||
visibilityPhones?: string[];
|
||||
};
|
||||
|
||||
@@ -192,6 +192,7 @@ type StoreRow = {
|
||||
closeTime2?: string | null;
|
||||
avgPrice?: number | null;
|
||||
settlementRate?: number;
|
||||
sortOrder?: number;
|
||||
category?: { id: string; name: string; parentId?: string | null } | null;
|
||||
};
|
||||
|
||||
@@ -409,6 +410,7 @@ export default function StoresPage() {
|
||||
? (d.visibilityPhones as string[])
|
||||
: [],
|
||||
isTest: !!d.isTest,
|
||||
sortOrder: d.sortOrder != null ? Number(d.sortOrder) : 0,
|
||||
});
|
||||
setDrawerOpen(true);
|
||||
}
|
||||
@@ -454,6 +456,7 @@ export default function StoresPage() {
|
||||
bankBranch: v.bankBranch ?? null,
|
||||
visibilityWhitelistEnabled: !!v.visibilityWhitelistEnabled,
|
||||
isTest: !!v.isTest,
|
||||
sortOrder: v.sortOrder != null ? Number(v.sortOrder) : 0,
|
||||
...(hasCoords
|
||||
? { latitude: Number(v.latitude), longitude: Number(v.longitude) }
|
||||
: {}),
|
||||
@@ -538,6 +541,7 @@ export default function StoresPage() {
|
||||
createForm.setFieldsValue({
|
||||
envPhotoUrls: [],
|
||||
settlementRate: 60,
|
||||
sortOrder: 0,
|
||||
openTime: '10:00',
|
||||
closeTime: '22:00',
|
||||
openTime2: undefined,
|
||||
@@ -626,6 +630,7 @@ export default function StoresPage() {
|
||||
bankAccountNo: values.bankAccountNo.replace(/\s/g, ''),
|
||||
bankBranch: values.bankBranch.trim(),
|
||||
settlementRate: Number(values.settlementRate ?? 60) / 100,
|
||||
sortOrder: values.sortOrder != null ? Number(values.sortOrder) : 0,
|
||||
visibilityWhitelistEnabled: !!values.visibilityWhitelistEnabled,
|
||||
}),
|
||||
});
|
||||
@@ -699,6 +704,7 @@ export default function StoresPage() {
|
||||
v ? <Tag color="orange">限测</Tag> : <Tag>公开</Tag>,
|
||||
},
|
||||
{ title: '介绍', dataIndex: 'intro', width: 160, ellipsis: true, render: (v) => v || '—' },
|
||||
{ title: '排序', dataIndex: 'sortOrder', width: 70 },
|
||||
{ title: '店长', dataIndex: ['account', 'name'], width: 90, render: (v) => v || '—' },
|
||||
{ title: '创建', dataIndex: 'createdAt', width: 160, render: fmtTime },
|
||||
{
|
||||
@@ -978,6 +984,13 @@ export default function StoresPage() {
|
||||
<Form.Item name="avgPrice" label="人均费用(选填)">
|
||||
<InputNumber min={0} precision={0} style={{ width: '100%' }} addonAfter="元" placeholder="用户端展示" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="sortOrder"
|
||||
label="排序"
|
||||
extra="数值越小越靠前;同排序时按距离(有定位)或创建时间"
|
||||
>
|
||||
<InputNumber min={0} precision={0} style={{ width: '100%' }} placeholder="0" />
|
||||
</Form.Item>
|
||||
<Space wrap style={{ width: '100%' }}>
|
||||
<Form.Item name="openTime" label="营业开始" rules={[{ required: true }]}>
|
||||
<Input type="time" style={{ width: 140 }} />
|
||||
@@ -1154,6 +1167,9 @@ export default function StoresPage() {
|
||||
<Form.Item name="phone" label="门店手机号(登录账号)" rules={[{ required: true, message: '请填写门店手机号' }]}>
|
||||
<Input placeholder="11位手机号" />
|
||||
</Form.Item>
|
||||
<Form.Item name="sortOrder" label="排序" extra="数值越小越靠前">
|
||||
<InputNumber min={0} precision={0} style={{ width: '100%' }} placeholder="0" />
|
||||
</Form.Item>
|
||||
<Form.Item name="address" label="详细地址" rules={[{ required: true, message: '请填写详细地址' }]}>
|
||||
<Input.TextArea rows={2} placeholder="请输入详细门牌号" />
|
||||
</Form.Item>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import { View, Text, Image } from '@tarojs/components';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import Taro, { useLoad, useRouter } from '@tarojs/taro';
|
||||
import { normalizeStorePackageImageUrls } from '@dukang/shared-types';
|
||||
import PageShell from '../../components/PageShell';
|
||||
import PageNavBar from '../../components/PageNavBar';
|
||||
import ProductCarousel from '../../components/ProductCarousel';
|
||||
import { request, toast } from '../../lib/api';
|
||||
|
||||
type StorePackage = {
|
||||
@@ -99,10 +100,6 @@ export default function StorePackageDetailPage() {
|
||||
}
|
||||
}
|
||||
|
||||
function previewImage(urls: string[], current: string) {
|
||||
Taro.previewImage({ urls, current }).catch(() => toast('无法预览图片'));
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<PageShell variant="scroll" className="store-package-detail-page">
|
||||
@@ -139,19 +136,16 @@ export default function StorePackageDetailPage() {
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
{imageUrls.map((url) => (
|
||||
<View
|
||||
key={url}
|
||||
className="store-package-detail-photo"
|
||||
onClick={() => previewImage(imageUrls, url)}
|
||||
>
|
||||
<Image
|
||||
className="store-package-detail-photo-image"
|
||||
src={url}
|
||||
mode="widthFix"
|
||||
{imageUrls.length > 0 ? (
|
||||
<View className="store-package-detail-gallery">
|
||||
<ProductCarousel
|
||||
images={imageUrls}
|
||||
alt={pkg.name}
|
||||
variant="detail"
|
||||
previewable
|
||||
/>
|
||||
</View>
|
||||
))}
|
||||
) : null}
|
||||
|
||||
<View className="store-package-detail-content">
|
||||
<View className="store-detail-package-field">
|
||||
|
||||
@@ -352,7 +352,7 @@
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.store-package-detail-photo {
|
||||
.store-package-detail-gallery {
|
||||
margin: 14px 0 0;
|
||||
border-radius: var(--radius-lg);
|
||||
overflow: hidden;
|
||||
@@ -360,10 +360,8 @@
|
||||
box-shadow: var(--shadow-card);
|
||||
}
|
||||
|
||||
.store-package-detail-photo-image {
|
||||
width: 100%;
|
||||
display: block;
|
||||
vertical-align: top;
|
||||
.store-package-detail-gallery .detail-carousel-wrap {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.store-package-detail-content {
|
||||
|
||||
Reference in New Issue
Block a user