feat: polish reporting templates and shared controls
This commit is contained in:
@@ -3,6 +3,7 @@ import { Edit3, Eye, Plus, Search, Trash2 } from 'lucide-react';
|
||||
import { adminApi, type ClientSmsApplication, type ClientSmsSignature, type ClientSmsTemplate, type TenantOption } from '@/api/adminApi';
|
||||
import { formatDateTime } from '@/utils/dateTime';
|
||||
import { Breadcrumb, Button, Input, Modal, Pagination, Select, Tabs, Tag, Textarea } from '@/components/ui';
|
||||
import { replaceLeadingSmsSignature } from '@/utils/smsSignature';
|
||||
|
||||
type TemplateFormState = {
|
||||
tenantId: string;
|
||||
@@ -85,17 +86,25 @@ function TemplateFormModal({
|
||||
const [customVariable, setCustomVariable] = useState('');
|
||||
const [variablesOpen, setVariablesOpen] = useState(false);
|
||||
const contentRef = useRef<HTMLTextAreaElement>(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<TemplateFormState>({
|
||||
tenantId: item?.tenantId ?? '',
|
||||
applicationId: item?.applicationId ?? '',
|
||||
signatureId: item?.signatureId ?? '',
|
||||
name: item?.name ?? '',
|
||||
content: item?.content ?? '',
|
||||
content: initialContent,
|
||||
category: item?.category ?? '行业通知',
|
||||
variables: item?.variables?.map((variable) => ({ name: variable.name, example: variable.example ?? undefined, required: variable.required ?? true })) ?? [],
|
||||
});
|
||||
const tenantApplications = applications.filter((application) => application.tenantId === form.tenantId && application.status !== 'deleted');
|
||||
const tenantSignatures = signatures.filter((signature) => signature.tenantId === form.tenantId && signature.auditStatus !== 'deleted');
|
||||
const tenantSignatures = signatures.filter((signature) => (
|
||||
signature.tenantId === form.tenantId
|
||||
&& signature.auditStatus !== 'deleted'
|
||||
&& (!signature.applicationId || signature.applicationId === form.applicationId)
|
||||
));
|
||||
const currentVariables = form.variables.length ? form.variables : extractVariables(form.content);
|
||||
|
||||
function update<Key extends keyof TemplateFormState>(key: Key, value: TemplateFormState[Key]) {
|
||||
@@ -106,6 +115,14 @@ function TemplateFormModal({
|
||||
setForm((current) => ({ ...current, content, variables: extractVariables(content) }));
|
||||
}
|
||||
|
||||
function selectSignature(signatureId: string) {
|
||||
const signature = tenantSignatures.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) {
|
||||
@@ -132,7 +149,7 @@ function TemplateFormModal({
|
||||
footer={(
|
||||
<>
|
||||
<Button onClick={onClose} variant="ghost">取消</Button>
|
||||
<Button disabled={!form.tenantId || !form.applicationId || !form.name || !form.content.trim()} onClick={() => onSubmit({ ...form, variables: currentVariables })}>保存</Button>
|
||||
<Button disabled={!form.tenantId || !form.applicationId || !form.signatureId || !form.name || !form.content.trim()} onClick={() => onSubmit({ ...form, variables: currentVariables })}>保存</Button>
|
||||
</>
|
||||
)}
|
||||
onClose={onClose}
|
||||
@@ -164,19 +181,21 @@ function TemplateFormModal({
|
||||
/>
|
||||
<Select
|
||||
label="签名"
|
||||
onChange={(event) => update('signatureId', event.target.value)}
|
||||
onChange={(event) => selectSignature(event.target.value)}
|
||||
options={[
|
||||
{ label: '不绑定签名', value: '' },
|
||||
{ label: '请选择签名', value: '' },
|
||||
...tenantSignatures.map((signature) => ({ label: signature.name, value: signature.id })),
|
||||
]}
|
||||
required
|
||||
value={form.signatureId}
|
||||
/>
|
||||
<Input label="模板名称" onChange={(event) => update('name', event.target.value)} placeholder="请输入模板名称" required value={form.name} />
|
||||
<Input label="模板分类" onChange={(event) => update('category', event.target.value)} placeholder="行业通知/营销推广/验证码" value={form.category} />
|
||||
<Textarea
|
||||
hint="模板内容必须以所选签名开头;选择或切换签名时系统会自动填入或替换完整签名,例如:【XX公司】验证码为${code}。"
|
||||
label="模板内容"
|
||||
onChange={(event) => setContent(event.target.value)}
|
||||
placeholder="例如:尊敬的${name},您的验证码为${code}。"
|
||||
placeholder="请选择签名后填写正文,例如:尊敬的${name},您的验证码为${code}。"
|
||||
required
|
||||
rows={8}
|
||||
ref={contentRef}
|
||||
|
||||
Reference in New Issue
Block a user