zhaobing’
11 months ago
48 changed files with 2711 additions and 17 deletions
@ -0,0 +1,178 @@ |
|||
'use strict'; |
|||
|
|||
|
|||
|
|||
async function getThingsDeploy (ctx) { |
|||
let rslt = {instances:{}}, errStatus = null; |
|||
let error = { name: 'FindError', message: '获取设备部署信息失败' }; |
|||
let structList=[] |
|||
try { |
|||
const models = ctx.fs.dc.models |
|||
const res=await models.ProjectBind.findAll() |
|||
if(res.length){ |
|||
res.map(item=>{ |
|||
structList.push({axyId:item.dataValues.axyProjectId,id:item.dataValues.id}) |
|||
}) |
|||
console.log('structList[id]',structList['gruop']) |
|||
|
|||
for(let id in structList){ |
|||
let iotaResponse = await ctx.app.fs.iotRequest.get(`things/${structList[id].axyId}/deploys`) |
|||
if (JSON.parse(iotaResponse)) { |
|||
for (const ids in JSON.parse(iotaResponse).instances) { |
|||
const instances = JSON.parse(iotaResponse).instances[ids]; |
|||
if (instances.type === 's.d') { |
|||
instances.instance.structId = structList[id].axyId; |
|||
instances.instance.xjId= structList[id].id |
|||
rslt.instances = Object.assign(rslt.instances, { [ids]: instances }) |
|||
} |
|||
} |
|||
error = null; |
|||
} |
|||
|
|||
} |
|||
|
|||
}else{ |
|||
throw '没有绑定的安心云结构物的数据!!!' |
|||
} |
|||
} catch (err) { |
|||
errStatus = err.status |
|||
ctx.fs.logger.error(`path: ${ctx.path}, error: ${err}`) |
|||
} |
|||
if (error) { |
|||
if (errStatus == 404) { |
|||
ctx.status = 200; |
|||
ctx.body = { |
|||
'instances': null |
|||
}; |
|||
} else { |
|||
ctx.status = errStatus; |
|||
ctx.body = error; |
|||
} |
|||
} else { |
|||
ctx.status = 200; |
|||
ctx.body = rslt |
|||
} |
|||
} |
|||
|
|||
async function getThingStatus (ctx) { |
|||
let structList = [] |
|||
let result=[] |
|||
try { |
|||
const models = ctx.fs.dc.models |
|||
const rslt=await models.ProjectBind.findAll() |
|||
if(rslt.length){ |
|||
rslt.map(item=>{ |
|||
structList.push(item.dataValues.axyProjectId) |
|||
}) |
|||
for(let id in structList){ |
|||
if(id!='group'){ |
|||
let iotaResponse = await ctx.app.fs.craw.get('thing/status', { query: { thingId:structList[id] } }) |
|||
result = [...result,...JSON.parse(iotaResponse)] |
|||
} |
|||
|
|||
} |
|||
|
|||
}else{ |
|||
throw '没有绑定的安心云结构物的数据!!!' |
|||
} |
|||
ctx.status = 200 |
|||
if (result) { |
|||
ctx.body = result |
|||
} |
|||
} catch (error) { |
|||
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`) |
|||
ctx.status = 200 |
|||
ctx.body = [] |
|||
} |
|||
} |
|||
//查询物联网卡相关信息
|
|||
async function getCardInfo (ctx) { |
|||
try{ |
|||
let rlst = [] |
|||
const { clickHouse } = ctx.app.fs |
|||
const { database: iota } = clickHouse.iot.opts.config |
|||
const {structIds}=ctx.request.body |
|||
if (structIds && structIds.length) { |
|||
const id = `(${structIds.map(item => `'${item.id}'`).join(',')})` |
|||
rlst = await clickHouse.dataAlarm.query(` |
|||
with tmp as ( SELECT cs.DeviceId as deviceId, |
|||
cs.CardNo as cardNo, |
|||
cs.PType as pType, |
|||
cs.Status as status, |
|||
cs.Total as total, |
|||
cs.Allowance as allowance, |
|||
cs.Time as time |
|||
FROM alarm.CardStatus cs |
|||
WHERE cs.DeviceId in ${id} |
|||
ORDER BY cs.Time DESC |
|||
LIMIT 1) |
|||
SELECT t.*,d.thingId,d.name FROM tmp t |
|||
LEFT JOIN ${iota}.Device d |
|||
ON Device.id = t.deviceId` ).toPromise()
|
|||
ctx.status = 200 |
|||
ctx.body = rlst |
|||
}else{ |
|||
ctx.status = 200 |
|||
ctx.body = rlst |
|||
} |
|||
|
|||
}catch(error){ |
|||
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`) |
|||
ctx.status = 400 |
|||
ctx.body = { |
|||
"message": "查询物联网卡相关信息失败" |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
async function createInvoke (ctx, next) { |
|||
let error = { name: 'CreateError', message: '命令下发失败' }; |
|||
const {searchId,data} = ctx.request.body |
|||
let rslt=[] |
|||
try { |
|||
if(searchId&&searchId.length&&Array.isArray(searchId)){ |
|||
for(let id in searchId){ |
|||
if(id!='group'){ |
|||
let dataToIota = { |
|||
deviceId:searchId[id].deviceId, |
|||
dimCapId:searchId[id].sid, |
|||
thingId:searchId[id].structId, |
|||
timeout: 300000 |
|||
} |
|||
let iotaResponse = await ctx.app.fs.iotInvoke.post(`capabilities/invoke`, {data:dataToIota}) |
|||
rslt.push({...searchId[id],...iotaResponse}) |
|||
error = null |
|||
} |
|||
|
|||
} |
|||
}else{ |
|||
|
|||
let iotaResponse = await ctx.app.fs.iotInvoke.post(`capabilities/invoke`, {data:searchId}) |
|||
rslt = iotaResponse |
|||
error = null; |
|||
} |
|||
} catch (err) { |
|||
ctx.fs.logger.error(`path: ${ctx.path}, error: ${err}`); |
|||
} |
|||
if (error) { |
|||
ctx.status = 400; |
|||
ctx.body = error; |
|||
} else { |
|||
ctx.status = 200; |
|||
ctx.body = rslt; |
|||
} |
|||
}; |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
module.exports = { |
|||
getThingsDeploy, |
|||
getThingStatus, |
|||
getCardInfo, |
|||
createInvoke |
|||
} |
|||
|
@ -0,0 +1,32 @@ |
|||
'use strict' |
|||
|
|||
async function findDetailBySNCard(ctx, next) { |
|||
try { |
|||
const { card } = ctx.params |
|||
const models = ctx.fs.dc.models |
|||
let option = { |
|||
attributes: ['id', 'name', 'equipment_no'], |
|||
where: { equipmentNo: {$like: `%${card}%`} }, |
|||
include: [ |
|||
{ |
|||
required: true, //inner join
|
|||
model: models.Project, |
|||
attributes: ['id', 'name'], |
|||
}, |
|||
], |
|||
} |
|||
const rlst = await models.Point.findAll(option) |
|||
ctx.body = rlst |
|||
ctx.status = 200 |
|||
} catch (error) { |
|||
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`) |
|||
ctx.status = 400 |
|||
ctx.body = { |
|||
message: '根据设备sn号查询相关信息失败', |
|||
} |
|||
} |
|||
} |
|||
|
|||
module.exports = { |
|||
findDetailBySNCard, |
|||
} |
@ -0,0 +1,141 @@ |
|||
'use strict' |
|||
const moment = require('moment') |
|||
|
|||
let axyTokenCache = { |
|||
token: null, |
|||
orgId: null, |
|||
expireTime: null, //过期时间
|
|||
} |
|||
|
|||
async function getAnxinyunToken(ctx) { |
|||
try { |
|||
if (!axyTokenCache.token || moment() > moment(axyTokenCache.expireTime)) { |
|||
if (ctx.app.fs.opts.axyProject.split('/').length === 3) { |
|||
const dataToAxy = { |
|||
p: ctx.app.fs.opts.axyProject.split('/')[0], |
|||
username: ctx.app.fs.opts.axyProject.split('/')[1], |
|||
password: ctx.app.fs.opts.axyProject.split('/')[2], |
|||
} |
|||
const axyResponse = await ctx.app.fs.anxinyun.post('project/login', { data: dataToAxy }) |
|||
if (axyResponse.authorized) { |
|||
axyTokenCache.token = axyResponse.token //放进缓存
|
|||
axyTokenCache.orgId = axyResponse.orgId //放进缓存
|
|||
axyTokenCache.expireTime = moment().add(1, 'hour').format('YYYY-MM-DD HH:mm:ss') |
|||
} |
|||
} |
|||
} |
|||
return axyTokenCache |
|||
} catch (error) { |
|||
ctx.fs.logger.error(`sechedule: laborAttendance, error: ${error}`) |
|||
} |
|||
} |
|||
//调用安心云结构物接口
|
|||
async function findAnxinyunProject(ctx, next) { |
|||
try { |
|||
let { type, url, params = {} } = ctx.request.body |
|||
let data = await getAnxinyunToken(ctx) |
|||
if (url && url.indexOf('{orgId}') != -1) { |
|||
url = url.replace(`{orgId}`, data.orgId) |
|||
} |
|||
const res = await ctx.app.fs.anxinyun[type](`${url}?token=${data.token}`, { |
|||
data: params.data || {}, |
|||
query: params.query || {}, |
|||
}) |
|||
ctx.status = 200 |
|||
ctx.body = res |
|||
} catch (error) { |
|||
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`) |
|||
ctx.status = 400 |
|||
ctx.body = { |
|||
message: '查询安心云项目失败', |
|||
} |
|||
} |
|||
} |
|||
async function addorEditRelation(ctx, next) { |
|||
let err='' |
|||
const { axyProjectId, structrueId, id } = ctx.request.body |
|||
try { |
|||
const models = ctx.fs.dc.models |
|||
//编辑
|
|||
if (id) { |
|||
const res=await models.ProjectBind.findOne({ where: { id,axyProjectId,structureId:structrueId } }) |
|||
if(res){ |
|||
err='所选安心云结构物和巡检结构物重复!!!' |
|||
throw '所选安心云结构物和巡检结构物重复!!!' |
|||
} |
|||
await models.ProjectBind.update({ axyProjectId, structrueId }, { where: { id } }) |
|||
ctx.status = 204 |
|||
} else { |
|||
//新增
|
|||
const res= await models.ProjectBind.findOne({ where: { axyProjectId,structureId:structrueId } }) |
|||
if(res){ |
|||
err='所选安心云结构物和巡检结构物重复!!!' |
|||
throw '所选安心云结构物和巡检结构物重复!!!' |
|||
} |
|||
await models.ProjectBind.create({ axyProjectId, structureId:structrueId }) |
|||
ctx.status = 204 |
|||
} |
|||
} catch (error) { |
|||
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`) |
|||
ctx.status = 400 |
|||
ctx.body = { |
|||
message: err?err:id?'编辑失败':'新增失败', |
|||
} |
|||
} |
|||
} |
|||
|
|||
async function getRelationList(ctx, next) { |
|||
try { |
|||
const models = ctx.fs.dc.models |
|||
const { limit, page, startTime, endTime } = ctx.query |
|||
let options = { |
|||
where: {}, |
|||
} |
|||
if (limit) { |
|||
options.limit = Number(limit) |
|||
} |
|||
if (page && limit) { |
|||
options.offset = Number(page) * Number(limit) |
|||
} |
|||
if (startTime && endTime) { |
|||
options.where.inspectTm = { $between: [startTime, endTime] } |
|||
} |
|||
const res = await models.ProjectBind.findAndCountAll(options) |
|||
ctx.body = res |
|||
ctx.status = 200 |
|||
} catch (error) { |
|||
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`) |
|||
ctx.status = 400 |
|||
ctx.body = { |
|||
message: '查询关联关系列表失败', |
|||
} |
|||
} |
|||
} |
|||
|
|||
async function deleteRelation(ctx, next) { |
|||
const {id} = ctx.params |
|||
try { |
|||
const models = ctx.fs.dc.models |
|||
const res = await models.ProjectBind.findOne({ where: { id:Number(id) } }) |
|||
if (!res) { |
|||
throw 'id不存在' |
|||
} |
|||
await models.ProjectBind.destroy({ where: { id:Number(id) } }) |
|||
ctx.status = 200 |
|||
} catch (error) { |
|||
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`) |
|||
ctx.status = 400 |
|||
ctx.body = { |
|||
message: '关联关系列表失败', |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
module.exports = { |
|||
findAnxinyunProject, |
|||
addorEditRelation, |
|||
getRelationList, |
|||
deleteRelation, |
|||
} |
@ -0,0 +1,43 @@ |
|||
/* eslint-disable*/ |
|||
'use strict'; |
|||
|
|||
module.exports = dc => { |
|||
const DataTypes = dc.ORM; |
|||
const sequelize = dc.orm; |
|||
const ProjectBind = sequelize.define("project_bind", { |
|||
id: { |
|||
type: DataTypes.INTEGER, |
|||
allowNull: false, |
|||
defaultValue: null, |
|||
comment: null, |
|||
primaryKey: true, |
|||
field: "id", |
|||
autoIncrement: true, |
|||
}, |
|||
axyProjectId: { |
|||
type: DataTypes.STRING, |
|||
allowNull: true, |
|||
defaultValue: null, |
|||
comment: '安心云项目id', |
|||
primaryKey: false, |
|||
field: "axy_project_id", |
|||
autoIncrement: false |
|||
}, |
|||
structureId: { |
|||
type: DataTypes.INTEGER, |
|||
allowNull: true, |
|||
defaultValue: null, |
|||
comment: '结构物id', |
|||
primaryKey: false, |
|||
field: "structure_id", |
|||
autoIncrement: false |
|||
}, |
|||
|
|||
}, { |
|||
tableName: "project_bind", |
|||
comment: "", |
|||
indexes: [] |
|||
}); |
|||
dc.models.ProjectBind = ProjectBind; |
|||
return ProjectBind; |
|||
}; |
@ -0,0 +1,19 @@ |
|||
'use strict'; |
|||
|
|||
const AIOTOverview = require('../../controllers/AIOTOverview/AIOTOverview'); |
|||
|
|||
module.exports = function (app, router, opts) { |
|||
app.fs.api.logAttr['GET/things/deploy'] = { content: '获取智能断路器', visible: true }; |
|||
router.get('/things/deploy', AIOTOverview.getThingsDeploy); |
|||
|
|||
app.fs.api.logAttr['GET/things/status'] = { content: '获取设备在离线', visible: true }; |
|||
router.get('/things/status', AIOTOverview.getThingStatus); |
|||
|
|||
app.fs.api.logAttr['POST/things/card'] = { content: '获取物联网卡相关信息', visible: true }; |
|||
router.post('/things/card', AIOTOverview.getCardInfo); |
|||
|
|||
//空开设备查询状态和开关设备
|
|||
app.fs.api.logAttr['POST/capabilities/invoke'] = { content: '及时采集', visible: true }; |
|||
router.post('/capabilities/invoke', AIOTOverview.createInvoke); |
|||
|
|||
}; |
@ -0,0 +1,8 @@ |
|||
'use strict' |
|||
|
|||
const groundDisasterInspection = require('../../controllers/groundDisasterInspection/groundDisasterInspection') |
|||
|
|||
module.exports = function (app, router, opts) { |
|||
app.fs.api.logAttr['GET/card/detail/:card'] = { content: '根据sn号查询相应的点位信息和结构物信息', visible: true } |
|||
router.get('card/detail/:card', groundDisasterInspection.findDetailBySNCard) |
|||
} |
@ -0,0 +1,19 @@ |
|||
'use strict'; |
|||
|
|||
const projectBind = require('../../controllers/projectBind/projectBind'); |
|||
|
|||
module.exports = function (app, router, opts) { |
|||
|
|||
app.fs.api.logAttr['POST/anxinyun/project/list'] = { content: '获取安心云项目列表', visible: false } |
|||
router.post('/anxinyun/project/list', projectBind.findAnxinyunProject) |
|||
|
|||
app.fs.api.logAttr['POST/anxinyun/project/relation'] = { content: '新增或编辑项目映射关系', visible: false } |
|||
router.post('/anxinyun/project/relation', projectBind.addorEditRelation) |
|||
|
|||
app.fs.api.logAttr['GET/anxinyun/project/relation/list'] = { content: '获取项目映射关系列表', visible: false } |
|||
router.get('/anxinyun/project/relation/list', projectBind.getRelationList) |
|||
|
|||
app.fs.api.logAttr['DELETE/anxinyun/project/relation/:id'] = { content: '删除项目映射关系', visible: false } |
|||
router.delete('/anxinyun/project/relation/:id', projectBind.deleteRelation) |
|||
|
|||
} |
@ -0,0 +1,163 @@ |
|||
// package/AIOTOverview/AIOTOverview.js
|
|||
import { getThingsDeploy, getThingsStatus, getCardInfo,getRelationList} from "../../utils/getApiUrl"; |
|||
import { Request } from "../../common"; |
|||
const moment = require("../../utils/moment"); |
|||
|
|||
Page({ |
|||
|
|||
/** |
|||
* 页面的初始数据 |
|||
*/ |
|||
data: { |
|||
data: [],//用电设备数据
|
|||
normal: 0,//正常
|
|||
abnormal: 0,//异常
|
|||
unknown: 0,//未知
|
|||
iotCardNormal: 0,//物联网卡正常
|
|||
iotCardNonactivated: 0,//物联网卡欠费
|
|||
iotCardHalt: 0,//物联网卡停机
|
|||
iotaCardData: [],//物联网卡数据
|
|||
searchId:[], |
|||
}, |
|||
//跳转流量监控明细
|
|||
navigatorToFlow() { |
|||
const jsonData = JSON.stringify(this.data.iotaCardData) |
|||
wx.navigateTo({ |
|||
url: `/package/AIOTOverview/flowMonitoring/flowMonitoring?data=` + encodeURIComponent(jsonData) |
|||
}) |
|||
}, |
|||
//跳转用电监控明细
|
|||
navigatorToEle() { |
|||
const jsonData2 = JSON.stringify(this.data.searchId) |
|||
wx.navigateTo({ |
|||
url: `/package/AIOTOverview/electricityMonitoring/electricityMonitoring?data2=${encodeURIComponent(jsonData2)}` |
|||
}) |
|||
}, |
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
async onLoad(options) { |
|||
wx.showLoading({ title: '加载中...' }); |
|||
const that = this |
|||
const devices = await Request.get(getThingsDeploy()) |
|||
const status = await Request.get(getThingsStatus()) |
|||
const rslt = await Request.get(getRelationList()) |
|||
let deviceId = [] //空开电源设备的id
|
|||
let deviceAll = [] |
|||
let searchId=[]//查询e9c设备状态的id
|
|||
let controlId=[] |
|||
if (devices) { |
|||
const dataList = devices |
|||
for (const id in dataList.instances) { |
|||
const instances = dataList?.instances[id] |
|||
if (instances.type == 's.d' && instances?.instance?.properties) { |
|||
deviceAll.push({ id, name: instances.instance?.properties?.name, structId: instances.instance?.structId }) |
|||
if (instances.type == 's.d' && instances.instance.properties.deviceType == 'sensor') { |
|||
if (instances.instance.properties.model == 'E9C') { |
|||
for (const key in instances?.instance?.interfaces) { |
|||
const d=Object.values(instances?.instance?.interfaces[key]?.capabilities) |
|||
if(d&&d.length){ |
|||
searchId.push({deviceId:id,cid:d[1]?.dimension?.id,sid:d[0]?.dimension?.id,name: instances.instance?.properties?.name, structId: instances.instance?.structId }) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
if (instances?.instance?.properties?.model == 'JG-RTU-S270') { |
|||
deviceId.push({ id, name: instances.instance?.properties?.name, structId: instances.instance?.structId,xjId:instances.instance?.xjId }) |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
if (status && status.length) { |
|||
const data = deviceId.map(item => { |
|||
return { |
|||
deviceId: item.id, |
|||
name: item.name, |
|||
status: status.find(q => q.deviceId == item.id)?.status, |
|||
structId: item?.structId, |
|||
xjId:item.xjId |
|||
} |
|||
}) |
|||
deviceAll.push({ id: '012ccc98-c99d-445e-8397-6da1b4567533', name: '设备二', structId: 'df48d7c5-d902-47b1-b671-d88d546ba3e4' }) |
|||
if (deviceAll && deviceAll.length) { |
|||
Request.post(getCardInfo(), { structIds: deviceAll }).then(res => { |
|||
if (res) { |
|||
if(rslt.rows.length){ |
|||
controlId=res.map(item=>{ |
|||
return { |
|||
...item, |
|||
xjId:rslt.rows.find(q=>q.axyProjectId==item.thingId)?.id |
|||
} |
|||
}) |
|||
} |
|||
that.setData({ |
|||
iotaCardData: controlId, |
|||
iotCardNormal: res?.filter(item => item.status == 0)?.length, |
|||
iotCardNonactivated: res?.filter(item => item.status == 1)?.length, |
|||
iotCardHalt: res?.filter(item => item.status == 2)?.length, |
|||
searchId:searchId |
|||
}) |
|||
} |
|||
}) |
|||
} |
|||
that.setData({ |
|||
data, |
|||
normal: data?.filter(item => item.status == 1)?.length, |
|||
unknown: data?.filter(item => item.status == -1)?.length, |
|||
abnormal: data?.filter(item => item.status == 0)?.length |
|||
}) |
|||
} |
|||
|
|||
wx.hideLoading() |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面初次渲染完成 |
|||
*/ |
|||
onReady() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面显示 |
|||
*/ |
|||
onShow() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面隐藏 |
|||
*/ |
|||
onHide() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面卸载 |
|||
*/ |
|||
onUnload() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 页面相关事件处理函数--监听用户下拉动作 |
|||
*/ |
|||
onPullDownRefresh() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 页面上拉触底事件的处理函数 |
|||
*/ |
|||
onReachBottom() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 用户点击右上角分享 |
|||
*/ |
|||
onShareAppMessage() { |
|||
|
|||
} |
|||
}) |
@ -0,0 +1,7 @@ |
|||
{ |
|||
"navigationBarTitleText": "AIOT总览", |
|||
"usingComponents": { |
|||
"van-button": "@vant/weapp/button/index" |
|||
|
|||
} |
|||
} |
@ -0,0 +1,62 @@ |
|||
<!--package/AIOTOverview/AIOTOverview.wxml--> |
|||
|
|||
<view> |
|||
<!--用电设备状态总览--> |
|||
<view class="card"> |
|||
<view class="top"> |
|||
<view style="display: flex; align-items: center;"> |
|||
<text class="fontStyle">用电设备状态总览</text> |
|||
</view> |
|||
<view class="detailStyle"> |
|||
<van-button type="info" round size="small" bindtap="navigatorToEle">查看详情</van-button> |
|||
</view> |
|||
</view> |
|||
<view class="card-content"> |
|||
<view class="row flex flex-between detail"> |
|||
<view class="content-left" style="font-weight: bold;">设备数量</view> |
|||
<view class="content-right" style="font-weight: bold;">{{data.length}}</view> |
|||
</view> |
|||
<view class="row flex flex-between detail"> |
|||
<view class="content-left">正常设备</view> |
|||
<view class="content-right">{{normal+'个'}}</view> |
|||
</view> |
|||
<view class="row flex flex-between detail"> |
|||
<view class="content-left">异常设备</view> |
|||
<view class="content-right" style="color:red">{{abnormal+'个'}}</view> |
|||
</view> |
|||
<view class="row flex flex-between detail"> |
|||
<view class="content-left">未知</view> |
|||
<view class="content-right">{{unknown+'个'}}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!--物联网卡状态总览--> |
|||
<view class="card"> |
|||
<view class="top"> |
|||
<view style="display: flex; align-items: center;"> |
|||
<text class="fontStyle">物联网卡状态总览</text> |
|||
</view> |
|||
<view class="detailStyle"> |
|||
<van-button type="info" round size="small" bindtap="navigatorToFlow">查看详情</van-button> |
|||
</view> |
|||
</view> |
|||
<view class="card-content"> |
|||
<view class="row flex flex-between detail"> |
|||
<view class="content-left" style="font-weight: bold;">设备数量</view> |
|||
<view class="content-right" style="font-weight: bold;">{{iotaCardData.length+'个'}}</view> |
|||
</view> |
|||
<view class="row flex flex-between detail"> |
|||
<view class="content-left">正常</view> |
|||
<view class="content-right">{{iotCardNormal+'个'}}</view> |
|||
</view> |
|||
<view class="row flex flex-between detail"> |
|||
<view class="content-left">未激活</view> |
|||
<view class="content-right">{{iotCardNonactivated+'个'}}</view> |
|||
</view> |
|||
<view class="row flex flex-between detail"> |
|||
<view class="content-left">停机</view> |
|||
<view class="content-right" style="color:red">{{iotCardHalt+'个'}}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
@ -0,0 +1,52 @@ |
|||
/* package/AIOTOverview/AIOTOverview.wxss */ |
|||
|
|||
|
|||
.card { |
|||
position: relative; |
|||
background-color: #fff; |
|||
border: 1px solid #ddd; |
|||
border-radius: 8px; |
|||
/* padding: 10px; */ |
|||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); |
|||
margin: 12px 12px; |
|||
} |
|||
|
|||
.top { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
padding: 10px; |
|||
|
|||
/* background-position: bottom; */ |
|||
} |
|||
|
|||
.card-content { |
|||
padding: 0 10px; |
|||
} |
|||
|
|||
.card-left { |
|||
margin-left: 23px; |
|||
margin-bottom: 10px; |
|||
font-weight: 500; |
|||
font-size: 16px; |
|||
color: #000000d9; |
|||
} |
|||
.detail{ |
|||
margin:10px 0 |
|||
} |
|||
.card-right { |
|||
margin-right: 18px; |
|||
margin-bottom: 10px; |
|||
color: #1684FF; |
|||
} |
|||
.fontStyle { |
|||
font-family: PingFangSC-Medium; |
|||
font-weight: bold; |
|||
} |
|||
.content-left { |
|||
font-size: 12px; |
|||
} |
|||
|
|||
.content-right { |
|||
font-size: 14px; |
|||
text-align: right; |
|||
} |
@ -0,0 +1,147 @@ |
|||
// package/AIOTOverview/electricityMonitoring/electricityMonitoring.js
|
|||
import { getProjectList,getRelationList,createInvoke} from "../../../utils/getApiUrl" |
|||
import {Request} from "../../../common" |
|||
|
|||
Page({ |
|||
|
|||
/** |
|||
* 页面的初始数据 |
|||
*/ |
|||
data: { |
|||
structList:[ ], |
|||
curStruId: 'all', // 选中结构物id
|
|||
list:[],//断路器设备list
|
|||
listCopy:[], |
|||
}, |
|||
onClose(e) { |
|||
// 获取报告
|
|||
// this.getPatrolReport();
|
|||
}, |
|||
switch1Change(e){ |
|||
wx.showLoading({ title: '加载中...' }); |
|||
const item=e.currentTarget.dataset.item |
|||
let searchId={ |
|||
deviceId:item.deviceId, |
|||
dimCapId:item.cid, |
|||
thingId:item.structId, |
|||
timeout: 300000, |
|||
param:e.detail.value?'开':'关' |
|||
} |
|||
Request.post(createInvoke(),{data:searchId}).then(res=>{ |
|||
if(res){ |
|||
wx.hideLoading() |
|||
}else{ |
|||
wx.hideLoading() |
|||
} |
|||
}) |
|||
|
|||
}, |
|||
onStruChange(e) { |
|||
if (e.detail) { |
|||
let data = [] |
|||
if (e.detail === 'all') { |
|||
data = this.data.listCopy |
|||
} else { |
|||
data = this.data.listCopy.filter(item => item.xjId === e.detail) |
|||
} |
|||
this.setData({ |
|||
curStruId: e.detail, |
|||
list: data |
|||
}) |
|||
} |
|||
}, |
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
async onLoad(options) { |
|||
wx.showLoading({ title: '加载中...' }); |
|||
const searchId= JSON.parse(decodeURIComponent(options.data2)) |
|||
let data={ |
|||
searchId |
|||
} |
|||
let listt=[] |
|||
//智能断路器的设备的状态
|
|||
const res1 =await Request.post(createInvoke(),data) |
|||
//获取结构物列表(巡检)
|
|||
// console.log('getProjectList',getProjectList)
|
|||
const res=await Request.get(getProjectList()) |
|||
const rslt=await Request.get(getRelationList()) |
|||
if(res.rows.length&&rslt.rows.length){ |
|||
const data=res.rows.map(item=>{ |
|||
return { |
|||
value: rslt.rows.find(q => item.id === q.structureId)?.structureId, |
|||
text:item.name |
|||
} |
|||
}) |
|||
if(res1&&res1.length){ |
|||
listt=res1.map(item=>{ |
|||
const c=rslt.rows?.find(q => q.axyProjectId == item.structId)?.structureId |
|||
return { |
|||
...item, |
|||
structName: res.rows.find(p=>p.id==c)?.name, |
|||
xjId: rslt.rows?.find(q => q.axyProjectId == item.structId)?.structureId |
|||
} |
|||
}) |
|||
} |
|||
data.unshift({text: '全部', value: 'all' }) |
|||
this.setData({ |
|||
structList:data, |
|||
list:listt, |
|||
listCopy:listt |
|||
}) |
|||
} |
|||
|
|||
wx.hideLoading() |
|||
|
|||
}, |
|||
|
|||
|
|||
/** |
|||
* 生命周期函数--监听页面初次渲染完成 |
|||
*/ |
|||
onReady() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面显示 |
|||
*/ |
|||
onShow() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面隐藏 |
|||
*/ |
|||
onHide() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面卸载 |
|||
*/ |
|||
onUnload() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 页面相关事件处理函数--监听用户下拉动作 |
|||
*/ |
|||
onPullDownRefresh() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 页面上拉触底事件的处理函数 |
|||
*/ |
|||
onReachBottom() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 用户点击右上角分享 |
|||
*/ |
|||
onShareAppMessage() { |
|||
|
|||
} |
|||
}) |
@ -0,0 +1,14 @@ |
|||
{ |
|||
|
|||
"navigationBarTitleText": "用电监控", |
|||
"usingComponents": { |
|||
"van-button": "@vant/weapp/button/index", |
|||
"van-cell": "@vant/weapp/cell/index", |
|||
"van-cell-group": "@vant/weapp/cell-group/index", |
|||
"van-dropdown-menu": "@vant/weapp/dropdown-menu/index", |
|||
"van-dropdown-item": "@vant/weapp/dropdown-item/index", |
|||
"van-empty": "@vant/weapp/empty/index", |
|||
"van-switch": "@vant/weapp/switch/index" |
|||
|
|||
} |
|||
} |
@ -0,0 +1,46 @@ |
|||
<!--package/AIOTOverview/electricityMonitoring/electricityMonitoring.wxml--> |
|||
<view> |
|||
<!--结构物选择器--> |
|||
<view class="select"> |
|||
<van-dropdown-menu active-color="#1989fa"> |
|||
<van-dropdown-item title="{{ '结构物' }}" bind:close="onClose" bind:change="onStruChange" value="{{ curStruId }}" options="{{ structList }}" /> |
|||
</van-dropdown-menu> |
|||
</view> |
|||
<!--渲染列表--> |
|||
<view wx:if="{{list.length}}"> |
|||
<view class="card" wx:for="{{list}}" wx:key='index'> |
|||
<!--头部--> |
|||
<view class="top"> |
|||
<view style="display: flex; align-items: center;"> |
|||
<text class="fontStyle">{{item.structName}}</text> |
|||
</view> |
|||
<view> |
|||
<switch disabled="{{!item.data.data||item.data.data.info&&item.data.data.info.includes('离线')}}" bindchange="switch1Change" data-item="{{item}}"/> |
|||
</view> |
|||
</view> |
|||
<!--内容部分--> |
|||
<view class="card-content"> |
|||
<view class="row flex flex-between detail"> |
|||
<view class="content-left" style="font-weight: bold;">{{item.name}}</view> |
|||
</view> |
|||
<view class="row flex flex-between detail"> |
|||
<view class="content-left">运行状态</view> |
|||
<view class="content-right" wx:if="{{!item.data.data}}">{{'离线'}}</view> |
|||
<view class="content-right" wx:if="{{item.data.data.info&&item.data.data.info.includes('离线')}}">{{'离线'}}</view> |
|||
<view class="content-right" wx:if="{{item.data.data.info&&item.data.data.info.includes('正常')}}">{{'正常'}}</view> |
|||
</view> |
|||
<view class="row flex flex-between detail"> |
|||
<view class="content-left">电源状态</view> |
|||
<view class="content-right" wx:if="{{!item.data.data}}">{{'离线'}}</view> |
|||
<view class="content-right" wx:if="{{item.data.data.info&&item.data.data.info.includes('离线')}}">{{'离线'}}</view> |
|||
<view class="content-right" wx:if="{{item.data.data.info&&item.data.data.info.includes('正常')}}">{{'正常'}}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view wx:else> |
|||
<van-empty description="暂无数据" /> |
|||
</view> |
|||
</view> |
|||
|
|||
|
@ -0,0 +1,64 @@ |
|||
/* package/AIOTOverview/electricityMonitoring/electricityMonitoring.wxss */ |
|||
.select { |
|||
width: 50%; |
|||
} |
|||
|
|||
.select .van-dropdown-menu { |
|||
box-shadow: none |
|||
} |
|||
|
|||
/* package/AIOTOverview/AIOTOverview.wxss */ |
|||
|
|||
|
|||
.card { |
|||
position: relative; |
|||
background-color: #fff; |
|||
border: 1px solid #ddd; |
|||
border-radius: 8px; |
|||
/* padding: 10px; */ |
|||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); |
|||
margin: 12px 12px; |
|||
} |
|||
|
|||
.top { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
padding: 10px; |
|||
|
|||
/* background-position: bottom; */ |
|||
} |
|||
|
|||
.card-content { |
|||
padding: 0 10px; |
|||
} |
|||
|
|||
.card-left { |
|||
margin-left: 23px; |
|||
margin-bottom: 10px; |
|||
font-weight: 500; |
|||
font-size: 16px; |
|||
color: #000000d9; |
|||
} |
|||
|
|||
.detail { |
|||
margin: 10px 0 |
|||
} |
|||
|
|||
.card-right { |
|||
margin-right: 18px; |
|||
margin-bottom: 10px; |
|||
color: #1684FF; |
|||
} |
|||
|
|||
.fontStyle { |
|||
font-family: PingFangSC-Medium; |
|||
font-weight: bold; |
|||
} |
|||
.content-left { |
|||
font-size: 12px; |
|||
} |
|||
|
|||
.content-right { |
|||
font-size: 14px; |
|||
text-align: right; |
|||
} |
@ -0,0 +1,117 @@ |
|||
// package/AIOTOverview/flowMonitoring/flowMonitoring.js
|
|||
import { getProjectList, getRelationList } from "../../../utils/getApiUrl"; |
|||
import { Request } from "../../../common"; |
|||
const moment = require("../../../utils/moment"); |
|||
Page({ |
|||
|
|||
/** |
|||
* 页面的初始数据 |
|||
*/ |
|||
data: { |
|||
structList: [], |
|||
curStruId: 'all', // 选中结构物id
|
|||
cardData: [], |
|||
cardDataCopy: [] |
|||
}, |
|||
onClose(e) { |
|||
// 获取报告
|
|||
// this.getPatrolReport();
|
|||
}, |
|||
onStruChange(e) { |
|||
if (e.detail) { |
|||
let data = [] |
|||
if (e.detail === 'all') { |
|||
data = this.data.cardDataCopy |
|||
} else { |
|||
data = this.data.cardDataCopy.filter(item => item.xjId === e.detail) |
|||
} |
|||
this.setData({ |
|||
curStruId: e.detail, |
|||
cardData: data |
|||
}) |
|||
} |
|||
}, |
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
async onLoad(options) { |
|||
let dd = [] |
|||
const complexArray = JSON.parse(decodeURIComponent(options.data)) |
|||
//获取结构物列表(巡检)
|
|||
const res = await Request.get(getProjectList()) |
|||
const rslt = await Request.get(getRelationList()) |
|||
if (res.rows.length && rslt.rows.length) { |
|||
const data = res.rows.map(item => { |
|||
return { |
|||
value: rslt.rows.find(q => item.id === q.structureId)?.id, |
|||
text: item.name |
|||
} |
|||
}) |
|||
data.unshift({ text: '全部', value: 'all' }) |
|||
if (complexArray && complexArray.length) { |
|||
dd = complexArray.map(item => { |
|||
return { |
|||
...item, |
|||
structName: data?.find(q => q.value == item.xjId)?.text |
|||
} |
|||
}) |
|||
} |
|||
this.setData({ |
|||
structList: data, |
|||
cardData:dd , |
|||
cardDataCopy:dd |
|||
}) |
|||
} |
|||
|
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面初次渲染完成 |
|||
*/ |
|||
onReady() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面显示 |
|||
*/ |
|||
onShow() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面隐藏 |
|||
*/ |
|||
onHide() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面卸载 |
|||
*/ |
|||
onUnload() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 页面相关事件处理函数--监听用户下拉动作 |
|||
*/ |
|||
onPullDownRefresh() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 页面上拉触底事件的处理函数 |
|||
*/ |
|||
onReachBottom() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 用户点击右上角分享 |
|||
*/ |
|||
onShareAppMessage() { |
|||
|
|||
} |
|||
}) |
@ -0,0 +1,11 @@ |
|||
{ |
|||
"navigationBarTitleText": "流量监控", |
|||
"usingComponents": { |
|||
"van-button": "@vant/weapp/button/index", |
|||
"van-cell": "@vant/weapp/cell/index", |
|||
"van-cell-group": "@vant/weapp/cell-group/index", |
|||
"van-dropdown-menu": "@vant/weapp/dropdown-menu/index", |
|||
"van-dropdown-item": "@vant/weapp/dropdown-item/index", |
|||
"van-empty": "@vant/weapp/empty/index" |
|||
} |
|||
} |
@ -0,0 +1,44 @@ |
|||
<!--package/AIOTOverview/flowMonitoring/flowMonitoring.wxml--> |
|||
<view> |
|||
<!--结构物选择器--> |
|||
<view class="select"> |
|||
<van-dropdown-menu active-color="#1989fa"> |
|||
<van-dropdown-item title="{{ '结构物' }}" bind:close="onClose" bind:change="onStruChange" value="{{ curStruId }}" options="{{ structList }}" /> |
|||
</van-dropdown-menu> |
|||
</view> |
|||
<!--渲染列表--> |
|||
<view wx:if="{{cardData.length}}"> |
|||
<view class="card" wx:for="{{cardData}}" wx:key='index'> |
|||
<view> |
|||
<!--头部--> |
|||
<view class="top"> |
|||
<view style="display: flex; align-items: center;"> |
|||
<text class="fontStyle">{{item.structName}}</text> |
|||
</view> |
|||
</view> |
|||
<!--内容部分--> |
|||
<view class="card-content"> |
|||
<view class="row flex flex-between detail"> |
|||
<view class="content-left" style="font-weight: bold;">{{item.name}}</view> |
|||
</view> |
|||
<view class="row flex flex-between detail"> |
|||
<view class="content-left">物联卡号:{{item.cardNo}}</view> |
|||
<view class="content-right">套餐类型:{{item.pType}}</view> |
|||
</view> |
|||
<view class="row flex flex-between detail content"> |
|||
<view wx:if="{{item.status==0}}" class="content-left">卡状态:正常</view> |
|||
<view wx:if="{{item.status==1}}" class="content-left">卡状态:未激活</view> |
|||
<view wx:if="{{item.status==2}}" class="content-left">卡状态:停机</view> |
|||
<view class="content-right">套餐总量:{{item.total}}</view> |
|||
</view> |
|||
<view class="row flex flex-between detail content"> |
|||
<view class="content-left">卡余额:{{item.allowance}}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view wx:else> |
|||
<van-empty description="暂无数据" /> |
|||
</view> |
|||
</view> |
@ -0,0 +1,70 @@ |
|||
/* package/AIOTOverview/flowMonitoring/flowMonitoring.wxss */ |
|||
|
|||
|
|||
.select { |
|||
width: 50%; |
|||
} |
|||
|
|||
.select .van-dropdown-menu { |
|||
box-shadow: none |
|||
} |
|||
|
|||
/* package/AIOTOverview/AIOTOverview.wxss */ |
|||
|
|||
|
|||
.card { |
|||
position: relative; |
|||
background-color: #fff; |
|||
border: 1px solid #ddd; |
|||
border-radius: 8px; |
|||
/* padding: 10px; */ |
|||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); |
|||
margin: 12px 12px; |
|||
} |
|||
|
|||
.top { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
padding: 10px; |
|||
|
|||
/* background-position: bottom; */ |
|||
} |
|||
|
|||
.card-content { |
|||
padding: 0 10px; |
|||
} |
|||
|
|||
.card-left { |
|||
margin-left: 23px; |
|||
margin-bottom: 10px; |
|||
font-weight: 500; |
|||
font-size: 16px; |
|||
color: #000000d9; |
|||
} |
|||
|
|||
.detail { |
|||
margin: 10px 0 |
|||
} |
|||
|
|||
.card-right { |
|||
margin-right: 18px; |
|||
margin-bottom: 10px; |
|||
color: #1684FF; |
|||
} |
|||
|
|||
.fontStyle { |
|||
font-family: PingFangSC-Medium; |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.content-left { |
|||
font-size: 12px; |
|||
width: 60%; |
|||
} |
|||
|
|||
.content-right { |
|||
font-size: 12px; |
|||
text-align: left; |
|||
width: 40%; |
|||
|
|||
} |
@ -0,0 +1,530 @@ |
|||
// package/report/report.js
|
|||
|
|||
import { getPointList,getPatrolTemplates,getPatrolTemplate,getTemplates,reportQuest,getPatrolPlan,getStructuresList,getDetail } from "../../utils/getApiUrl"; |
|||
import {Request} from "../../common"; |
|||
const moment = require("../../utils/moment"); |
|||
|
|||
Page({ |
|||
data: { |
|||
sms:'',//设备号
|
|||
sList:[],//根据sn号查询的结构物列表
|
|||
structListIndex: undefined,//结构物id
|
|||
struct:'',//结构物
|
|||
pointList:[],//点位列表
|
|||
pointIndex:undefined,//点位索引
|
|||
list:[],//初始数据
|
|||
pointVis:false,//点位输入框的可见性
|
|||
formVis:false,//表单项可见性
|
|||
handleObj:'',//处理对象
|
|||
handleGoal:'',//处理目的
|
|||
installLocation:'',//安装位置
|
|||
rtuNo:'',//RTU编号
|
|||
isPlanState: false, |
|||
structList: [],//结构物列表
|
|||
data:[],//巡检计划的数据(包括点位,设备等等)
|
|||
patrolTemplate:[],//巡检模板
|
|||
templateData:[],//巡检模板总数居
|
|||
patrolTemplateIndex:undefined,//巡检模板索引
|
|||
itemData: '', // 点位
|
|||
address: '', // 当前位置
|
|||
imgUrl: getApp().globalData.imgUrl, |
|||
checkItems: [], // 检查项
|
|||
inspectContentArr: [], // 巡检内容
|
|||
isCommitting: false, |
|||
}, |
|||
|
|||
//卡号接收
|
|||
onInputChange(e){ |
|||
this.setData({ |
|||
sms:e.detail, |
|||
sList:[] |
|||
}) |
|||
}, |
|||
//根据sn号搜索
|
|||
searchDetail(){ |
|||
const id=this.data.sms |
|||
if(id){ |
|||
Request.get(getDetail(id)).then(res => { |
|||
if(res){ |
|||
//结构物
|
|||
if(!res.length){ |
|||
wx.showToast({ |
|||
title: '未查询到相关数据', |
|||
icon: 'none', |
|||
duration: 1500 |
|||
}) |
|||
return; |
|||
} |
|||
const uniqueResults = res.reduce((acc, item) => { |
|||
const existingItem = acc.find(project => project.id === item.project.id); |
|||
if (!existingItem) { |
|||
acc.push({ |
|||
id: item.project.id, |
|||
name: item.project.name |
|||
}); |
|||
} |
|||
return acc |
|||
}, []) |
|||
this.setData({ |
|||
sList:uniqueResults, |
|||
list:res |
|||
}) |
|||
} |
|||
}) |
|||
} |
|||
}, |
|||
//点位改变函数
|
|||
pointChange(e){ |
|||
const that = this |
|||
// that.getPatrolTemplate()
|
|||
Request.get(getPatrolTemplates()).then(res=>{ |
|||
if(res){ |
|||
const rlst=res.rows?.map(item=>{return { |
|||
id:item.id, |
|||
name:item.name |
|||
}}) |
|||
that.setData({patrolTemplate:rlst,templateData:res.rows, |
|||
pointIndex:e.detail.value, |
|||
formVis:true, |
|||
inspectContentArr:[], |
|||
patrolTemplateIndex:null |
|||
}) |
|||
} |
|||
}) |
|||
}, |
|||
//整理设备和检查项
|
|||
getPatrolTemplate(templateId,pointDevices=[]) { |
|||
const that=this |
|||
Request.get(getPatrolTemplate(templateId)).then(res => { |
|||
const checkItems = res.rows[0].checkItems; |
|||
let inspectContentArr = []; |
|||
// 有绑定设备的点位,每个设备都要检查各个检查项
|
|||
if (pointDevices.length) { |
|||
pointDevices.forEach(device => { |
|||
inspectContentArr.push({ |
|||
deviceName: device.name, |
|||
deviceId: device.id, |
|||
checkItems: checkItems.map(c => ({ |
|||
id: `${device.id}-${c.id}`, |
|||
name: c.name, |
|||
isNormal: true, |
|||
msgInp: null, |
|||
level: null, |
|||
imgs: [], |
|||
})) |
|||
}) |
|||
}); |
|||
} else { |
|||
inspectContentArr.push({ |
|||
checkItems: checkItems.map(c => ({ |
|||
id: c.id, |
|||
name: c.name, |
|||
isNormal: true, |
|||
msgInp: null, |
|||
level: null, |
|||
imgs: [], |
|||
})) |
|||
}) |
|||
} |
|||
this.setData({ |
|||
checkItems, |
|||
inspectContentArr: inspectContentArr, |
|||
}) |
|||
}) |
|||
}, |
|||
//收集输入框的值
|
|||
input1Change(e){ |
|||
const that = this |
|||
that.setData({handleObj:e.detail}) |
|||
}, |
|||
input2Change(e){ |
|||
const that = this |
|||
that.setData({handleGoal:e.detail}) |
|||
}, |
|||
input3Change(e){ |
|||
const that = this |
|||
that.setData({installLocation:e.detail}) |
|||
}, |
|||
input4Change(e){ |
|||
const that = this |
|||
that.setData({rtuNo:e.detail}) |
|||
}, |
|||
|
|||
|
|||
|
|||
// 预览图片
|
|||
previewImg: function (e) { |
|||
const { deviceidx, itemidx, index } = e.currentTarget.dataset; |
|||
// 所有图片
|
|||
const imgs = this.data.inspectContentArr[deviceidx].checkItems[itemidx].imgs; |
|||
const newImgs = imgs.map(i => this.data.imgUrl + i); |
|||
wx.previewImage({ |
|||
// 当前显示图片
|
|||
current: newImgs[index], |
|||
// 所有图片
|
|||
urls: newImgs |
|||
}) |
|||
}, |
|||
//结构物改变函数
|
|||
structChange(event) { |
|||
const that = this |
|||
const projectId=that.data.sList.find(item=>item.id==that.data?.sList[Number(event.detail.value)].id)?.id |
|||
const query={projectId} |
|||
Request.get(getPointList(query)).then(res => { |
|||
if(res){ |
|||
that.setData({data:res}) |
|||
} |
|||
}) |
|||
that.setData({ |
|||
pointVis:false, |
|||
pointList:[],//选择结构物后先置空先前的点位列表
|
|||
formVis:false, |
|||
pointIndex:null, |
|||
inspectContentArr:[] |
|||
}) |
|||
const rlst=that.data.list?.filter(item=>item.project.id==projectId)?.map(item=>{ |
|||
return { |
|||
id: item.id, |
|||
name: item.name |
|||
} |
|||
}) |
|||
|
|||
that.setData({ |
|||
structListIndex:event.detail.value, |
|||
pointList:rlst, |
|||
pointVis:true |
|||
}) |
|||
|
|||
|
|||
}, |
|||
|
|||
//选择异常或者正常
|
|||
handleChangeTwo(e) { |
|||
const { deviceidx, itemidx } = e.currentTarget.dataset; |
|||
let nextInspectContentArr = this.data.inspectContentArr; |
|||
|
|||
nextInspectContentArr[deviceidx].checkItems[itemidx].isNormal = e.detail; |
|||
if (e.detail) { // 清除异常数据
|
|||
nextInspectContentArr[deviceidx].checkItems[itemidx].msgInp = null; |
|||
nextInspectContentArr[deviceidx].checkItems[itemidx].level = null; |
|||
nextInspectContentArr[deviceidx].checkItems[itemidx].imgs = []; |
|||
} |
|||
this.setData({ inspectContentArr: nextInspectContentArr }) |
|||
}, |
|||
//返回前一页
|
|||
bindCancel() { |
|||
wx.navigateBack(); |
|||
}, |
|||
// 开始巡检录入
|
|||
addPatrolRecord: function () { |
|||
const that = this; |
|||
if (that.data.isCommitting) { return } |
|||
let { |
|||
rtuNo, |
|||
installLocation, |
|||
handleGoal, |
|||
handleObj, |
|||
patrolTemplate, |
|||
patrolTemplateIndex, |
|||
structListIndex, |
|||
pointIndex, |
|||
inspectContentArr, |
|||
pointList, |
|||
sList |
|||
} = that.data; |
|||
let alarm = false; |
|||
|
|||
|
|||
if (!patrolTemplateIndex) { |
|||
wx.showToast({ |
|||
title: '请选择模板', |
|||
icon: 'none', |
|||
duration: 1500 |
|||
}) |
|||
return; |
|||
} |
|||
if (!pointIndex) { |
|||
wx.showToast({ |
|||
title: '请选择点位', |
|||
icon: 'none', |
|||
duration: 1500 |
|||
}) |
|||
return; |
|||
} |
|||
|
|||
let reportArr = inspectContentArr.map(d => ({ ...d, alarm:d.checkItems.some(q=>q.isNormal==false)?true:false })) |
|||
for (const d of reportArr[0]?.checkItems) { |
|||
if (d.isNormal === null) { |
|||
wx.showToast({ |
|||
title: '请填写完整', |
|||
icon: 'none', |
|||
duration: 1500 |
|||
}) |
|||
return |
|||
} |
|||
if ((!d.isNormal) && (!d.level || !d.msgInp)) { |
|||
wx.showToast({ |
|||
title: '异常项必须输入巡查详情和选择严重等级', |
|||
icon: 'none', |
|||
duration: 2000 |
|||
}) |
|||
return |
|||
} |
|||
if (d.isNormal === false) { |
|||
alarm = true; // 巡检记录异常
|
|||
} |
|||
} |
|||
|
|||
const { id, name, departmentId, deptName } = wx.getStorageSync('userInfo'); |
|||
const newData = that.data.data.map((item) => { |
|||
// let pointDevices=[]
|
|||
// item.devices.map(child=>{
|
|||
// const {pointDevice,...newItem } = child;
|
|||
// pointDevices.push({device:newItem,deviceId:pointDevice.deviceId})
|
|||
// })
|
|||
// 使用对象的解构赋值去掉 project 和 devices 属性
|
|||
const { project, devices, ...newItem } = item; |
|||
// return {...newItem,pointDevices}
|
|||
return {...newItem} |
|||
|
|||
}); |
|||
const nextItemData=newData.find(item=>item.id===pointList[pointIndex].id) |
|||
let datas = { |
|||
patrolPlanId: -1, |
|||
pointId: sList[pointIndex].id, |
|||
inspectionTime: moment().format('YYYY-MM-DD HH:mm:ss'), |
|||
points: { |
|||
user: { id, name, department: { id: departmentId, name: deptName } }, |
|||
project: sList[structListIndex], |
|||
itemData:nextItemData, |
|||
inspectContent: reportArr, |
|||
aboutDisaster:{ rtuNo, |
|||
installLocation, |
|||
handleGoal, |
|||
handleObj} |
|||
}, |
|||
alarm, |
|||
projectId: sList[structListIndex].id |
|||
} |
|||
wx.showLoading({ title: '提交中...' }); |
|||
that.setData({ isCommitting: true }); |
|||
Request.post(reportQuest(), datas).then(res => { |
|||
wx.hideLoading(); |
|||
that.setData({ isCommitting: false }); |
|||
wx.showToast({ |
|||
title: '提交成功', |
|||
icon: 'success' |
|||
}) |
|||
setTimeout(() => { |
|||
that.bindCancel(); |
|||
}, 1500) |
|||
}) |
|||
}, |
|||
//多张图片上传
|
|||
uploadImg: function (data, deviceidx, itemidx) { |
|||
wx.showLoading({ |
|||
title: '上传中...', |
|||
mask: true, |
|||
}) |
|||
let that = this, |
|||
i = data.i ? data.i : 0, |
|||
success = data.success ? data.success : 0, |
|||
fail = data.fail ? data.fail : 0; |
|||
let imgs = that.data.inspectContentArr[deviceidx].checkItems[itemidx].imgs; |
|||
wx.uploadFile({ |
|||
url: data.url, |
|||
filePath: data.path[i], |
|||
name: 'file', |
|||
success: (resp) => { |
|||
wx.hideLoading(); |
|||
success++; |
|||
let str = JSON.parse(resp.data) // 返回的结果,可能不同项目结果不一样
|
|||
str = str.uploaded |
|||
if (imgs.length >= 20) { |
|||
let nextInspectContentArr = that.data.inspectContentArr; |
|||
nextInspectContentArr[deviceidx].checkItems[itemidx].imgs = imgs; |
|||
that.setData({ inspectContentArr: nextInspectContentArr }); |
|||
return false; |
|||
} else { |
|||
imgs.push(str); |
|||
let nextInspectContentArr = that.data.inspectContentArr; |
|||
nextInspectContentArr[deviceidx].checkItems[itemidx].imgs = imgs; |
|||
that.setData({ inspectContentArr: nextInspectContentArr }); |
|||
} |
|||
}, |
|||
fail: (res) => { |
|||
fail++; |
|||
console.log('fail:' + i + "fail:" + fail); |
|||
}, |
|||
complete: () => { |
|||
i++; |
|||
if (i == data.path.length) { // 当图片传完时,停止调用
|
|||
console.log('执行完毕'); |
|||
console.log('成功:' + success + " 失败:" + fail); |
|||
} else { // 若图片还没有传完,则继续调用函数
|
|||
data.i = i; |
|||
data.success = success; |
|||
data.fail = fail; |
|||
that.uploadImg(data, deviceidx, itemidx); // 递归,回调自己
|
|||
} |
|||
} |
|||
}); |
|||
}, |
|||
// 上传图片
|
|||
chooseImg: function (e) { // 这里是选取图片的方法
|
|||
const { deviceidx, itemidx } = e.currentTarget.dataset; |
|||
const that = this; |
|||
let pics = []; |
|||
const detailPics = that.data.inspectContentArr[deviceidx].checkItems[itemidx].imgs; |
|||
if (detailPics.length >= 20) { |
|||
wx.showToast({ |
|||
title: '最多选择20张图片上传', |
|||
icon: 'none' |
|||
}); |
|||
return; |
|||
} |
|||
wx.chooseMedia({ |
|||
count: 20, // 基础库2.25.0前,最多可支持9个文件,2.25.0及以后最多可支持20个文件
|
|||
mediaType: ['image'], // 文件类型
|
|||
sizeType: ['original', 'compressed'], // original 原图,compressed 压缩图,默认二者都有
|
|||
sourceType: ['album', 'camera'], // album 从相册选图,camera 使用相机,默认二者都有
|
|||
success: function (res) { |
|||
const imgs = res.tempFiles; |
|||
for (let i = 0; i < imgs.length; i++) { |
|||
if (res.tempFiles[i].size > 15728640) { |
|||
wx.showToast({ title: '图片大于15M,不可上传', icon: 'none' }); |
|||
return; |
|||
} |
|||
const fileNameArr = res.tempFiles[i].tempFilePath.split('.'); |
|||
const extension = res.tempFiles[i].tempFilePath.split('.')[fileNameArr.length - 1]; |
|||
if (extension !== 'jpg' && extension !== 'png' && extension !== 'jpeg') { |
|||
wx.showToast({ title: '只能上传jpg、jpeg、png格式的图片', icon: 'none' }); |
|||
return; |
|||
} |
|||
pics.push(imgs[i].tempFilePath) |
|||
} |
|||
that.uploadImg({ |
|||
url: getApp().globalData.webUrl + '_upload/attachments/project', // 图片上传的接口
|
|||
path: pics, // 选取的图片的地址数组
|
|||
}, deviceidx, itemidx); |
|||
}, |
|||
}) |
|||
}, |
|||
// 删除图片
|
|||
deleteImg: function (e) { |
|||
const { deviceidx, itemidx, index } = e.currentTarget.dataset; |
|||
let imgs = this.data.inspectContentArr[deviceidx].checkItems[itemidx].imgs; |
|||
imgs.splice(index, 1); |
|||
let nextInspectContentArr = this.data.inspectContentArr; |
|||
nextInspectContentArr[deviceidx].checkItems[itemidx].imgs = imgs; |
|||
this.setData({ inspectContentArr: nextInspectContentArr }) |
|||
}, |
|||
// 巡查详情
|
|||
bindInput: function (e) { |
|||
const { deviceidx, itemidx } = e.currentTarget.dataset; |
|||
let nextInspectContentArr = this.data.inspectContentArr; |
|||
|
|||
nextInspectContentArr[deviceidx].checkItems[itemidx].msgInp = e.detail.value; |
|||
this.setData({ inspectContentArr: nextInspectContentArr }) |
|||
}, |
|||
|
|||
handleChangeThree(e) { |
|||
const { deviceidx, itemidx } = e.currentTarget.dataset; |
|||
let nextInspectContentArr = this.data.inspectContentArr; |
|||
nextInspectContentArr[deviceidx].checkItems[itemidx].level = e.detail; |
|||
this.setData({ inspectContentArr: nextInspectContentArr }) |
|||
}, |
|||
|
|||
|
|||
//巡检模板改变
|
|||
patrolTemplateChange(e){ |
|||
const that=this |
|||
that.getPatrolTemplate(that.data.patrolTemplate[e.detail.value].id) |
|||
that.setData({ |
|||
patrolTemplateIndex:e.detail.value |
|||
}) |
|||
|
|||
|
|||
}, |
|||
bindShowMsg() { |
|||
this.setData({ |
|||
select: !this.data.select |
|||
}) |
|||
}, |
|||
|
|||
mySelect(e) { |
|||
var name = e.currentTarget.dataset.name |
|||
this.setData({ |
|||
tihuoWay: name, |
|||
select: false |
|||
}) |
|||
}, |
|||
/** |
|||
* 页面的初始数据 |
|||
*/ |
|||
// data: {
|
|||
|
|||
// },
|
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad(options) { |
|||
const that=this |
|||
wx.setNavigationBarTitle({ |
|||
title: options.key, |
|||
}) |
|||
|
|||
|
|||
}, |
|||
|
|||
|
|||
/** |
|||
* 生命周期函数--监听页面初次渲染完成 |
|||
*/ |
|||
onReady() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面显示 |
|||
*/ |
|||
onShow() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面隐藏 |
|||
*/ |
|||
onHide() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面卸载 |
|||
*/ |
|||
onUnload() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 页面相关事件处理函数--监听用户下拉动作 |
|||
*/ |
|||
onPullDownRefresh() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 页面上拉触底事件的处理函数 |
|||
*/ |
|||
onReachBottom() { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 用户点击右上角分享 |
|||
*/ |
|||
onShareAppMessage() { |
|||
|
|||
} |
|||
}) |
@ -0,0 +1,25 @@ |
|||
{ |
|||
"navigationBarBackgroundColor": "#1979ff", |
|||
"navigationBarTextStyle": "white", |
|||
"navigationBarTitleText": "地灾巡检", |
|||
"enablePullDownRefresh": false, |
|||
"componentFramework": "glass-easel", |
|||
"usingComponents": { |
|||
"van-button": "@vant/weapp/button/index", |
|||
"van-field": "@vant/weapp/field/index", |
|||
"van-cell": "@vant/weapp/cell/index", |
|||
"van-cell-group": "@vant/weapp/cell-group/index", |
|||
"van-picker": "@vant/weapp/picker/index", |
|||
"van-popup": "@vant/weapp/popup/index", |
|||
"van-icon": "@vant/weapp/icon/index", |
|||
"van-collapse": "@vant/weapp/collapse/index", |
|||
"van-collapse-item": "@vant/weapp/collapse-item/index", |
|||
"van-divider": "@vant/weapp/divider/index", |
|||
"t-cell-group": "tdesign-miniprogram/cell-group/cell-group", |
|||
"t-cell": "tdesign-miniprogram/cell/cell", |
|||
"t-picker": "tdesign-miniprogram/picker/picker", |
|||
"t-picker-item": "tdesign-miniprogram/picker-item/picker-item", |
|||
"van-radio": "@vant/weapp/radio/index", |
|||
"van-radio-group": "@vant/weapp/radio-group/index" |
|||
} |
|||
} |
@ -0,0 +1,95 @@ |
|||
<view class="popBox"> |
|||
<view> |
|||
<van-cell-group class="mission-card"> |
|||
<van-cell-group> |
|||
<van-field value="{{ sms }}" bind:input="onInputChange" center clearable label="设备SN号" placeholder="设备SN号" border="{{ false }}" use-button-slot> |
|||
<van-button slot="button" size="small" type="info" bindtap="searchDetail"> |
|||
搜索 |
|||
</van-button> |
|||
</van-field> |
|||
</van-cell-group> |
|||
<van-cell wx:if="{{sList.length}}"> |
|||
<view style="display:flex"> |
|||
<view class="fs-cell-title" style="">结构物:</view> |
|||
<picker style="width:100%;text-align:left" bindchange="structChange" data-type='jiegouwu' value="{{0}}" range="{{sList}}" range-key="name"> |
|||
<view class="fs-cell-content" style="width:100%"> |
|||
{{structListIndex||structListIndex==0?sList[structListIndex].name:'请选择'}} |
|||
<van-icon name="arrow" style="float:right;position:relative; top:4px" /> |
|||
</view> |
|||
</picker> |
|||
</view> |
|||
</van-cell> |
|||
<van-cell wx:if="{{pointVis}}"> |
|||
<view style="display:flex"> |
|||
<view class="fs-cell-title" style="">当前点位:</view> |
|||
<picker style="width:100%;text-align:left" bindchange="pointChange" data-type='point' value="{{0}}" range="{{pointList}}" range-key="name"> |
|||
<view class="fs-cell-content" style="width:100%"> |
|||
{{pointIndex||pointIndex==0?pointList[pointIndex].name:'请选择'}} |
|||
<van-icon name="arrow" style="float:right;position:relative; top:4px" /> |
|||
</view> |
|||
</picker> |
|||
</view> |
|||
</van-cell> |
|||
<!--表单项渲染--> |
|||
<view wx:if="{{formVis}}"> |
|||
<van-cell-group > |
|||
<van-field value="{{handleObj}}" bind:change="input1Change" type="textarea" autosize label="排查及处理对象:" placeholder="排查及处理对象" accordion title-width="110px" /> |
|||
<van-field value="{{ handleGoal }}" bind:change="input2Change" type="textarea" autosize label="排查及处理目的:" placeholder="排查及处理目的" accordion title-width="110px"/> |
|||
<van-field value="{{ installLocation }}" bind:change="input3Change" type="textarea" autosize label="安装位置:" placeholder="安装位置" accordion /> |
|||
<van-field value="{{ rtuNo }}" type="textarea" bind:change="input4Change" autosize label="RTU编号:" placeholder="RTU编号" accordion /> |
|||
</van-cell-group> |
|||
<van-cell > |
|||
<view style="display:flex"> |
|||
<view class="fs-cell-title">巡检模板:</view> |
|||
<picker style="width:100%;text-align:left" bindchange="patrolTemplateChange" data-type='template' value="{{0}}" range="{{patrolTemplate}}" range-key="name"> |
|||
<view class="fs-cell-content" style="width:100%"> |
|||
{{patrolTemplateIndex||patrolTemplateIndex==0?patrolTemplate[patrolTemplateIndex].name:'请选择'}} |
|||
<van-icon name="arrow" style="float:right;position:relative; top:4px" /> |
|||
</view> |
|||
</picker> |
|||
</view> |
|||
</van-cell> |
|||
</view> |
|||
</van-cell-group> |
|||
</view> |
|||
|
|||
<!-- 渲染巡检内容 --> |
|||
<view wx:for="{{inspectContentArr}}" wx:key="id" wx:for-item="device" wx:for-index="deviceidx"> |
|||
<view wx:if="{{device.deviceName}}" class="flex flex-start" style="height: 40px">{{device.deviceName}}</view> |
|||
<view wx:for="{{device.checkItems}}" wx:key="id" wx:for-index="itemidx"> |
|||
<view class="flex-between"> |
|||
<view class="item-name">{{item.name}}:</view> |
|||
<van-radio-group style="padding:10px 15px;" data-deviceidx="{{deviceidx}}" data-itemidx="{{itemidx}}" bindchange="handleChangeTwo" value="{{item.isNormal}}"> |
|||
<van-radio style="margin-right: 20px;" class="radio-text" color="#1979ff" name="{{true}}">正常</van-radio> |
|||
<van-radio class="radio-text" checked-color="#CC0000" name="{{false}}">异常</van-radio> |
|||
</van-radio-group> |
|||
</view> |
|||
<view class="divider" /> |
|||
<van-radio-group class="flex-end" style="padding:10px 15px;" data-deviceidx="{{deviceidx}}" data-itemidx="{{itemidx}}" bindchange="handleChangeThree" wx:if="{{item.isNormal === false}}"> |
|||
<van-radio style="margin-right: 20px;" class="radio-text" checked-color="#FF9900" name="轻微">轻微</van-radio> |
|||
<van-radio style="margin-right: 20px;" class="radio-text" checked-color="#FF3300" name="中度">中度</van-radio> |
|||
<van-radio class="radio-text" checked-color="#990000" name="严重">严重</van-radio> |
|||
</van-radio-group> |
|||
<textarea class="textarea" placeholder="请输入巡查详情" maxlength="-1" wx:if="{{item.isNormal === false}}" data-deviceidx="{{deviceidx}}" data-itemidx="{{itemidx}}" bindinput="bindInput" /> |
|||
<view class="weui-uploader" style="padding: 20rpx 30rpx;overflow-y:scroll;" wx:if="{{item.isNormal === false}}"> |
|||
<view class="img-v weui-uploader__bd" style="overflow:hidden;"> |
|||
<view class="pic" wx:for="{{item.imgs}}" wx:for-item="img" wx:key="*this"> |
|||
<image class="weui-uploader__img showImg" src="{{imgUrl + img}}" data-index="{{index}}" data-deviceidx="{{deviceidx}}" data-itemidx="{{itemidx}}" mode="aspectFill" bindtap="previewImg"> |
|||
<icon type="cancel" class="delete-btn" data-index="{{index}}" data-deviceidx="{{deviceidx}}" data-itemidx="{{itemidx}}" catchtap="deleteImg" /> |
|||
</image> |
|||
</view> |
|||
<!-- 用来提示用户上传图片 --> |
|||
<view class="weui-uploader__input-box pic" data-item="{{item.name}}" data-deviceidx="{{deviceidx}}" data-itemidx="{{itemidx}}" bindtap="chooseImg"> |
|||
<image class="upload" src="/images/upload.png" /> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="divider" /> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="btnBox"> |
|||
<view class="cancel" bindtap="bindCancel">取消</view> |
|||
<view class="submit" bindtap="addPatrolRecord">提交</view> |
|||
</view> |
|||
</view> |
@ -0,0 +1,132 @@ |
|||
.divider { |
|||
width: 100%; |
|||
height: 0px; |
|||
border-top: 1px solid #F5F5F5; |
|||
} |
|||
|
|||
|
|||
.flex-between { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
} |
|||
|
|||
.flex-end { |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
} |
|||
|
|||
.popBox { |
|||
position: absolute; |
|||
left: 50%; |
|||
z-index: 1000; |
|||
background: #fff; |
|||
width: 95%; |
|||
margin-left: -356rpx; |
|||
padding: 20rpx 0; |
|||
} |
|||
|
|||
.item-name { |
|||
margin: 20rpx 0 0 30rpx; |
|||
} |
|||
|
|||
.btnBox { |
|||
padding: 50px 30rpx; |
|||
overflow: hidden; |
|||
font-size: 30rpx; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
} |
|||
|
|||
.cancel { |
|||
width: 38vw; |
|||
height: 42px; |
|||
line-height: 42px; |
|||
text-align: center; |
|||
background: #fff; |
|||
border: 1px solid #006BE3; |
|||
border-radius: 24px; |
|||
font-weight: 600; |
|||
font-size: 16px; |
|||
color: #1684FF; |
|||
} |
|||
|
|||
.submit { |
|||
width: 38vw; |
|||
height: 42px; |
|||
line-height: 42px; |
|||
text-align: center; |
|||
background: #1684FF; |
|||
border: 1px solid #006BE3; |
|||
border-radius: 24px; |
|||
font-weight: 600; |
|||
font-size: 16px; |
|||
color: #FFFFFF; |
|||
} |
|||
|
|||
.pic { |
|||
float: left; |
|||
position: relative; |
|||
margin-right: 8px; |
|||
margin-bottom: 8px; |
|||
} |
|||
|
|||
.showImg { |
|||
width: 160rpx; |
|||
height: 160rpx; |
|||
} |
|||
|
|||
.delete-btn { |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
} |
|||
|
|||
.upload { |
|||
width: 63px; |
|||
height: 63px; |
|||
} |
|||
|
|||
.block { |
|||
display: block; |
|||
} |
|||
|
|||
.icon { |
|||
width: 18px; |
|||
height: 18px; |
|||
margin-right: 5px; |
|||
} |
|||
|
|||
.radio-text { |
|||
font-size: 14px; |
|||
color: #323233; |
|||
} |
|||
|
|||
.van-radio-group { |
|||
display: flex; |
|||
} |
|||
|
|||
.textarea { |
|||
width: 84%; |
|||
margin: 0 auto; |
|||
padding: 20rpx; |
|||
height: 120rpx; |
|||
border: 1px solid #61616166; |
|||
} |
|||
.mission-card-title { |
|||
background-color: #fff; |
|||
overflow: auto; |
|||
padding: 24rpx 16px; |
|||
display: flex; |
|||
align-items: center |
|||
} |
|||
.fs-cell-title { |
|||
max-width: 6.2em; |
|||
min-width: 6.2em; |
|||
margin-right: 12px; |
|||
text-align: left; |
|||
color: var(--field-label-color, #646566) |
|||
} |
|||
|
|||
.fs-cell-content { |
|||
color: var(--field-input-text-color, #323233) |
|||
} |
@ -0,0 +1,6 @@ |
|||
|
|||
'use strict'; |
|||
import projectBinding from './projectBinding' |
|||
export default { |
|||
...projectBinding |
|||
} |
@ -0,0 +1,59 @@ |
|||
'use strict'; |
|||
import { basicAction } from '@peace/utils' |
|||
import { ApiTable } from '$utils' |
|||
|
|||
export function getanxinyunProject(data) { |
|||
return dispatch => basicAction({ |
|||
type: 'post', |
|||
dispatch: dispatch, |
|||
data, |
|||
actionType: 'GET_ANXINYUN_PROJECT', |
|||
url: `${ApiTable.getanxinyunProject}`, |
|||
msg: { error: '获取安心云结构物失败' }, |
|||
reducer: { name: 'anxinyunProject'} |
|||
}); |
|||
} |
|||
|
|||
|
|||
export function addorEditRelation(data) { |
|||
return dispatch => basicAction({ |
|||
type: 'post', |
|||
dispatch: dispatch, |
|||
data, |
|||
actionType: 'ADD_OR_EDIT_RELATION', |
|||
url: `${ApiTable.addorEditRelation}`, |
|||
msg: { option:data?.id? '编辑绑定关系':'新增绑定关系' }, |
|||
// reducer: { name: 'anxinyunProject'}
|
|||
}); |
|||
} |
|||
|
|||
export function getRelation(query) { |
|||
return dispatch => basicAction({ |
|||
type: 'get', |
|||
query, |
|||
dispatch: dispatch, |
|||
actionType: 'GET_RELATION', |
|||
url: `${ApiTable.getRelation}`, |
|||
msg: { error:'查询项目映射关系失败' }, |
|||
reducer: { name: 'relation'} |
|||
}); |
|||
} |
|||
|
|||
export function delRelation(id) { |
|||
return dispatch => basicAction({ |
|||
type: 'delete', |
|||
dispatch: dispatch, |
|||
actionType: 'DEL_RELATION', |
|||
url: ApiTable.delRelation.replace('{id}', id), |
|||
msg: { option:'删除项目映射关系' }, |
|||
// reducer: { name: 'anxinyunProject'}
|
|||
}); |
|||
} |
|||
|
|||
|
|||
export default{ |
|||
getanxinyunProject, |
|||
getRelation, |
|||
addorEditRelation, |
|||
delRelation |
|||
} |
@ -0,0 +1,88 @@ |
|||
import React, { useRef,useState,useEffect } from 'react' |
|||
import { Button, Form } from 'antd' |
|||
import { connect } from 'react-redux'; |
|||
import { InfoCircleOutlined } from '@ant-design/icons' |
|||
import { ModalForm, ProFormSelect, ProFormText, ProFormDatePicker } from '@ant-design/pro-form' |
|||
import moment from 'moment' |
|||
function RelationModal(props) { |
|||
const { title, triggerRender, editData = null, onFinish, devices,actions,dispatch,proejctListOpt,structureListOpt } = props |
|||
const{projectBinding}=actions |
|||
const formItemLayout = { labelCol: { span: 6 }, wrapperCol: { span: 16 } } |
|||
const initialValues = editData? { ...editData,} : {} |
|||
const [form] = Form.useForm() |
|||
const formRef = useRef() |
|||
|
|||
|
|||
return ( |
|||
<ModalForm |
|||
formRef={formRef} |
|||
title={title || ''} |
|||
initialValues={initialValues} |
|||
trigger={triggerRender ? triggerRender : <Button type='primary'>{title || ''}</Button>} |
|||
layout='horizontal' |
|||
grid={true} |
|||
{...formItemLayout} |
|||
modalProps={{ |
|||
destroyOnClose: true, |
|||
onCancel: () => {}, |
|||
}} |
|||
onFinish={async values => { |
|||
// console.log('values1',editData)
|
|||
let value={ |
|||
anxinyunProject:values?.anxinyunProject, |
|||
structName:values?.structName, |
|||
id:initialValues?initialValues.key:null |
|||
} |
|||
return onFinish && (await onFinish(value)) |
|||
// return true;
|
|||
}} |
|||
width={500}> |
|||
<ProFormSelect |
|||
rules={[{ required: true, message: '安心云结构物' }]} |
|||
showSearch |
|||
options={proejctListOpt?.map(s => { |
|||
return { label: s.label, value: s.value } |
|||
})} |
|||
name='anxinyunProject' |
|||
label='安心云结构物' |
|||
/> |
|||
<ProFormSelect |
|||
rules={[{ required: true, message: '关联结构物' }]} |
|||
showSearch |
|||
options={structureListOpt?.map(s => { |
|||
return { label: s.label, value: s.value } |
|||
})} |
|||
name='structName' |
|||
label='关联结构物' |
|||
/> |
|||
</ModalForm> |
|||
) |
|||
} |
|||
function mapStateToProps(state) { |
|||
const {auth, global, device } = state; |
|||
return { |
|||
loading: device.isRequesting, |
|||
clientHeight: global.clientHeight, |
|||
actions: global.actions, |
|||
}; |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
export const DEVICE_TYPES = [ |
|||
'安防系统', |
|||
'厨房系统', |
|||
'电梯', |
|||
'供电系统', |
|||
'空调', |
|||
'排水系统', |
|||
'水系统', |
|||
'通道门禁', |
|||
'通风系统', |
|||
'通信系统', |
|||
'显示视频', |
|||
'消防系统', |
|||
'照明系统', |
|||
] |
|||
export default connect(mapStateToProps)(RelationModal) |
@ -0,0 +1,5 @@ |
|||
'use strict'; |
|||
|
|||
import ProjectBinding from './projectBinding' |
|||
|
|||
export { ProjectBinding }; |
@ -0,0 +1,304 @@ |
|||
import React, { useEffect, useState, useRef, useMemo } from 'react' |
|||
import { Spin, Popconfirm, message, Button, Input, Select } from 'antd' |
|||
import { connect } from 'react-redux' |
|||
import ProTable from '@ant-design/pro-table' |
|||
import moment from 'moment' |
|||
import RelationModal from '../components/relationModal' |
|||
function ProjectBinding(props) { |
|||
const {loading, clientHeight, actions, dispatch, devices,anxinyunProjectLoading,relationLoading } = props |
|||
const { projectBinding, projectRegime } = actions |
|||
const tableRef = useRef() |
|||
const proTableFormRef = useRef() |
|||
const [proejctListOpt, setProjectListOpt] = useState([])//安心云结构物
|
|||
const [structureListOpt, setStructureListOpt] = useState([])//巡检结构物
|
|||
const [dataSource, setDataSource] = useState([]) |
|||
// const [dataCopy,setDataCopy]=useState([])
|
|||
const [tableParams, setTableParams] = useState({}) |
|||
// const fetchData = async () => {
|
|||
// let data={
|
|||
// url:"users/{orgId}/projects",
|
|||
// type:"get"
|
|||
// }
|
|||
// dispatch(projectBinding.getanxinyunProject(data)).then(async res=>{
|
|||
// if(res.success){
|
|||
// const d=res.payload.data?.map(item=>{
|
|||
// return {
|
|||
// label:item?.projects[0]?.name,
|
|||
// value:item?.projects[0]?.id
|
|||
// }
|
|||
// })
|
|||
// setProjectListOpt(d)
|
|||
// const r2= await dispatch(projectRegime.getProjectList())
|
|||
// const dp=r2.pauseStatemap(item=>{
|
|||
// return {
|
|||
// label:item?.name,
|
|||
// value:item?.id
|
|||
// }
|
|||
// })
|
|||
// setStructureListOpt(dp)
|
|||
// const r= await dispatch(projectBinding.getRelation())
|
|||
// const list = r?.payload?.data?.rows?.map(item=>{
|
|||
// return {
|
|||
// key: item.id,
|
|||
// anxinyunProject:d?.find(q=>q.value===item.axyProjectId)?.label,
|
|||
// structName:dp?.find(q=>q.value===item.structureId)?.label
|
|||
// }
|
|||
// })
|
|||
// setDataSource(list)
|
|||
// }
|
|||
// })
|
|||
|
|||
// }
|
|||
//初始化
|
|||
useEffect(() => { |
|||
let data = { |
|||
url:'organizations/{orgId}/structures', |
|||
// url: 'users/{orgId}/projects',
|
|||
type: 'get', |
|||
} |
|||
dispatch(projectBinding.getanxinyunProject(data)).then(res => { |
|||
if (res.success) { |
|||
const d = res.payload.data?.map(item => { |
|||
return { |
|||
label: item?.name, |
|||
value: item?.iotaThingId, |
|||
} |
|||
}) |
|||
setProjectListOpt(d) |
|||
} |
|||
}) |
|||
dispatch(projectRegime.getProjectList()).then(res => { |
|||
if (res.success) { |
|||
const dp = res.payload.data?.rows?.map(item => { |
|||
return { |
|||
label: item?.name, |
|||
value: item?.id, |
|||
} |
|||
}) |
|||
setStructureListOpt(dp) |
|||
} |
|||
}) |
|||
}, []) |
|||
const queryData = () => { |
|||
dispatch(projectBinding.getRelation()).then(res => { |
|||
if (res.success) { |
|||
const list = res?.payload?.data?.rows?.map(item => { |
|||
return { |
|||
key: item.id, |
|||
anxinyunProject: proejctListOpt?.find(q => q.value === item.axyProjectId)?.value, |
|||
structName: structureListOpt?.find(q => q.value === item.structureId)?.value, |
|||
} |
|||
}) |
|||
setDataSource(list) |
|||
// setDataCopy(list)
|
|||
} |
|||
}) |
|||
} |
|||
useEffect(() => { |
|||
if (proejctListOpt && structureListOpt && proejctListOpt.length && structureListOpt.length) { |
|||
queryData() |
|||
} |
|||
}, [proejctListOpt, structureListOpt]) |
|||
|
|||
const onFinish = async values => { |
|||
const dataToSave = { axyProjectId: values?.anxinyunProject, structrueId: values?.structName, id: values?.id } |
|||
return dispatch(projectBinding.addorEditRelation(dataToSave)).then(res => { |
|||
if (res.success) { |
|||
queryData() |
|||
// tableRef.current.reload()
|
|||
return true |
|||
} else { |
|||
return false |
|||
} |
|||
}) |
|||
} |
|||
//删除按钮
|
|||
const handleDelete = id => { |
|||
dispatch(projectBinding.delRelation(id)).then(res => { |
|||
if (res.success) { |
|||
queryData() |
|||
} |
|||
}) |
|||
} |
|||
|
|||
const filterOption = (input, option) => (option?.label ?? '').toLowerCase().includes(input.toLowerCase()) |
|||
|
|||
const columns = [ |
|||
{ |
|||
title: '安心云结构物', |
|||
dataIndex: 'anxinyunProject', |
|||
ellipsis: true, |
|||
valueType: 'select', |
|||
fieldProps: { |
|||
options: proejctListOpt, |
|||
}, |
|||
renderFormItem: () => ( |
|||
<Select |
|||
showSearch |
|||
// style={{paddingLeft:10}}
|
|||
allowClear |
|||
placeholder='请选择' |
|||
options={proejctListOpt?.map(item => ({ label: item.label, value: item.value }))} |
|||
filterOption={filterOption} |
|||
optionFilterProp='children'></Select> |
|||
), |
|||
// fieldProps: {
|
|||
// showSearch: true,
|
|||
// defaultValue: '',
|
|||
// },
|
|||
// onFilter: (value, record) => record.name.includes(value),
|
|||
// search:false
|
|||
}, |
|||
{ |
|||
title: '结构物名称', |
|||
dataIndex: 'structName', |
|||
ellipsis: true, |
|||
valueType: 'select', |
|||
fieldProps: { |
|||
options: structureListOpt, |
|||
}, |
|||
renderFormItem: () => ( |
|||
<Select |
|||
showSearch |
|||
// style={{paddingLeft:10}}
|
|||
allowClear |
|||
placeholder='请选择' |
|||
options={structureListOpt?.map(item => ({ label: item.label, value: item.value }))} |
|||
filterOption={filterOption} |
|||
optionFilterProp='children'></Select> |
|||
), |
|||
// fieldProps: {
|
|||
// showSearch: true,
|
|||
// defaultValue: '',
|
|||
// },
|
|||
// search:false
|
|||
valueType: 'select', |
|||
fieldProps: { |
|||
options: structureListOpt, |
|||
}, |
|||
}, |
|||
{ |
|||
title: '操作', |
|||
width: 160, |
|||
key: 'option', |
|||
valueType: 'option', |
|||
render: (text, record) => { |
|||
const options = [] |
|||
options.push( |
|||
<RelationModal |
|||
proejctListOpt={proejctListOpt} |
|||
triggerRender={<a>修改映射关系</a>} |
|||
editData={record} |
|||
structureListOpt={structureListOpt} |
|||
title='修改映射关系' |
|||
onFinish={onFinish} |
|||
key='editModel' |
|||
/> |
|||
) |
|||
|
|||
options.push( |
|||
<Popconfirm |
|||
key='del' |
|||
placement='top' |
|||
title='是否确认删除映射关系?' |
|||
onConfirm={() => handleDelete(record.key)} |
|||
okText='是' |
|||
cancelText='否'> |
|||
<a>删除</a> |
|||
</Popconfirm> |
|||
) |
|||
|
|||
return options |
|||
}, |
|||
}, |
|||
] |
|||
// useMemo(()=>{
|
|||
|
|||
// })
|
|||
|
|||
const tableDatas = useMemo(() => { |
|||
const { anxinyunProject, structName } = tableParams |
|||
let rslt = dataSource |
|||
rslt = rslt |
|||
.filter(s => (anxinyunProject ? (s.anxinyunProject ? s.anxinyunProject === anxinyunProject : false) : true)) |
|||
?.filter(s => (structName ? (s.structName ? s.structName === structName : false) : true)) |
|||
return rslt |
|||
}) |
|||
|
|||
// const searchHandler=()=>{
|
|||
// const anxinyunProject=proTableFormRef.current.getFieldsValue()?.anxinyunProject
|
|||
// const structName=proTableFormRef.current.getFieldsValue()?.structName
|
|||
// setDataSource(
|
|||
// dataCopy.filter(f =>
|
|||
// (!anxinyunProject || f.anxinyunProject?.includes(anxinyunProject)) &&
|
|||
// (!structName || f?.structName === structName)
|
|||
// )
|
|||
// )
|
|||
|
|||
// }
|
|||
|
|||
return ( |
|||
<Spin spinning={anxinyunProjectLoading||relationLoading}> |
|||
<div id='patrol-record' className='global-main'> |
|||
{/* <Spin spinning={loading}> */} |
|||
<div style={{ marginBottom: 19 }}> |
|||
<div className='top' style={{ marginBottom: 19 }}> |
|||
<div className='title'> |
|||
<span className='line'></span> |
|||
<span className='cn'>项目绑定</span> |
|||
<span className='en'> PROJECT</span> |
|||
</div> |
|||
<div></div> |
|||
</div> |
|||
</div> |
|||
<RelationModal |
|||
structureListOpt={structureListOpt} |
|||
proejctListOpt={proejctListOpt} |
|||
triggerRender={<Button type='primary'>新增</Button>} |
|||
title='新增映射关系' |
|||
onFinish={onFinish} |
|||
key='addModel' |
|||
/> |
|||
<ProTable |
|||
formRef={proTableFormRef} |
|||
rowKey='id' |
|||
options={false} |
|||
request={async params => { |
|||
setTableParams(params) |
|||
return { |
|||
data: [], |
|||
success: true, |
|||
} |
|||
}} |
|||
actionRef={tableRef} |
|||
columns={columns} |
|||
pagination={{ pageSize: 10, size: 'default', className: 'global-pagination' }} |
|||
dataSource={tableDatas || []} |
|||
search={{ |
|||
labelWidth: 100, |
|||
|
|||
}} |
|||
// search={{
|
|||
// optionRender: ({searchText, resetText}, {form}, dom) => [
|
|||
// <Button type="primary" onClick={searchHandler}>查询</Button>,
|
|||
// ]
|
|||
// }}
|
|||
></ProTable> |
|||
{/* </Spin> */} |
|||
</div> |
|||
</Spin> |
|||
) |
|||
} |
|||
|
|||
function mapStateToProps(state) { |
|||
const { auth, global, device,anxinyunProject, relation} = state |
|||
return { |
|||
loading: device.isRequesting, |
|||
clientHeight: global.clientHeight, |
|||
actions: global.actions, |
|||
relationLoading:relation.isRequesting, |
|||
anxinyunProjectLoading:anxinyunProject.isRequesting, |
|||
} |
|||
} |
|||
|
|||
export default connect(mapStateToProps)(ProjectBinding) |
@ -0,0 +1,15 @@ |
|||
'use strict'; |
|||
|
|||
import reducers from './reducers'; |
|||
import routes from './routes'; |
|||
import actions from './actions'; |
|||
import { getNavItem } from './nav-item'; |
|||
|
|||
export default { |
|||
key: 'projectBinding', |
|||
name: '项目绑定', |
|||
reducers: reducers, |
|||
routes: routes, |
|||
actions: actions, |
|||
getNavItem: getNavItem |
|||
}; |
@ -0,0 +1,13 @@ |
|||
import React from 'react'; |
|||
import { Link } from 'react-router-dom'; |
|||
import { Menu } from 'antd'; |
|||
import { Func } from '$utils'; |
|||
export function getNavItem(user, dispatch) { |
|||
return ( |
|||
<Menu.Item icon={<img src='/assets/images/menu/device.png' style={{ width: 24, height: 24 }} />} |
|||
key="projectBinding"> |
|||
<Link to="/projectBinding">项目绑定</Link> |
|||
</Menu.Item> |
|||
|
|||
); |
|||
} |
@ -0,0 +1,5 @@ |
|||
'use strict'; |
|||
|
|||
export default { |
|||
|
|||
} |
@ -0,0 +1,13 @@ |
|||
'use strict'; |
|||
import { ProjectBinding } from './containers'; |
|||
|
|||
export default [{ |
|||
type: 'inner', |
|||
route: { |
|||
path: '/projectBinding', |
|||
key: 'projectBinding', |
|||
breadcrumb: '项目绑定', |
|||
component: ProjectBinding, |
|||
|
|||
} |
|||
}]; |
Loading…
Reference in new issue