master
lion 2 weeks ago
parent cd89a2ac65
commit a2bbeb9ade

@ -13,5 +13,5 @@ VUE_APP_OA_URL_TYPE = '{"采购入库":51,"请示入库":54,"调拨入库":55,"
#VUE_APP_UPLOAD_API = http://192.168.60.99:9004/api/admin/upload-file #VUE_APP_UPLOAD_API = http://192.168.60.99:9004/api/admin/upload-file
# 正式oa # 正式oa
VUE_APP_OA_URL = http://192.168.60.18:2021 #VUE_APP_OA_URL = http://192.168.60.18:2021
VUE_APP_OA_URL_TYPE = '{"采购入库":51,"请示入库":54,"调拨入库":55,"领用出库":56,"处置出库":57,"调令出库":53}' #VUE_APP_OA_URL_TYPE = '{"采购入库":51,"请示入库":54,"调拨入库":55,"领用出库":56,"处置出库":57,"调令出库":53}'

@ -1,9 +1,10 @@
import request from '@/utils/request' import request from '@/utils/request'
export function getGasConfig() { export function getGasConfig(params) {
return request({ return request({
url: '/api/admin/gas-config/index', url: '/api/admin/gas-config/index',
method: 'get' method: 'get',
params
}) })
} }

@ -51,6 +51,14 @@ export function getStocktakingPlanLinkList(data) {
}) })
} }
// 删除盘点计划物资关联
export function deleteStocktakingPlanLink(params) {
return request({
url: '/api/admin/material-infos-plan-link/destroy',
method: 'get',
params
})
}
// 获取单个盘点计划详情 // 获取单个盘点计划详情
export function getStocktakingPlanLinkDetail(params) { export function getStocktakingPlanLinkDetail(params) {
return request({ return request({

@ -573,32 +573,63 @@
window.open('/admin/#/myprint?ids=' + this.printArr, '_blank') window.open('/admin/#/myprint?ids=' + this.printArr, '_blank')
}, },
async exportExcel(sheetName) { async exportExcel(sheetName) {
const export_fields = {
'wuzibianma': '物资编码',
'wuzibianma_material_infos_wuzibianma_relation.fenlei_detail.name': '所属种类',
'zichanmingcheng': '物资名称',
'wuzileixing': '物资类型',
'guigexinghao': '物资型号',
'wuziguige': '物资规格',
'wuzibianma_material_infos_wuzibianma_relation.jiliangdanwei': '单位',
'rukupici': '入库批次',
'zaikushuliang': '在库数量',
'shunxuhao': '顺序号',
'wuzizhuangtai_detail.value': '物资状态',
'chubeifangshi_detail.value': '储备方式',
'materialstorages.cangkumingcheng': '所在仓库',
'shelfs.huojiamingcheng': '所在货架',
'huojiaceng': '所在货架层',
'dengjifenlei_detail.value': '等级分类',
'chanquanxinxi_detail.value': '产权信息',
'shifouweigudingzichan': '是否为固定资产',
'gudingzichanbianma': '固定资产编码',
'chubeinnianxian': '储备年限',
'cunfangyaoqiu': '存放要求',
'weihuyaoqiu': '维护要求',
'equipment_maintain_configs_id_relation.name': '保养频次',
}
const res = await index(Object.assign(this.select, { const res = await index(Object.assign(this.select, {
page: 1, page: 1,
page_size: 9999, page_size: 9999,
table_name: 'inventorys' table_name: 'inventorys',
is_export: 1,
"export_fields[wuzibianma]": '物资编码',
"export_fields[wuzibianma_material_infos_wuzibianma_relation.material_info_type]": '一级分类',
"export_fields[wuzibianma_material_infos_wuzibianma_relation.material_info_type]": '二级分类',
"export_fields[wuzibianma_material_infos_wuzibianma_relation.fenlei_detail.name]": '所属种类',
"export_fields[zichanmingcheng]": '物资名称',
"export_fields[wuzileixing]": '物资类型',
"export_fields[guigexinghao]": '物资型号',
"export_fields[wuziguige]": '物资规格',
"export_fields[wuzibianma_material_infos_wuzibianma_relation.jiliangdanwei]": '单位',
"export_fields[rukupici]": '入库批次',
"export_fields[zaikushuliang]": '在库数量',
"export_fields[shunxuhao]": '顺序号',
"export_fields[wuzizhuangtai_detail.value]": '物资状态',
"export_fields[chubeifangshi_detail.value]": '储备方式',
"export_fields[materialstorages.cangkumingcheng]": '所在仓库',
"export_fields[shelfs.huojiamingcheng]": '所在货架',
"export_fields[huojiaceng]": '所在货架层',
"export_fields[dengjifenlei_detail.value]": '等级分类',
"export_fields[chanquanxinxi_detail.value]": '产权信息',
"export_fields[shifouweigudingzichan]": '是否为固定资产',
"export_fields[gudingzichanbianma]": '固定资产编码',
"export_fields[chubeinnianxian]": '储备年限',
"export_fields[cunfangyaoqiu]": '存放要求',
"export_fields[weihuyaoqiu]": '维护要求',
"export_fields[equipment_maintain_configs_id_relation.name]": '保养频次',
}),true) }),true)
if (res.data) {
const headers = this.form.map(i => {
return {
key: i.field,
title: i.name
}
})
const data = res.data.map(row => headers.map(header => row[header.key]))
data.unshift(headers.map(header => header.title))
const wb = XLSX.utils.book_new()
const ws = XLSX.utils.aoa_to_sheet(data)
XLSX.utils.book_append_sheet(wb, ws, sheetName)
const wbout = XLSX.write(wb, {
bookType: 'xlsx',
bookSST: true,
type: 'array'
})
saveAs(new Blob([wbout], {
type: 'application/octet-stream'
}), `自管物资${sheetName}.xlsx`)
}
}, },
showCode(e, row) { showCode(e, row) {
console.log(e, row) console.log(e, row)

File diff suppressed because it is too large Load Diff

@ -274,7 +274,7 @@ export default {
const xinghao = item.guigexinghao ? '型号:' + item.guigexinghao : '型号' const xinghao = item.guigexinghao ? '型号:' + item.guigexinghao : '型号'
const pici = item.rukupici ? '批次:' + item.rukupici : '批次' const pici = item.rukupici ? '批次:' + item.rukupici : '批次'
const total_num = const total_num =
item.wuzileixing === '一物一码' ? '同批数量:' + item.total_num : '数量:' + item.total_num item.wuzileixing === '一物一码' ? '同批数量:' + item.chushishuliang : '数量:' + item.chushishuliang
const piciNum = pici + ' ' + total_num const piciNum = pici + ' ' + total_num
const shunxuhao = item.wuzileixing === '一物一码' ? '批内序号:' + item.shunxuhao : ' ' const shunxuhao = item.wuzileixing === '一物一码' ? '批内序号:' + item.shunxuhao : ' '
let hexId = parseInt(item.id, 10).toString(16).toUpperCase() let hexId = parseInt(item.id, 10).toString(16).toUpperCase()

@ -3,26 +3,33 @@
<!-- Camera Section --> <!-- Camera Section -->
<el-row :gutter="20" class="camera-section"> <el-row :gutter="20" class="camera-section">
<el-col v-for="camera in cameras" :key="camera.id" :span="8"> <el-col v-for="camera in cameras" :key="camera.id" :span="8">
<el-card shadow="never"> <el-card shadow="hover">
<div slot="header" class="clearfix"> <div slot="header" class="clearfix" @click="handleCameraClick(camera.camera_url)">
<span>{{ camera.name }}</span> <span>{{ camera.name }}</span>
<el-button style="float: right; padding: 3px 0" type="text" :class="camera.status === '离线' ? 'offline' : ''">{{ camera.status }}</el-button> <!-- <el-button style="float: right; padding: 3px 0" type="text" :class="camera.status === '离线' ? 'offline' : ''">{{ camera.status }}</el-button> -->
</div> </div>
<div class="camera-body"> <div class="camera-body" @click="handleCameraClick(camera.camera_url)">
<el-image <el-image
style="width: 100%; height: 180px; background-color: #000; display: flex; align-items: center; justify-content: center;" style="
:src="camera.image" width: 100%;
height: 180px;
background-color: #000;
display: flex;
align-items: center;
justify-content: center;
"
:src="camera.image?camera.image.url:''"
fit="cover" fit="cover"
> >
<div slot="error" class="image-slot"> <!-- <div slot="error" class="image-slot">
<i class="el-icon-picture-outline" style="font-size: 40px; color: #ccc;" /> <i class="el-icon-picture-outline" style="font-size: 40px; color: #ccc" />
<div style="color: #ccc;">EZVIZ</div> <div style="color: #ccc">EZVIZ</div>
</div> </div>
<div slot="placeholder" class="image-slot"> <div slot="placeholder" class="image-slot">
<i class="el-icon-loading" style="font-size: 40px; color: #ccc;" /> <i class="el-icon-loading" style="font-size: 40px; color: #ccc" />
</div> </div> -->
</el-image> </el-image>
<div class="camera-info">视频通道: {{ camera.channel }}</div> <div class="camera-info">点击跳转账号admin密码abc125634</div>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
@ -37,16 +44,27 @@
<div class="environment-card" :class="getCardClass(point.status)"> <div class="environment-card" :class="getCardClass(point.status)">
<div class="env-header"> <div class="env-header">
<span>{{ point.name }}</span> <span>{{ point.name }}</span>
<el-tag size="small" :type="getTagType(point.status)" effect="dark" class="status-tag"> <!-- <el-tag
<i v-if="point.status === ''" class="el-icon-success" style="margin-right: 4px;" /> size="small"
:type="getTagType(point.status)"
effect="dark"
class="status-tag"
>
<i
v-if="point.status === '正常'"
class="el-icon-success"
style="margin-right: 4px"
/>
{{ point.status }} {{ point.status }}
</el-tag> </el-tag> -->
</div> </div>
<el-row class="env-data"> <el-row class="env-data">
<el-col :span="12"> <el-col :span="12">
<div class="data-item"> <div class="data-item">
<div class="label">CO浓度</div> <div class="label">CO浓度</div>
<div class="value" :class="point.status === '预警' ? 'warning-value' : ''">{{ point.coConcentration }}</div> <div class="value" :class="point.status === '预警' ? 'warning-value' : ''">
{{ point.coConcentration }}
</div>
</div> </div>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@ -85,29 +103,7 @@ export default {
name: 'MonitorPage', name: 'MonitorPage',
data() { data() {
return { return {
cameras: [ cameras: [],
{
id: 1,
name: '摄像头1',
status: '离线',
image: 'https://img.freepik.com/free-vector/cctv-surveillance-system-concept_23-2148529272.jpg',
channel: '[DS-2CD2225XM-LGLSE(AE1005192)- AE1005192]'
},
{
id: 2,
name: '摄像头2',
status: '离线',
image: 'https://img.freepik.com/premium-photo/security-camera-perspective-hallway-corridor-monitoring-space-3d-rendering_172660-215.jpg',
channel: '[DS-2CD2225XM-LGLSE(AE1005068)- AE1005068]'
},
{
id: 3,
name: '摄像头3',
status: '离线',
image: 'https://img.freepik.com/premium-photo/video-surveillance-camera-record-street-cctv-camera-work-building_169016-21553.jpg',
channel: '[DS-2CD2225XM-LGLSE(AE1005197)- AE1005197]'
}
],
environmentPoints: [] environmentPoints: []
} }
}, },
@ -117,26 +113,48 @@ export default {
methods: { methods: {
async loadEnvironmentPoints() { async loadEnvironmentPoints() {
try { try {
const response = await getGasList() const response = await getGasList({
// show_relation:['image']
})
const list = response.data ? response.data : [] const list = response.data ? response.data : []
console.log('原始数据:', list) console.log('原始数据:', list)
// node_id1,3,5 // node_id1,3,5
const wantedNodeIds = ['1', '3', '5'] const wantedNodeIds = ['1', '3', '5']
const filtered = wantedNodeIds.map(nodeId => { const filtered = wantedNodeIds
.map(nodeId => {
const group = list.filter(item => String(item.node_id) === nodeId) const group = list.filter(item => String(item.node_id) === nodeId)
if (group.length === 0) return null 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)) group.sort(
(a, b) =>
new Date(b.record_time) -
new Date(a.record_time)
)
return group[0] return group[0]
}).filter(Boolean) })
.filter(Boolean)
console.log('filtered:', filtered)
this.environmentPoints = filtered.map(item => ({ this.environmentPoints = filtered.map(item => ({
id: item.id, id: item.id,
name: item.gas_config && item.gas_config.name ? item.gas_config.name : `监控点${item.node_id}`, name:
item.gas_config && item.gas_config.name
? item.gas_config.name
: `监控点${item.node_id}`,
status: item.status || '正常', status: item.status || '正常',
coConcentration: item.co_concentration != null && item.co_concentration !== '' ? `${item.co_concentration} ppm` : '-', coConcentration:
temperature: item.temperature != null && item.temperature !== '' ? `${item.temperature}` : '-', 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} %` : '-', humidity: item.humidity != null && item.humidity !== '' ? `${item.humidity} %` : '-',
updateTime: item.record_time || '' updateTime: item.record_time || ''
})) }))
this.cameras = filtered.map(item => ({
id: item.id,
name: item.gas_config.camera_name,
camera_url: item.gas_config.camera_url,
image: item.gas_config.image
}))
} catch (error) { } catch (error) {
console.error('环境检测数据获取失败:', error) console.error('环境检测数据获取失败:', error)
this.$message && this.$message.error('环境检测数据获取失败') this.$message && this.$message.error('环境检测数据获取失败')
@ -154,6 +172,14 @@ export default {
if (status === '正常') return 'success' if (status === '正常') return 'success'
if (status === '预警') return 'warning' if (status === '预警') return 'warning'
return 'info' return 'info'
},
handleCameraClick(cameraUrl) {
// console.log(cameraUrl)
if (cameraUrl) {
window.open(cameraUrl, '_blank')
} else {
this.$message.error('摄像头URL为空')
}
} }
} }
} }
@ -171,15 +197,16 @@ export default {
.el-card { .el-card {
border: none; // Remove default card border if desired border: none; // Remove default card border if desired
cursor: pointer;
} }
.clearfix:before, .clearfix:before,
.clearfix:after { .clearfix:after {
display: table; display: table;
content: ""; content: '';
} }
.clearfix:after { .clearfix:after {
clear: both clear: both;
} }
.camera-body { .camera-body {
@ -188,7 +215,7 @@ export default {
margin-bottom: 10px; margin-bottom: 10px;
border-radius: 4px; border-radius: 4px;
overflow: hidden; overflow: hidden;
box-shadow: 0 2px 12px 0 rgba(0,0,0,.1); box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
.image-slot { .image-slot {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -208,7 +235,7 @@ export default {
} }
.offline { .offline {
color: #F56C6C; // Style for offline button color: #f56c6c; // Style for offline button
} }
.environment-section { .environment-section {
@ -225,13 +252,14 @@ export default {
color: #fff; // Default text color for cards color: #fff; // Default text color for cards
&.status-normal-blue { &.status-normal-blue {
background-color: #409EFF; // Blue for normal status background-color: #409eff; // Blue for normal status
} }
&.status-warning { &.status-warning {
background-color: #E6A23C; // Yellow for warning status background-color: #e6a23c; // Yellow for warning status
} }
&.status-normal-green { // Assuming point C has a distinct 'green normal' status &.status-normal-green {
background-color: #67C23A; // Green for normal status // Assuming point C has a distinct 'green normal' status
background-color: #67c23a; // Green for normal status
} }
.env-header { .env-header {
@ -246,8 +274,14 @@ export default {
border-radius: 10px; // Make tag more pill-shaped border-radius: 10px; // Make tag more pill-shaped
border: none; border: none;
// Match background to card, or use Element UI types // Match background to card, or use Element UI types
&.el-tag--success { background-color: rgba(255, 255, 255, 0.2); color: #fff;} &.el-tag--success {
&.el-tag--warning { background-color: rgba(255, 255, 255, 0.2); color: #fff;} background-color: rgba(255, 255, 255, 0.2);
color: #fff;
}
&.el-tag--warning {
background-color: rgba(255, 255, 255, 0.2);
color: #fff;
}
} }
} }

@ -20,6 +20,7 @@
</div> </div>
<!-- 视频与设备信息两行两列布局 --> <!-- 视频与设备信息两行两列布局 -->
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="监控点名称"> <el-form-item label="监控点名称">
@ -38,13 +39,12 @@
<el-input v-model="point.videoName" placeholder="请输入摄像头名称" /> <el-input v-model="point.videoName" placeholder="请输入摄像头名称" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="设备地址"> <el-form-item label="设备地址">
<el-input v-model="point.deviceAddress" placeholder="请输入设备地址" /> <el-input v-model="point.deviceAddress" placeholder="请输入设备地址" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="节点ID"> <el-form-item label="节点ID">
<el-input v-model="point.nodeId" placeholder="请输入节点ID" /> <el-input v-model="point.nodeId" placeholder="请输入节点ID" />
@ -52,6 +52,24 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="摄像头封面">
<el-upload
class="upload-demo"
:action="uploadAction"
:on-success="(response, file, fileList) => handleImageSuccess(response, file, fileList, index)"
:on-remove="(file, fileList) => handleImageRemove(file, fileList, index)"
:limit="1"
:file-list="point.imageFileList"
list-type="picture-card"
>
<i class="el-icon-plus" />
</el-upload>
</el-form-item>
</el-col>
</el-row>
<!-- 环境监测阈值 --> <!-- 环境监测阈值 -->
<el-divider content-position="left">环境监测阈值超过此值将触发预警</el-divider> <el-divider content-position="left">环境监测阈值超过此值将触发预警</el-divider>
<el-form-item label="CO浓度阈值"> <el-form-item label="CO浓度阈值">
@ -196,7 +214,8 @@ export default {
{ phone: '13900139000', name: '李四' } { phone: '13900139000', name: '李四' }
] ]
}, },
saveLoading: false saveLoading: false,
uploadAction: `${process.env.VUE_APP_BASE_API}api/admin/upload-file`
} }
}, },
mounted() { mounted() {
@ -207,10 +226,17 @@ export default {
// //
async loadMonitorConfig() { async loadMonitorConfig() {
try { try {
const response = await getGasConfig() const response = await getGasConfig({
show_relation:['image']
})
// //
const list = response.data ? response.data : [] const list = response.data ? response.data : []
this.monitorPoints = list.map(item => ({ this.monitorPoints = list.map(item => {
const imageFileList = []
if (item.image_id && item.image) {
imageFileList.push(item.image)
}
return {
id: item.id, id: item.id,
name: item.name || `监控点${item.id}`, name: item.name || `监控点${item.id}`,
videoUrl: item.camera_url, videoUrl: item.camera_url,
@ -221,8 +247,11 @@ export default {
humidityMinThreshold: Number(item.humidity_low_threshold), humidityMinThreshold: Number(item.humidity_low_threshold),
humidityMaxThreshold: Number(item.humidity_high_threshold), humidityMaxThreshold: Number(item.humidity_high_threshold),
deviceAddress: item.device_id, deviceAddress: item.device_id,
nodeId: item.node_id nodeId: item.node_id,
})) image_id: item.image_id || '',
imageFileList: imageFileList
}
})
} catch (error) { } catch (error) {
console.error('加载监控点配置失败:', error) console.error('加载监控点配置失败:', error)
this.$message.error('加载监控点配置失败') this.$message.error('加载监控点配置失败')
@ -322,13 +351,25 @@ export default {
tempMinThreshold: 15, tempMinThreshold: 15,
tempMaxThreshold: 30, tempMaxThreshold: 30,
humidityMinThreshold: 30, humidityMinThreshold: 30,
humidityMaxThreshold: 70 humidityMaxThreshold: 70,
image_id: '',
imageFileList: []
}) })
}, },
async saveMonitorSettings(index) { async saveMonitorSettings(index) {
this.saveLoading = true this.saveLoading = true
try { try {
const point = this.monitorPoints[index] const point = this.monitorPoints[index]
// ID
let imageId = ''
if (point.imageFileList && point.imageFileList.length > 0) {
const file = point.imageFileList[0]
if (file.response) {
imageId = file.response.id
} else if (file.id) {
imageId = file.id
}
}
const param = { const param = {
id: point.id, id: point.id,
name: point.name, name: point.name,
@ -340,7 +381,8 @@ export default {
humidity_low_threshold: point.humidityMinThreshold, humidity_low_threshold: point.humidityMinThreshold,
humidity_high_threshold: point.humidityMaxThreshold, humidity_high_threshold: point.humidityMaxThreshold,
device_id: point.deviceAddress, device_id: point.deviceAddress,
node_id: point.nodeId node_id: point.nodeId,
image_id: imageId
} }
await saveGasConfig(param) await saveGasConfig(param)
this.$message({ this.$message({
@ -355,6 +397,20 @@ export default {
this.saveLoading = false this.saveLoading = false
} }
}, },
handleImageSuccess(response, file, fileList, index) {
//
this.monitorPoints[index].imageFileList = fileList
// ID
if (response && response.id) {
this.monitorPoints[index].image_id = response.id
}
},
handleImageRemove(file, fileList, index) {
//
this.monitorPoints[index].imageFileList = fileList
// ID
this.monitorPoints[index].image_id = ''
},
async deleteMonitorPoint(index) { async deleteMonitorPoint(index) {
try { try {
await this.$confirm('确定要删除此监控点吗?', '提示', { await this.$confirm('确定要删除此监控点吗?', '提示', {

Loading…
Cancel
Save