Files
dukang/apps/mini-hq/src/pages/promo/generate.tsx
T
2026-08-04 21:38:49 +08:00

127 lines
4.1 KiB
TypeScript

import { useEffect, useState } from 'react';
import { View, Text, Input, Button } from '@tarojs/components';
import Taro from '@tarojs/taro';
import type { PromoCodeItem } from '@dukang/shared-types';
import HqHeader from '../../components/HqHeader';
import { request, toast } from '../../lib/api';
import { useHqSession } from '../../lib/session';
import { navTo } from '../../lib/session';
import { buildPromoQrDataUrl } from '../../lib/promo-qr';
import './index.css';
import './index.css';
export default function PromoGeneratePage() {
useHqSession();
const [name, setName] = useState('');
const [code, setCode] = useState('');
const [creating, setCreating] = useState(false);
const [created, setCreated] = useState<PromoCodeItem | null>(null);
const [qrUrl, setQrUrl] = useState('');
useEffect(() => {
if (!created?.landingUrl) {
setQrUrl('');
return;
}
void buildPromoQrDataUrl(created.landingUrl).then(setQrUrl).catch(() => setQrUrl(''));
}, [created]);
async function handleGenerate() {
const trimmed = name.trim();
if (!trimmed) {
toast('请填写渠道名称');
return;
}
setCreating(true);
try {
const payload: { name: string; code?: string } = { name: trimmed };
if (code.trim()) payload.code = code.trim().toUpperCase();
const row = await request<PromoCodeItem>('/admin/promo-codes', {
method: 'POST',
data: payload,
});
setCreated(row);
toast('推广码已生成', 'success');
} catch (e) {
toast(e instanceof Error ? e.message : '生成失败');
} finally {
setCreating(false);
}
}
function copyLink() {
if (!created?.landingUrl) return;
Taro.setClipboardData({ data: created.landingUrl }).then(() => toast('推广链接已复制', 'success'));
}
return (
<View className="hq-page promo-page">
<HqHeader title="生成推广码" back />
<View className="hq-card" style="margin:16px">
<Text style="display:block;font-size:14px;color:var(--hq-muted);margin-bottom:16px">
填写渠道信息,生成专属溯源推广码与落地链接。
</Text>
<Text className="hq-label">渠道名称 *</Text>
<Input
className="hq-input"
placeholder="如:郑州品鉴会、门店地推"
value={name}
onInput={(e) => setName(e.detail.value)}
/>
<Text className="hq-label" style="margin-top:16px">自定义码值(选填)</Text>
<Input
className="hq-input"
placeholder="留空则系统自动生成,如 DKDEMO1"
value={code}
onInput={(e) => setCode(e.detail.value.toUpperCase())}
/>
<Button
className="hq-btn hq-btn--primary hq-btn--block"
style="margin-top:20px"
loading={creating}
disabled={creating}
onClick={handleGenerate}
>
生成推广码
</Button>
</View>
{created && (
<View className="promo-result">
<View className="promo-result__qr-wrap">
{qrUrl ? (
<View
className="promo-result__qr"
style={{ backgroundImage: `url(${qrUrl})` }}
/>
) : (
<View className="promo-result__qr promo-result__qr--loading">
<Text className="material-symbols-outlined">hourglass_top</Text>
</View>
)}
</View>
<Text className="promo-result__title">{created.name}</Text>
<Text className="promo-result__code">码值:{created.code}</Text>
<View className="promo-result__actions">
<View className="promo-card__btn promo-card__btn--outline" onClick={copyLink}>
<Text className="material-symbols-outlined" style="font-size:18px">link</Text>
<Text>复制链接</Text>
</View>
<View
className="promo-card__btn promo-card__btn--ghost"
onClick={() => navTo(`/pages/promo/detail?id=${created.id}`)}
>
<Text>查看详情</Text>
</View>
</View>
</View>
)}
</View>
);
}