完成设备检测

master
lynn 3 months ago
parent 4fb45727b1
commit 41431d2cce

@ -0,0 +1,35 @@
import request from '@/utils/request'
export function getGasConfig() {
return request({
url: '/api/admin/gas-config/index',
method: 'get'
})
}
export function saveGasConfig(data) {
return request({
url: '/api/admin/gas-config/save',
method: 'post',
data
})
}
export function destroyGasConfig(params) {
return request({
url: '/api/admin/gas-config/destroy',
method: 'get',
params
})
}
export function getGasList(params) {
return request({
url: '/api/admin/gas/index',
method: 'get',
params
})
}

@ -153,41 +153,41 @@
width="600"
:mask-closable="false"
>
<Form ref="maintenanceForm" :model="form" :rules="formRules" :label-width="120">
<FormItem label="实际维护日期" prop="actual_date">
<DatePicker v-model="form.actual_date" type="date" placeholder="请选择实际维护日期" style="width: 100%" />
</FormItem>
<FormItem label="维护备注" prop="notes">
<Input v-model="form.notes" type="textarea" :rows="4" placeholder="请输入维护备注" />
</FormItem>
<FormItem label="上传图片" prop="photos">
<Upload
ref="upload"
:before-upload="handleBeforeUpload"
:on-success="handleUploadSuccess"
:on-error="handleUploadError"
:on-remove="handleRemove"
:max-size="2048"
multiple
type="drag"
:action="baseUrl + 'api/admin/upload-file'"
>
<div style="padding: 20px 0">
<Icon type="ios-cloud-upload" size="52" style="color: #3399ff" />
<p>点击或拖拽文件到此处上传</p>
</div>
</Upload>
</FormItem>
<FormItem label="签名" prop="signature">
<div class="signature-pad-wrapper">
<canvas ref="signaturePad" class="signature-canvas" />
<Button size="small" style="margin-top: 8px;" @click="clearSignature"></Button>
</div>
</FormItem>
</Form>
<Form ref="maintenanceForm" :model="form" :rules="formRules" :label-width="120">
<FormItem label="实际维护日期" prop="actual_date">
<DatePicker v-model="form.actual_date" type="date" placeholder="请选择实际维护日期" style="width: 100%" />
</FormItem>
<FormItem label="维护备注" prop="notes">
<Input v-model="form.notes" type="textarea" :rows="4" placeholder="请输入维护备注" />
</FormItem>
<FormItem label="上传图片" prop="photos">
<Upload
ref="upload"
:before-upload="handleBeforeUpload"
:on-success="handleUploadSuccess"
:on-error="handleUploadError"
:on-remove="handleRemove"
:max-size="2048"
multiple
type="drag"
:action="baseUrl + 'api/admin/upload-file'"
>
<div style="padding: 20px 0">
<Icon type="ios-cloud-upload" size="52" style="color: #3399ff" />
<p>点击或拖拽文件到此处上传</p>
</div>
</Upload>
</FormItem>
<FormItem label="签名" prop="signature">
<div class="signature-pad-wrapper">
<canvas ref="signaturePad" class="signature-canvas" />
<Button size="small" style="margin-top: 8px;" @click="clearSignature"></Button>
</div>
</FormItem>
</Form>
<template slot="footer">
<Button @click="closeModal"></Button>
<Button type="primary" @click="submitMaintenance"></Button>
<Button @click="closeModal"></Button>
<Button type="primary" @click="submitMaintenance"></Button>
</template>
</Modal>
@ -198,66 +198,66 @@
width="900"
:mask-closable="true"
>
<div class="modal-body">
<div class="form-group">
<label>记录编号:</label>
<div class="form-value">{{ currentRecord.no }}</div>
</div>
<div class="form-group">
<label>维护物资:</label>
<div class="form-value">{{ currentRecord.stocks_item_name }}</div>
</div>
<div class="form-group">
<label>计划维护日期:</label>
<div class="form-value">{{ currentRecord.planned_maintenance_date }}</div>
</div>
<div class="form-group">
<label>实际维护日期:</label>
<div class="form-value">{{ currentRecord.maintenance_date || '-' }}</div>
</div>
<div class="form-group">
<label>负责人:</label>
<div class="form-value">{{ currentRecord.responsible_admin_name }}</div>
</div>
<div class="form-group">
<label>状态:</label>
<div class="form-value">{{ getStatusText(currentRecord.status) }}</div>
</div>
<div class="form-group">
<label>维护备注:</label>
<div class="form-value">{{ currentRecord.maintenance_notes || '-' }}</div>
</div>
<div class="form-group">
<label>维护照片:</label>
<div v-if="currentRecord.files && currentRecord.files.length" class="photo-gallery">
<img
v-for="(file, idx) in currentRecord.files"
:key="'file-' + idx"
:src="file.url"
class="photo-preview"
style="cursor:pointer;"
alt="维护图片"
@click="previewImage(file.url)"
>
</div>
<div v-else class="form-value">-</div>
</div>
<div class="form-group">
<label>签名照片:</label>
<div v-if="currentRecord.sign && currentRecord.sign.url" class="photo-gallery">
<img
:src="currentRecord.sign.url"
class="sign-preview"
style="cursor:pointer;"
alt="签名图片"
@click="previewImage(currentRecord.sign.url)"
>
<div class="modal-body">
<div class="form-group">
<label>记录编号:</label>
<div class="form-value">{{ currentRecord.no }}</div>
</div>
<div class="form-group">
<label>维护物资:</label>
<div class="form-value">{{ currentRecord.stocks_item_name }}</div>
</div>
<div class="form-group">
<label>计划维护日期:</label>
<div class="form-value">{{ currentRecord.planned_maintenance_date }}</div>
</div>
<div class="form-group">
<label>实际维护日期:</label>
<div class="form-value">{{ currentRecord.maintenance_date || '-' }}</div>
</div>
<div class="form-group">
<label>负责人:</label>
<div class="form-value">{{ currentRecord.responsible_admin_name }}</div>
</div>
<div class="form-group">
<label>状态:</label>
<div class="form-value">{{ getStatusText(currentRecord.status) }}</div>
</div>
<div class="form-group">
<label>维护备注:</label>
<div class="form-value">{{ currentRecord.maintenance_notes || '-' }}</div>
</div>
<div class="form-group">
<label>维护照片:</label>
<div v-if="currentRecord.files && currentRecord.files.length" class="photo-gallery">
<img
v-for="(file, idx) in currentRecord.files"
:key="'file-' + idx"
:src="file.url"
class="photo-preview"
style="cursor:pointer;"
alt="维护图片"
@click="previewImage(file.url)"
>
</div>
<div v-else class="form-value">-</div>
</div>
<div class="form-group">
<label>签名照片:</label>
<div v-if="currentRecord.sign && currentRecord.sign.url" class="photo-gallery">
<img
:src="currentRecord.sign.url"
class="sign-preview"
style="cursor:pointer;"
alt="签名图片"
@click="previewImage(currentRecord.sign.url)"
>
</div>
<div v-else class="form-value">-</div>
</div>
</div>
<div v-else class="form-value">-</div>
</div>
</div>
<template slot="footer">
<Button @click="closeViewModal"></Button>
<Button @click="closeViewModal"></Button>
</template>
</Modal>
@ -273,21 +273,21 @@
width="500"
:mask-closable="false"
>
<Form ref="createForm" :model="createForm" :rules="createFormRules" :label-width="120">
<FormItem label="维护物资" prop="material_id">
<div class="material-select">
<Input v-model="createForm.material_name" readonly placeholder="请选择维护物资" style="width: calc(100% - 100px);" />
<input v-model="createForm.material_id" type="hidden">
<Button type="primary" style="margin-left: 8px;" @click="openMaterialModal"></Button>
</div>
</FormItem>
<FormItem label="计划维护日期" prop="planned_maintenance_date">
<DatePicker v-model="createForm.planned_maintenance_date" type="date" placeholder="请选择计划维护日期" style="width: 100%" />
</FormItem>
</Form>
<Form ref="createForm" :model="createForm" :rules="createFormRules" :label-width="120">
<FormItem label="维护物资" prop="material_id">
<div class="material-select">
<Input v-model="createForm.material_name" readonly placeholder="请选择维护物资" style="width: calc(100% - 100px);" />
<input v-model="createForm.material_id" type="hidden">
<Button type="primary" style="margin-left: 8px;" @click="openMaterialModal"></Button>
</div>
</FormItem>
<FormItem label="计划维护日期" prop="planned_maintenance_date">
<DatePicker v-model="createForm.planned_maintenance_date" type="date" placeholder="请选择计划维护日期" style="width: 100%" />
</FormItem>
</Form>
<template slot="footer">
<Button @click="closeCreateModal"></Button>
<Button type="primary" @click="submitCreateMaintenance"></Button>
<Button @click="closeCreateModal"></Button>
<Button type="primary" @click="submitCreateMaintenance"></Button>
</template>
</Modal>

@ -79,6 +79,8 @@
</template>
<script>
import { getGasList } from '@/api/monitor'
export default {
name: 'MonitorPage',
data() {
@ -106,31 +108,51 @@ export default {
channel: '[DS-2CD2225XM-LGLSE(AE1005197)- AE1005197]'
}
],
environmentPoints: [
{ id: 'A', name: '监控点 A', status: '正常', coConcentration: '2.5 ppm', temperature: '24.5 ℃', humidity: '45 %', updateTime: '2024-01-05' },
{ id: 'B', name: '监控点 B', status: '预警', coConcentration: '8.2 ppm', temperature: '26.8 ℃', humidity: '52 %', updateTime: '2024-01-05' },
{ id: 'C', name: '监控点 C', status: '正常', coConcentration: '1.8 ppm', temperature: '23.9 ℃', humidity: '48 %', updateTime: '2024-01-05' }
]
environmentPoints: []
}
},
mounted() {
this.loadEnvironmentPoints()
},
methods: {
async loadEnvironmentPoints() {
try {
const response = await getGasList()
const list = response.data ? response.data : []
// node_id1,3,5
const wantedNodeIds = ['1', '3', '5']
const filtered = wantedNodeIds.map(nodeId => {
const group = list.filter(item => String(item.node_id) === nodeId)
if (group.length === 0) return null
group.sort((a, b) => new Date(b.update_time || b.created_at || 0) - new Date(a.update_time || a.created_at || 0))
return group[0]
}).filter(Boolean)
const nodeIdMap = { '5': '3', '3': '2', '1': '1' }
this.environmentPoints = filtered.map(item => ({
id: item.id,
name: `监控点${nodeIdMap[String(item.node_id)] || item.node_id}`,
status: item.status || '正常',
coConcentration: item.co_concentration != null && item.co_concentration !== '' ? `${item.co_concentration} ppm` : '-',
temperature: item.temperature != null && item.temperature !== '' ? `${item.temperature}` : '-',
humidity: item.humidity != null && item.humidity !== '' ? `${item.humidity} %` : '-',
updateTime: item.record_time || ''
}))
} catch (error) {
this.$message && this.$message.error('环境检测数据获取失败')
}
},
getCardClass(status) {
if (status === '正常') {
// Assuming the green normal status is also '' based on context,
// We check the ID for C to apply green, otherwise blue
// Or better, add a specific status like 'Normal-Green' if data allows
return 'status-normal-blue' // Default blue for ''
// For point C, if we assume its status implies green:
// return pointId === 'C' ? 'status-normal-green' : 'status-normal-blue';
return 'status-normal-blue'
} else if (status === '预警') {
return 'status-warning'
}
return ''
},
getTagType(status) {
if (status === '正常') return 'success' // Element UI tag type for green/blue normal
if (status === '预警') return 'warning' // Element UI tag type for yellow warning
return 'info' // Default
if (status === '正常') return 'success'
if (status === '预警') return 'warning'
return 'info'
}
}
}

@ -6,9 +6,18 @@
</div>
<!-- 监控点配置 -->
<el-form ref="monitorForm" :model="monitorPoints" label-width="120px">
<el-form ref="monitorForm" label-width="120px">
<!-- 添加监控点按钮 -->
<div class="add-monitor-section">
<el-button type="primary" @click="addMonitorPoint" icon="el-icon-plus">
添加监控点
</el-button>
</div>
<div v-for="(point, index) in monitorPoints" :key="`point-${index}`" class="monitor-point-config">
<div class="point-header">监控点 {{ point.name }}</div>
<div class="point-header">
<span>监控点 {{ point.name }}</span>
</div>
<!-- 视频配置 -->
<el-form-item :label="`摄像头地址`">
@ -19,10 +28,19 @@
<el-input v-model="point.videoName" placeholder="请输入摄像头名称" />
</el-form-item>
<!-- 环境监测阈值 -->
<el-divider content-position="left">环境监测阈值</el-divider>
<el-form-item label="CO浓度阈值(ppm)">
<el-form-item label="设备地址">
<el-input v-model="point.deviceAddress" placeholder="请输入设备地址" />
</el-form-item>
<el-form-item label="节点ID">
<el-input v-model="point.nodeId" placeholder="请输入节点ID" />
</el-form-item>
<!-- 环境监测阈值 -->
<el-divider content-position="left">环境监测阈值超过此值将触发预警</el-divider>
<el-form-item label="CO浓度阈值">
<el-input-number
v-model="point.coThreshold"
:min="0"
@ -31,9 +49,9 @@
:precision="1"
controls-position="right"
/>
<span class="description">超过此值将触发预警</span>
<span class="threshold-label">PPM</span>
</el-form-item>
<el-form-item label="温度阈值(℃)">
<el-row>
<el-col :span="11">
@ -79,6 +97,28 @@
</el-col>
</el-row>
</el-form-item>
<!-- 监控点配置保存按钮 -->
<el-form-item>
<el-button type="primary" @click="saveMonitorSettings(index)" :loading="saveLoading" icon="el-icon-check">
保存
</el-button>
<el-button
v-if="point.id"
type="danger"
@click="deleteMonitorPoint(index)"
icon="el-icon-delete"
>
删除
</el-button>
<el-button
v-else
@click="cancelAddMonitorPoint(index)"
icon="el-icon-close"
>
取消
</el-button>
</el-form-item>
</div>
</el-form>
@ -112,62 +152,55 @@
</el-table-column>
</el-table>
</el-form>
<el-form-item>
<el-button type="primary" @click="saveSettings"></el-button>
<el-button @click="resetForm"></el-button>
</el-form-item>
</el-card>
</div>
</template>
<script>
import { getGasConfig, saveGasConfig, destroyGasConfig } from '@/api/monitor'
export default {
name: 'WarningSetting',
data() {
return {
monitorPoints: [
{
name: 'A',
videoName: '摄像头1',
videoUrl: 'ezopen://open.ys7.com/203751922/1.cga',
coThreshold: 5.0,
tempMinThreshold: 15,
tempMaxThreshold: 30,
humidityMinThreshold: 30,
humidityMaxThreshold: 70
},
{
name: 'B',
videoName: '摄像头2',
videoUrl: 'ezopen://open.ys7.com/F59651352/1.cga',
coThreshold: 5.0,
tempMinThreshold: 15,
tempMaxThreshold: 30,
humidityMinThreshold: 30,
humidityMaxThreshold: 70
},
{
name: 'C',
videoName: '摄像头3',
videoUrl: 'ezopen://open.ys7.com/G39410642/1.cga',
coThreshold: 5.0,
tempMinThreshold: 15,
tempMaxThreshold: 30,
humidityMinThreshold: 30,
humidityMaxThreshold: 70
}
],
monitorPoints: [],
warningForm: {
phoneNumber: '',
receivers: [
{ phone: '13800138000', name: '张三' },
{ phone: '13900139000', name: '李四' }
]
}
},
saveLoading: false
}
},
mounted() {
this.loadMonitorConfig()
},
methods: {
//
async loadMonitorConfig() {
try {
const response = await getGasConfig()
//
const list = response.data ? response.data : []
this.monitorPoints = list.map(item => ({
id: item.id,
videoUrl: item.camera_url,
videoName: item.camera_name,
coThreshold: Number(item.co_threshold),
tempMinThreshold: Number(item.temperature_low_threshold),
tempMaxThreshold: Number(item.temperature_high_threshold),
humidityMinThreshold: Number(item.humidity_low_threshold),
humidityMaxThreshold: Number(item.humidity_high_threshold),
deviceAddress: item.device_id,
nodeId: item.node_id
}))
} catch (error) {
console.error('加载监控点配置失败:', error)
this.$message.error('加载监控点配置失败')
}
},
addReceiver() {
if (!this.warningForm.phoneNumber) {
this.$message.warning('请输入手机号')
@ -205,6 +238,76 @@ export default {
//
this.$refs.monitorForm && this.$refs.monitorForm.resetFields()
this.$refs.warningForm && this.$refs.warningForm.resetFields()
},
addMonitorPoint() {
this.monitorPoints.push({
name: '监控点',
videoName: '',
videoUrl: '',
deviceAddress: '',
nodeId: '',
coThreshold: 5.0,
tempMinThreshold: 15,
tempMaxThreshold: 30,
humidityMinThreshold: 30,
humidityMaxThreshold: 70
})
},
async saveMonitorSettings(index) {
this.saveLoading = true
try {
const point = this.monitorPoints[index]
const param = {
id: point.id,
camera_url: point.videoUrl,
camera_name: point.videoName,
co_threshold: point.coThreshold,
temperature_low_threshold: point.tempMinThreshold,
temperature_high_threshold: point.tempMaxThreshold,
humidity_low_threshold: point.humidityMinThreshold,
humidity_high_threshold: point.humidityMaxThreshold,
device_id: point.deviceAddress,
node_id: point.nodeId
}
await saveGasConfig(param)
this.$message({
message: '监控点配置保存成功',
type: 'success'
})
await this.loadMonitorConfig()
} catch (error) {
console.error('保存监控点配置失败:', error)
this.$message.error('保存监控点配置失败')
} finally {
this.saveLoading = false
}
},
async deleteMonitorPoint(index) {
try {
await this.$confirm('确定要删除此监控点吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
const pointToDelete = this.monitorPoints[index]
console.log(pointToDelete)
await destroyGasConfig({ id: pointToDelete.id })
this.monitorPoints.splice(index, 1)
this.$message({
type: 'success',
message: '删除成功!'
})
} catch (error) {
if (error !== 'cancel') {
console.error('删除监控点失败:', error)
this.$message.error('删除监控点失败')
}
}
},
cancelAddMonitorPoint(index) {
this.monitorPoints.splice(index, 1)
}
}
}
@ -237,6 +340,18 @@ export default {
font-weight: bold;
margin-bottom: 15px;
color: #409EFF;
}
.el-form-item:last-child {
margin-bottom: 0;
.el-button {
margin-right: 10px;
&:last-child {
margin-right: 0;
}
}
}
}
@ -251,5 +366,9 @@ export default {
color: #909399;
font-size: 12px;
}
.add-monitor-section {
margin-bottom: 20px;
}
}
</style>

Loading…
Cancel
Save