fix:完善门店和总部管理端
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { View, Text, Button } from '@tarojs/components';
|
||||
import Taro, { useRouter } from '@tarojs/taro';
|
||||
import type { PromoCodeItem, PromoCodeStats } from '@dukang/shared-types';
|
||||
import HqHeader from '../../components/HqHeader';
|
||||
import { request, toast } from '../../lib/api';
|
||||
import { useHqSession } from '../../lib/session';
|
||||
import { buildPromoQrDataUrl, promoConversion } from '../../lib/promo-qr';
|
||||
import './index.css';
|
||||
import './index.css';
|
||||
|
||||
type PromoDetail = PromoCodeItem & { stats?: PromoCodeStats };
|
||||
|
||||
export default function PromoDetailPage() {
|
||||
useHqSession();
|
||||
const router = useRouter();
|
||||
const id = router.params.id ?? '';
|
||||
const [row, setRow] = useState<PromoDetail | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [updating, setUpdating] = useState(false);
|
||||
const [qrUrl, setQrUrl] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
if (!id) return;
|
||||
setLoading(true);
|
||||
request<PromoDetail>(`/admin/promo-codes/${id}`)
|
||||
.then(setRow)
|
||||
.catch(() => setRow(null))
|
||||
.finally(() => setLoading(false));
|
||||
}, [id]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!row?.landingUrl) {
|
||||
setQrUrl('');
|
||||
return;
|
||||
}
|
||||
void buildPromoQrDataUrl(row.landingUrl).then(setQrUrl).catch(() => setQrUrl(''));
|
||||
}, [row?.landingUrl]);
|
||||
|
||||
async function toggleStatus() {
|
||||
if (!row) return;
|
||||
const next = row.status === 'ACTIVE' ? 'DISABLED' : 'ACTIVE';
|
||||
const label = next === 'DISABLED' ? '停用' : '启用';
|
||||
const ok = await Taro.showModal({
|
||||
title: `确认${label}`,
|
||||
content: next === 'DISABLED' ? '停用后扫码将不再追踪数据' : '启用后恢复追踪',
|
||||
});
|
||||
if (!ok.confirm) return;
|
||||
setUpdating(true);
|
||||
try {
|
||||
const updated = await request<PromoCodeItem>(`/admin/promo-codes/${id}/status`, {
|
||||
method: 'PUT',
|
||||
data: { status: next },
|
||||
});
|
||||
setRow((prev) => (prev ? { ...prev, ...updated } : updated));
|
||||
toast(`已${label}`, 'success');
|
||||
} catch (e) {
|
||||
toast(e instanceof Error ? e.message : '操作失败');
|
||||
} finally {
|
||||
setUpdating(false);
|
||||
}
|
||||
}
|
||||
|
||||
function copyLink() {
|
||||
if (!row?.landingUrl) return;
|
||||
Taro.setClipboardData({ data: row.landingUrl }).then(() => toast('推广链接已复制', 'success'));
|
||||
}
|
||||
|
||||
function downloadQr() {
|
||||
if (!qrUrl) return;
|
||||
if (process.env.TARO_ENV === 'h5') {
|
||||
const a = document.createElement('a');
|
||||
a.href = qrUrl;
|
||||
a.download = `promo-${row?.code ?? 'qr'}.png`;
|
||||
a.click();
|
||||
toast('已开始下载', 'success');
|
||||
return;
|
||||
}
|
||||
Taro.previewImage({ urls: [qrUrl] });
|
||||
}
|
||||
|
||||
const stats = row?.stats ?? (row ? {
|
||||
scanCount: row.scanCount,
|
||||
orderCount: row.orderCount,
|
||||
conversionRate: parseFloat(promoConversion(row.scanCount, row.orderCount)) || 0,
|
||||
} : null);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<View className="hq-page promo-page">
|
||||
<HqHeader title="推广码详情" back />
|
||||
<View className="promo-empty">加载中…</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (!row) {
|
||||
return (
|
||||
<View className="hq-page promo-page">
|
||||
<HqHeader title="推广码详情" back />
|
||||
<View className="promo-empty">推广码不存在</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View className="hq-page promo-page">
|
||||
<HqHeader title="推广码详情" back />
|
||||
|
||||
<View className="promo-detail-card">
|
||||
<View className="promo-detail-card__qr">
|
||||
{qrUrl ? (
|
||||
<View className="promo-result__qr" style={{ backgroundImage: `url(${qrUrl})` }} />
|
||||
) : null}
|
||||
</View>
|
||||
<View className="promo-detail-card__info">
|
||||
<Text className="promo-detail-card__name">{row.name}</Text>
|
||||
<Text
|
||||
className={`promo-card__badge ${
|
||||
row.status === 'ACTIVE' ? 'promo-card__badge--active' : 'promo-card__badge--disabled'
|
||||
}`}
|
||||
>
|
||||
{row.status === 'ACTIVE' ? '运行中' : '已停用'}
|
||||
</Text>
|
||||
<Text className="promo-detail-card__meta">码值 {row.code}</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{stats && (
|
||||
<View className="promo-stats-grid">
|
||||
<View className="promo-stat-card">
|
||||
<Text className="material-symbols-outlined promo-stat-card__icon">visibility</Text>
|
||||
<Text className="promo-stat-card__label">扫码UV</Text>
|
||||
<Text className="promo-stat-card__value">{stats.scanCount}</Text>
|
||||
</View>
|
||||
<View className="promo-stat-card">
|
||||
<Text className="material-symbols-outlined promo-stat-card__icon">shopping_cart</Text>
|
||||
<Text className="promo-stat-card__label">下单数</Text>
|
||||
<Text className="promo-stat-card__value">{stats.orderCount}</Text>
|
||||
</View>
|
||||
<View className="promo-stat-card">
|
||||
<Text className="material-symbols-outlined promo-stat-card__icon">trending_up</Text>
|
||||
<Text className="promo-stat-card__label">转化率</Text>
|
||||
<Text className="promo-stat-card__value">{stats.conversionRate}%</Text>
|
||||
</View>
|
||||
<View className="promo-stat-card">
|
||||
<Text className="material-symbols-outlined promo-stat-card__icon">schedule</Text>
|
||||
<Text className="promo-stat-card__label">创建时间</Text>
|
||||
<Text className="promo-stat-card__value promo-stat-card__value--sm">
|
||||
{new Date(row.createdAt).toLocaleDateString('zh-CN')}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
<View className="hq-card" style="margin:0 16px">
|
||||
<Text className="hq-muted" style="display:block;font-size:12px;margin-bottom:8px">落地链接</Text>
|
||||
<Text style="display:block;font-size:13px;word-break:break-all">{row.landingUrl}</Text>
|
||||
</View>
|
||||
|
||||
<View className="promo-detail-actions">
|
||||
<Button className="hq-btn hq-btn--outline hq-btn--block" onClick={copyLink}>
|
||||
复制推广链接
|
||||
</Button>
|
||||
<Button className="hq-btn hq-btn--primary hq-btn--block" onClick={downloadQr}>
|
||||
下载二维码
|
||||
</Button>
|
||||
<Button
|
||||
className="hq-btn hq-btn--ghost hq-btn--block"
|
||||
loading={updating}
|
||||
disabled={updating}
|
||||
onClick={toggleStatus}
|
||||
>
|
||||
{row.status === 'ACTIVE' ? '停用推广码' : '启用推广码'}
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user