127 lines
4.1 KiB
TypeScript
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>
|
|
);
|
|
}
|