SendMailModal.jsx
4.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import React, { useState, useEffect } from 'react'
import { Modal, Form, Input, Button, Space, message, Tag, Alert } from 'antd'
import { SendOutlined, MailOutlined } from '@ant-design/icons'
import request from '../utils/request'
// 验证逗号分隔的多个邮箱
const validateEmails = (rule, value) => {
if (!value || !value.trim()) return Promise.reject(new Error('请输入收件人邮箱'))
const emails = value.split(',').map(e => e.trim()).filter(e => e)
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
const invalid = emails.find(e => !emailRegex.test(e))
if (invalid) return Promise.reject(new Error(`邮箱格式不正确: ${invalid}`))
return Promise.resolve()
}
export default function SendMailModal({ open, onClose, script, onSent }) {
const [form] = Form.useForm()
const [sending, setSending] = useState(false)
useEffect(() => {
if (open && script) {
form.resetFields()
setTimeout(() => {
form.setFieldsValue({
recipientEmails: script.recipientEmails || '',
emailSubject: script.emailSubject || '',
})
}, 0)
}
}, [open, script])
const handleSend = async () => {
try {
const values = await form.validateFields()
setSending(true)
const res = await request.post(`/sql-manage/${script.id}/send-mail`, {
recipientEmails: values.recipientEmails,
emailSubject: values.emailSubject,
})
if (res.success) {
message.success(res.message)
if (onSent) onSent()
onClose()
} else {
message.error(res.message)
}
} catch (e) {
if (e.errorFields) return // 表单验证失败
message.error(e.message || '发送失败')
} finally {
setSending(false)
}
}
if (!script) return null
// 解析收件人列表用于标签展示
const parseEmailTags = (text) => {
if (!text) return []
return text.split(',').map(e => e.trim()).filter(e => e)
}
return (
<Modal
title={
<Space>
<SendOutlined />
<span>手动发送邮件</span>
<Tag color="blue">{script.name}</Tag>
</Space>
}
open={open}
onCancel={onClose}
width={560}
footer={
<Space>
<Button onClick={onClose}>取消</Button>
<Button
type="primary"
icon={<SendOutlined />}
loading={sending}
onClick={handleSend}
>
发送邮件
</Button>
</Space>
}
>
<Alert
type="info"
showIcon
style={{ marginBottom: 16 }}
message="手动发送将执行脚本SQL,生成Excel附件并发送邮件到指定收件人。收件人可与脚本配置的不同。"
/>
<Form form={form} layout="vertical">
<Form.Item
name="recipientEmails"
label="收件人邮箱"
tooltip="多个收件人用英文逗号分隔"
rules={[{ validator: validateEmails }]}
>
<Input.TextArea
placeholder="例如:zhangsan@company.com,lisi@company.com"
autoSize={{ minRows: 2, maxRows: 4 }}
onChange={() => {
// 实时更新标签展示
}}
/>
</Form.Item>
<Form.Item shouldUpdate={(prev, cur) => prev.recipientEmails !== cur.recipientEmails}>
{({ getFieldValue }) => {
const emails = parseEmailTags(getFieldValue('recipientEmails'))
if (emails.length === 0) return null
return (
<div style={{ marginTop: -12, marginBottom: 16 }}>
<span style={{ fontSize: 12, color: '#999', marginRight: 8 }}>收件人预览:</span>
<Space size={4} wrap>
{emails.map((email, i) => (
<Tag key={i} color="blue" icon={<MailOutlined />}>{email}</Tag>
))}
</Space>
</div>
)
}}
</Form.Item>
<Form.Item
name="emailSubject"
label="邮件主题"
tooltip="为空则使用脚本配置的主题或自动生成"
>
<Input placeholder="例如:月度终端支付明细报表(自定义)" />
</Form.Item>
<div style={{ padding: '8px 12px', background: '#f6f6f6', borderRadius: 6, fontSize: 12, color: '#888' }}>
<div>邮件将自动附带Excel附件,包含脚本查询结果数据。</div>
{script.purpose && (
<div style={{ marginTop: 4 }}>
<span style={{ color: '#666' }}>脚本用途:</span>{script.purpose}
</div>
)}
</div>
</Form>
</Modal>
)
}