Files
ZDXX/zhandianxinxi/光谱数据监控/src/views/MaintenanceLogs.vue
2026-01-09 09:44:40 +08:00

304 lines
8.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-config-provider :locale="zhCn">
<el-dialog
v-model="visible"
title="🔧 维修与故障日志中心"
width="85%"
top="5vh"
destroy-on-close
append-to-body
>
<div class="logs-container">
<div class="toolbar">
<div class="filter-group">
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
@change="fetchLogs"
style="width: 260px"
/>
<el-input
v-model="keyword"
placeholder="搜索:设备名 / 工程师 / 内容"
style="width: 300px"
clearable
@clear="fetchLogs"
@keyup.enter="fetchLogs"
>
<template #prefix><el-icon><Search /></el-icon></template>
</el-input>
<el-button type="primary" @click="fetchLogs">查询</el-button>
</div>
<div class="action-group">
<el-button type="success" icon="Plus" @click="openAddDialog">新增记录</el-button>
</div>
</div>
<el-table
:data="logsList"
border
stripe
v-loading="loading"
height="550"
style="width: 100%; margin-top: 15px"
>
<el-table-column prop="timestamp" label="记录时间" width="170" sortable />
<el-table-column prop="device_name" label="设备名称" width="180">
<template #default="{ row }">
<el-tag effect="plain">{{ formatDisplayName(row.device_name) }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="location" label="地点" width="150" show-overflow-tooltip />
<el-table-column prop="engineer" label="工程师" width="120" />
<el-table-column prop="content" label="维修/故障详情" min-width="300" show-overflow-tooltip />
<el-table-column label="操作" width="180" align="center" fixed="right">
<template #default="{ row }">
<el-button
type="primary"
link
icon="Edit"
@click="openEditDialog(row)"
style="margin-right: 5px;"
>
修改
</el-button>
<el-popconfirm title="确定删除这条记录吗?" @confirm="deleteLog(row.id)">
<template #reference>
<el-button type="danger" link icon="Delete">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
<el-dialog
v-model="logDialog.visible"
:title="logDialog.isEdit ? '✏️ 修改维修记录' : '📝 新增维修记录'"
width="500px"
append-to-body
>
<el-form :model="logDialog.form" label-width="80px" label-position="top">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="设备名称">
<el-input
v-model="logDialog.form.device_name"
placeholder="例: 106_Tower"
:disabled="logDialog.isEdit"
/>
<div v-if="logDialog.isEdit" class="form-tip">
<el-icon><InfoFilled /></el-icon> 为了数据追溯修改模式下禁止更改关联设备
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="工程师">
<el-input v-model="logDialog.form.engineer" placeholder="例: 张工" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="地点">
<el-input v-model="logDialog.form.location" placeholder="例: 3号楼顶层" />
</el-form-item>
<el-form-item label="事件内容">
<el-input
v-model="logDialog.form.content"
type="textarea"
:rows="4"
placeholder="描述故障原因及处理结果..."
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="logDialog.visible = false">取消</el-button>
<el-button type="primary" @click="submitLog" :loading="logDialog.submitting">
{{ logDialog.isEdit ? '保存修改' : '提交保存' }}
</el-button>
</template>
</el-dialog>
</el-dialog>
</el-config-provider>
</template>
<script setup>
import { ref, reactive } from 'vue'
import axios from 'axios'
import { ElMessage, ElConfigProvider } from 'element-plus'
import { Search, Plus, Delete, Edit, InfoFilled } from '@element-plus/icons-vue'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
const API_BASE = import.meta.env.DEV ? 'http://127.0.0.1:5000' : ''
// --- 核心状态 ---
const visible = ref(false)
const loading = ref(false)
const logsList = ref([])
const keyword = ref('')
const dateRange = ref([])
// 弹窗状态封装
const logDialog = reactive({
visible: false,
submitting: false,
isEdit: false,
form: {
id: null,
device_name: '',
engineer: '',
location: '',
content: ''
}
})
// --- 方法逻辑 ---
// 1. 暴露给父组件的打开方法
const open = (prefillData = null) => {
visible.value = true
// 如果从设备卡片点击进来,自动筛选该设备
if (prefillData && prefillData.deviceName) {
keyword.value = prefillData.deviceName
}
fetchLogs()
}
// 2. 获取数据列表
const fetchLogs = async () => {
loading.value = true
try {
const params = { keyword: keyword.value }
if (dateRange.value && dateRange.value.length === 2) {
params.start_date = dateRange.value[0]
params.end_date = dateRange.value[1]
}
const res = await axios.get(`${API_BASE}/api/logs/list`, { params })
logsList.value = res.data.data
} catch (e) {
ElMessage.error('加载日志中心数据失败')
} finally {
loading.value = false
}
}
// 3. 处理新增
const openAddDialog = () => {
logDialog.isEdit = false
logDialog.form = {
id: null,
// 自动带入当前的搜索词作为设备名,提高录入效率
device_name: keyword.value || '',
engineer: '',
location: '',
content: ''
}
logDialog.visible = true
}
// 4. 处理修改
const openEditDialog = (row) => {
logDialog.isEdit = true
logDialog.form = {
id: row.id,
device_name: row.device_name,
engineer: row.engineer,
location: row.location,
content: row.content
}
logDialog.visible = true
}
// 5. 提交表单(核心逻辑区分)
const submitLog = async () => {
if (!logDialog.form.device_name || !logDialog.form.content) {
return ElMessage.warning('设备名称和事件内容为必填项')
}
logDialog.submitting = true
try {
const endpoint = logDialog.isEdit ? '/api/logs/update' : '/api/logs/add'
await axios.post(`${API_BASE}${endpoint}`, logDialog.form)
ElMessage.success(logDialog.isEdit ? '日志已成功修改' : '日志已添加')
logDialog.visible = false
fetchLogs() // 刷新列表
} catch (e) {
ElMessage.error('操作失败,请检查网络或后端服务')
} finally {
logDialog.submitting = false
}
}
// 6. 删除逻辑
const deleteLog = async (id) => {
try {
await axios.post(`${API_BASE}/api/logs/delete`, { id })
ElMessage.success('记录已安全删除')
fetchLogs()
} catch (e) {
ElMessage.error('删除操作失败')
}
}
// 格式化名称工具
const formatDisplayName = (name) => name ? name.toUpperCase().replace(/_/g, ' ') : ''
// 暴露方法给父组件 Dashboard 调用
defineExpose({ open })
</script>
<style scoped>
.logs-container {
padding: 10px;
}
.toolbar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
flex-wrap: wrap;
gap: 15px;
}
.filter-group {
display: flex;
gap: 12px;
align-items: center;
}
.form-tip {
font-size: 12px;
color: #909399;
margin-top: 6px;
display: flex;
align-items: center;
gap: 4px;
}
/* 调整输入框禁用时的样式,保持可读性 */
:deep(.el-input.is-disabled .el-input__wrapper) {
background-color: #f5f7fa;
box-shadow: 0 0 0 1px #e4e7ed inset;
}
:deep(.el-input.is-disabled .el-input__inner) {
color: #606266;
-webkit-text-fill-color: #606266;
}
</style>