import { useEffect, useMemo, useRef, useState } from 'react'; import { Edit3, MessageSquare, Plus, Search, Trash2 } from 'lucide-react'; import { Button, Input, Modal, Pagination, Select, Tag, Textarea } from '@/components/ui'; import { clientApi, type ClientSmsApplication, type ClientSmsSignature, type ClientSmsTemplate } from '@/api/adminApi'; import { formatDateTime } from '@/utils/dateTime'; import { replaceLeadingSmsSignature } from '@/utils/smsSignature'; type TemplateVariable = { name: string; example?: string; required?: boolean; }; type TemplateFormState = { applicationId: string; signatureId: string; name: string; category: string; content: string; variables: TemplateVariable[]; }; const statusTone: Record = { approved: 'success', pending: 'info', rejected: 'danger', draft: 'warning', }; const statusLabel: Record = { approved: '已通过', pending: '审核中', rejected: '已驳回', draft: '草稿', disabled: '已禁用', }; const recommendedVariables = [ ['验证码', 'code'], ['手机号', 'phone'], ['姓名', 'name'], ['日期', 'date'], ['金额', 'amount'], ['时间', 'time'], ['余额', 'balance'], ['地址', 'address'], ['快递单号', 'trackingNumber'], ['链接', 'link'], ]; function extractVariables(content: string): TemplateVariable[] { return Array.from(new Set(Array.from(content.matchAll(/\$\{([^}]+)\}/g)).map((match) => match[1]))) .map((name) => ({ name, required: true })); } function billingUnits(content: string) { if (!content) return 1; return content.length <= 70 ? 1 : Math.ceil(content.length / 67); } function TemplateModal({ applications, item, onClose, onSubmit, signatures, }: { applications: ClientSmsApplication[]; item?: ClientSmsTemplate; onClose: () => void; onSubmit: (state: TemplateFormState) => void; signatures: ClientSmsSignature[]; }) { const [customVariable, setCustomVariable] = useState(''); const [variablesOpen, setVariablesOpen] = useState(false); const contentRef = useRef(null); const initialSignature = signatures.find((signature) => signature.id === item?.signatureId); const initialContent = item?.signatureId ? replaceLeadingSmsSignature(item.content, initialSignature?.name) : item?.content ?? ''; const [form, setForm] = useState({ applicationId: item?.applicationId ?? '', signatureId: item?.signatureId ?? '', name: item?.name ?? '', category: item?.category ?? '行业通知', content: initialContent, variables: item?.variables?.map((variable) => ({ name: variable.name, example: variable.example ?? undefined, required: variable.required ?? true })) ?? [], }); const application = applications.find((candidate) => candidate.id === form.applicationId); const availableSignatures = signatures.filter((signature) => ( signature.auditStatus === 'approved' && (!application || signature.tenantId === application.tenantId) && (!signature.applicationId || signature.applicationId === form.applicationId) )); const variables = form.variables.length ? form.variables : extractVariables(form.content); function update(key: Key, value: TemplateFormState[Key]) { setForm((current) => ({ ...current, [key]: value })); } function setContent(content: string) { setForm((current) => ({ ...current, content, variables: extractVariables(content) })); } function selectSignature(signatureId: string) { const signature = availableSignatures.find((candidate) => candidate.id === signatureId); setForm((current) => { const content = replaceLeadingSmsSignature(current.content, signature?.name); return { ...current, signatureId, content, variables: extractVariables(content) }; }); } function insertVariable(name: string) { const normalized = name.trim(); if (!normalized) return; const token = `\${${normalized}}`; const textarea = contentRef.current; const start = textarea?.selectionStart ?? form.content.length; const end = textarea?.selectionEnd ?? start; setContent(`${form.content.slice(0, start)}${token}${form.content.slice(end)}`); requestAnimationFrame(() => { contentRef.current?.focus(); contentRef.current?.setSelectionRange(start + token.length, start + token.length); }); } function updateVariableExample(name: string, example: string) { update('variables', variables.map((variable) => variable.name === name ? { ...variable, example } : variable)); } return ( )} onClose={onClose} open size="xl" title={item ? '编辑短信模板' : '添加短信模板'} >
selectSignature(event.target.value)} options={[{ label: '请选择签名', value: '' }, ...availableSignatures.map((signature) => ({ label: signature.name, value: signature.id }))]} required value={form.signatureId} /> update('name', event.target.value)} placeholder="请输入模板名称" value={form.name} /> update('category', event.target.value)} placeholder="行业通知/营销推广/验证码" value={form.category} />