send-form.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <template>
  2. <wd-popup v-model="visible" position="bottom" closable custom-style="border-radius: 16rpx 16rpx 0 0;">
  3. <view class="p-24rpx">
  4. <view class="mb-24rpx text-32rpx text-[#333] font-semibold">
  5. 发送测试邮件
  6. </view>
  7. <wd-form ref="sendFormRef" :model="sendFormData" :rules="sendFormRules">
  8. <wd-cell-group border>
  9. <wd-textarea
  10. v-model="sendFormData.content"
  11. label="模板内容"
  12. label-width="180rpx"
  13. disabled
  14. :rows="3"
  15. />
  16. <wd-input
  17. v-model="sendFormData.toMails"
  18. label="收件邮箱"
  19. label-width="180rpx"
  20. prop="toMails"
  21. clearable
  22. placeholder="多个邮箱用逗号分隔"
  23. />
  24. <wd-input
  25. v-model="sendFormData.ccMails"
  26. label="抄送邮箱"
  27. label-width="180rpx"
  28. clearable
  29. placeholder="多个邮箱用逗号分隔"
  30. />
  31. <wd-input
  32. v-model="sendFormData.bccMails"
  33. label="密送邮箱"
  34. label-width="180rpx"
  35. clearable
  36. placeholder="多个邮箱用逗号分隔"
  37. />
  38. <template v-for="param in template?.params" :key="param">
  39. <wd-input
  40. v-model="sendFormData.templateParams[param]"
  41. :label="`参数 ${param}`"
  42. label-width="180rpx"
  43. :prop="`templateParams.${param}`"
  44. clearable
  45. :placeholder="`请输入参数 ${param}`"
  46. />
  47. </template>
  48. </wd-cell-group>
  49. </wd-form>
  50. <view class="mt-24rpx">
  51. <wd-button type="primary" block :loading="sendLoading" @click="handleSendSubmit">
  52. 发送
  53. </wd-button>
  54. </view>
  55. </view>
  56. </wd-popup>
  57. </template>
  58. <script lang="ts" setup>
  59. import type { MailTemplate } from '@/api/system/mail/template'
  60. import { computed, ref, watch } from 'vue'
  61. import { useToast } from 'wot-design-uni'
  62. import { sendMail } from '@/api/system/mail/template'
  63. import { isEmail } from '@/utils/validator'
  64. const props = defineProps<{
  65. modelValue: boolean
  66. template?: MailTemplate
  67. }>()
  68. const emit = defineEmits<{
  69. 'update:modelValue': [value: boolean]
  70. 'success': []
  71. }>()
  72. const toast = useToast()
  73. const visible = computed({
  74. get() {
  75. return props.modelValue
  76. },
  77. set(value: boolean) {
  78. emit('update:modelValue', value)
  79. },
  80. })
  81. const sendLoading = ref(false)
  82. const sendFormRef = ref<any>()
  83. const sendFormData = ref({
  84. content: '',
  85. toMails: '',
  86. ccMails: '',
  87. bccMails: '',
  88. templateParams: {} as Record<string, string>,
  89. })
  90. /** 发送表单校验规则 */
  91. const sendFormRules = computed(() => {
  92. const rules: Record<string, any> = {
  93. toMails: [{ required: true, message: '收件邮箱不能为空' }],
  94. }
  95. if (props.template?.params) {
  96. props.template.params.forEach((param) => {
  97. rules[`templateParams.${param}`] = [{ required: true, message: `参数 ${param} 不能为空` }]
  98. })
  99. }
  100. return rules
  101. })
  102. /** 格式化邮箱列表 */
  103. function normalizeMailList(text: string) {
  104. const list = text
  105. .split(/[,,;;\s]+/)
  106. .map(s => s.trim())
  107. .filter(Boolean)
  108. const invalid = list.find(item => !isEmail(item))
  109. if (invalid) {
  110. toast.warning(`邮箱格式不正确:${invalid}`)
  111. return null
  112. }
  113. return list
  114. }
  115. /** 初始化发送表单 */
  116. function initSendForm() {
  117. sendFormData.value = {
  118. content: props.template?.content || '',
  119. toMails: '',
  120. ccMails: '',
  121. bccMails: '',
  122. templateParams: {},
  123. }
  124. if (props.template?.params) {
  125. props.template.params.forEach((param) => {
  126. sendFormData.value.templateParams[param] = ''
  127. })
  128. }
  129. }
  130. watch(
  131. () => props.modelValue,
  132. (val) => {
  133. if (val) {
  134. initSendForm()
  135. }
  136. },
  137. )
  138. /** 提交发送 */
  139. async function handleSendSubmit() {
  140. const { valid } = await sendFormRef.value.validate()
  141. if (!valid) {
  142. return
  143. }
  144. const toMails = normalizeMailList(sendFormData.value.toMails)
  145. if (!toMails || toMails.length === 0) {
  146. return
  147. }
  148. const ccMails = normalizeMailList(sendFormData.value.ccMails)
  149. if (ccMails === null) {
  150. return
  151. }
  152. const bccMails = normalizeMailList(sendFormData.value.bccMails)
  153. if (bccMails === null) {
  154. return
  155. }
  156. sendLoading.value = true
  157. try {
  158. await sendMail({
  159. templateCode: props.template?.code || '',
  160. templateParams: sendFormData.value.templateParams,
  161. toMails,
  162. ccMails: ccMails.length > 0 ? ccMails : undefined,
  163. bccMails: bccMails.length > 0 ? bccMails : undefined,
  164. })
  165. toast.success('邮件发送成功')
  166. emit('success')
  167. visible.value = false
  168. } finally {
  169. sendLoading.value = false
  170. }
  171. }
  172. </script>