Files
smart-crop-ui/crop-x/src/app/(app)/central-config/message/send/components/SendMessageDialog.tsx

258 lines
9.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState } from 'react';
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Card } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Calendar } from '@/components/ui/calendar';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { Send, Clock, CalendarIcon } from 'lucide-react';
import { format } from 'date-fns';
import { zhCN } from 'date-fns/locale';
import { MessageTemplate } from '@/types/message';
import { MessageSendFormData } from '../types';
interface SendMessageDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
templates: MessageTemplate[];
formData: MessageSendFormData;
onFormDataChange: (data: MessageSendFormData) => void;
onSend: () => void;
getTypeIcon: (type: string) => JSX.Element;
getTypeLabel: (type: string) => string;
}
export function SendMessageDialog({
open,
onOpenChange,
templates,
formData,
onFormDataChange,
onSend,
getTypeIcon,
getTypeLabel
}: SendMessageDialogProps) {
const replaceVariables = (content: string, variables: Record<string, string>): string => {
let result = content;
Object.entries(variables).forEach(([key, value]) => {
result = result.replace(new RegExp(`\\{\\{${key}\\}\\}`, 'g'), value || `{{${key}}}`);
});
return result;
};
const handleTemplateChange = (templateId: string) => {
const template = templates.find(t => t.id === templateId);
if (template) {
// 初始化变量
const vars: Record<string, string> = {};
template.variables.forEach(v => {
vars[v] = '';
});
onFormDataChange({
...formData,
templateId,
type: template.type,
subject: template.subject || '',
content: template.content,
variables: vars,
});
}
};
const selectedTemplate = templates.find(t => t.id === formData.templateId);
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-3xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>
<div className="flex items-center gap-2">
<Send className="w-5 h-5 text-green-600" />
</div>
</DialogTitle>
<DialogDescription className="sr-only">
</DialogDescription>
</DialogHeader>
<div className="space-y-4">
{/* 选择模版 */}
<div>
<Label> *</Label>
<Select value={formData.templateId} onValueChange={handleTemplateChange}>
<SelectTrigger>
<SelectValue placeholder="请选择消息模版" />
</SelectTrigger>
<SelectContent>
{templates.filter(t => t.isActive).map(template => (
<SelectItem key={template.id} value={template.id}>
<div className="flex items-center gap-2">
{getTypeIcon(template.type)}
<span>{template.name}</span>
<Badge variant="outline" className="text-xs">
{getTypeLabel(template.type)}
</Badge>
</div>
</SelectItem>
))}
</SelectContent>
</Select>
</div>
{/* 发送方式 */}
<div>
<Label> *</Label>
<Select
value={formData.sendType}
onValueChange={(value: 'immediate' | 'scheduled') => onFormDataChange({ ...formData, sendType: value })}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="immediate">
<div className="flex items-center gap-2">
<Send className="w-4 h-4" />
</div>
</SelectItem>
<SelectItem value="scheduled">
<div className="flex items-center gap-2">
<Clock className="w-4 h-4" />
</div>
</SelectItem>
</SelectContent>
</Select>
</div>
{/* 定时发送设置 */}
{formData.sendType === 'scheduled' && (
<div className="grid grid-cols-2 gap-4">
<div>
<Label> *</Label>
<Popover>
<PopoverTrigger asChild>
<Button variant="outline" className="w-full justify-start">
<CalendarIcon className="w-4 h-4 mr-2" />
{formData.scheduledDate ? (
format(formData.scheduledDate, 'yyyy年MM月dd日', { locale: zhCN })
) : (
'选择日期'
)}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar
mode="single"
selected={formData.scheduledDate}
onSelect={(date) => onFormDataChange({ ...formData, scheduledDate: date })}
locale={zhCN}
disabled={(date) => date < new Date(new Date().setHours(0, 0, 0, 0))}
/>
</PopoverContent>
</Popover>
</div>
<div>
<Label> *</Label>
<Input
type="time"
value={formData.scheduledTime}
onChange={(e) => onFormDataChange({ ...formData, scheduledTime: e.target.value })}
/>
</div>
</div>
)}
{/* 接收人 */}
<div>
<Label> *</Label>
<Textarea
value={formData.recipients}
onChange={(e) => onFormDataChange({ ...formData, recipients: e.target.value })}
placeholder={
formData.type === 'sms' ? '输入手机号,多个用逗号或换行分隔' :
formData.type === 'email' ? '输入邮箱地址,多个用逗号或换行分隔' :
formData.type === 'push' ? '输入设备ID或用户ID多个用逗号或换行分隔' :
'输入用户名,多个用逗号或换行分隔'
}
rows={3}
/>
<p className="text-xs text-muted-foreground mt-1">
使
</p>
</div>
{/* 消息主题(邮件和推送) */}
{(formData.type === 'email' || formData.type === 'push') && (
<div>
<Label></Label>
<Input
value={formData.subject}
onChange={(e) => onFormDataChange({ ...formData, subject: e.target.value })}
placeholder="输入消息主题"
/>
</div>
)}
{/* 变量填写 */}
{selectedTemplate && selectedTemplate.variables.length > 0 && (
<div>
<Label> *</Label>
<Card className="p-4 bg-gray-50">
<div className="grid grid-cols-2 gap-4">
{selectedTemplate.variables.map(variable => (
<div key={variable}>
<Label htmlFor={`var-${variable}`} className="text-xs">
{variable}
</Label>
<Input
id={`var-${variable}`}
value={formData.variables[variable] || ''}
onChange={(e) => onFormDataChange({
...formData,
variables: {
...formData.variables,
[variable]: e.target.value,
},
})}
placeholder={`输入 ${variable}`}
className="mt-1"
/>
</div>
))}
</div>
</Card>
</div>
)}
{/* 消息内容预览 */}
{formData.content && (
<div>
<Label></Label>
<Card className="p-4 bg-blue-50 border-blue-200">
<pre className="text-sm whitespace-pre-wrap">
{replaceVariables(formData.content, formData.variables)}
</pre>
</Card>
</div>
)}
</div>
<DialogFooter>
<Button variant="outline" onClick={() => onOpenChange(false)}>
</Button>
<Button onClick={onSend} className="bg-green-600 hover:bg-green-700">
<Send className="w-4 h-4 mr-2" />
{formData.sendType === 'immediate' ? '立即发送' : '创建定时任务'}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}