Commit f9d08cac authored by zhangjianqian's avatar zhangjianqian

应急处置消息 socket

parent 85929e34
......@@ -112,7 +112,11 @@
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
</dependency>
<!-- websocket 支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- servlet包 -->
<dependency>
<groupId>javax.servlet</groupId>
......
package com.zehong.common.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
......@@ -98,7 +98,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
// 过滤请求
.authorizeRequests()
// 对于登录login 验证码captchaImage 允许匿名访问
.antMatchers("/login", "/captchaImage", "/detector/detectorReport/**").anonymous()
.antMatchers("/login", "/captchaImage","/websocket/**","/websocketServer", "/detector/detectorReport/**").anonymous()
.antMatchers(
HttpMethod.GET,
"/*.html",
......
package com.zehong.system.controller;
import java.util.List;
import com.alibaba.fastjson.JSONObject;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
......
package com.zehong.system.controller;
import com.alibaba.fastjson.JSONObject;
import com.zehong.system.domain.TEventReceive;
import com.zehong.system.service.ITEventReceiveService;
import com.zehong.system.service.WebSocketServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/websocket")
public class WebSocketController {
private static final Logger log = LoggerFactory.getLogger(WebSocketController.class);
@Autowired
private WebSocketServer webSocketServer;
@Autowired
private ITEventReceiveService tEventReceiveService;
@GetMapping("/send")
public void send(Integer enterpriseId){
try {
//List<TEventReceive> list = tEventReceiveService.getReadReceiveList( enterpriseId);
webSocketServer.batchSendMessage(JSONObject.toJSONString("success"));
} catch (Exception e) {
log.error("wesocket发送失败!");
}
}
}
package com.zehong.system.domain;
import javax.websocket.Session;
import java.util.concurrent.atomic.AtomicInteger;
/**
* <websocket信息对象>
* <用于存储secket连接信息>
* @author wzh
* @version 2018-07-08 18:49
* @see [相关类/方法] (可选)
**/
public class WebSocketBean {
/**
* 连接session对象
*/
private Session session;
/**
* 连接错误次数
*/
private AtomicInteger erroerLinkCount = new AtomicInteger(0);
public int getErroerLinkCount() {
// 线程安全,以原子方式将当前值加1,注意:这里返回的是自增前的值
return erroerLinkCount.getAndIncrement();
}
public void cleanErrorNum()
{
// 清空计数
erroerLinkCount = new AtomicInteger(0);
}
public Session getSession() {
return session;
}
public void setSession(Session session) {
this.session = session;
}
}
\ No newline at end of file
......@@ -58,4 +58,6 @@ public interface TEventReceiveMapper
* @return 结果
*/
public int deleteTEventReceiveByIds(String[] ids);
public List<TEventReceive> getReadReceiveList(Integer enterpriseId);
}
......@@ -58,4 +58,6 @@ public interface ITEventReceiveService
* @return 结果
*/
public int deleteTEventReceiveById(String id);
public List<TEventReceive> getReadReceiveList(Integer enterpriseId);
}
package com.zehong.system.service;
import javax.websocket.EndpointConfig;
import javax.websocket.Session;
/**
* <基于javax websocket通讯>
* <功能详细描述>
* @author wzh
* @version 2018-07-08 17:11
* @see [相关类/方法] (可选)
**/
public interface WebSocketServer {
/**
* 连接建立成功调用的方法
* @param session session 对象
*/
public void onOpen(Session session, EndpointConfig config);
/**
* 断开连接方法
*/
public void onClose(Session session);
/**
* 收到客户端消息后调用的方法
* @param session session 对象
* @param message 返回客户端的消息
*/
public void onMessage(Session session, String message);
/**
* 发生异常时触发的方法
* @param session session 对象
* @param throwable 抛出的异常
*/
public void onError(Session session, Throwable throwable);
/**
* 向单个客户端发送消息
* @param session session 对象
* @param message 发送给客户端的消息
*/
public void sendMessage(Session session, String message);
/**
* 向所有在线用户群发消息
* @param message 发送给客户端的消息
*/
public void batchSendMessage(String message);
}
\ No newline at end of file
package com.zehong.system.service.impl;
import java.util.List;
import com.alibaba.fastjson.JSONObject;
import com.zehong.common.utils.DateUtils;
import com.zehong.system.controller.WebSocketController;
import com.zehong.system.service.WebSocketServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.zehong.system.mapper.TEventReceiveMapper;
......@@ -14,11 +19,14 @@ import com.zehong.system.service.ITEventReceiveService;
* @author zehong
* @date 2022-03-18
*/
@Slf4j
@Service
public class TEventReceiveServiceImpl implements ITEventReceiveService
{
@Autowired
private TEventReceiveMapper tEventReceiveMapper;
@Autowired
private WebSocketServer webSocketServer;
/**
* 查询事件接报
......@@ -69,7 +77,14 @@ public class TEventReceiveServiceImpl implements ITEventReceiveService
@Override
public int updateTEventReceive(TEventReceive tEventReceive)
{
return tEventReceiveMapper.updateTEventReceive(tEventReceive);
int a = tEventReceiveMapper.updateTEventReceive(tEventReceive);
try {
//List<TEventReceive> list = tEventReceiveService.getReadReceiveList( enterpriseId);
webSocketServer.batchSendMessage(JSONObject.toJSONString("success"));
} catch (Exception e) {
log.error("wesocket发送失败!");
}
return a;
}
/**
......@@ -95,4 +110,9 @@ public class TEventReceiveServiceImpl implements ITEventReceiveService
{
return tEventReceiveMapper.deleteTEventReceiveById(id);
}
@Override
public List<TEventReceive> getReadReceiveList(Integer enterpriseId){
return tEventReceiveMapper.getReadReceiveList(enterpriseId);
}
}
package com.zehong.system.service.impl;
import com.zehong.system.domain.WebSocketBean;
import com.zehong.system.service.WebSocketServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.servlet.server.Session;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* <基于javax websocket通讯>
* <各个方法的参数都是可以根据项目的实际情况改的>
* @author wzh
* @version 2018-07-08 17:11
* @see [相关类/方法] (可选)
**/
@ServerEndpoint(value = "/websocketServer")
@Component("webSocketService")
public class WebSocketServiceImpl implements WebSocketServer {
private Logger log = LoggerFactory.getLogger(WebSocketServiceImpl.class);
/**
* 错误最大重试次数
*/
private static final int MAX_ERROR_NUM = 10;
/**
* 用来存放每个客户端对应的webSocket对象。
*/
private static Map<String,WebSocketBean> webSocketInfo;
static
{
// concurrent包的线程安全map
webSocketInfo = new ConcurrentHashMap<>();
}
@OnOpen
@Override
public void onOpen(javax.websocket.Session session, EndpointConfig config) {
// 如果是session没有激活的情况,就是没有请求获取或session,这里可能会取出空,需要实际业务处理
/* HttpSession httpSession= (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
if(httpSession != null)
{
log.info("获取到httpsession" + httpSession.getId());
}else {
log.error("未获取到httpsession");
}*/
// 连接成功当前对象放入websocket对象集合
WebSocketBean bean = new WebSocketBean();
bean.setSession(session);
webSocketInfo.put(session.getId(),bean);
log.info("客户端连接服务器session id :"+session.getId()+",当前连接数:" + webSocketInfo.size());
}
@OnClose
@Override
public void onClose(javax.websocket.Session session) {
// 客户端断开连接移除websocket对象
webSocketInfo.remove(session.getId());
log.info("客户端断开连接,当前连接数:" + webSocketInfo.size());
}
@OnMessage
@Override
public void onMessage(javax.websocket.Session session, String message) {
log.info("客户端 session id: "+session.getId()+",消息:" + message);
// 此方法为客户端给服务器发送消息后进行的处理,可以根据业务自己处理,这里返回页面
sendMessage(session, "服务端返回" + message);
}
@OnError
@Override
public void onError(javax.websocket.Session session, Throwable throwable) {
log.error("发生错误"+ throwable.getMessage(),throwable);
}
@Override
public void sendMessage(javax.websocket.Session session, String message) {
try
{
// 发送消息
session.getBasicRemote().sendText(message);
// 清空错误计数
webSocketInfo.get(session.getId()).cleanErrorNum();
}
catch (Exception e)
{
log.error("发送消息失败"+ e.getMessage(),e);
int errorNum = webSocketInfo.get(session.getId()).getErroerLinkCount();
// 小于最大重试次数重发
if(errorNum <= MAX_ERROR_NUM)
{
sendMessage(session, message);
}
else{
log.error("发送消息失败超过最大次数");
// 清空错误计数
webSocketInfo.get(session.getId()).cleanErrorNum();
}
}
}
@Override
public void batchSendMessage(String message) {
Set<Map.Entry<String, WebSocketBean>> set = webSocketInfo.entrySet();
for (Map.Entry<String, WebSocketBean> map : set)
{
sendMessage(map.getValue().getSession(),message);
}
}
}
......@@ -29,6 +29,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectTEventHandleVo"/>
<where>
<if test="eventId != null "> and event_id = #{eventId}</if>
<if test="eventType != null "> and event_type = #{eventType}</if>
</where>
</select>
......
......@@ -30,7 +30,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
select id, event_name, event_type, event_grade, address, longitude, latitude,
company_read,government_read,informant, infor_time, informant_phone, `describe`, `status`,enterprise_id, enterprise_name, remarks, is_del, create_time from t_event_receive
</sql>
<select id="getReadReceiveList" resultMap="TEventReceiveResult">
<include refid="selectTEventReceiveVo"/>
<where>
<if test="enterpriseId != null and enterpriseId != -2"> and enterprise_id = #{enterpriseId}</if>
</where>
</select>
<select id="selectTEventReceiveList" parameterType="TEventReceive" resultMap="TEventReceiveResult">
<include refid="selectTEventReceiveVo"/>
<where>
......
......@@ -63,8 +63,8 @@
position: absolute;
.out-circle {
width: 16px;
height: 16px;
width: 18px;
height: 18px;
background: rgba(14, 116, 218, 0.1);
box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.1);
/*opacity: 0.1;*/
......@@ -73,8 +73,8 @@
align-items: center;
.in-circle {
width: 12px;
height: 12px;
width: 8px;
height: 8px;
margin: 0 auto;
background: rgba(14, 116, 218, 1);
border-radius: 50%;
......@@ -83,7 +83,7 @@
}
.long-line {
width: 2px;
width: 1px;
height: 98px;
background: #ffffff;
box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.1);
......@@ -101,7 +101,7 @@
margin-bottom: 30px;
.timeline-title {
font-size: 14px;
font-size: 15px;
word-break: break-all;
margin-bottom: 16px;
color: #d9d9d9;
......@@ -110,7 +110,7 @@
}
.timeline-date {
font-size: 16px;
font-size: 13px;
color: #dfe4ed;
font-weight: 500;
margin-bottom: 16px;
......
......@@ -31,10 +31,21 @@
<div v-if="userType==-2" class="button-div" @click="showList(item.id)" >预案指引</div>
<div v-if="item.status==3 && userType==-2" class="button-div" @click="endevent(item.id)">事件结案</div>
<div v-if="userType!=-2" class="button-div" @click="showList(item.id)">信息处置</div>
<div class="button-div" @click="showDetail(item.id,$event)">详情</div>
<div class="button-div" @click="showDetail(item.id,item.eventName)">详情</div>
</div>
<div :id = "item.id" style="display: none;margin-top: 15px;margin-bottom: 20px;">
<timeline :timeline-list="handleList"></timeline>
</div>
<div id = "detail" class="show-detail" style="display: none;margin-top: 15px;margin-bottom: 20px;position:fixed;right: 470px;width: 300px;
background: rgba(0, 0, 0, 0.7);top: 110px">
<div class="el-form-div" style="height: 30px;">
<div class="detail-title">{{detailTitle}}</div>
<div style="cursor: pointer;" @click="closeDetail()">
<img style="width: 20px;height: 20px;margin-top: 5px;" src="@/assets/mapImages/closeBtn.png" alt="" />
</div>
</div>
<timeline :timeline-list="handleList"></timeline>
<div style="height: 40px;">
</div>
</div>
</div>
......@@ -166,6 +177,7 @@
</template>
<script>
import { mapGetters } from 'vuex'
import { listReceive, getReceive, delReceive, addReceive, updateReceive } from "@/api/system/receive";
import { listHandle, getHandle, delHandle, addHandle, updateHandle, exportHandle } from "@/api/system/handle";
import { listPlanInfo } from "@/api/system/planInfo";
......@@ -201,6 +213,7 @@ export default {
status:5,
enterpriseId:""
},
detailTitle:"",
form:'',
// 遮罩层
loading: true,
......@@ -226,6 +239,11 @@ export default {
}
};
},
computed:{
...mapGetters([
"emergencyData"
]),
},
mounted() {
// this.$nextTick(()=>{
// this.getScrollHeight();
......@@ -235,40 +253,79 @@ export default {
if(this.userType!=-2){
this.queryParams.enterpriseId = response.data.deptId;
}
this.getList();
this.getList(1);
});
//定时检测新消息
setInterval(() => {
var params = this.queryParams;
if(this.userType==-2){
params.governmentRead=0
}else {
params.companyRead=0
}
listReceive(params).then(response => {
var newList = response.rows;
newList.forEach((model) => {
this.receiveList.forEach((item) => {
if(item.id == model.id){
console.log("---------------"+item.id)
if(this.userType==-2){
item.governmentRead =0;
}else {
item.companyRead =0;
}
}
});
});
});
}, 5000);
this.socket();
// //定时检测新消息
// setInterval(() => {
//
// }, 5000);
},
watch:{
emergencyData:{
handler (val) {
this.showDetail(val.eventId,val.eventName);
console.log('深度监听:', val);
},
deep: true
}
},
methods: {
socket() {
console.log("socket执行");
this.ws = new WebSocket(
"ws://192.168.2.17:8903/gassafety/websocketServer"
);
this.ws.onopen = (evt) => {
console.log("WebSockets开启");
};
this.ws.onmessage = (evt) => {
console.log("推送", evt);
const obj = JSON.parse(evt.data);
console.log("接受socketobj", obj);
this.getNow();
};
this.ws.onclose = () => {
console.log("ws协议关闭");
};
},
getNow(){
var params = this.queryParams;
if(this.userType==-2){
params.governmentRead=0
}else {
params.companyRead=0
}
listReceive(params).then(response => {
var newList = response.rows;
newList.forEach((model) => {
this.receiveList.forEach((item) => {
if(item.id == model.id){
if(this.userType==-2){
item.governmentRead =0;
item.status=3;
}else {
item.companyRead =0;
}
}
});
});
});
},
/** 查询事件接报列表 */
getList() {
getList(type) {
console.log("******"+type)
listReceive(this.queryParams).then(response => {
this.receiveList = response.rows;
if(type==1){
if(this.$route.query.eventId!=undefined){
this.showDetail(this.$route.query.eventId,this.$route.query.eventName);
}
}
//this.total = response.total;
console.log(this.receiveList)
//console.log(this.receiveList)
});
},
//获取事件处置列表
......@@ -285,6 +342,11 @@ export default {
this.open = true;
this.title = "事件处置";
this.queryParams2.eventId= id
if(this.userType==-2){
this.queryParams2.eventType= 2;
}else {
this.queryParams2.eventType= 1;
}
this.getHandleList();
},
choice() {
......@@ -299,6 +361,7 @@ export default {
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.fileList=[]
this.readonly1=false;
this.display="";
this.display2="display:none";
......@@ -306,7 +369,7 @@ export default {
this.title2 = "添加事件处置";
this.form.eventId = this.queryParams2.eventId
},
/** 修改按钮操作 */
/** 新增预案 */
handleUpdate() {
this.reset();
this.readonly1=true;
......@@ -373,10 +436,11 @@ export default {
});
},
upReceive(id){
var receiveform = {id:id,status:3}
var receiveform = {id:id}
if(this.form.eventType==2){
receiveform.companyRead=0;
}else {
receiveform.status=3;
receiveform.governmentRead=0;
}
updateReceive(receiveform).then(response => {
......@@ -435,27 +499,23 @@ export default {
assignTask(item){
this.$parent.handleUpdate(item);
},
async showDetail(id,event){
async showDetail(id,title){
var that = this;
that.detailTitle=title;
that.queryParams2.eventId= id
that.queryParams2.pageSize=100;
if(event.target.innerText=="详情"){
await listHandle(that.queryParams2).then(response => {
this.handleList = response.rows;
if(response.total==0){
this.msgSuccess("暂无详情");
}else{
event.target.innerText="关闭";
document.getElementById(id).style.display="";
that.updateRead(id);
}
});
}else {
event.target.innerText="详情";
document.getElementById(id).style.display="none";
}
await listHandle(that.queryParams2).then(response => {
this.handleList = response.rows;
if(response.total==0){
this.msgSuccess("暂无详情");
}else{
document.getElementById("detail").style.display="";
that.updateRead(id);
}
});
},
closeDetail(id,event){
document.getElementById("detail").style.display="none";
},
//更改读取状态
updateRead(id){
......@@ -607,6 +667,12 @@ export default {
border-width: 0;
color: rgb(48, 180, 107);
}
.detail-title{
height: 100%;
width: 270px;
color: white;
margin-left: 20px;
}
.massage{
color: #00ffff;
}
......
......@@ -11,11 +11,30 @@
<!--<img src="@/assets/xiaoxi.png" :hidden="xiaohidden" style="height: 40px;width: 40px;margin-top: 5px;cursor: pointer;">-->
<!--</div>-->
<!-- <search id="header-search" class="right-menu-item" /> -->
          <el-badge :value="total" :max="99" class="item" >
            <i class="el-icon-chat-dot-round" style="width: 10px;height: 10px;" @click="$router.push('/emergency/emergency')"></i>
          </el-badge>
<!--          <el-badge :value="total" :max="99" class="item" >-->
<!--            <i class="el-icon-chat-dot-round" style="width: 10px;height: 10px;" ></i>-->
<!--          </el-badge>-->
<el-dropdown class="avatar-container right-menu-item hover-effect" style="margin-right: 0px" trigger="click">
<div class="avatar-wrapper" >
<el-badge :value="total" :max="99" class="item" >
   <i class="el-icon-chat-dot-round" style="width: 10px;height: 10px;" ></i>
 </el-badge>
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-if="total==0">
<span>暂无消息</span>
</el-dropdown-item>
<div v-for="(item,index) in receivedList" >
<el-dropdown-item v-if="index==0" @click.native="openMassage(item.id,item.eventName)">
<span>您有新消息:{{item.eventName}}</span>
</el-dropdown-item>
<el-dropdown-item v-if="index>0" divided @click.native="openMassage(item.id,item.eventName)">
<span>您有新消息:{{item.eventName}}</span>
</el-dropdown-item>
</div>
</el-dropdown-menu>
</el-dropdown>
<screenfull id="screenfull" class="right-menu-item hover-effect" />
<!-- <el-tooltip content="布局大小" effect="dark" placement="bottom">
......@@ -46,7 +65,7 @@
</template>
<script>
import { mapGetters } from 'vuex'
import { mapGetters,mapMutations } from 'vuex'
import Breadcrumb from '@/components/Breadcrumb'
import TopNav from '@/components/TopNav'
import Hamburger from '@/components/Hamburger'
......@@ -69,13 +88,15 @@ export default {
userType:-2,
total:null,
xiaohidden:false,
receivedList:[],
routerPath:"",
}
},
computed: {
...mapGetters([
'sidebar',
'avatar',
'device'
'device',
]),
setting: {
get() {
......@@ -95,36 +116,23 @@ export default {
}
},
mounted(){
getUserProfile().then(response => {
this.userType = response.data.deptId;
});
//定时检测新消息
setInterval(() => {
var params = {
pageNum: 1,
pageSize: 100,
status:5,
enterpriseId:this.userType
};
if(this.userType==-2){
params.governmentRead=0;
params.enterpriseId=null;
}else {
params.companyRead=0
}
console.log(params)
listReceive(params).then(response => {
console.log("total==",response);
if(response.total!=0){
this.total= response.total;
}else{
this.total= "";
}
});
}, 5000);
getUserProfile().then(response => {
this.userType = response.data.deptId;
if(this.userType!=-2){
this.queryParams.enterpriseId = response.data.deptId;
}
this.getList();
});
this.socket();
},
methods: {
...mapMutations({
SET_EMERGENCY:"bigWindowCompany/SET_EMERGENCY"
}
),
toggleSideBar() {
this.$store.dispatch('app/toggleSideBar')
},
......@@ -138,6 +146,61 @@ mounted(){
location.href = '/index';
})
}).catch(() => {});
},
openMassage(id,title){
//this.$router.push('/emergency/emergency?eventid='+id);
this.routerPath="/emergency/emergency";
if(window.location.pathname==this.routerPath){
// this.$parent.showDetail(id,title);
this.SET_EMERGENCY({
eventId:id,
eventName:title,
})
}else {
this.$router.push({path: this.routerPath,query:{eventId:id,eventName:title}});
}
},
socket() {
console.log("socket执行");
this.ws = new WebSocket(
"ws://192.168.2.17:8903/gassafety/websocketServer"
);
this.ws.onopen = (evt) => {
console.log("WebSockets开启");
};
this.ws.onmessage = (evt) => {
console.log("推送", evt);
const obj = JSON.parse(evt.data);
console.log("接受socketobj", obj);
this.getList();
};
this.ws.onclose = () => {
console.log("ws协议关闭");
};
},
getList(){
console.log(this.userType)
var params = {
pageNum: 1,
pageSize: 100,
status:5,
enterpriseId:this.userType
};
if(this.userType==-2){
params.governmentRead=0;
params.enterpriseId=null;
}else {
params.companyRead=0
}
listReceive(params).then(response => {
this.receivedList = response.rows;
if(response.total!=0){
this.total= response.total;
}else{
this.total= "";
}
});
}
}
}
......
......@@ -24,5 +24,6 @@ const getters = {
defaultRoutes:state => state.permission.defaultRoutes,
sidebarRouters:state => state.permission.sidebarRouters,
company:state=>state.bigWindowCompany.company,
emergencyData:state=>state.bigWindowCompany.emergencyData,
}
export default getters
......@@ -11,6 +11,11 @@ import { getCompany } from "@/api/bigWindow/getDevice";
const state = {
// 公司名称
company: {},
//应急处置消息详情
emergencyData:{
eventId:99999,
eventName:"",
}
};
const mutations = {
......@@ -21,6 +26,13 @@ const mutations = {
}));
console.log(state.company);
},
SET_EMERGENCY: (state, emergencyData) => {
state.emergencyData=emergencyData
}
};
const actions = {
......
......@@ -355,13 +355,13 @@ export default {
name: "医 院",
},
{
val: 14,
val: 15,
ischeck: false,
imgurl: require("@/assets/image/yj-xf.png"),
name: "消防队伍",
},
{
val: 15,
val: 16,
ischeck: false,
imgurl: require("@/assets/image/yj-xj.png"),
name: "巡检人员",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment