You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

566 lines
19 KiB

<template>
<!-- 筛选与搜索区域 -->
<el-card class="card1" style="margin-bottom: 1vh;">
<div class="condition">
<div class="condition-item">
<el-text size="large">搜索</el-text>
<el-input v-model="searchForm.chineseSimplified" style="width: 12vw" placeholder="请输入原文内容" clearable />
</div>
<!-- 移除语言状态筛选 -->
<div class="btn">
<el-button type="primary" @click="search">搜索</el-button>
<el-button type="success" @click="reset">重置</el-button>
</div>
</div>
</el-card>
<el-card class="card2">
<!-- 功能按钮区域 -->
<div class="add-item">
<el-button type="success" @click="handleAdd">添加</el-button>
<el-button class="add-item-export" @click="handleBatchImport">批量导入</el-button>
</div>
<div>
<el-table :data="tableData" style="width: 82vw;height:72vh;" :row-style="{ height: '50px' }">
<el-table-column type="index" label="序号" width="80px" fixed="left">
<template #default="scope">
<span>{{ scope.$index + 1 + (pagination.pageNum - 1) * pagination.pageSize }}</span>
</template>
</el-table-column>
<el-table-column prop="chineseSimplified" label="原文(中文)" width="180px">
<template #default="scope">
<el-tooltip :content="scope.row.chineseSimplified" placement="top"
v-if="scope.row.chineseSimplified && scope.row.chineseSimplified.length > 20">
<span>{{ truncateText(scope.row.chineseSimplified) }}</span>
</el-tooltip>
<span v-else>{{ scope.row.chineseSimplified }}</span>
</template>
</el-table-column>
<el-table-column prop="english" label="英文" width="200px" header-align="center">
<template #default="scope">
<div style="display: flex; align-items: center; justify-content: space-between;">
<div style="flex: 1;">
<el-tooltip :content="scope.row.english" placement="top"
v-if="scope.row.english && scope.row.english.length > 15">
<span>{{ truncateText(scope.row.english) }}</span>
</el-tooltip>
<span v-else>{{ scope.row.english }}</span>
</div>
<el-tag :type="scope.row.english ? 'success' : 'info'" size="small"
style="margin-left: 8px;">
{{ scope.row.english ? '已翻译' : '未翻译' }}
</el-tag>
</div>
</template>
</el-table-column>
<el-table-column prop="thai" label="泰语" width="200px" header-align="center">
<template #default="scope">
<div style="display: flex; align-items: center; justify-content: space-between;">
<div style="flex: 1;">
<el-tooltip :content="scope.row.thai" placement="top"
v-if="scope.row.thai && scope.row.thai.length > 15">
<span>{{ truncateText(scope.row.thai) }}</span>
</el-tooltip>
<span v-else>{{ scope.row.thai }}</span>
</div>
<el-tag :type="scope.row.thai ? 'success' : 'info'" size="small" style="margin-left: 8px;">
{{ scope.row.thai ? '已翻译' : '未翻译' }}
</el-tag>
</div>
</template>
</el-table-column>
<el-table-column prop="chineseTraditional" label="繁体中文" width="180px" header-align="center">
<template #default="scope">
<div style="display: flex; align-items: center; justify-content: space-between;">
<div style="flex: 1;">
<el-tooltip :content="scope.row.chineseTraditional" placement="top"
v-if="scope.row.chineseTraditional && scope.row.chineseTraditional.length > 15">
<span>{{ truncateText(scope.row.chineseTraditional) }}</span>
</el-tooltip>
<span v-else>{{ scope.row.chineseTraditional }}</span>
</div>
<el-tag :type="scope.row.chineseTraditional ? 'success' : 'info'" size="small"
style="margin-left: 8px;">
{{ scope.row.chineseTraditional ? '已翻译' : '未翻译' }}
</el-tag>
</div>
</template>
</el-table-column>
<el-table-column prop="malay" label="马来语" width="200px" header-align="center">
<template #default="scope">
<div style="display: flex; align-items: center; justify-content: space-between;">
<div style="flex: 1;">
<el-tooltip :content="scope.row.malay" placement="top"
v-if="scope.row.malay && scope.row.malay.length > 15">
<span>{{ truncateText(scope.row.malay) }}</span>
</el-tooltip>
<span v-else>{{ scope.row.malay }}</span>
</div>
<el-tag :type="scope.row.malay ? 'success' : 'info'" size="small" style="margin-left: 8px;">
{{ scope.row.malay ? '已翻译' : '未翻译' }}
</el-tag>
</div>
</template>
</el-table-column>
<el-table-column prop="vietnamese" label="越南语" width="200px" header-align="center">
<template #default="scope">
<div style="display: flex; align-items: center; justify-content: space-between;">
<div style="flex: 1;">
<el-tooltip :content="scope.row.vietnamese" placement="top"
v-if="scope.row.vietnamese && scope.row.vietnamese.length > 15">
<span>{{ truncateText(scope.row.vietnamese) }}</span>
</el-tooltip>
<span v-else>{{ scope.row.vietnamese }}</span>
</div>
<el-tag :type="scope.row.vietnamese ? 'success' : 'info'" size="small"
style="margin-left: 8px;">
{{ scope.row.vietnamese ? '已翻译' : '未翻译' }}
</el-tag>
</div>
</template>
</el-table-column>
<!-- 移除状态列 -->
<el-table-column prop="configTime" label="配置时间" width="180px" header-align="center">
<template #default="scope">
{{ moment(scope.row.configTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column prop="operation" label="操作" width="155px" fixed="right" header-align="center">
<template #default="scope">
<div style="display:flex; justify-content:center; ">
<el-button type="primary" text @click="handleEdit(scope.row)">编辑</el-button>
<el-button type="danger" text @click="handleDelete(scope.row)">删除</el-button>
</div>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页组件 -->
<div style="margin-top: 10px;display: flex;">
<el-pagination background v-model:current-page="pagination.pageNum" v-model:page-size="pagination.pageSize"
layout="total, sizes, prev, pager, next, jumper" :total="pagination.total" style="margin-top: 1vh;"
@size-change="handleSizeChange" @current-change="handleCurrentChange" />
</div>
</el-card>
<!-- 确认删除对话框 -->
<ConfirmDialog v-model="showDeleteDialog" message="删除该翻译记录!" @confirm="handleDeleteConfirm"
@cancel="handleDeleteCancel" @close="handleDeleteClose" />
<!-- 编辑对话框 -->
<el-dialog v-model="showEditDialog" :title="editForm.id ? '编辑翻译' : '新增翻译'" width="30vw" draggable>
<el-form :model="editForm" label-width="120px">
<el-form-item label="原文(中文):">
<el-input v-model="editForm.chineseSimplified" placeholder="请输入原文内容" show-word-limit />
</el-form-item>
<el-form-item label="英文:">
<el-input v-model="editForm.english" placeholder="请输入英文翻译" show-word-limit />
</el-form-item>
<el-form-item label="泰语:">
<el-input v-model="editForm.thai" placeholder="请输入泰语翻译" show-word-limit />
</el-form-item>
<el-form-item label="繁体中文:">
<el-input v-model="editForm.chineseTraditional" placeholder="请输入繁体中文翻译" show-word-limit />
</el-form-item>
<el-form-item label="马来语:">
<el-input v-model="editForm.malay" placeholder="请输入马来语翻译" show-word-limit />
</el-form-item>
<el-form-item label="越南语:">
<el-input v-model="editForm.vietnamese" placeholder="请输入越南语翻译" show-word-limit />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="showEditDialog = false">取消</el-button>
<el-button type="primary" @click="handleSave">保存</el-button>
</template>
</el-dialog>
<!-- 批量导入对话框 -->
<el-dialog v-model="showImportDialog" title="批量导入" width="40vw" draggable>
<div style="margin-bottom: 20px;">
<el-text>下载导入模板:</el-text>
<el-button type="text" @click="downloadTemplate">中文/英文/泰语/繁体中文/马来语/越南语模板</el-button>
</div>
<el-upload class="upload-demo" drag action="#" :auto-upload="false" :on-change="handleFileChange"
:show-file-list="false">
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
</el-upload>
<template #footer>
<el-button @click="showImportDialog = false">取消</el-button>
<el-button type="primary" @click="handleImport">导入</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { ElMessage, ElMessageBox } from 'element-plus';
import { onMounted, ref, computed } from 'vue'
import API from "@/util/http.js"
import moment from 'moment'
import { UploadFilled } from '@element-plus/icons-vue'
import ConfirmDialog from '@/components/dialogs/ConfirmDialog.vue'
// 引入AdminStore
import { useAdminStore } from '@/store/index.js';
import { storeToRefs } from "pinia";
const adminStore = useAdminStore();
const { adminData } = storeToRefs(adminStore);
// 响应式数据
const tableData = ref([])
const pagination = ref({
pageNum: 1,
pageSize: 20,
total: 0
})
const searchForm = ref({
chineseSimplified: '',
// 移除languageStatus字段
})
const showEditDialog = ref(false)
const showImportDialog = ref(false)
const showDeleteDialog = ref(false)
const currentDeleteRow = ref(null) // 当前要删除的行数据
const editForm = ref({
id: '',
chineseSimplified: '',
english: '',
thai: '',
chineseTraditional: '',
malay: '',
vietnamese: '',
// modules: [],
configTime: new Date()
})
// 移除计算属性 - 不再需要统一的状态计算
// const translationStatus = computed(() => {
// return (row) => {
// const hasTranslation = row.english || row.thai || row.chineseTraditional || row.malay || row.vietnamese
// return hasTranslation ? 'translated' : 'untranslated'
// }
// })
// 方法定义
const truncateText = (text) => {
if (!text) return ''
return text.length > 20 ? text.substring(0, 20) + '...' : text
}
// 移除getStatusType方法,因为现在每个语言列单独判断状态
// const getStatusType = (status) => {
// return status === 'translated' ? 'success' : 'info'
// }
// 搜索功能
const search = async () => {
await getTranslationList()
}
// 重置功能
const reset = () => {
searchForm.value = {
chineseSimplified: '',
// 移除languageStatus
}
getTranslationList()
}
// 获取翻译列表
const getTranslationList = async () => {
try {
const params = {
pageNum: pagination.value.pageNum,
pageSize: pagination.value.pageSize,
...searchForm.value
}
// 这里调用实际的API接口
const res = await API({
url: '/language/getTranslation',
data: params
})
if (res.code === 200) {
// 不再需要设置统一的状态字段
tableData.value = res.data.list
pagination.value.total = res.data.total
}
} catch (error) {
console.error('获取翻译列表失败:', error)
ElMessage.error('获取数据失败')
}
}
// 编辑翻译
const handleEdit = (row) => {
editForm.value = { ...row }
showEditDialog.value = true
}
// 新增翻译
const handleAdd = () => {
editForm.value = {
id: '',
chineseSimplified: '',
english: '',
thai: '',
chineseTraditional: '',
malay: '',
vietnamese: '',
// modules: [],
configTime: new Date()
}
showEditDialog.value = true
}
const getMenuTree = async function () {
// 获取菜单树
try {
const result = await request({
url: '/menu/tree',
data: {
id: adminData.value.roleId,
}
})
if (result.code === 200) {
adminStore.setMenuTree(result.data)
}
return result.data // 直接返回接口响应数据
} catch (error) {
console.error('菜单数据请求失败:', error)
// return { code: 500, msg: '获取菜单失败' }
ElMessage.error('网络异常')
adminStore.clearState()
}
}
// 保存翻译
const handleSave = async () => {
// 原文必填校验
if (!editForm.value.chineseSimplified || editForm.value.chineseSimplified.trim() === '') {
ElMessage.error('原文为必填项')
return
}
// 纯文本校验
const fields = ['english', 'thai', 'chineseTraditional', 'malay', 'vietnamese']
for (const field of fields) {
if (editForm.value[field] && /<[^>]*>/.test(editForm.value[field])) {
ElMessage.error('译文仅支持纯文本,不支持HTML标签')
return
}
}
try {
const url = editForm.value.id ? '/language/updateTranslation' : '/language/addTranslation'
const res = await API({
url: url,
data: editForm.value
})
if (res.code === 200) {
ElMessage.success(editForm.value.id ? '编辑成功' : '添加成功')
showEditDialog.value = false
getTranslationList()
} else if (res.code === 0) {
// 处理后端返回的错误信息
ElMessage.error(res.msg || '操作失败')
} else {
// 处理其他错误码
ElMessage.error(res.msg || '操作失败')
}
} catch (error) {
console.error('保存失败:', error)
ElMessage.error('保存失败')
}
// 点击保存后,刷新菜单树
await getMenuTree()
}
// 删除翻译 - 打开确认对话框
const handleDelete = (row) => {
currentDeleteRow.value = row
showDeleteDialog.value = true
}
// 确认删除
const handleDeleteConfirm = async () => {
try {
const res = await API({
url: '/language/deleteTranslation',
data: { id: currentDeleteRow.value.id }
})
if (res.code === 200) {
ElMessage.success('删除成功')
getTranslationList()
}
} catch (error) {
console.error('删除失败:', error)
ElMessage.error('删除失败')
} finally {
showDeleteDialog.value = false
currentDeleteRow.value = null
}
// 点击删除后,刷新菜单树
await getMenuTree()
}
// 取消删除
const handleDeleteCancel = () => {
showDeleteDialog.value = false
currentDeleteRow.value = null
}
// 关闭删除对话框
const handleDeleteClose = () => {
showDeleteDialog.value = false
currentDeleteRow.value = null
}
// 批量导入
const handleBatchImport = () => {
showImportDialog.value = true
}
// 下载模板
const downloadTemplate = () => {
// 这里实现下载模板的逻辑
ElMessage.info('模板下载功能待实现')
}
// 文件变化处理
const handleFileChange = (file) => {
// 这里处理文件上传逻辑
console.log('文件变化:', file)
}
// 导入处理
const handleImport = () => {
// 这里实现导入逻辑
ElMessage.info('导入功能待实现')
}
// 分页处理
const handleSizeChange = (val) => {
pagination.value.pageSize = val
pagination.value.pageNum = 1
getTranslationList()
}
const handleCurrentChange = (val) => {
pagination.value.pageNum = val
getTranslationList()
}
// 生命周期
onMounted(() => {
getTranslationList()
})
</script>
<style scoped lang="scss">
// 搜索卡片样式 - 与活动管理一致
.card1 {
background: #F3FAFE;
}
// 数据表格卡片样式 - 与活动管理一致
.card2 {
background: #E7F4FD;
}
// 表头背景等 - 与活动管理一致
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
.condition {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 16px;
}
.condition-item {
display: flex;
align-items: center;
min-width: 180px;
}
.btn {
display: flex;
align-items: center;
gap: 4px;
}
.add-item {
display: flex;
align-items: center;
gap: 4px;
margin-bottom: 1vh;
.add-item-export {
background-color: #5870FF;
color: white;
}
}
// 标签样式
.el-tag {
border: none;
}
// 上传组件样式
.upload-demo {
width: 100%;
}
:deep(.el-upload-dragger) {
width: 100%;
height: 180px;
}
</style>