完成报告模板请求
This commit is contained in:
parent
986f573956
commit
595054eb43
71
src/api/report/template.js
Normal file
71
src/api/report/template.js
Normal file
@ -0,0 +1,71 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 获取报告模板列表
|
||||
* @param {Object} params - 查询参数
|
||||
* @param {number} [params.page=1] - 页码
|
||||
* @param {number} [params.pageSize=10] - 每页条数
|
||||
* @param {string} [params.templateCode] - 模板编号
|
||||
* @param {string} [params.templateName] - 模板名称
|
||||
* @param {string} [params.templateType] - 模板类型
|
||||
* @param {number} [params.status] - 状态
|
||||
* @returns {Promise} 返回模板列表数据
|
||||
*/
|
||||
export function getTemplateList(params = {}) {
|
||||
return request.get('/api/reports/templates', {
|
||||
params: {
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
...params
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模板详情
|
||||
* @param {string|number} id - 模板ID
|
||||
* @returns {Promise} 返回模板详情数据
|
||||
*/
|
||||
export function getTemplateDetail(id) {
|
||||
return request.get(`/api/reports/templates/${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建报告模板
|
||||
* @param {Object} data - 模板数据
|
||||
* @returns {Promise} 返回创建结果
|
||||
*/
|
||||
export function createTemplate(data) {
|
||||
return request.post('/api/reports/templates', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新报告模板
|
||||
* @param {string|number} id - 模板ID
|
||||
* @param {Object} data - 更新数据
|
||||
* @returns {Promise} 返回更新结果
|
||||
*/
|
||||
export function updateTemplate(id, data) {
|
||||
return request.put(`/api/reports/templates/${id}`, data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除报告模板
|
||||
* @param {string|number} id - 模板ID
|
||||
* @returns {Promise} 返回删除结果
|
||||
*/
|
||||
export function deleteTemplate(id) {
|
||||
return request.delete(`/api/reports/templates/${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新模板状态
|
||||
* @param {string|number} id - 模板ID
|
||||
* @param {number} status - 状态:0-禁用 1-启用
|
||||
* @returns {Promise} 返回更新结果
|
||||
*/
|
||||
export function updateTemplateStatus(id, status) {
|
||||
return request.put(`/api/reports/templates/${id}/status`, {
|
||||
status: status === 1 ? 1 : 0 // 确保只发送 1 或 0
|
||||
})
|
||||
}
|
||||
@ -137,6 +137,7 @@ const handleLogout = () => {
|
||||
<span>报告管理</span>
|
||||
</template>
|
||||
<el-menu-item index="/report/daily">报告管理</el-menu-item>
|
||||
<el-menu-item index="/report/reportTemplates">报告模板</el-menu-item>
|
||||
<el-menu-item index="/report/analysis">分析报告</el-menu-item>
|
||||
<el-menu-item index="/report/about">项目背景</el-menu-item>
|
||||
</el-sub-menu>
|
||||
|
||||
@ -79,6 +79,11 @@ const router = createRouter({
|
||||
name: 'DailyReports',
|
||||
component: () => import('../views/report/daily/index.vue')
|
||||
},
|
||||
{
|
||||
path: 'report/reportTemplates',
|
||||
name: 'ReportTemplates',
|
||||
component: () => import('../views/report/reportTemplates/index.vue')
|
||||
},
|
||||
{
|
||||
path: 'report/analysis',
|
||||
name: 'AnalysisReports',
|
||||
|
||||
880
src/views/report/reportTemplates/index.vue
Normal file
880
src/views/report/reportTemplates/index.vue
Normal file
@ -0,0 +1,880 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, computed, watch } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus, Search, Refresh } from '@element-plus/icons-vue'
|
||||
import {
|
||||
getTemplateList,
|
||||
createTemplate,
|
||||
updateTemplate,
|
||||
deleteTemplate,
|
||||
updateTemplateStatus
|
||||
} from '@/api/report/template'
|
||||
import { formatDateTime } from '@/utils/format'
|
||||
|
||||
// 模板类型选项
|
||||
const templateTypeOptions = [
|
||||
{ label: '日报', value: 'daily' },
|
||||
{ label: '周报', value: 'weekly' },
|
||||
{ label: '月报', value: 'monthly' },
|
||||
{ label: '自定义', value: 'custom' }
|
||||
]
|
||||
|
||||
// 状态选项
|
||||
const statusOptions = [
|
||||
{ label: '启用', value: 1 },
|
||||
{ label: '禁用', value: 0 }
|
||||
]
|
||||
|
||||
// 搜索条件
|
||||
const searchForm = ref({
|
||||
templateCode: '',
|
||||
templateName: '',
|
||||
templateType: '',
|
||||
status: ''
|
||||
})
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([])
|
||||
const loading = ref(false)
|
||||
|
||||
// 分页配置
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const total = ref(0)
|
||||
|
||||
// 存储所有数据的数组
|
||||
const allData = ref([])
|
||||
|
||||
// 按字段排序的辅助函数
|
||||
const sortArrayByField = (array, field, direction = 'asc') => {
|
||||
return [...array].sort((a, b) => {
|
||||
if (!a[field]) return direction === 'asc' ? 1 : -1;
|
||||
if (!b[field]) return direction === 'asc' ? -1 : 1;
|
||||
|
||||
const valueA = a[field].toString().toLowerCase();
|
||||
const valueB = b[field].toString().toLowerCase();
|
||||
|
||||
if (valueA < valueB) return direction === 'asc' ? -1 : 1;
|
||||
if (valueA > valueB) return direction === 'asc' ? 1 : -1;
|
||||
return 0;
|
||||
});
|
||||
};
|
||||
|
||||
// 前端过滤数据
|
||||
const filteredData = computed(() => {
|
||||
let result = [...allData.value];
|
||||
|
||||
// 模板编号过滤
|
||||
if (searchForm.value.templateCode) {
|
||||
const keyword = searchForm.value.templateCode.toLowerCase();
|
||||
result = result.filter(item =>
|
||||
item.template_code?.toLowerCase().includes(keyword)
|
||||
);
|
||||
}
|
||||
|
||||
// 模板名称过滤
|
||||
if (searchForm.value.templateName) {
|
||||
const keyword = searchForm.value.templateName.toLowerCase();
|
||||
result = result.filter(item =>
|
||||
item.template_name?.toLowerCase().includes(keyword)
|
||||
);
|
||||
}
|
||||
|
||||
// 模板类型过滤
|
||||
if (searchForm.value.templateType) {
|
||||
result = result.filter(item =>
|
||||
item.template_type === searchForm.value.templateType
|
||||
);
|
||||
}
|
||||
|
||||
// 状态过滤 - 只在状态值为 0 或 1 时进行过滤
|
||||
if (searchForm.value.status === 0 || searchForm.value.status === 1) {
|
||||
result = result.filter(item =>
|
||||
item.status === searchForm.value.status
|
||||
);
|
||||
}
|
||||
|
||||
// 按创建时间正序排序
|
||||
return sortArrayByField(result, 'created_at', 'asc');
|
||||
});
|
||||
|
||||
// 分页后的表格数据
|
||||
const paginatedData = computed(() => {
|
||||
const start = (currentPage.value - 1) * pageSize.value;
|
||||
const end = start + pageSize.value;
|
||||
return filteredData.value.slice(start, end);
|
||||
});
|
||||
|
||||
// 更新表格数据
|
||||
const updateTableData = () => {
|
||||
tableData.value = paginatedData.value;
|
||||
total.value = filteredData.value.length;
|
||||
};
|
||||
|
||||
// 获取模板列表
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await getTemplateList();
|
||||
if (res.success) {
|
||||
allData.value = res.data || [];
|
||||
updateTableData();
|
||||
} else {
|
||||
ElMessage.error(res.message || '获取模板列表失败');
|
||||
allData.value = [];
|
||||
tableData.value = [];
|
||||
total.value = 0;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取模板列表错误:', error);
|
||||
ElMessage.error('获取模板列表失败');
|
||||
allData.value = [];
|
||||
tableData.value = [];
|
||||
total.value = 0;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 处理搜索
|
||||
const handleSearch = () => {
|
||||
currentPage.value = 1;
|
||||
updateTableData();
|
||||
};
|
||||
|
||||
// 重置搜索
|
||||
const resetSearch = () => {
|
||||
// 重置所有搜索条件为初始值
|
||||
searchForm.value = {
|
||||
templateCode: '',
|
||||
templateName: '',
|
||||
templateType: '',
|
||||
status: '' // 状态重置为空字符串
|
||||
};
|
||||
currentPage.value = 1;
|
||||
updateTableData();
|
||||
};
|
||||
|
||||
// 监听搜索条件、分页变化
|
||||
watch(
|
||||
[
|
||||
() => searchForm.value.templateCode,
|
||||
() => searchForm.value.templateName,
|
||||
() => searchForm.value.templateType,
|
||||
() => searchForm.value.status,
|
||||
() => currentPage.value,
|
||||
() => pageSize.value
|
||||
],
|
||||
() => {
|
||||
updateTableData();
|
||||
}
|
||||
);
|
||||
|
||||
// 刷新列表
|
||||
const handleRefresh = () => {
|
||||
getList()
|
||||
}
|
||||
|
||||
// 新增/编辑对话框
|
||||
const dialogVisible = ref(false)
|
||||
const dialogTitle = ref('')
|
||||
const formMode = ref('create') // create or edit
|
||||
const form = ref({
|
||||
template_name: '',
|
||||
template_type: '',
|
||||
content_structure: {
|
||||
sections: []
|
||||
},
|
||||
variables: {},
|
||||
status: 1
|
||||
})
|
||||
|
||||
// 修改表单规则,移除模板编号的必填验证
|
||||
const formRules = {
|
||||
template_name: [
|
||||
{ required: true, message: '请输入模板名称', trigger: 'blur' },
|
||||
{ min: 2, max: 100, message: '长度在 2 到 100 个字符', trigger: 'blur' }
|
||||
],
|
||||
template_type: [
|
||||
{ required: true, message: '请选择模板类型', trigger: 'change' }
|
||||
]
|
||||
}
|
||||
|
||||
// 修改打开新增对话框的处理函数
|
||||
const handleAdd = () => {
|
||||
formMode.value = 'create';
|
||||
dialogTitle.value = '新增模板';
|
||||
form.value = {
|
||||
template_name: '',
|
||||
template_type: '',
|
||||
content_structure: defaultTemplateStructure,
|
||||
variables: defaultVariables,
|
||||
status: 1
|
||||
};
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
// 打开编辑对话框
|
||||
const handleEdit = (row) => {
|
||||
formMode.value = 'edit'
|
||||
dialogTitle.value = '编辑模板'
|
||||
// 深拷贝数据,避免直接修改表格数据
|
||||
form.value = JSON.parse(JSON.stringify(row))
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
const formRef = ref(null)
|
||||
const handleSubmit = async () => {
|
||||
if (!formRef.value) return
|
||||
|
||||
await formRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
try {
|
||||
const submitData = { ...form.value }
|
||||
let res
|
||||
|
||||
if (formMode.value === 'create') {
|
||||
res = await createTemplate(submitData)
|
||||
} else {
|
||||
const id = submitData.id
|
||||
delete submitData.id
|
||||
res = await updateTemplate(id, submitData)
|
||||
}
|
||||
|
||||
if (res.success) {
|
||||
ElMessage.success(`${formMode.value === 'create' ? '新增' : '编辑'}成功`)
|
||||
dialogVisible.value = false
|
||||
getList()
|
||||
} else {
|
||||
ElMessage.error(res.message || `${formMode.value === 'create' ? '新增' : '编辑'}失败`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`${formMode.value === 'create' ? '新增' : '编辑'}模板错误:`, error)
|
||||
ElMessage.error(`${formMode.value === 'create' ? '新增' : '编辑'}失败`)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 删除模板
|
||||
const handleDelete = (row) => {
|
||||
// 如果模板有关联的报告,直接提示不能删除
|
||||
if (row.report_count > 0) {
|
||||
ElMessage.warning(`该模板下已关联${row.report_count}份报告,不能删除`);
|
||||
return;
|
||||
}
|
||||
|
||||
ElMessageBox.confirm('确认删除该模板吗?此操作不可恢复', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
try {
|
||||
const res = await deleteTemplate(row.id)
|
||||
if (res.success) {
|
||||
ElMessage.success('删除成功')
|
||||
getList()
|
||||
} else {
|
||||
ElMessage.error(res.message || '删除失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除模板错误:', error)
|
||||
ElMessage.error(error.response?.data?.message || error.message || '删除失败')
|
||||
}
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
// 更新模板状态
|
||||
const handleStatusChange = async (row) => {
|
||||
// 保存原始状态,用于出错时恢复
|
||||
const originalStatus = row.status;
|
||||
|
||||
// 如果要禁用且模板有关联的报告,直接阻止操作
|
||||
if (originalStatus === 0 && row.report_count > 0) {
|
||||
ElMessage.warning(`该模板下已关联${row.report_count}份报告,不能禁用`);
|
||||
row.status = 1; // 恢复开关状态
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await updateTemplateStatus(row.id, originalStatus);
|
||||
if (res.success) {
|
||||
ElMessage.success('状态更新成功');
|
||||
await getList(); // 刷新列表
|
||||
} else {
|
||||
row.status = originalStatus === 1 ? 0 : 1; // 恢复状态
|
||||
ElMessage.error(res.message || '状态更新失败');
|
||||
}
|
||||
} catch (error) {
|
||||
row.status = originalStatus === 1 ? 0 : 1; // 恢复状态
|
||||
console.error('更新模板状态错误:', error);
|
||||
ElMessage.error(error.response?.data?.message || error.message || '状态更新失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 格式化JSON显示
|
||||
const formatJSON = (json) => {
|
||||
try {
|
||||
return JSON.stringify(json, null, 2)
|
||||
} catch (error) {
|
||||
return '{}'
|
||||
}
|
||||
}
|
||||
|
||||
// 查看详情对话框
|
||||
const detailVisible = ref(false)
|
||||
const currentTemplate = ref(null)
|
||||
|
||||
// 查看模板详情
|
||||
const handleView = (row) => {
|
||||
currentTemplate.value = row;
|
||||
detailVisible.value = true;
|
||||
};
|
||||
|
||||
// 获取字段类型中文名称
|
||||
const getFieldTypeName = (type) => {
|
||||
const typeMap = {
|
||||
text: '文本',
|
||||
textarea: '多行文本',
|
||||
number: '数字',
|
||||
datetime: '日期时间',
|
||||
select: '下拉选择',
|
||||
checkbox: '多选框',
|
||||
radio: '单选框',
|
||||
image: '图片上传'
|
||||
};
|
||||
return typeMap[type] || type;
|
||||
};
|
||||
|
||||
// 添加默认的模板结构
|
||||
const defaultTemplateStructure = {
|
||||
sections: [
|
||||
{
|
||||
title: "基本信息",
|
||||
fields: [
|
||||
{
|
||||
name: "inspector",
|
||||
label: "巡检人员",
|
||||
type: "text",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: "inspection_time",
|
||||
label: "巡检时间",
|
||||
type: "datetime",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: "weather",
|
||||
label: "天气状况",
|
||||
type: "select",
|
||||
options: ["晴", "多云", "阴", "雨", "雪"],
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: "temperature",
|
||||
label: "温度(℃)",
|
||||
type: "number",
|
||||
required: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "水质监测",
|
||||
fields: [
|
||||
{
|
||||
name: "water_temperature",
|
||||
label: "水温(℃)",
|
||||
type: "number",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: "ph_value",
|
||||
label: "pH值",
|
||||
type: "number",
|
||||
required: true,
|
||||
min: 0,
|
||||
max: 14
|
||||
},
|
||||
{
|
||||
name: "dissolved_oxygen",
|
||||
label: "溶解氧(mg/L)",
|
||||
type: "number",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: "turbidity",
|
||||
label: "浊度(NTU)",
|
||||
type: "number",
|
||||
required: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "生态观察",
|
||||
fields: [
|
||||
{
|
||||
name: "plant_status",
|
||||
label: "植物状况",
|
||||
type: "textarea",
|
||||
required: true,
|
||||
placeholder: "请描述植物生长情况、是否发现外来物种等"
|
||||
},
|
||||
{
|
||||
name: "animal_observation",
|
||||
label: "动物观察",
|
||||
type: "textarea",
|
||||
required: true,
|
||||
placeholder: "请记录观察到的动物种类、数量等"
|
||||
},
|
||||
{
|
||||
name: "photos",
|
||||
label: "现场照片",
|
||||
type: "image",
|
||||
required: true,
|
||||
max_count: 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "问题记录",
|
||||
fields: [
|
||||
{
|
||||
name: "issues",
|
||||
label: "发现的问题",
|
||||
type: "checkbox",
|
||||
options: [
|
||||
"水质异常",
|
||||
"植物病虫害",
|
||||
"外来物种入侵",
|
||||
"人为破坏",
|
||||
"设备故障",
|
||||
"其他"
|
||||
],
|
||||
required: false
|
||||
},
|
||||
{
|
||||
name: "issue_description",
|
||||
label: "问题描述",
|
||||
type: "textarea",
|
||||
required: false,
|
||||
placeholder: "请详细描述发现的问题"
|
||||
},
|
||||
{
|
||||
name: "emergency_level",
|
||||
label: "紧急程度",
|
||||
type: "radio",
|
||||
options: ["一般", "较急", "紧急", "特急"],
|
||||
required: false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "处理建议",
|
||||
fields: [
|
||||
{
|
||||
name: "suggestions",
|
||||
label: "处理建议",
|
||||
type: "textarea",
|
||||
required: false,
|
||||
placeholder: "请提出处理问题的建议"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// 添加默认的变量定义
|
||||
const defaultVariables = {
|
||||
location: {
|
||||
type: "string",
|
||||
label: "巡检地点",
|
||||
default: "主湿地公园"
|
||||
},
|
||||
department: {
|
||||
type: "string",
|
||||
label: "巡检部门",
|
||||
default: "生态保护科"
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="report-templates">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>报告模板</span>
|
||||
<div class="header-btns">
|
||||
<el-button type="primary" :icon="Plus" @click="handleAdd">新增模板</el-button>
|
||||
<el-button :icon="Refresh" @click="handleRefresh">刷新</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 搜索表单 -->
|
||||
<el-form :model="searchForm" inline class="search-form">
|
||||
<el-form-item label="模板编号" label-width="80px">
|
||||
<el-input
|
||||
v-model="searchForm.templateCode"
|
||||
placeholder="请输入模板编号"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="模板名称" label-width="80px">
|
||||
<el-input
|
||||
v-model="searchForm.templateName"
|
||||
placeholder="请输入模板名称"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="模板类型" label-width="80px">
|
||||
<el-select
|
||||
v-model="searchForm.templateType"
|
||||
placeholder="请选择类型"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in templateTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" label-width="80px">
|
||||
<el-select
|
||||
v-model="searchForm.status"
|
||||
placeholder="请选择状态"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in statusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="search-buttons">
|
||||
<el-button type="primary" :icon="Search" @click="handleSearch">搜索</el-button>
|
||||
<el-button @click="resetSearch">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 模板列表 -->
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="tableData"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="60" align="center"/>
|
||||
<el-table-column prop="template_code" label="模板编号" width="120" align="center"/>
|
||||
<el-table-column prop="template_name" label="模板名称" min-width="150" show-overflow-tooltip align="center"/>
|
||||
<el-table-column prop="template_type" label="模板类型" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
:type="row.template_type === 'daily' ? 'primary' :
|
||||
row.template_type === 'weekly' ? 'success' :
|
||||
row.template_type === 'monthly' ? 'warning' :
|
||||
row.template_type === 'custom' ? 'danger' :
|
||||
'info'"
|
||||
size="small"
|
||||
>
|
||||
{{ row.template_type === 'daily' ? '日报' :
|
||||
row.template_type === 'weekly' ? '周报' :
|
||||
row.template_type === 'monthly' ? '月报' :
|
||||
row.template_type === 'custom' ? '自定义' :
|
||||
'未知' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="report_count" label="关联报告" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.report_count > 0 ? 'warning' : 'info'" size="small">
|
||||
{{ row.report_count > 0 ? `${row.report_count}份报告` : '无报告' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-switch
|
||||
v-model="row.status"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
@change="() => handleStatusChange(row)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="created_at" label="创建时间" width="160" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ formatDateTime(row.created_at) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="updated_at" label="更新时间" width="160" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ formatDateTime(row.updated_at) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="250" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="handleView(row)">查看</el-button>
|
||||
<el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button type="danger" link @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页器 -->
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
v-model:current-page="currentPage"
|
||||
v-model:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
background
|
||||
layout="total, sizes, prev, pager, next"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 新增/编辑对话框 -->
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogTitle"
|
||||
width="800px"
|
||||
destroy-on-close
|
||||
>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="formRules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="模板名称" prop="template_name">
|
||||
<el-input
|
||||
v-model="form.template_name"
|
||||
placeholder="请输入模板名称"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="模板类型" prop="template_type">
|
||||
<el-select
|
||||
v-model="form.template_type"
|
||||
placeholder="请选择模板类型"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in templateTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="内容结构">
|
||||
<el-input
|
||||
v-model="form.content_structure"
|
||||
type="textarea"
|
||||
:rows="10"
|
||||
:value="formatJSON(form.content_structure)"
|
||||
@input="val => form.content_structure = JSON.parse(val || '{}')"
|
||||
placeholder="请输入JSON格式的内容结构"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="变量定义">
|
||||
<el-input
|
||||
v-model="form.variables"
|
||||
type="textarea"
|
||||
:rows="6"
|
||||
:value="formatJSON(form.variables)"
|
||||
@input="val => form.variables = JSON.parse(val || '{}')"
|
||||
placeholder="请输入JSON格式的变量定义"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-switch
|
||||
v-model="form.status"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">确定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 添加查看详情对话框 -->
|
||||
<el-dialog
|
||||
v-model="detailVisible"
|
||||
title="模板详情"
|
||||
width="800px"
|
||||
destroy-on-close
|
||||
>
|
||||
<el-descriptions
|
||||
v-if="currentTemplate"
|
||||
:column="2"
|
||||
border
|
||||
>
|
||||
<el-descriptions-item label="模板编号" :span="2">
|
||||
{{ currentTemplate.template_code }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="模板名称" :span="2">
|
||||
{{ currentTemplate.template_name }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="模板类型">
|
||||
<el-tag
|
||||
:type="currentTemplate.template_type === 'daily' ? 'primary' :
|
||||
currentTemplate.template_type === 'weekly' ? 'success' :
|
||||
currentTemplate.template_type === 'monthly' ? 'warning' :
|
||||
currentTemplate.template_type === 'custom' ? 'danger' :
|
||||
'info'"
|
||||
>
|
||||
{{ currentTemplate.template_type === 'daily' ? '日报' :
|
||||
currentTemplate.template_type === 'weekly' ? '周报' :
|
||||
currentTemplate.template_type === 'monthly' ? '月报' :
|
||||
currentTemplate.template_type === 'custom' ? '自定义' :
|
||||
'未知' }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">
|
||||
<el-tag :type="currentTemplate.status === 1 ? 'success' : 'info'">
|
||||
{{ currentTemplate.status === 1 ? '启用' : '禁用' }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 内容结构 -->
|
||||
<div v-if="currentTemplate?.content_structure?.sections" class="template-content mt-20">
|
||||
<div v-for="(section, sIndex) in currentTemplate.content_structure.sections" :key="sIndex" class="section-item">
|
||||
<h3 class="section-title">{{ section.title }}</h3>
|
||||
<el-table :data="section.fields" border style="width: 100%">
|
||||
<el-table-column prop="label" label="字段名称" width="150" />
|
||||
<el-table-column prop="name" label="字段标识" width="150" />
|
||||
<el-table-column label="字段类型" width="120">
|
||||
<template #default="{ row }">
|
||||
<el-tag size="small">{{ getFieldTypeName(row.type) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="是否必填" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.required ? 'danger' : 'info'" size="small">
|
||||
{{ row.required ? '是' : '否' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="其他设置">
|
||||
<template #default="{ row }">
|
||||
<div v-if="row.options">选项: {{ row.options.join(', ') }}</div>
|
||||
<div v-if="row.min !== undefined">最小值: {{ row.min }}</div>
|
||||
<div v-if="row.max !== undefined">最大值: {{ row.max }}</div>
|
||||
<div v-if="row.max_count">最大数量: {{ row.max_count }}</div>
|
||||
<div v-if="row.placeholder">提示文本: {{ row.placeholder }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 变量定义 -->
|
||||
<div v-if="currentTemplate?.variables" class="variables mt-20">
|
||||
<h3 class="section-title">变量定义</h3>
|
||||
<el-table :data="Object.entries(currentTemplate.variables).map(([key, value]) => ({
|
||||
key,
|
||||
...value
|
||||
}))" border style="width: 100%">
|
||||
<el-table-column prop="key" label="变量名" width="150" />
|
||||
<el-table-column prop="label" label="显示名称" width="150" />
|
||||
<el-table-column prop="type" label="类型" width="120">
|
||||
<template #default="{ row }">
|
||||
<el-tag size="small">{{ getFieldTypeName(row.type) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="default" label="默认值" />
|
||||
</el-table>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.report-templates {
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.header-btns {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.search-form {
|
||||
margin-bottom: 24px;
|
||||
padding: 24px;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 16px;
|
||||
margin-right: 24px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-input),
|
||||
:deep(.el-select) {
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
.search-buttons {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.mt-20 {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.template-content {
|
||||
.section-item {
|
||||
margin-bottom: 24px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin: 16px 0;
|
||||
padding-left: 10px;
|
||||
border-left: 4px solid var(--el-color-primary);
|
||||
}
|
||||
</style>
|
||||
Loading…
x
Reference in New Issue
Block a user