邮件模版

This commit is contained in:
2026-03-13 10:20:53 +08:00
parent 3c27591fc7
commit 213ca978b7
17 changed files with 21350 additions and 744 deletions

View File

@@ -1,163 +1,260 @@
<template>
<div>
<div class="crumbs">
<el-breadcrumb separator="/">
<el-breadcrumb-item>
<i class="el-icon-message"></i> Mailbox template list
</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="container">
<div>
<quill-editor ref="myTextEditor" v-model="tempForm.content" :options="editorOption"></quill-editor>
<el-upload class="avatar-uploader" :action="baseUrl+'api/Suggest/upImg'" name="img" :show-file-list="false"
:on-success="uploadSuccess">
</el-upload>
</div>
</div>
<div class="admin-container">
<h2>{{ $t('mailboxMould.title') }}</h2>
<p class="subtitle">{{ $t('mailboxMould.subtitle') }}</p>
</div>
<div class="toolbar">
<el-select
v-model="filters.journalId"
:placeholder="$t('mailboxMould.journalPlaceholder')"
style="width: 300px; margin-right: 10px;"
@change="fetchList"
>
<el-option
v-for="j in journalList"
:key="j.journal_id"
:label="j.title"
:value="String(j.journal_id)"
></el-option>
</el-select>
<el-select
v-model="filters.scene"
:placeholder="$t('mailboxMould.scenePlaceholder')"
clearable
style="width: 200px; margin-right: 10px;"
@change="fetchList"
@clear="fetchList"
>
<el-option :label="$t('mailboxMould.inviteSubmission')" value="invite_submission"></el-option>
<el-option :label="$t('mailboxMould.promoteCitation')" value="promote_citation"></el-option>
<el-option :label="$t('mailboxMould.generalThanks')" value="general_thanks"></el-option>
</el-select>
<el-select
v-model="filters.language"
:placeholder="$t('mailboxMould.languagePlaceholder')"
clearable
style="width: 120px; margin-right: 10px;"
@change="fetchList"
@clear="fetchList"
>
<el-option label="EN" value="en"></el-option>
<el-option label="ZH" value="zh"></el-option>
</el-select>
<el-button type="primary" icon="el-icon-search" @click="fetchList" style="margin-right: 10px;">
{{ $t('mailboxMould.searchBtn') }}
</el-button>
<div class="right-actions">
<el-button type="primary" plain icon="el-icon-plus" @click="handleCreate">{{ $t('mailboxMould.createTemplate') }}</el-button>
</div>
</div>
<el-table :data="tableData" border style="width: 100%; margin-top: 20px;" v-loading="loading">
<el-table-column prop="title" :label="$t('mailboxMould.colTitle')" min-width="220">
<template slot-scope="scope">
<div class="title-cell">
<strong>{{ scope.row.title }}</strong>
</div>
</template>
</el-table-column>
<el-table-column prop="subject" :label="$t('mailboxMould.colSubject')" min-width="220">
<template slot-scope="scope">
<span>{{ scope.row.subject || '-' }}</span>
</template>
</el-table-column>
<el-table-column prop="scene" :label="$t('mailboxMould.colScene')">
<template slot-scope="scope">
<el-tag size="small" type="info">{{ scope.row.scene }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="language" :label="$t('mailboxMould.colLanguage')" width="100">
<template slot-scope="scope">
{{ String(scope.row.language || '').toUpperCase() }}
</template>
</el-table-column>
<el-table-column prop="version" :label="$t('mailboxMould.colVersion')" width="100"></el-table-column>
<el-table-column :label="$t('mailboxMould.colStatus')" width="120">
<template slot-scope="scope">
<span :class="['status-dot', scope.row.status]"></span>
{{ scope.row.status === 'active' ? $t('mailboxMould.active') : $t('mailboxMould.inactive') }}
</template>
</el-table-column>
<el-table-column width="160">
<template slot-scope="scope">
<el-button type="text" icon="el-icon-view" @click="handlePreview(scope.row)"></el-button>
<el-button type="text" icon="el-icon-edit" @click="handleEdit(scope.row)"></el-button>
<el-button type="text" icon="el-icon-delete" class="delete-btn" @click="handleDelete(scope.row)"></el-button>
</template>
</el-table-column>
</el-table>
<el-dialog
:title="$t('mailboxMould.previewTitle')"
:visible.sync="previewVisible"
width="80%"
>
<div class="preview-body" v-html="previewContent"></div>
<span slot="footer" class="dialog-footer">
<el-button @click="previewVisible = false">{{ $t('mailboxMould.previewClose') }}</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
// 引入富文本quill-editor相关组件依赖
import {
quillEditor,
Quill
} from 'vue-quill-editor'
// import {
// container,
// QuillWatch
// } from 'quill-image-extend-module'
// import ImageResize from 'quill-image-resize-module' // 引用,调整图片大小
// Quill.register('modules/imageResize', ImageResize)
const API = {
listTemplates: 'api/mail_template/listTemplates',
getAllJournal: 'api/Journal/getAllJournal',
deleteTemplate: 'api/mail_template/deleteTemplate'
};
export default {
data() {
return {
baseUrl: this.Common.baseUrl,
mediaUrl: this.Common.mediaUrl,
tempForm: {
content: ''
},
editorOption: {
placeholder: 'Please enter...',
modules: {
toolbar: {
container: [
['bold', 'italic', 'underline', 'strike'],
['blockquote', 'code-block'],
[{
'header': 1
}, {
'header': 2
}],
[{
'list': 'ordered'
}, {
'list': 'bullet'
}],
[{
'script': 'sub'
}, {
'script': 'super'
}],
[{
'indent': '-1'
}, {
'indent': '+1'
}],
[{
'direction': 'rtl'
}],
[{
'size': ['small', false, 'large', 'huge']
}],
[{
'header': [1, 2, 3, 4, 5, 6, false]
}],
[{
'color': []
}, {
'background': []
}],
[{
'font': []
}],
[{
'align': []
}],
['link', 'image']
],
// 工具栏
handlers: {
image: function(value) {
if (value) {
// upload点击上传事件
document.querySelector('.avatar-uploader input').click()
} else {
this.quill.format('image', false)
}
}
}
},
// 调整图片大小
// imageResize: {
// displayStyles: {
// backgroundColor: 'black',
// border: 'none',
// color: 'white'
// },
// modules: ['Resize', 'DisplaySize', 'Toolbar']
// }
}
},
};
},
created() {
this.getDate();
},
// components: {
// quillEditor
// },
methods: {
// 获取编辑列表数据
getDate() {
},
// 富文本编辑器
onEditorChange({
editor,
html,
text
}) {
this.content = html;
},
// 上传成功
uploadSuccess(res) {
let quill = this.$refs.myTextEditor.quill;
// 获取光标所在位置
let length = quill.getSelection().index
// 插入图片 res.upurl为服务器返回的图片地址
quill.insertEmbed(length, 'image', this.baseUrl + res.data.icon)
// 调整光标到最后
quill.setSelection(length + 1)
}
}
};
export default {
data() {
return {
searchQuery: '',
loading: false,
journalList: [],
filters: {
journalId: '',
scene: '',
language: ''
},
tableData: [],
previewVisible: false,
previewContent: ''
};
},
created() {
this.loadJournals();
},
methods: {
loadJournals() {
this.$api
.post(API.getAllJournal, {})
.then(res => {
const list = (res && res.data && res.data.journals) || res.data || [];
const mapped = (Array.isArray(list) ? list : []).map(j => ({
journal_id: j.journal_id || j.id,
title: j.title || j.name || ''
}));
this.journalList = mapped;
if (mapped.length > 0) {
this.filters.journalId = String(mapped[0].journal_id);
}
this.fetchList();
})
.catch(() => {
this.journalList = [];
});
},
fetchList() {
this.loading = true;
const params = {
journal_id: this.filters.journalId || '',
scene: this.filters.scene || '',
language: this.filters.language || ''
};
this.$api
.post(API.listTemplates, params)
.then(res => {
this.loading = false;
const list = (res && res.data && res.data.list) || [];
this.tableData = (Array.isArray(list) ? list : []).map(item => ({
id: item.template_id || item.id,
template_id: item.template_id || item.id,
title: item.title,
subject: item.subject,
body_html: item.body_html,
description: item.description || '',
scene: item.scene,
language: item.language,
version: item.version,
status: item.status || 'active'
}));
})
.catch(() => {
this.loading = false;
this.tableData = [];
});
},
handleCreate() {
this.$router.push({ path: '/mailboxMouldDetail' });
},
handleEdit(row) {
console.log('Editing:', row);
// 跳转到详情页,后续可带上模板 ID
const templateId = row && (row.template_id || row.id);
this.$router.push({ path: '/mailboxMouldDetail', query: templateId ? { template_id: String(templateId) } : {} });
},
handlePreview(row) {
this.previewContent = row && row.body_html ? row.body_html : (row && row.body ? row.body : '');
this.previewVisible = true;
},
handleDelete(row) {
const templateId = row && (row.template_id || row.id);
if (!templateId) return;
this.$confirm(this.$t('mailboxMould.deleteConfirm'), this.$t('mailboxMould.colActions'), {
confirmButtonText: this.$t('mailboxMould.confirm'),
cancelButtonText: this.$t('mailboxMould.cancel'),
type: 'warning'
}).then(() => {
this.$api.post(API.deleteTemplate, { template_id: String(templateId) }).then(res => {
if (res && res.code === 0) {
this.$message.success(this.$t('mailboxMould.deleteSuccess'));
this.fetchList();
} else {
this.$message.error((res && res.msg) || this.$t('mailboxMould.deleteFail'));
}
}).catch(() => {
this.$message.error(this.$t('mailboxMould.deleteFail'));
});
}).catch(() => {});
}
}
};
</script>
<style scoped>
.avatar-uploader {
height: 0;
}
.avatar-uploader .el-upload--text {
height: 0 !important;
border: 0;
}
</style>
.admin-container {
padding: 20px;
background: #fff;
}
.subtitle {
color: #666;
font-size: 14px;
margin-bottom: 20px;
}
.toolbar {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.right-actions {
margin-left: auto;
display: flex;
gap: 8px;
}
.status-dot {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 5px;
}
.status-dot.active {
background-color: #52c41a;
}
.delete-btn {
color: #f5222d !important;
}
.preview-body {
max-height: 70vh;
overflow: auto;
padding: 10px;
border: 1px solid #eee;
background: #fff;
}
</style>