完成报告模板请求
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>
|
<span>报告管理</span>
|
||||||
</template>
|
</template>
|
||||||
<el-menu-item index="/report/daily">报告管理</el-menu-item>
|
<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/analysis">分析报告</el-menu-item>
|
||||||
<el-menu-item index="/report/about">项目背景</el-menu-item>
|
<el-menu-item index="/report/about">项目背景</el-menu-item>
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
|
|||||||
@ -79,6 +79,11 @@ const router = createRouter({
|
|||||||
name: 'DailyReports',
|
name: 'DailyReports',
|
||||||
component: () => import('../views/report/daily/index.vue')
|
component: () => import('../views/report/daily/index.vue')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'report/reportTemplates',
|
||||||
|
name: 'ReportTemplates',
|
||||||
|
component: () => import('../views/report/reportTemplates/index.vue')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'report/analysis',
|
path: 'report/analysis',
|
||||||
name: 'AnalysisReports',
|
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