Files
admin-web/src/modules/notifications/components/TemplateEditorDialog.vue
T

51 lines
3.9 KiB
Vue
Raw Normal View History

2026-08-12 18:24:05 +08:00
<script setup lang="ts">
import { computed, reactive, ref } from 'vue'
import AppDialog from '@/shared/components/AppDialog.vue'
const open = defineModel<boolean>({ default: false })
const contentInput = ref<{ textarea?: HTMLTextAreaElement } | null>(null)
const form = reactive({ code: '', title: '', content: '' })
const variables = [{ label: '客户名称', value: 'customerName' }, { label: '订单号', value: 'orderNo' }, { label: '柜号', value: 'containerNo' }, { label: '金额', value: 'amount' }, { label: '日期', value: 'date' }]
const preview = computed(() => form.title || form.content ? `[系统] ${form.title || '未填写标题'}\n${form.content || '未填写模板内容'}` : '填写标题和内容后,将在这里显示预览效果。')
function normalizeCode(value: string) { form.code = value.replace(/[^A-Za-z0-9_]/g, '').toUpperCase() }
function insertVariable(name: string) {
const textarea = contentInput.value?.textarea
const value = `\${${name}}`
const start = textarea?.selectionStart ?? form.content.length
const end = textarea?.selectionEnd ?? start
form.content = `${form.content.slice(0, start)}${value}${form.content.slice(end)}`.slice(0, 1000)
}
</script>
<template>
<AppDialog v-model="open" title="新增消息模板" width="min(760px, calc(100vw - 28px))" :show-confirm="false" destroy-on-close>
<el-alert title="当前仅承载站内系统消息模板;保存接口待后端契约冻结" type="info" :closable="false" show-icon />
<el-form class="template-form" label-position="top">
<div class="form-grid">
<el-form-item label="模板CODE" required><el-input :model-value="form.code" maxlength="40" placeholder="如:ORDER_SHIPPED_NOTICE" @update:model-value="normalizeCode(String($event))" /><small>仅支持字母、数字和下划线</small></el-form-item>
<el-form-item label="模板类型" required><el-input model-value="系统" disabled /></el-form-item>
</div>
<el-form-item label="模板标题" required><el-input v-model="form.title" maxlength="60" show-word-limit placeholder="请输入模板标题" /></el-form-item>
<el-form-item label="模板内容" required><el-input ref="contentInput" v-model="form.content" type="textarea" :rows="6" maxlength="1000" show-word-limit placeholder="请输入模板内容" /></el-form-item>
<div class="variable-row"><span>常用变量</span><el-button v-for="item in variables" :key="item.value" size="small" @click="insertVariable(item.value)">{{ item.label }}</el-button></div>
<section class="template-preview"><strong>内容预览</strong><p>{{ preview }}</p></section>
</el-form>
<template #footer="{ close }"><div class="dialog-actions"><el-button @click="close">取消</el-button><el-button type="primary" disabled>保存模板</el-button></div></template>
</AppDialog>
</template>
<style scoped>
.template-form { margin-top: 18px; }
.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
small { display: block; margin-top: 5px; color: var(--cc-muted); font-size: 12px; }
.variable-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 18px; color: var(--cc-muted); font-size: 12px; }
.variable-row :deep(.el-button) { margin-left: 0; }
.template-preview { overflow: hidden; border: 1px solid var(--cc-border); border-radius: 8px; }
.template-preview strong { display: block; padding: 9px 14px; border-bottom: 1px solid var(--cc-border); background: #f8fafc; color: var(--cc-text); font-size: 13px; }
.template-preview p { min-height: 76px; margin: 0; padding: 16px; white-space: pre-wrap; overflow-wrap: anywhere; color: var(--cc-muted); font-size: 13px; line-height: 1.7; }
.dialog-actions { display: flex; justify-content: flex-end; gap: 10px; }
.dialog-actions :deep(.el-button) { margin-left: 0; }
@media (max-width: 560px) { .form-grid { grid-template-columns: 1fr; gap: 0; } }
</style>