This commit is contained in:
wujinliang
2026-08-27 21:48:15 +08:00
parent 550d8add97
commit b47323edf3
53 changed files with 624 additions and 82 deletions
@@ -18,17 +18,28 @@ const recipientIdsText = ref('')
const variables = reactive<Record<string, string>>({})
const form = reactive({ tenantId: '0', templateCode: '', recipientType: 'PLATFORM_ROLE' as RecipientType, roleCode: '', scheduledAt: '' })
const selectedTemplate = computed(() => props.templates.find((item) => item.templateCode === form.templateCode) ?? null)
const scheduled = computed({ get: () => Boolean(form.scheduledAt), set: (value) => { if (!value) form.scheduledAt = '' } })
function toDateTimeValue(date: Date) {
const pad = (value: number) => String(value).padStart(2, '0')
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
}
const scheduled = computed({
get: () => Boolean(form.scheduledAt),
set: (value: boolean) => {
if (value && !form.scheduledAt) form.scheduledAt = toDateTimeValue(new Date(Date.now() + 5 * 60 * 1000))
if (!value) form.scheduledAt = ''
},
})
const needsIds = computed(() => ['USER', 'MEMBERSHIP'].includes(form.recipientType))
const needsRole = computed(() => ['TENANT_ROLE', 'PLATFORM_ROLE'].includes(form.recipientType))
const allowedRecipients = computed(() => scope.value === 'platform'
? [{ label: '指定平台用户', value: 'USER' }, { label: '平台角色', value: 'PLATFORM_ROLE' }]
: [{ label: '指定企业成员', value: 'MEMBERSHIP' }, { label: '企业角色', value: 'TENANT_ROLE' }, { label: '企业全部成员', value: 'TENANT_ALL' }])
: [{ label: '指定企业成员', value: 'USER' }, { label: '企业角色', value: 'TENANT_ROLE' }, { label: '企业全部成员', value: 'TENANT_ALL' }])
watch(scope, (value) => { form.tenantId = value === 'platform' ? '0' : ''; form.recipientType = value === 'platform' ? 'PLATFORM_ROLE' : 'TENANT_ALL'; form.roleCode = ''; recipientIdsText.value = '' })
watch(selectedTemplate, (value) => { for (const key of Object.keys(variables)) delete variables[key]; for (const key of value?.variableWhitelist ?? []) variables[key] = '' })
function reset() { scope.value = 'platform'; Object.assign(form, { tenantId: '0', templateCode: '', recipientType: 'PLATFORM_ROLE', roleCode: '', scheduledAt: '' }); recipientIdsText.value = ''; error.value = null; for (const key of Object.keys(variables)) delete variables[key] }
const MAX_LONG_ID = 9_223_372_036_854_775_807n
function parseIds() { return [...new Set(recipientIdsText.value.split(/[\s,,]+/).map((value) => value.trim()).filter(Boolean))] }
function idempotencyKey() { return typeof crypto !== 'undefined' && crypto.randomUUID ? crypto.randomUUID() : `notification-${Date.now()}-${Math.random().toString(36).slice(2)}` }
async function submit() {
@@ -36,7 +47,7 @@ async function submit() {
const recipientIds = parseIds()
if (!form.templateCode) return ElMessage.warning('请选择已激活模板')
if (scope.value === 'customer' && !form.tenantId) return ElMessage.warning('请选择目标企业')
if (needsIds.value && (!recipientIds.length || recipientIds.some((value) => !/^\d+$/.test(value)))) return ElMessage.warning('请输入有效的数字用户或成员 ID')
if (needsIds.value && (!recipientIds.length || recipientIds.length > 1000 || recipientIds.some((value) => !/^\d+$/.test(value) || BigInt(value) > MAX_LONG_ID))) return ElMessage.warning('请输入有效的数字用户 ID,单次最多 1000 个且不能超过 19 位')
if (needsRole.value && !form.roleCode.trim()) return ElMessage.warning('请输入角色编码')
if (Object.values(variables).some((value) => !value.trim())) return ElMessage.warning('请填写全部模板变量')
submitting.value = true
@@ -56,7 +67,7 @@ async function submit() {
<PlatformTenantSelector v-if="scope === 'customer'" v-model="form.tenantId" label="目标企业" />
<el-form-item label="消息模板" required><el-select v-model="form.templateCode" filterable placeholder="请选择已激活模板"><el-option v-for="item in templates" :key="item.id" :label="`${item.templateName}(${item.templateCode})`" :value="item.templateCode" /></el-select></el-form-item>
<div class="form-grid"><el-form-item label="接收对象" required><el-select v-model="form.recipientType"><el-option v-for="item in allowedRecipients" :key="item.value" :label="item.label" :value="item.value" /></el-select></el-form-item><el-form-item v-if="needsRole" label="角色编码" required><el-input v-model="form.roleCode" maxlength="64" placeholder="请输入服务端角色编码" /></el-form-item></div>
<el-form-item v-if="needsIds" label="接收人 ID" required><el-input v-model="recipientIdsText" type="textarea" :rows="2" placeholder="多个数字 ID 使用逗号或换行分隔,最多 1000 个" /></el-form-item>
<el-form-item v-if="needsIds" label="接收人用户 ID" required><el-input v-model="recipientIdsText" type="textarea" :rows="2" placeholder="多个用户 ID 使用逗号或换行分隔,最多 1000 个" /></el-form-item>
<section v-if="selectedTemplate?.variableWhitelist.length" class="variables"><strong>模板变量</strong><el-form-item v-for="key in selectedTemplate.variableWhitelist" :key="key" :label="key" required><el-input v-model="variables[key]" maxlength="2000" /></el-form-item></section>
<el-form-item label="定时发送"><div class="schedule-row"><el-switch v-model="scheduled" aria-label="启用定时发送" /><span>启用</span><el-date-picker v-model="form.scheduledAt" type="datetime" value-format="YYYY-MM-DDTHH:mm:ss" placeholder="选择发送时间" :disabled="!scheduled" /></div></el-form-item>
</el-form>