21 lines
6.2 KiB
Vue
21 lines
6.2 KiB
Vue
<script setup lang="ts">
|
|
import '@/styles/adminWorkbench.css'
|
|
import '@/styles/adminDensity.css'
|
|
import { onMounted, ref, watch } from 'vue'; import { Plus } from '@lucide/vue'; import { ElMessage, ElMessageBox } from 'element-plus'
|
|
import AdminPage from '@/shared/components/AdminPage.vue'; import DataTable,{type DataTableColumn} from '@/shared/components/DataTable.vue'; import ListPageLayout from '@/shared/components/ListPageLayout.vue'; import QueryToolbar,{type QueryField,type QueryModel} from '@/shared/components/QueryToolbar.vue'; import LoadErrorState from '@/shared/components/LoadErrorState.vue'; import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'; import TemplateEditorDialog from '../components/TemplateEditorDialog.vue'; import { changeTemplateStatus, listTemplates } from '../api/notificationCenter'; import type { NotificationTemplate, TemplateStatus } from '../types'; import { getApiErrorDetails,getApiErrorMessage,type ApiErrorDetails } from '@/shared/api/http'; import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
|
const access=useAccessPreviewStore(),page=ref(1),pageSize=ref(20),loading=ref(false),actionId=ref(''),error=ref<ApiErrorDetails|null>(null),editorOpen=ref(false),editing=ref<NotificationTemplate|null>(null),result=ref({records:[] as NotificationTemplate[],total:0,pages:0}),filters=ref<QueryModel>({code:'',category:'',title:'',status:''})
|
|
const queryFields:QueryField[]=[{key:'code',type:'input',label:'模板CODE',placeholder:'模板CODE'},{key:'category',type:'input',label:'业务分类',placeholder:'业务分类'},{key:'title',type:'input',label:'名称或标题',placeholder:'模板名称/标题'},{key:'status',type:'select',label:'状态',placeholder:'全部状态',options:[{label:'草稿',value:'DRAFT'},{label:'已激活',value:'ACTIVE'},{label:'已禁用',value:'DISABLED'}]}]
|
|
const columns:DataTableColumn[]=[{key:'actions',label:'操作',width:190,fixed:'left',slotName:'actions'},{key:'templateCode',prop:'templateCode',label:'模板CODE',minWidth:190},{key:'templateName',prop:'templateName',label:'模板名称',minWidth:170},{key:'category',prop:'category',label:'业务分类',width:130},{key:'titleTemplate',prop:'titleTemplate',label:'消息标题模板',minWidth:220},{key:'bodyTemplate',prop:'bodyTemplate',label:'正文模板',minWidth:320,showOverflowTooltip:true},{key:'status',label:'状态',width:100,slotName:'status'},{key:'version',prop:'version',label:'版本',width:80}]
|
|
function statusLabel(v:TemplateStatus){return {DRAFT:'草稿',ACTIVE:'已激活',DISABLED:'已禁用'}[v]}
|
|
async function load(){loading.value=true;error.value=null;try{const d=await listTemplates({page:page.value,size:pageSize.value,templateCode:String(filters.value.code||'').trim()||undefined,category:String(filters.value.category||'').trim()||undefined,title:String(filters.value.title||'').trim()||undefined,status:(filters.value.status||undefined) as TemplateStatus|undefined});result.value={records:d.records,total:d.total,pages:d.pages}}catch(e){error.value=getApiErrorDetails(e,'模板加载失败')}finally{loading.value=false}}
|
|
function search(){page.value===1?void load():page.value=1}function create(){editing.value=null;editorOpen.value=true}function edit(row:NotificationTemplate){editing.value=row;editorOpen.value=true}
|
|
async function changeStatus(row:NotificationTemplate){const target=row.status==='DRAFT'?'ACTIVE':'DISABLED';try{await ElMessageBox.confirm(target==='ACTIVE'?'激活后模板不可再编辑,确定继续吗?':'禁用后首期不可重新启用,确定继续吗?',`${target==='ACTIVE'?'激活模板':'禁用模板'} · ${row.templateName || row.templateCode || '—'}`,{type:'warning',customClass: 'admin-density-confirm admin-workbench'});actionId.value=row.id;await changeTemplateStatus(row.id,target,row.version);ElMessage.success(target==='ACTIVE'?'模板已激活':'模板已禁用');await load()}catch(e){if(e!=='cancel'&&e!=='close')ElMessage.error(getApiErrorMessage(e,'模板状态变更失败'))}finally{actionId.value=''}}
|
|
watch([page,pageSize],load);onMounted(load)
|
|
</script>
|
|
<template><AdminPage class="admin-density admin-workbench"><ListPageLayout aria-label="消息模板列表"><section class="workbench-table is-page-surface"><DataTable appearance="integrated" column-settings-mode="show" :results-visible="!error" v-model:page="page" v-model:page-size="pageSize" :data="result.records" :columns="columns" preference-key="notifications-templates-table" :loading="loading" :total="result.total" row-key="id" empty-text="暂无消息模板">
|
|
<template #toolbar-start><h1>模板管理</h1></template>
|
|
<template #filters><QueryToolbar v-model="filters" ariaLabel="消息模板筛选" :fields="queryFields" preference-key="notifications-templates-query" @search="search"/></template>
|
|
<template #notices><template v-if="error"><LoadErrorState title="模板加载失败" :message="error.message" :loading="loading" @retry="load"><template #details><ApiErrorMeta :details="error"/></template></LoadErrorState></template></template>
|
|
|
|
<template #toolbar-actions><el-button v-if="access.can('platform:notification:template:create')" type="primary" @click="create"><Plus :size="16"/>新增模板</el-button></template><template #pagination-left><span>共 {{result.total}} 个模板</span></template><template #actions="{row}"><div class="density-actions row-actions admin-text-actions"><el-button v-if="access.can('platform:notification:template:edit')&&(row as NotificationTemplate).status==='DRAFT'" class="density-action" data-tone="neutral" @click="edit(row as NotificationTemplate)">编辑</el-button><el-button v-if="access.can('platform:notification:template:status')&&(row as NotificationTemplate).status!=='DISABLED'" class="density-action" :data-tone="(row as NotificationTemplate).status==='ACTIVE'?'danger':'success'" :loading="actionId===(row as NotificationTemplate).id" @click="changeStatus(row as NotificationTemplate)">{{(row as NotificationTemplate).status==='DRAFT'?'激活':'禁用'}}</el-button></div></template><template #status="{row}"><el-tag>{{statusLabel((row as NotificationTemplate).status)}}</el-tag></template></DataTable></section></ListPageLayout><TemplateEditorDialog v-model="editorOpen" :template="editing" @success="load"/></AdminPage></template>
|