12 Commits

Author SHA1 Message Date
guanj
276ef60389 绘制关键指标概览页面 2026-05-29 16:23:56 +08:00
guanj
7bcc68a9df 绘制电脑治理信息页面 2026-05-27 10:10:19 +08:00
dk
17e47c1f07 fix(APP功能调整): 文档中的第7、8、10没有做;第4点需要再核查下ITIC、F47曲线中的可容忍事件、不可容忍事件的显示是否正确。 2026-05-15 11:16:00 +08:00
guanj
eb72146e0d 提交代码 2026-04-25 15:22:50 +08:00
guanj
ce78b65875 提交代码 2026-04-24 09:13:17 +08:00
guanj
747d3139cf 调整app页面图标样式 2026-04-17 08:50:07 +08:00
guanj
bac0f83f64 提交app 2026-04-13 10:12:04 +08:00
guanj
db097bc64a 调整消息推送 2026-04-03 14:48:45 +08:00
guanj
9f593bd428 1 2026-04-01 10:00:55 +08:00
guanj
966d6d342c 提交app代码 2026-04-01 10:00:04 +08:00
guanj
66cee2922d 联调app 2026-03-30 08:43:13 +08:00
guanj
00e34c168f 提交app 2026-03-17 14:00:55 +08:00
148 changed files with 28426 additions and 11440 deletions

View File

@@ -0,0 +1,7 @@
---
name: New prompt
description: New prompt
invokable: true
---
Please write a thorough suite of unit tests for this code, making sure to cover all relevant edge cases

View File

@@ -0,0 +1,5 @@
---
description: A description of your rule
---
请用中文回答!

27
App.vue
View File

@@ -1,9 +1,11 @@
<script> <script>
import { queryDictDataCache } from './common/api/dictionary.js' import { queryDictDataCache } from './common/api/dictionary.js'
import { getImageUrl } from '@/common/api/basic' import { getImageUrl } from '@/common/api/basic'
import { checkAppUpdate } from './common/js/update.js'
export default { export default {
onLaunch: function () { onLaunch: function () {
checkAppUpdate()
// uni.onPushMessage((res) => { // uni.onPushMessage((res) => {
// console.log("收到推送消息:",res) //监听推送消息 // console.log("收到推送消息:",res) //监听推送消息
// }) // })
@@ -22,21 +24,38 @@ export default {
uni.onPushMessage((res) => { uni.onPushMessage((res) => {
console.log('收到推送消息:', res.data.payload.path) //监听推送消息 console.log('收到推送消息:', res.data.payload.path) //监听推送消息
if (res.data.payload && res.data.payload.path) { if (res.data.payload && res.data.payload.path) {
uni.navigateTo({ uni.setStorageSync('messageParams', {
engineeringName: '',
engineeringId: '', //工程ID
projectName: '',
projectId: '', //項目ID
deviceName: '',
deviceId: '', //设备ID
lineName: '',
lineId: '', //测点ID
type: res.data.payload.path.split('type=')[1],
})
uni.switchTab({
url: res.data.payload.path, url: res.data.payload.path,
}) })
// uni.navigateTo({
// url: res.data.payload.path,
// })
} }
}) })
}, },
onHide: function () { onHide: function () {
console.log('App Hide') console.log('App Hide')
}, },
methods: {},
} }
</script> </script>
<style lang="scss"> <style lang="scss">
/*每个页面公共css */ /*每个页面公共css */
@import './common/css/base.scss'; @import './common/css/base.scss';
@import '@/static/iconfont/iconfont.css';
/deep/ uni-tabbar .uni-tabbar__badge { /deep/ uni-tabbar .uni-tabbar__badge {
width: auto; width: auto;
@@ -47,4 +66,10 @@ export default {
font-size: 20rpx; font-size: 20rpx;
padding: 0 8rpx; padding: 0 8rpx;
} }
// .uni-page-refresh__path {
// stroke: #007aff !important; /* 改成你想要的颜色,比如红色 #ff0000 */
// }
// .uni-page-refresh__icon {
// fill: #007aff !important; /* 改成你想要的颜色,比如红色 #ff0000 */
// }
</style> </style>

10
changelog.md Normal file
View File

@@ -0,0 +1,10 @@
# 更新日志
## 1.0.0 (2025-10-15)
- 初始版本发布
- 实现字母索引列表功能
- 支持按拼音首字母分组展示数据
- 集成右侧快速字母导航功能
- 添加滚动监听和高亮显示当前字母
- 支持签到状态显示和补签操作
- 优化空数据状态展示

View File

@@ -1,197 +1,242 @@
import request from '../js/request' import request from '../js/request'
import config from '../js/config'
// 获取设备
// 获取设备 export function getDeviceList(params) {
export function getDeviceList(params) { return request({
return request({ url: '/cs-device-boot/EquipmentDelivery/queryEquipmentByProject',
url: '/cs-device-boot/EquipmentDelivery/queryEquipmentByProject', method: 'post',
method: 'post', data: params,
data: params, })
}) }
}
/**
/** * 设备统计
* 设备统计 * @param {*} id 工程id
* @param {*} id 工程id * @returns
* @returns */
*/ const date = new Date()
export function getDevCount(id) { const year = date.getFullYear() // 年份 4 位
return request({ const month = (date.getMonth() + 1).toString().padStart(2, '0') // 月份自动补 0
url: '/cs-device-boot/deviceUser/devCount', const currentYearMonth = `${year}-${month}`
method: 'post', export function getDevCount(id) {
return request({
data: { id }, url: '/cs-device-boot/deviceUser/devCount',
}) method: 'post',
} data: { id: id, time: currentYearMonth },
})
// 获取直连设备模板信息 }
export function getModel(nDid) {
return request({ // 获取直连设备模板信息
url: '/access-boot/device/model', export function getModel(nDid) {
method: 'post', return request({
data: { url: '/access-boot/device/model',
nDid, method: 'post',
}, data: {
}) nDid,
} },
})
// 直连设备接入 }
export function addDevice(params) {
return request({ // 直连设备接入
url: '/access-boot/device/access', export function addDevice(params) {
method: 'post', return request({
header: { url: '/access-boot/device/access',
'Content-Type': 'application/json', method: 'post',
}, header: {
data: params, 'Content-Type': 'application/json',
}) },
} data: params,
})
// 直连设备注册 }
export function registerDevice(nDid, type) {
return request({ // 直连设备注册
url: '/access-boot/device/register', export function registerDevice(nDid, type) {
method: 'post', return request({
data: { url: '/access-boot/device/register',
nDid, method: 'post',
type, data: {
}, nDid,
}) type,
} },
})
// 查询拓扑图模板 }
export const getTopoTemplate = () => {
return request({ // 查询拓扑图模板
url: '/cs-device-boot/topologyTemplate/queryImage', export const getTopoTemplate = () => {
method: 'POST', return request({
}) url: '/cs-device-boot/topologyTemplate/queryImage',
} method: 'POST',
})
// 查询拓扑图模板监测点 }
export const queryByTopoId = (id) => {
return request({ // 查询拓扑图模板监测点
url: '/cs-device-boot/lineTemplate/queryByTopoId', export const queryByTopoId = (id) => {
method: 'POST', return request({
data: { url: '/cs-device-boot/lineTemplate/queryByTopoId',
topoId: id, method: 'POST',
}, data: {
}) topoId: id,
} },
// 查询设备拓扑图 })
export const queryTopologyDiagram = (devId) => { }
return request({ // 查询设备拓扑图
url: '/cs-device-boot/lineTopologyDiagram/queryTopologyDiagram', export const queryTopologyDiagram = (devId) => {
method: 'POST', return request({
data: { url: '/cs-device-boot/lineTopologyDiagram/queryTopologyDiagram',
devId, method: 'POST',
}, data: {
}) devId,
} },
})
// 设备扫码移交 }
export const transferDevice = (id, userId) => { // 设备扫码移交
return request({
url: '/cs-device-boot/deviceUser/transfer', export const transferDevice = (id, userId) => {
method: 'POST', return request({
data: { url: '/cs-device-boot/deviceUser/transfer',
ids: id, method: 'POST',
userId: userId || uni.getStorageSync('userInfo').userIndex, data: {
}, ids: id,
}) userId: userId || uni.getStorageSync('userInfo').userIndex,
} },
// 设备扫码分享 })
}
export const shareDevice = (id, userId) => { // 设备扫码分享
return request({
url: '/cs-device-boot/deviceUser/share', export const shareDevice = (id, userId) => {
method: 'POST', return request({
data: { url: '/cs-device-boot/deviceUser/share',
ids: id, method: 'POST',
}, data: {
}) ids: id,
} },
})
// 设备删除 }
export const deleteDevice = (id) => { // 设备删除
return request({
url: '/cs-device-boot/deviceUser/delete', export const deleteDevice = (id) => {
method: 'POST', return request({
data: { url: '/cs-device-boot/deviceUser/delete',
eid: id, method: 'POST',
}, data: {
}) eid: id,
} },
})
// 设备查询通过id获取 }
export const queryDeivceById = (id) => {
return request({ // 设备查询通过id获取
url: '/cs-device-boot/EquipmentDelivery/queryEquipmentById', export const queryDeivceById = (id) => {
method: 'POST', return request({
data: { url: '/cs-device-boot/EquipmentDelivery/queryEquipmentById',
ids: id, method: 'POST',
}, data: {
}) ids: id,
} },
})
// 字典树接口通过id }
export const queryByid = (id) => {
return request({ // 字典树接口通过id
url: '/system-boot/dictTree/queryByid', export const queryByid = (id) => {
method: 'post', return request({
data: { url: '/system-boot/dictTree/queryByid',
id, method: 'post',
}, data: {
}) id,
} },
})
//设备修改监测点信息 }
export const updateDevice = (params) => {
return request({ //设备修改监测点信息
url: '/cs-device-boot/lineTopologyDiagram/auditList', export const updateDevice = (params) => {
method: 'POST', return request({
header: { url: '/cs-device-boot/lineTopologyDiagram/auditList',
'Content-Type': 'application/json', method: 'POST',
}, header: {
data: params, 'Content-Type': 'application/json',
}) },
} data: params,
})
// 设备用户列表 }
export const queryDeviceUser = (devId) => {
return request({ // 设备用户列表
url: '/cs-device-boot/deviceUser/queryUserById', export const queryDeviceUser = (devId) => {
method: 'POST', return request({
data: { url: '/cs-device-boot/deviceUser/queryUserById',
devId, method: 'POST',
}, data: {
}) devId,
} },
})
// 取消分享 }
export const cancelShare = (params) => {
return request({ // 取消分享
url: '/cs-device-boot/deviceUser/cancelShare', export const cancelShare = (params) => {
method: 'POST', return request({
data: params, url: '/cs-device-boot/deviceUser/cancelShare',
}) method: 'POST',
} data: params,
})
// 取消调试 }
export const cancelDebug = (params) => {
return request({ // 取消调试
url: '/cs-device-boot/EquipmentDelivery/deleteTest', export const cancelDebug = (params) => {
method: 'POST', return request({
data: params, url: '/cs-device-boot/EquipmentDelivery/deleteTest',
}) method: 'POST',
} data: params,
})
// 完成调试 }
export const finishDebug = (params) => {
return request({ // 完成调试
url: '/cs-device-boot/EquipmentDelivery/testcompletion', export const finishDebug = (params) => {
method: 'POST', return request({
data: params, url: '/cs-device-boot/EquipmentDelivery/testcompletion',
}) method: 'POST',
} data: params,
})
}
// 置顶设备、工程
export const engineeringPinToTop = (params) => {
return request({
url: '/cs-device-boot/csUserPins/engineeringPinToTop',
method: 'POST',
data: params,
header: {
'Content-Type': 'application/json',
},
})
}
// 查询工程树
export const lineTree = (params) => {
return request({
url: '/cs-device-boot/csLedger/AppLineTree',
method: 'POST',
// data: {
// type: 'engineering',
// },
// header: {
// 'Content-Type': 'application/json',
// },
})
}
// 查询工程
export const queryEngineeringPage = (params) => {
return request({
url: '/cs-device-boot/engineering/queryEngineeringPage',
method: 'POST',
data: params,
header: {
'Content-Type': 'application/json',
},
})
}
// 通过ndid查询出厂设备
export const queryEquipmentByndid = (params) => {
return request({
url: '/cs-device-boot/EquipmentDelivery/queryEquipmentByndid',
method: 'POST',
data: params,
})
}

View File

@@ -1,71 +1,79 @@
import request from '../js/request' import request from '../js/request'
import config from '../js/config' import config from '../js/config'
export function queryDictData(dictTypeName) { export function queryDictData(dictTypeName) {
return request({ return request({
url: '/dictData/getDicDataByTypeName', url: '/dictData/getDicDataByTypeName',
method: 'get', method: 'get',
data: { data: {
dictTypeName, dictTypeName,
}, },
}) })
} }
export function queryDictDataCache(dictTypeName) { export function queryDictDataCache(dictTypeName) {
return request({ return request({
url: '/system-boot/dictType/dictDataCache', url: '/system-boot/dictType/dictDataCache',
method: 'get', method: 'get',
}) })
} }
// 字典树接口通过code // 字典树接口通过code
export const queryByCode = (code) => { export const queryByCode = (code) => {
return request({ return request({
url: '/system-boot/dictTree/queryByCode', url: '/system-boot/dictTree/queryByCode',
method: 'post', method: 'post',
data: { data: {
code, code,
}, },
}) })
} }
// 字典树接口 // 字典树接口
export const queryCsDictTree = (pid) => { export const queryCsDictTree = (pid) => {
return request({ return request({
url: '/system-boot/dictTree/query', url: '/system-boot/dictTree/query',
method: 'post', method: 'post',
data: { data: {
pid, pid,
}, },
}) })
} }
// 字典树接口
// 字典树接口通过id export const queryStatistical = (data) => {
export const queryByid = (id) => { return request({
return request({ url: '/system-boot/csstatisticalset/queryStatistical',
url: '/system-boot/dictTree/queryByid', method: 'post',
method: 'post', data: data,
data: { })
id, }
},
}) // 字典树接口通过id
} export const queryByid = (id) => {
return request({
// 程序版本 url: '/system-boot/dictTree/queryByid',
export const queryEdDataPage = () => { method: 'post',
return request({ data: {
url: '/cs-device-boot/edData/queryEdDataPage', id,
method: 'post', },
header: { })
'Content-Type': 'application/json;charset=UTF-8', }
},
data: { // 程序版本
pageNum: 1, export const queryEdDataPage = () => {
devName: '', return request({
devType: '', url: '/cs-device-boot/edData/queryEdDataPage',
pageSize: 999, method: 'post',
versionStartDate: '', header: {
versionendDate: '', 'Content-Type': 'application/json;charset=UTF-8',
}, },
}) data: {
} pageNum: 1,
devName: '',
devType: '',
pageSize: 999,
versionStartDate: '',
versionendDate: '',
},
})
}

View File

@@ -1,10 +1,57 @@
import request from '../js/request' import request from '../js/request'
// apf-》获取模块状态 // apf-》获取模块状态
export function getModuleState(params) { export function getModuleState(params) {
return request({ return request({
url: '/cs-harmonic-boot/data/getModuleState', url: '/cs-harmonic-boot/data/getModuleState',
method: 'post', method: 'post',
data: params, data: params,
}) })
} }
export function getBaseRealData(id) {
return request({
url: '/cs-harmonic-boot/realData/getBaseRealData?lineId=' + id,
method: 'post',
})
}
// 查询App暂态事件总数
export function queryAppEventCounts(params) {
return request({
url: '/cs-harmonic-boot/eventUser/queryAppEventCounts',
method: 'post',
data: params,
header: {
'Content-Type': 'application/json',
},
})
}
// 查询App稳态事件总数
export function queryAppHarmonicCounts(params) {
return request({
url: '/cs-harmonic-boot/csHarmonic/queryAppHarmonicCounts',
method: 'post',
data: params,
header: {
'Content-Type': 'application/json',
},
})
}
// 查询App稳态越限监测点
export function queryAppHarmonicLine(params) {
return request({
url: '/cs-harmonic-boot/csHarmonic/queryAppHarmonicLine',
method: 'post',
data: params,
header: {
'Content-Type': 'application/json',
},
})
}
// 暂态事件波形分析
export function analyseWave(params) {
return request({
url: '/cs-harmonic-boot/event/analyseWave',
method: 'get',
params,
})
}

View File

@@ -1,17 +1,45 @@
import request from '../js/request'; import request from '../js/request';
import config from '../js/config'; import config from '../js/config';
/** /**
* 已读暂态 * 已读暂态
* @returns {*} * @returns {*}
*/ */
export function updateStatus(params) { export function updateStatus(params) {
return request({ return request({
url: '/cs-harmonic-boot/eventUser/updateStatus', url: '/cs-harmonic-boot/eventUser/updateStatus',
method: 'post', method: 'post',
header: { header: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
data: params, data: params,
}) })
} }
/**
* 稳态详情
* @returns {*}
*/
export function queryHarmonicDetail(params) {
return request({
url: '/cs-harmonic-boot/csHarmonic/queryHarmonicDetail',
method: 'post',
header: {
'Content-Type': 'application/json',
},
data: params,
})
}
/**
* 运行告警事件详
* @returns {*}
*/
export function queryAlarmDetail(params) {
return request({
url: '/cs-harmonic-boot/csAlarm/queryAlarmDetail',
method: 'post',
header: {
'Content-Type': 'application/json',
},
data: params,
})
}

View File

@@ -1,128 +1,128 @@
import request from '../js/request' import request from '../js/request'
import config from '../js/config' import config from '../js/config'
export function addAppProject(params, files) { export function addAppProject(params, files) {
if (files.length === 0) { if (files.length === 0) {
return request({ return request({
url: '/cs-device-boot/project/addAppProject', url: '/cs-device-boot/project/addAppProject',
method: 'post', method: 'post',
data: params, data: params,
}) })
} else { } else {
return uni.uploadFile({ return uni.uploadFile({
url: config.domain + '/cs-device-boot/project/addAppProject', //仅为示例,非真实的接口地址 url: config.domain + '/cs-device-boot/project/addAppProject', //仅为示例,非真实的接口地址
files: files, files: files,
header: { header: {
Authorization: uni.getStorageSync('access_token'), Authorization: uni.getStorageSync('access_token'),
}, },
formData: params, formData: params,
}) })
} }
} }
// 修改项目 // 修改项目
export function updateAppProject(params, files) { export function updateAppProject(params, files) {
if (files.length === 0) { if (files.length === 0) {
return request({ return request({
url: '/cs-device-boot/project/auditAppProject', url: '/cs-device-boot/project/auditAppProject',
method: 'post', method: 'post',
data: params, data: params,
}) })
} else { } else {
return uni.uploadFile({ return uni.uploadFile({
url: config.domain + '/cs-device-boot/project/auditAppProject', //仅为示例,非真实的接口地址 url: config.domain + '/cs-device-boot/project/auditAppProject', //仅为示例,非真实的接口地址
files: files, files: files,
header: { header: {
Authorization: uni.getStorageSync('access_token'), Authorization: uni.getStorageSync('access_token'),
}, },
formData: params, formData: params,
}) })
} }
} }
export function getProjectList(params) { export function getProjectList(params) {
return request({ return request({
url: '/cs-device-boot/project/queryProject', url: '/cs-device-boot/project/queryProject',
method: 'post', method: 'post',
data: params, data: params,
header: { header: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
}) })
} }
// 删除项目 // 删除项目
export function deleteProject(id) { export function deleteProject(id) {
return request({ return request({
url: '/cs-device-boot/project/auditAppProject', url: '/cs-device-boot/project/auditAppProject',
method: 'post', method: 'post',
data: { data: {
id, id,
status: 0, status: 0,
}, },
}) })
} }
// 查询拓扑图 // 查询拓扑图
export function queryTopologyDiagramPage(params) { export function queryTopologyDiagramPage(params) {
return request({ return request({
url: '/cs-device-boot/topologyDiagram/queryTopologyDiagramPage', url: '/cs-device-boot/topologyDiagram/queryTopologyDiagramPage',
method: 'post', method: 'post',
data: Object.assign( data: Object.assign(
{ {
pageNum: 1, pageNum: 1,
pageSize: 999, pageSize: 999,
projectId: '', projectId: '',
searchValue: '', searchValue: '',
}, },
params, params,
), ),
header: { header: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
}) })
} }
// 删除拓扑图 // 删除拓扑图
export function deleteAppTopologyDiagram(id) { export function deleteAppTopologyDiagram(id) {
return request({ return request({
url: '/cs-device-boot/topologyDiagram/AuditAppTopologyDiagram', url: '/cs-device-boot/topologyDiagram/AuditAppTopologyDiagram',
method: 'post', method: 'post',
data: { data: {
id, id,
status: 0, status: 0,
}, },
}) })
} }
// 删除拓扑图 // 删除拓扑图
export function checkCanDelete(id) { export function checkCanDelete(id) {
return request({ return request({
url: '/cs-device-boot/topologyDiagram/checkCanDelete', url: '/cs-device-boot/topologyDiagram/checkCanDelete',
method: 'post', method: 'post',
data: { data: {
id, id,
}, },
}) })
} }
// 新增拓扑图 // 新增拓扑图
export function addAppTopologyDiagram(params, filePath) { export function addAppTopologyDiagram(params, filePath) {
return uni.uploadFile({ return uni.uploadFile({
url: config.domain + '/cs-device-boot/topologyDiagram/addAppTopologyDiagram', //仅为示例,非真实的接口地址 url: config.domain + '/cs-device-boot/topologyDiagram/addAppTopologyDiagram', //仅为示例,非真实的接口地址
filePath, filePath,
name: 'file', name: 'file',
header: { header: {
Authorization: uni.getStorageSync('access_token'), Authorization: uni.getStorageSync('access_token'),
}, },
formData: Object.assign( formData: Object.assign(
{ {
topologyDiagramName: '', topologyDiagramName: '',
projectId: '', projectId: '',
}, },
params, params,
), ),
}) })
} }

40
common/api/report.js Normal file
View File

@@ -0,0 +1,40 @@
import request from '../js/request'
// 下载稳态报告
export function downloadHarmonicReport(data) {
return request({
url: '/cs-report-boot/csAppReport/downloadHarmonicReport',
method: 'post',
data,
header: {
'Content-Type': 'application/json',
},
})
}
// 申请暂态报告
export function applicationReport(data) {
return request({
url: '/cs-report-boot/csAppReport/applicationReport',
method: 'post',
data,
header: {
'Content-Type': 'application/json',
},
})
}
// 生成暂态报告
export function createEventReport(params) {
return request({
url: '/cs-report-boot/csAppReport/createEventReport',
method: 'post',
params,
})
}
// 下载暂态报告
export function downloadEventReport(params) {
return request({
url: '/cs-report-boot/csAppReport/downloadEventReport',
method: 'post',
params,
})
}

View File

@@ -1,238 +1,245 @@
import request from '../js/request' import request from '../js/request'
/** /**
* 发送验证码 * 发送验证码
* @param {*} params.type 0:登录 1:注册 2:修改密码 6:忘记密码 4:更换手机号第二步获取验证码 5:更换手机号第一步获取验证码 * @param {*} params.type 0:登录 1:注册 2:修改密码 6:忘记密码 4:更换手机号第二步获取验证码 5:更换手机号第一步获取验证码
* @returns * @returns
*/ */
export function apiGetYms(params) { export function apiGetYms(params) {
return request({ return request({
url: '/user-boot/appUser/authCode', url: '/user-boot/appUser/authCode',
data: { data: {
phone: params.phone, phone: params.phone,
devCode: uni.getStorageSync('devCode'), devCode: uni.getStorageSync('devCode'),
type: params.type, type: params.type,
}, },
method: 'POST', method: 'POST',
}) })
} }
/** /**
* 登录 * 登录
* @param {*} params.type 0:ysm 1:pwd * @param {*} params.type 0:ysm 1:pwd
* @returns * @returns
*/ */
export function apiLogin(params) { export function apiLogin(params) {
console.log(uni.getStorageSync('devCode')) console.log(uni.getStorageSync('devCode'))
return request({ return request({
url: '/shiningCloud/user/login', url: '/shiningCloud/user/login',
data: { data: {
phone: params.phone, phone: params.phone,
devCode: uni.getStorageSync('devCode'), devCode: uni.getStorageSync('devCode'),
key: params.key.trim(), key: params.key.trim(),
type: params.type, type: params.type,
}, },
method: 'POST', method: 'POST',
}) })
} }
/** /**
* 验证码登录 * 验证码登录
* @param {*} params.type 0:ysm 1:pwd * @param {*} params.type 0:ysm 1:pwd
* @returns * @returns
*/ */
export function apiYsmLogin(params) { export function apiYsmLogin(params) {
uni.setStorageSync('access_token', 'Basic bmpjbmFwcDpuamNucHFz') uni.setStorageSync('access_token', 'Basic bmpjbmFwcDpuamNucHFz')
return request({ return request({
url: '/pqs-auth/oauth/token', url: '/pqs-auth/oauth/token',
data: { data: {
grant_type: 'sms_code', grant_type: 'sms_code',
phone: params.phone, phone: params.phone,
smsCode: params.smsCode.trim(), smsCode: params.smsCode.trim(),
}, },
method: 'POST', method: 'POST',
}) })
} }
/** /**
* 注册 * 注册
* @param {*} params * @param {*} params
* @returns * @returns
*/ */
export function apiRegister(params) { export function apiRegister(params) {
return request({ return request({
url: '/user-boot/appUser/register', url: '/user-boot/appUser/register',
data: { data: {
phone: params.phone, phone: params.phone,
devCode: uni.getStorageSync('devCode'), devCode: uni.getStorageSync('devCode'),
code: params.code.trim(), code: params.code.trim(),
}, },
method: 'POST', method: 'POST',
}) })
} }
/** /**
* app用户注册完自动登录 * app用户注册完自动登录
* @param params * @param params
* @returns {*} * @returns {*}
*/ */
export function autoLogin(phone) { export function autoLogin(phone) {
return request({ return request({
url: '/pqs-auth/oauth/autoLogin', url: '/pqs-auth/oauth/autoLogin',
data: { data: {
phone: phone, phone: phone,
}, },
method: 'POST', method: 'POST',
}) })
} }
// 第一次登录设置密码 // 第一次登录设置密码
export function apiSetPsd(params) { export function apiSetPsd(params) {
return request({ return request({
url: '/shiningCloud/user/setPsd', url: '/shiningCloud/user/setPsd',
data: { data: {
userId: uni.getStorageSync('userInfo').userIndex, userId: uni.getStorageSync('userInfo').userIndex,
devCode: uni.getStorageSync('devCode'), devCode: uni.getStorageSync('devCode'),
password: params.password.trim(), password: params.password.trim(),
}, },
method: 'POST', method: 'POST',
}) })
} }
// 重置密码 // 重置密码
export function apiReSetPsd(params) { export function apiReSetPsd(params) {
return request({ return request({
url: '/user-boot/appUser/resetPsd', url: '/user-boot/appUser/resetPsd',
data: { data: {
phone: params.phone, phone: params.phone,
code: params.code.trim(), code: params.code.trim(),
devCode: uni.getStorageSync('devCode'), devCode: uni.getStorageSync('devCode'),
password: params.password.trim(), password: params.password.trim(),
}, },
method: 'POST', method: 'POST',
}) })
} }
// 更换手机号第一步 // 更换手机号第一步
export function apiComfirmCode(params) { export function apiComfirmCode(params) {
return request({ return request({
url: '/user-boot/appUser/confirmCode', url: '/user-boot/appUser/confirmCode',
data: { data: {
devCode: uni.getStorageSync('devCode'), devCode: uni.getStorageSync('devCode'),
phone: params.phone, phone: params.phone,
code: params.code.trim(), code: params.code.trim(),
}, },
method: 'POST', method: 'POST',
}) })
} }
// 重新绑定手机号 // 重新绑定手机号
export function apiRebindPhone(params) { export function apiRebindPhone(params) {
return request({ return request({
url: '/user-boot/appUser/rebindPhone', url: '/user-boot/appUser/rebindPhone',
data: { data: {
devCode: uni.getStorageSync('devCode'), devCode: uni.getStorageSync('devCode'),
userId: uni.getStorageSync('userInfo').userIndex, userId: uni.getStorageSync('userInfo').userIndex,
phoneNew: params.phone, phoneNew: params.phone,
code: params.code.trim(), code: params.code.trim(),
}, },
method: 'POST', method: 'POST',
}) })
} }
// 角色升级 // 角色升级
export function roleUpdate({ userId, referralCode }) { export function roleUpdate({ userId, referralCode }) {
return request({ return request({
url: '/user-boot/appRole/roleUpdate', url: '/user-boot/appRole/roleUpdate',
method: 'post', method: 'post',
data: { data: {
devCode: uni.getStorageSync('devCode'), devCode: uni.getStorageSync('devCode'),
referralCode, referralCode,
userId, userId,
}, },
}) })
} }
// 密码登录 // 密码登录
export function apiPwdLogin(params) { export function apiPwdLogin(params) {
return request({ return request({
url: '/pqs-auth/oauth/token', url: '/pqs-auth/oauth/token',
header: { header: {
Authorization: 'Basic bmpjbnRlc3Q6bmpjbnBxcw==', // 客户端信息加密摘要认证 Authorization: 'Basic bmpjbnRlc3Q6bmpjbnBxcw==', // 客户端信息加密摘要认证
}, },
params, params,
method: 'POST', method: 'POST',
}) })
} }
//登录获取公钥 //登录获取公钥
export function gongkey(data) { export function gongkey(data) {
console.log(data) console.log(data)
return request({ return request({
url: '/user-boot/user/generateSm2Key', url: '/user-boot/user/generateSm2Key',
method: 'get', method: 'get',
data: data, data: data,
}) })
} }
// 修改手机号 // 修改手机号
export function apiModifyPsd(params) { export function apiModifyPsd(params) {
return request({ return request({
url: '/user-boot/appUser/modifyPsd', url: '/user-boot/appUser/modifyPsd',
data: { data: {
devCode: uni.getStorageSync('devCode'), devCode: uni.getStorageSync('devCode'),
userId: uni.getStorageSync('userInfo').userIndex, userId: uni.getStorageSync('userInfo').userIndex,
phone: params.phone, phone: params.phone,
password: params.password.trim(), password: params.password.trim(),
code: params.code.trim(), code: params.code.trim(),
}, },
method: 'POST', method: 'POST',
}) })
} }
// 更改用户信息 // 更改用户信息
export function apiUpdateUser(params) { export function apiUpdateUser(params) {
return request({ return request({
url: '/user-boot/user/updateAppUser', url: '/user-boot/user/updateAppUser',
data: { data: {
...params, ...params,
}, },
header: { header: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
method: 'PUT', method: 'PUT',
}) })
} }
// 更改用户信息 // 更改用户信息
export function apiDeleteUser(params) { export function apiDeleteUser(params) {
return request({ return request({
url: '/user-boot/user/delete', url: '/user-boot/user/delete',
data: { data: {
id: uni.getStorageSync('userInfo').userIndex, id: uni.getStorageSync('userInfo').userIndex,
}, },
method: 'DELETE', method: 'DELETE',
}) })
} }
// 更新用户推送标识 // 更新用户推送标识
export function apiUpdatePush(params) { export function apiUpdatePush(params) {
uni.getPushClientId({ uni.getPushClientId({
success: (res) => { success: (res) => {
console.log('🚀 ~ apiUpdatePush111 ~ res:', res) console.log('🚀 ~ apiUpdatePush111 ~ res:', res)
let push_clientid = res.cid let push_clientid = res.cid
console.log(push_clientid, 'push_clientid') console.log(push_clientid, 'push_clientid')
request({ request({
url: '/user-boot/appUser/updateDevCode', url: '/user-boot/appUser/updateDevCode',
data: { data: {
devCode: push_clientid, devCode: push_clientid,
userId: uni.getStorageSync('userInfo').userIndex, userId: uni.getStorageSync('userInfo').userIndex,
}, },
method: 'POST', method: 'POST',
}) })
}, },
fail(err) { fail(err) {
console.log('🚀 ~ apiUpdatePush222 ~ res:', err) console.log('🚀 ~ apiUpdatePush222 ~ res:', err)
}, },
}) })
} }
// 获取当前版本号
export function getLastData() {
return request({
url: '/cs-system-boot/appVersion/getLastData?versionType=APP',
method: 'POST',
})
}

View File

@@ -1,287 +1,311 @@
page { page {
background: #f3f4f5; background: #f3f4f5;
} }
// mt0,mr0,mb0,ml0 --> mt100,mr100,mb100,ml100 // mt0,mr0,mb0,ml0 --> mt100,mr100,mb100,ml100
@for $i from 0 through 100 { @for $i from 0 through 100 {
.mt#{$i} { .mt#{$i} {
margin-top: #{$i}rpx; margin-top: #{$i}rpx;
} }
.mr#{$i} { .mr#{$i} {
margin-right: #{$i}rpx; margin-right: #{$i}rpx;
} }
.mb#{$i} { .mb#{$i} {
margin-bottom: #{$i}rpx; margin-bottom: #{$i}rpx;
} }
.ml#{$i} { .ml#{$i} {
margin-left: #{$i}rpx; margin-left: #{$i}rpx;
} }
.pt#{$i} { .pt#{$i} {
padding-top: #{$i}rpx; padding-top: #{$i}rpx;
} }
.pr#{$i} { .pr#{$i} {
padding-right: #{$i}rpx; padding-right: #{$i}rpx;
} }
.pb#{$i} { .pb#{$i} {
padding-bottom: #{$i}rpx; padding-bottom: #{$i}rpx;
} }
.pl#{$i} { .pl#{$i} {
padding-left: #{$i}rpx; padding-left: #{$i}rpx;
} }
} .pd#{$i} {
padding: #{$i}rpx;
.center { }
display: flex; }
align-items: center;
justify-content: center; .center {
} display: flex;
align-items: center;
.space-between { justify-content: center;
display: flex; }
justify-content: space-between;
} .space-between {
display: flex;
.hide-txt { justify-content: space-between;
overflow-x: hidden; }
white-space: nowrap;
text-overflow: ellipsis; .hide-txt {
word-break: break-all; overflow-x: hidden;
-webkit-line-clamp: 1; white-space: nowrap;
} text-overflow: ellipsis;
word-break: break-all;
.clamp-txt { -webkit-line-clamp: 1;
overflow: hidden; }
display: -webkit-box;
-webkit-box-orient: vertical; .clamp-txt {
-webkit-line-clamp: 2; overflow: hidden;
word-break: break-all; display: -webkit-box;
} -webkit-box-orient: vertical;
-webkit-line-clamp: 2;
.fixed-btn { word-break: break-all;
position: fixed; }
right: 80rpx;
bottom: 200rpx; .fixed-btn {
width: 126rpx; position: fixed;
height: 126rpx; right: 80rpx;
background: $uni-theme-white; bottom: 200rpx;
border-radius: 50%; width: 126rpx;
display: flex; height: 126rpx;
align-items: center; background: $uni-theme-white;
justify-content: center; border-radius: 50%;
box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.2); display: flex;
align-items: center;
image { justify-content: center;
height: 66rpx; box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.2);
width: 66rpx;
} image {
} height: 66rpx;
width: 66rpx;
.grid-card { }
border-radius: 12rpx; }
margin-bottom: 20rpx;
.grid-card {
.grid-card-title { border-radius: 12rpx;
padding: 0 0 20rpx; margin-bottom: 20rpx;
font-size: 28rpx;
color: #111; .grid-card-title {
font-weight: 700; padding: 0 0 20rpx;
} font-size: 28rpx;
color: #111;
.grid-card-content-4, font-weight: 700;
.grid-card-content-2, }
.grid-card-content-1,
.grid-card-content-3, .grid-card-content-4,
.grid-card-content-5, .grid-card-content-2,
.grid-card-content-6 { .grid-card-content-1,
display: grid; .grid-card-content-3,
border-left: 2rpx solid #ccc; .grid-card-content-5,
border-top: 2rpx solid #ccc; .grid-card-content-6 {
font-size: 24rpx; display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr; border-left: 2rpx solid #ccc;
border-top: 2rpx solid #ccc;
.item { font-size: 24rpx;
padding: 0 4rpx; grid-template-columns: 1fr 1fr 1fr 1fr;
display: flex;
align-items: center; .item {
justify-content: center; padding: 0 4rpx;
text-align: center; display: flex;
border-bottom: 2rpx solid #ccc; align-items: center;
border-right: 2rpx solid #ccc; justify-content: center;
padding: 4rpx; text-align: center;
background: $uni-theme-white; border-bottom: 2rpx solid #ccc;
} border-right: 2rpx solid #ccc;
padding: 4rpx;
.item-title { background: $uni-theme-white;
background: unset; }
padding: 8rpx 4rpx;
} .item-title {
} background: unset;
padding: 8rpx 4rpx;
.grid-card-content-1 { }
grid-template-columns: 1fr; }
}
.grid-card-content-2 { .grid-card-content-1 {
grid-template-columns: 1fr 2fr; grid-template-columns: 1fr;
} }
.grid-card-content-2 {
.grid-card-content-3 { grid-template-columns: 1fr 2fr;
grid-template-columns: 1fr 2fr 2fr; }
}
.grid-card-content-3 {
.grid-card-content-5 { grid-template-columns: 1fr 2fr 2fr;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr; }
}
.grid-card-content-5 {
.grid-card-content-6 { grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr; }
}
} .grid-card-content-6 {
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
.index { }
.header { }
margin: 0 20rpx;
display: grid; .index {
grid-gap: 20rpx; .header {
grid-template-columns: 1fr 1fr 1fr ; margin: 0 20rpx;
.header-item { display: grid;
display: flex; grid-gap: 20rpx;
flex-direction: column; grid-template-columns: 1fr 1fr 1fr;
align-items: center; .header-item {
justify-content: center; display: flex;
padding: 10rpx 10rpx 20rpx; flex-direction: column;
color: #fff; align-items: center;
font-size: 28rpx; justify-content: center;
background: $uni-theme-color; padding: 10rpx 10rpx 20rpx;
border-radius: 12rpx; color: #fff;
.header-item-value { font-size: 28rpx;
font-size: 44rpx; background: $uni-theme-color;
} border-radius: 12rpx;
.header-item-label { .header-item-value {
font-size: 24rpx; font-size: 44rpx;
} }
} .header-item-label {
} font-size: 26rpx;
} }
}
.nav { }
position: sticky; }
top: 0;
left: 0; .nav {
padding: 20rpx 20rpx 0; position: sticky;
padding-left: 0; top: 0;
display: flex; left: 0;
flex-wrap: wrap; padding: 20rpx 20rpx 0;
background: rgb(243, 244, 245); padding-left: 0;
z-index: 2; display: flex;
flex-wrap: wrap;
.nav-menu { background: rgb(243, 244, 245);
padding: 6rpx 20rpx; z-index: 2;
margin-left: 20rpx;
margin-bottom: 20rpx; .nav-menu {
font-size: 24rpx; padding: 6rpx 20rpx;
border-radius: 8rpx; margin-left: 20rpx;
background: #ebeaec; margin-bottom: 20rpx;
color: #666; font-size: 24rpx;
&-active { border-radius: 8rpx;
background: #dfe5f7; background: #ebeaec;
color: $uni-theme-color; color: #666;
} &-active {
&-btn { background: #dfe5f7;
background: $uni-theme-color; color: $uni-theme-color;
color: #fff; }
} &-btn {
} background: $uni-theme-color;
} color: #fff;
}
.btn { }
display: flex; }
align-items: center;
justify-content: center; .btn {
flex: 1; display: flex;
background: $uni-theme-color; align-items: center;
color: #fff; justify-content: center;
height: 80rpx; flex: 1;
border-radius: 12rpx; background: $uni-theme-color;
} color: #fff;
height: 80rpx;
.btn-small { border-radius: 12rpx;
display: inline-flex; }
align-items: center;
justify-content: center; .btn-small {
padding: 0 40rpx; display: inline-flex;
background: $uni-theme-color; align-items: center;
color: #fff; justify-content: center;
height: 60rpx; padding: 0 40rpx;
font-size: 24rpx; background: $uni-theme-color;
border-radius: 12rpx; color: #fff;
} height: 60rpx;
font-size: 24rpx;
.device { border-radius: 12rpx;
/deep/ .uni-card:first-of-type { }
margin-top: 0 !important;
} .device {
} /deep/ .uni-card:first-of-type {
margin-top: 0 !important;
.content { }
/deep/ .uni-forms-item:last-of-type { }
margin-bottom: 0 !important;
} .content {
position: relative; /deep/ .uni-forms-item:last-of-type {
} margin-bottom: 0 !important;
}
.status-point-success { position: relative;
display: inline-block; }
width: 16rpx;
height: 16rpx; .status-point-success {
border-radius: 50%; display: inline-block;
background: greenyellow; width: 16rpx;
overflow: hidden; height: 16rpx;
} border-radius: 50%;
background: greenyellow;
.status-point-error { overflow: hidden;
display: inline-block; }
width: 16rpx;
height: 16rpx; .status-point-error {
border-radius: 50%; display: inline-block;
background: red; width: 16rpx;
overflow: hidden; height: 16rpx;
} border-radius: 50%;
background: red;
.popup-header { overflow: hidden;
display: flex; }
align-items: center;
justify-content: space-between; .popup-header {
padding: 0 20rpx; display: flex;
height: 80rpx; align-items: center;
background: #fff; justify-content: space-between;
border-radius: 20rpx 20rpx 0 0; padding: 0 20rpx;
overflow: hidden; height: 80rpx;
border-bottom: 1px solid #eee; background: #fff;
.popup-header-title { border-radius: 20rpx 20rpx 0 0;
font-size: 32rpx; overflow: hidden;
color: #333; border-bottom: 1px solid #eee;
} .popup-header-title {
.popup-header-close { font-size: 32rpx;
font-size: 32rpx; color: #333;
color: #666; }
} .popup-header-close {
} font-size: 32rpx;
color: #666;
}
image { }
will-change: transform;//解决加载时瞬间拉伸问题
width: auto;//解决加载时瞬间拉伸问题 image {
height: auto;//解决加载时瞬间拉伸问题 will-change: transform; //解决加载时瞬间拉伸问题
image-rendering:-moz-crisp-edges; width: auto; //解决加载时瞬间拉伸问题
image-rendering:-o-crisp-edges; height: auto; //解决加载时瞬间拉伸问题
image-rendering:-webkit-optimize-contrast; image-rendering: -moz-crisp-edges;
image-rendering: crisp-edges; image-rendering: -o-crisp-edges;
-ms-interpolation-mode:nearest-neighbor; image-rendering: -webkit-optimize-contrast;
} image-rendering: crisp-edges;
-ms-interpolation-mode: nearest-neighbor;
}
.canneng-index-title {
font-size: 30rpx;
}
.boxClick:active {
// transform: scale(0.94);
// opacity: 0.8;
animation: elastic-bounce 0.5s;
}
@keyframes elastic-bounce {
0% {
transform: scale(1);
}
50% {
transform: scale(0.96);
}
100% {
transform: scale(1);
}
}

View File

@@ -1,7 +1,7 @@
const debug = false // true 是连地服务端本地false 是连接线上 const debug = true // true 是连地服务端本地false 是连接线上
const development = { const development = {
domain: 'http://192.168.1.62:10215', domain: 'http://192.168.1.103:10215',
} }
const production = { const production = {

View File

@@ -1,92 +1,98 @@
export default { export default {
onPullDownRefresh() { onPullDownRefresh() {
this.store && this.store.reload() if (this.store.isListAtTop) {
}, this.store && this.store.reload()
onReachBottom() { }
if (this.store.status != 'noMore') { },
this.store.next && this.store.next() onReachBottom() {
} if (this.store.status != 'noMore') {
}, this.store.next && this.store.next()
data() { }
return { },
store: {}, data() {
} return {
}, store: {},
methods: { }
DataSource(url) { },
var me = this methods: {
return { DataSource(url) {
data: [], var me = this
status: 'noMore', return {
empty: false, data: [],
total: 0, copyData: {},
header: { status: 'noMore',
'Content-Type': 'application/json;charset=UTF-8', empty: false,
}, isListAtTop: true,
params: { total: 0,
pageNum: 1, header: {
pageSize: 20, 'Content-Type': 'application/json;charset=UTF-8',
}, },
timer: null, params: {
callBack: null, pageNum: 1,
firstCallBack: null, pageSize: 20,
loadedCallback: null, },
reload() { timer: null,
if (this.status == 'loading') return callBack: null,
this.data = [] firstCallBack: null,
this.empty = false loadedCallback: null,
this.params.pageNum = 1 reload() {
this.next() if (this.status == 'loading') return
}, this.data = []
search() { this.empty = false
// 节流搜索 this.params.pageNum = 1
clearTimeout(this.timer) this.next()
this.timer = setTimeout(() => { },
this.reload() search() {
}, 300) // 节流搜索
}, clearTimeout(this.timer)
next() { this.timer = setTimeout(() => {
this.status = 'loading' this.reload()
me.$request({ }, 300)
url: url, },
data: this.params, next() {
header: this.header, this.status = 'loading'
method: 'POST', me.$request({
debounce: false, url: url,
}).then((res) => { data: this.params,
console.warn(res) header: this.header,
let resultData = res.data?.list || res.data?.records || res.data || [] method: 'POST',
if (this.params.pageNum == 1) { debounce: false,
this.data = resultData }).then((res) => {
if (resultData.length == 0 || resultData == 0) { console.warn(res)
this.empty = true let resultData = res.data?.list || res.data?.records || res.data || []
this.status = 'noMore' this.copyData = res.data
} else if (resultData.length < this.params.pageSize) { if (this.params.pageNum == 1) {
this.status = 'noMore' this.data = resultData
} else if (res.total == resultData.length) { if (resultData.length == 0 || resultData == 0) {
this.status = 'noMore' this.empty = true
} else { this.status = 'noMore'
this.status = 'more' } else if (resultData.length < this.params.pageSize) {
} this.status = 'noMore'
} else { } else if (res.total == resultData.length) {
this.data.push(...resultData) this.status = 'noMore'
if (resultData.length < this.params.pageSize) { } else {
this.status = 'noMore' this.status = 'more'
} else { }
this.status = 'more' } else {
} this.data.push(...resultData)
} if (resultData.length < this.params.pageSize) {
if (this.params.pageNum == 1) { this.status = 'noMore'
this.firstCallBack && this.firstCallBack() } else {
} this.status = 'more'
this.loadedCallback && this.loadedCallback() }
this.params.pageNum++ }
this.total = res.total if (this.params.pageNum == 1) {
this.loading = false this.firstCallBack && this.firstCallBack()
uni.stopPullDownRefresh() }
}) this.loadedCallback && this.loadedCallback()
}, this.params.pageNum++
} this.total = res.total || res.data?.total
},
}, this.loading = false
} uni.stopPullDownRefresh()
})
},
}
},
},
}

View File

@@ -1,5 +1,5 @@
export const MQTT_IP = 'pqmcn.com:8085/mqtt'//mqtt地址端口, 使用emqx时一定要加mqtt // export const MQTT_IP = 'pqmcn.com:8085/mqtt'//mqtt地址端口, 使用emqx时一定要加mqtt
// export const MQTT_IP = '192.168.1.24:8085/mqtt'//mqtt地址端口, 使用emqx时一定要加mqtt export const MQTT_IP = '192.168.1.103:38083/mqtt'//mqtt地址端口, 使用emqx时一定要加mqtt
const MQTT_USERNAME = 't_user'//mqtt用户名 const MQTT_USERNAME = 't_user'//mqtt用户名
const MQTT_PASSWORD = 'njcnpqs'//密码 const MQTT_PASSWORD = 'njcnpqs'//密码

View File

@@ -27,7 +27,7 @@ export default (options = {}) => {
} }
uni.request({ uni.request({
url, url,
timeout: 1000 *30, timeout: 1000 * 60,
data: { data: {
...options.data, ...options.data,
}, },
@@ -39,7 +39,7 @@ export default (options = {}) => {
}, },
method: options.method || 'GET', method: options.method || 'GET',
success: async (res) => { success: async (res) => {
console.log(res) // console.log(res)
if (arr.indexOf(options.url) > -1) { if (arr.indexOf(options.url) > -1) {
setTimeout(() => { setTimeout(() => {
arr.splice(arr.indexOf(options.url), 1) arr.splice(arr.indexOf(options.url), 1)

227
common/js/update.js Normal file
View File

@@ -0,0 +1,227 @@
import { getLastData } from '../api/user.js'
export const checkAppUpdate = () => {
// 开发环境跳过检查
const isDev = process.env.NODE_ENV === 'development'
// if (isDev) {
console.log('开发环境,不执行更新检查')
return
// }
// 获取当前应用信息
plus.runtime.getProperty(plus.runtime.appid, (info) => {
const currentVersion = info.version
getLastData()
.then((res) => {
// let res = {
// data: {
// versionName: 'v1.6.83',
// forceUpdate: '1',
// androidPath: 'https://app.liuyingyong.cn/build/download/3c26e400-3a33-11f1-8997-a16e76fa35b3',
// // androidPath: 'http://112.4.144.18:8040/shiningCloud/file/canneng_wulian.apk',
// iosPath: 'xxxx',
// },
// }
if (!res?.data) {
console.log('未获取到版本信息')
return
}
// 适配新的接口返回格式
const { versionName, androidPath, iosPath, forceUpdate = '1' } = res.data
// 版本相同则不需要更新
if (versionName.includes(currentVersion)) {
console.log('已是最新版本')
return
}
const isForce = forceUpdate === '1' // 字符串 '1' 表示强制更新
const iosUrl = iosPath
handleUpdate({ version: versionName, androidPath, iosUrl, isForce })
})
.catch((err) => {
console.error('获取版本接口失败', err)
})
})
}
/**
* 处理更新逻辑
*/
const handleUpdate = ({ version, androidPath, iosUrl, isForce }) => {
const isAndroid = plus.os.name === 'Android'
const isIOS = plus.os.name === 'iOS'
if (isAndroid) {
handleAndroidUpdate({ androidPath, isForce })
} else if (isIOS) {
handleIOSUpdate({ iosUrl, isForce })
} else {
console.warn('未知操作系统')
}
}
/**
* 处理安卓更新
*/
const handleAndroidUpdate = ({ androidPath, isForce }) => {
if (!androidPath?.length) {
console.error('未找到安卓安装包')
uni.showToast({
title: '更新包不存在',
icon: 'error',
})
return
}
const downloadUrl = androidPath
uni.showModal({
title: '更新提示',
content: '发现新版本,是否立即更新?',
showCancel: !isForce, // 强制更新隐藏取消按钮
confirmText: '去更新',
cancelText: '暂不更新',
success: (modalRes) => {
if (modalRes.confirm) {
downloadAndInstallApk(downloadUrl)
} else if (isForce) {
// 强制更新且用户取消,退出应用
plus.runtime.quit()
}
},
})
}
/**
* 处理iOS更新
*/
const handleIOSUpdate = ({ iosUrl, isForce }) => {
if (!iosUrl) {
console.error('未找到iOS下载链接')
uni.showToast({
title: '更新链接不存在',
icon: 'error',
})
return
}
uni.showModal({
title: '更新提示',
content: '发现新版本,请前往 App Store 更新',
showCancel: !isForce,
confirmText: '去更新',
cancelText: '暂不更新',
success: (modalRes) => {
if (modalRes.confirm) {
plus.runtime.openURL(iosUrl)
}
// 强制更新时,无论确认还是取消都退出应用
if (isForce) {
setTimeout(() => {
plus.runtime.quit()
}, 300) // 给跳转留一点时间
}
},
})
}
/**
* 下载并安装APK安卓专用
*/
const downloadAndInstallApk = (url) => {
// 显示原生进度条
let progressWaiting = plus.nativeUI.showWaiting('正在下载中,请稍等...', {
modal: true,
round: true,
close: false, // 不允许用户关闭
padlock: true, // 锁定屏幕
})
const options = {
filename: '_doc/update/canneng_wulian.apk',
timeout: 120,
}
const downloadTask = plus.downloader.createDownload(url, options, (downloadedFile, status) => {
progressWaiting.close()
if (status === 200) {
installApk(downloadedFile.filename, url)
} else {
handleDownloadError(url)
}
})
// // 更新进度
downloadTask.addEventListener('statechanged', (task) => {
if (task.state === 3 && task.totalSize > 0) {
const percent = ((task.downloadedSize / task.totalSize) * 100).toFixed(0)
console.log("🚀 ~ downloadAndInstallApk ~ percent:", percent)
// 直接更新 waiting 的标题,不会闪烁
progressWaiting.setTitle(`正在下载更新 ${percent}%`)
}
})
downloadTask.start()
}
/**
* 安装APK
*/
const installApk = (filePath, downloadUrl) => {
console.log('🚀 ~ installApk ~ filePath:', filePath)
plus.runtime.install(
filePath,
{ force: true },
() => {
// 安装成功
uni.showModal({
title: '安装成功',
content: '是否立即重启应用?',
showCancel: false,
confirmText: '立即重启',
success: () => {
plus.runtime.restart()
},
})
},
(error) => {
console.error('安装失败', error)
uni.showModal({
title: '安装失败',
content: `安装失败:${error.message}\n请检查是否已开启安装权限`,
confirmText: '重试',
cancelText: '取消',
success: (res) => {
if (res.confirm) {
downloadAndInstallApk(downloadUrl)
}
},
})
},
)
}
/**
* 处理下载错误
*/
const handleDownloadError = (downloadUrl) => {
uni.showModal({
title: '下载失败',
content: '网络异常或下载链接失效,是否重试?',
confirmText: '重试',
cancelText: '取消',
success: (res) => {
if (res.confirm) {
downloadAndInstallApk(downloadUrl)
}
},
})
}

View File

@@ -107,39 +107,61 @@ function formatTime(time, option) {
} }
// 获取当天日期(年月日) // 获取当天日期(年月日)
function getToday() { function getToday() {
const today = new Date(); const today = new Date()
const year = today.getFullYear(); const year = today.getFullYear()
const month = String(today.getMonth() + 1).padStart(2, '0'); // 月份从0开始需+1 const month = String(today.getMonth() + 1).padStart(2, '0') // 月份从0开始需+1
const day = String(today.getDate()).padStart(2, '0'); const day = String(today.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`; return `${year}-${month}-${day}`
} }
// 获取当天日期 往前推30天 // 获取当天日期 往前推30天
function getBeforeDays(days = 30) { function getBeforeDays(days = 30) {
const today = new Date(); const today = new Date()
// 计算往前推N天的时间戳1天=86400000毫秒 // 计算往前推N天的时间戳1天=86400000毫秒
const beforeDate = new Date(today.getTime() - days * 24 * 60 * 60 * 1000); const beforeDate = new Date(today.getTime() - days * 24 * 60 * 60 * 1000)
return formatDate(beforeDate); return formatDate(beforeDate)
} }
function formatDate(date) { function formatDate(date) {
const year = date.getFullYear(); const year = date.getFullYear()
// 月份从0开始补零到2位 // 月份从0开始补零到2位
const month = String(date.getMonth() + 1).padStart(2, '0'); const month = String(date.getMonth() + 1).padStart(2, '0')
// 日期补零到2位 // 日期补零到2位
const day = String(date.getDate()).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`; return `${year}-${month}-${day}`
} }
// 获取3个月前的日期 // 获取3个月前的日期
function getThreeMonthsAgo() { function getThreeMonthsAgo() {
const threeMonthsAgo = new Date(); const threeMonthsAgo = new Date()
threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3); // 月份减3 threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3) // 月份减3
const year = threeMonthsAgo.getFullYear(); const year = threeMonthsAgo.getFullYear()
const month = String(threeMonthsAgo.getMonth() + 1).padStart(2, '0'); const month = String(threeMonthsAgo.getMonth() + 1).padStart(2, '0')
const day = String(threeMonthsAgo.getDate()).padStart(2, '0'); const day = String(threeMonthsAgo.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`; return `${year}-${month}-${day}`
} }
//获取月最后一天
function getMonthFirstAndLastDay(monthStr) {
// 1. 校验输入格式正则匹配YYYY-MM
const reg = /^\d{4}-\d{2}$/
if (!reg.test(monthStr)) {
throw new Error('输入格式错误,请传入"YYYY-MM"格式的字符串例如2026-03')
}
// 2. 拆分年、月
const [year, month] = monthStr.split('-').map(Number)
// 3. 生成当月第一天直接拼接01
const firstDay = `${year}-${String(month).padStart(2, '0')}-01`
// 4. 生成当月最后一天核心利用Date的特性下个月0号 = 当月最后一天)
// 注意月份是0开始的0=1月11=12月所以month+1是下一个月
const lastDayDate = new Date(year, month, 0) // 下个月0号 = 当月最后一天
const lastDay = `${year}-${String(month).padStart(2, '0')}-${String(lastDayDate.getDate()).padStart(2, '0')}`
return {
firstDay,
lastDay,
}
}
const h5Helper = { const h5Helper = {
isAndroid: function () { isAndroid: function () {
@@ -167,7 +189,7 @@ const getUserLocation = (call) => {
success: function (address) { success: function (address) {
call(address) call(address)
}, },
fail: (err) => { fail: (err) => {
uni.showModal({ uni.showModal({
title: '提示', title: '提示',
content: '定位失败,请打开定位权限', content: '定位失败,请打开定位权限',
@@ -309,12 +331,14 @@ const getDictData = (key) => {
resolve(dictData.filter((item) => item.code === key)[0]?.children || []) resolve(dictData.filter((item) => item.code === key)[0]?.children || [])
} else { } else {
// 查询字典 // 查询字典
queryDictDataCache().then((res) => { queryDictDataCache()
uni.setStorageSync(cacheKey.dictData, res.data) .then((res) => {
resolve(res.data.filter((item) => item.code === key)[0]?.children || []) uni.setStorageSync(cacheKey.dictData, res.data)
}).catch(err=>{ resolve(res.data.filter((item) => item.code === key)[0]?.children || [])
reject(err) })
}) .catch((err) => {
reject(err)
})
} }
}) })
} }
@@ -333,5 +357,6 @@ export default {
getDictData, getDictData,
getToday, getToday,
getBeforeDays, getBeforeDays,
getThreeMonthsAgo getThreeMonthsAgo,
getMonthFirstAndLastDay,
} }

View File

@@ -0,0 +1,510 @@
<template xlang="wxml">
<view class="tki-tree">
<view class="tki-tree-mask" :class="{ show: showTree }" @tap="_cancel"></view>
<view class="tki-tree-cnt" :class="{ show: showTree }">
<view class="tki-tree-bar">
<view class="tki-tree-bar-cancel" :style="{ color: cancelColor }" hover-class="hover-c" @tap="_cancel">
取消</view>
<view class="tki-tree-bar-title" :style="{ color: titleColor }">{{ title }}</view>
<view class="tki-tree-bar-confirm" :style="{ color: confirmColor }" hover-class="hover-c"
@tap="_confirm">确定</view>
</view>
<view class="tki-tree-bar1">
<uni-search-bar class="uni-input" radius="5" placeholder="请输入关键字搜索" clearButton="none" @input="input" />
<!-- <uni-search-bar
v-model="searchValue"
clearButton="none"
bgColor="#fff"
placeholder="请输入关键词"
@input="input"
></uni-search-bar> -->
</view>
<view class="tki-tree-view">
<scroll-view class="tki-tree-view-sc" :scroll-y="true">
<block v-for="(item, index) in treeList" :key="index">
<view class="tki-tree-item" :style="[
{
paddingLeft: item.rank * 15 + 'px',
zIndex: item.rank * -1 + 50,
},
]" :class="{
border: border === true,
show: item.show,
last: item.lastRank,
showchild: item.showChild,
open: item.open,
}">
<view class="tki-tree-label" @tap.stop="_treeItemTap(item, index)">
<image class="tki-tree-icon"
:src="item.lastRank ? lastIcon : item.showChild ? currentIcon : defaultIcon">
</image>
{{ item.name }}
</view>
<view class="tki-tree-check" @tap.stop="_treeItemSelect(item, index)"
v-if="selectParent ? true : item.lastRank">
<view class="tki-tree-check-yes" v-if="item.checked"
:style="{ 'border-color': confirmColor }">
<view class="tki-tree-check-yes-b" :style="{ 'background-color': confirmColor }">
</view>
</view>
<view class="tki-tree-check-no" v-if="!item.checked"
:style="{ 'border-color': confirmColor }"></view>
</view>
</view>
</block>
</scroll-view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'Cn-MultipleTree',
props: {
lazy: {
type: Boolean,
default: false,
},
range: {
type: Array,
default: function () {
return []
},
},
idKey: {
type: String,
default: 'id',
},
rangeKey: {
type: String,
default: 'name',
},
title: {
type: String,
default: '',
},
multiple: {
type: Boolean,
default: true,
},
selectParent: {
//是否可以选父级
type: Boolean,
default: false,
},
foldAll: {
//折叠时关闭所有已经打开的子集,再次打开时需要一级一级打开
type: Boolean,
default: false,
},
confirmColor: {
// 确定按钮颜色
type: String,
default: '#376cf3', // #07bb07
},
cancelColor: {
// 取消按钮颜色
type: String,
default: '', // #757575
},
titleColor: {
// 标题颜色
type: String,
default: '', // #757575
},
currentIcon: {
// 展开时候的ic
type: String,
default:
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFEAAABRCAYAAACqj0o2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MEQ0QTM0MzQ1Q0RBMTFFOUE0MjY4NzI1Njc1RjI1ODIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MEQ0QTM0MzU1Q0RBMTFFOUE0MjY4NzI1Njc1RjI1ODIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowRDRBMzQzMjVDREExMUU5QTQyNjg3MjU2NzVGMjU4MiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowRDRBMzQzMzVDREExMUU5QTQyNjg3MjU2NzVGMjU4MiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PidwepsAAAK0SURBVHja7JxbTsJAFIYHww7ciStgCeoGvGxAiOsgURegoL5720AXYLiIr0aJviq3Zx3PhIEnKG3ndtr+f3KixrSUj/ZjzjClIqUUiFm2gAAQAREQEUAEREAERAQQAREQAREBREAEREBEEqa67h9RFDWllDv0awWYlqlQHmu1WjMRRMoV1QFttA12y3xRtdNczq8EsE4/f8FumX2q77ROvNXk8UGMEKdUz6tYJHljaZAbuyUH+UR1to5BEohTuqwPCeS4pAA/qY6o/kyHOAMCeRK3owJnj+rH1jjxhqpVsstaebCz6TmnHWyXyY+xHjSBWBY/bvSgadtXBj9u9KCN3rnIfkzkQVsTEEX0Y2IP2oKo/HhMICcFAThUcwVZNGU6FdbX/XURzkbVF4+ybGhjPrFdgP66QdXNurGtSdk6Xdb9nAJ8oDo3OQlsQZzkdPw41ONBo6vI5scDefRjZg+6gpg3Pxp50CXEvPjR2IOuIXL3oxUPuobI3Y9WPOgDIlc/WvOgL4iL/vqFCcD7LH0xB4hj7cfQ/fWH9qCT+FhG0tN+DBk1PzjOM0SVllixcsBT1AvYc/kAPhc0hRg/3uvxoCgKRN9+dOrBUBB9+9GpB0NC9OVH5x4MDdG1H714kANEV3705kEOEBf9dcPi/lQnsuvLg1wgSu3Ha0v7Uh4MMgUXeuG71H407a+VBy9CPQkOdw+MtB+nGbd/D+FBbhBNxo9SjwcngJjNj0E9yBFiFj8G9SBXiGn8GNyDnCEm8SMLD3KHGOdHNh7kDjHOj2w8mAeIi/5arX+c6b/fxHz9oADEdGdjR/fXCw/OOB5oVfCOgnepz8IB14PMw03jCmTE+QBx5z0gAmKSqK9OUF+hcAeIhu/QYr4Qie8rjW83hhMBERARQAREQAREBBABERCLnH8BBgA+TQI7U4t53AAAAABJRU5ErkJggg==',
},
defaultIcon: {
// 折叠时候的ic
type: String,
default:
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFEAAABRCAYAAACqj0o2AAACE0lEQVR4Xu3c200DMRCF4XEltJAOkEugA+ggpUAHoQMqiFMCdEAJUMEiS4mEELlIO7bPOeN9i6K1rG/952myyea1WiCtXmEuYBPR4RBMxInoIOCwhOtJLKVszWyXc/5y2BvNEq6I+/3+kFK6M7OHnPM7jcLKjbZAvD/uaZtzflm5P4rbWyJWgDcze1LPuzVihfxUz7sH4ilJ2bx7Isrm3RtRMu8RiHJ5j0SUyXs0okTeCIj0eSMh0uaNhkiZNyIiXd7IiDR5oyNS5M2ACJ83EyJs3myIkHkzIsLlzYwIkzc7IkTeCojD81ZCHJa3GuKQvBURu+etjNgtb3XELnlHQGyedyTEZnlHQ2ySd0RE97wjI7rlHR3RJe+JeIrbLOecD6ePpZQ6W1kn2epo4MUrPOKyLN8ppYq1+y1VStncOjIdGnFZlo+U0uOtWOeOY2TE12Ouq//pEA7xXL7XfvcufR8K0Svfv6CREN3yDYfYIt9QiK3yjYTYLF95xB75SiP2ylcZsVu+cogj8pVCHJWvEuKwfOkREfKlRkTJlxkRJl86RMR8qRBR82VChM0XHpEhX2hElnyREWnyhUNkzBcKkTVfJETafIcjKuQ7FFEl35GIMvl2R1TMtyuiar49EWXzbY5oZpv/hibXTF2h3+s60FRKeT6+3TjMS3nrA3ZFRD8xrfY3ER1kJ+JEdBBwWGKeRAfEH1wS5WFZSDB/AAAAAElFTkSuQmCC',
},
lastIcon: {
// 没有子集的ic
type: String,
default: '',
},
border: {
// 是否有分割线
type: Boolean,
default: false,
},
},
data() {
return {
showTree: false,
treeList: [],
selectIndex: -1,
returnedItem: [], //定义一个空数组
pids: [],
ancestorsIds: [],
childNums: [],
dataTree: [],
inputTimer: null, // 节流定时器标识
searchValue: '',
}
},
computed: {},
methods: {
_show() {
this.showTree = true
if (this.searchValue != '') {
this.searchValue = ''
this.input('')
}
},
_hide() {
this.showTree = false
},
_cancel() {
this._hide()
this.$emit('cancel', '')
},
_confirm() {
// 处理所选数据
let rt = [],
obj = {}
this.treeList.forEach((v, i) => {
if (this.treeList[i].checked) {
// rt.push(this.treeList[i].id)
rt.push(this.treeList[i])
}
})
this._hide()
console.log('🚀 ~ rt:', rt)
if (rt.length == 0) return
this.$emit('confirm', rt)
},
//扁平化树结构
_renderTreeList(list = [], rank = 0, parentId = [], parents = []) {
list.forEach((item) => {
this.treeList.push({
id: item[this.idKey],
name: item[this.rangeKey],
source: item,
parentId, // 父级id数组
parents, // 父级id数组
rank, // 层级
showChild: false, //子级是否显示
open: false, //是否打开
show: rank === 0, // 自身是否显示
hideArr: [],
orChecked: item.checked ? item.checked : false,
checked: item.checked ? item.checked : false,
childNum: 0,
})
if (Array.isArray(item.children) && item.children.length > 0) {
let parentid = [...parentId],
parentArr = [...parents]
delete parentArr.children
parentid.push(item[this.idKey])
parentArr.push({
[this.idKey]: item[this.idKey],
[this.rangeKey]: item[this.rangeKey],
rank: rank,
})
// lazy
if (!this.lazy) {
this._renderTreeList(item.children, rank + 1, parentid, parentArr)
}
} else {
this.treeList[this.treeList.length - 1].lastRank = true
}
})
},
// 处理默认选择
_defaultSelect() {
this.treeList.forEach((v, i) => {
if (v.checked) {
this.treeList.forEach((v2, i2) => {
if (v.parentId.toString().indexOf(v2.parentId.toString()) >= 0) {
v2.show = true
if (v.parentId.includes(v2.id)) {
v2.showChild = true
v2.open = true
}
}
})
}
})
},
getOwn(id, arr) {
//利用foreach循环遍历
arr.forEach((item) => {
//判断递归结束条件
if (item[this.idKey] == id) {
// 存储数据到空数组
this.returnedItem = item
} else if (item.children != null) //判断chlidren是否有数据
{
//递归调用
this.getOwn(id, item.children)
}
})
return this.returnedItem
},
setShow(id, arr, isShow) {
arr.forEach((item, index) => {
if (item.parentId.includes(id)) {
this.treeList[index].showChild = isShow
this.treeList[index].show = isShow
} else if (item.children !== undefined) {
this.setShow(id, item.children, isShow)
}
})
},
// 点击
_treeItemTap(item, index) {
// console.log(item)
if (item.lastRank === true) {
this.treeList[index].checked = !this.treeList[index].checked
if (!this.multiple) {
this._fixSingle(index)
}
return
}
let id = item.id
item.showChild = !item.showChild
// qingqian
if (item.showChild) {
// const range = this.range
const range = this.dataTree
const parentIdArr = item.parentId
// 找到当前元素
const own = this.getOwn(id, range)
const checkedChildren = own.children
// 子元素插入的索引位置
const nextIndex = this.treeList.findIndex((itemT) => itemT.id === item.id)
console.log(checkedChildren)
if (checkedChildren === undefined || checkedChildren.length < 1) {
return
}
// 子节点数量
this.treeList[index].childNum = checkedChildren.length
const newRank = item.rank + 1
checkedChildren.forEach((itemC) => {
const childObj = {
id: itemC[this.idKey],
name: itemC[this.rangeKey],
source: {},
parentId: [item.id], // 父级id数组
parents: [item], // 父级id数组
rank: newRank, // 层级
showChild: false, //子级是否显示
open: false, //是否打开
show: 1, // 自身是否显示
hideArr: [],
orChecked: this.treeList[index].checked,
checked: this.treeList[index].checked,
}
if (!this.treeList.some((itemT) => itemT.id === itemC[this.idKey])) {
this.treeList.splice(nextIndex + 1, 0, childObj)
}
})
}
// 展开/隐藏子级/孙级
let list = this.treeList
item.open = item.showChild ? true : !item.open
list.forEach((childItem, i) => {
if (item.showChild === false) {
//隐藏所有子级
if (!childItem.parentId.includes(id)) {
return
}
//TODO: 修改
if (!this.foldAll) {
if (childItem.lastRank !== true && !childItem.open) {
childItem.showChild = false
this.setShow(childItem.id, this.treeList, false)
}
// 为隐藏的内容添加一个标记
if (childItem.show) {
childItem.hideArr[item.rank] = id
}
} else {
if (childItem.lastRank !== true) {
childItem.showChild = false
// 继续隐藏子级的的子级
this.setShow(childItem.id, this.treeList, false)
}
}
if (childItem.children !== undefined) {
childItem.children.forEach((childItem1, i1) => {
if (!childItem1.parentId.includes(childItem.id)) {
return
}
childItem.children[i1].showChild = false
childItem.children[i1].show = false
})
}
childItem.show = false
} else {
// 打开子集
if (childItem.parentId[childItem.parentId.length - 1] === id) {
childItem.show = true
}
// 打开被隐藏的子集
if (childItem.parentId.includes(id) && !this.foldAll) {
// console.log(childItem.hideArr)
if (childItem.hideArr[item.rank] === id) {
childItem.show = true
if (childItem.open && childItem.showChild) {
childItem.showChild = true
} else {
childItem.showChild = false
}
childItem.hideArr[item.rank] = null
}
}
}
})
},
// 通过父id处理子级
syncChecked(trees, pid, checked) {
trees.forEach((item, index) => {
if (item.parentId.includes(pid)) {
this.treeList[index].checked = checked
this.syncChecked(trees, item.id, checked)
} else if (item.children !== undefined) {
this.syncChecked(item.children, pid, checked)
}
})
},
// 获取父级往上所有层级的id 并同步状态
setAncestors(pids, checked) {
this.treeList.forEach((item, index) => {
if (pids.includes(item.id)) {
if (checked && this.childNums[item.id] !== undefined && item.childNum === this.childNums[item.id]) {
// 子级全部选中, 父级才选中
this.treeList[index].checked = true
} else {
this.treeList[index].checked = false
}
this.setAncestors(item.parentId, checked)
}
})
},
_treeItemSelect(item, index) {
this.treeList[index].checked = !this.treeList[index].checked
// 选父级, 子级自动全选
this.syncChecked(this.treeList, item.id, this.treeList[index].checked)
if (item.rank > 0) {
item.parentId.forEach((pid, indexP) => {
const parent = this.treeList.filter((i) => i.id === pid)
const childNum = parent.length > 0 ? parent[0].childNum : 0
if (this.childNums[pid] === undefined) {
this.childNums[pid] = 1
} else if (this.childNums[pid] < childNum) {
this.childNums[pid]++
}
})
//子级选择/选满/取消选择, 父级往上同步状态
this.setAncestors(item.parentId, this.treeList[index].checked)
}
if (!this.multiple) {
this._fixSingle(index)
}
},
_fixSingle(index) {
this.treeList.forEach((v, i) => {
this.treeList[i].checked = i === index
})
},
// 重置数据
_reTreeList() {
this.treeList.forEach((v, i) => {
this.treeList[i].checked = v.orChecked
})
},
_initTree(range = this.range) {
this.treeList = []
this.dataTree = JSON.parse(JSON.stringify(range))
this._renderTreeList(range)
this.$nextTick(() => {
this._defaultSelect(range)
})
},
// 筛选
input(val) {
// 清除上一次的定时器,避免频繁执行
if (this.inputTimer) {
clearTimeout(this.inputTimer)
}
// 设置新的定时器,指定延迟后执行过滤逻辑
this.inputTimer = setTimeout(() => {
const keyword = val
// 执行树形过滤和初始化
this._initTree(this.filterNodes(this.range, keyword))
// 清空定时器标识
clearTimeout(this.inputTimer)
this.inputTimer = null
}, 500)
// this._initTree(this.filterNodes(this.range, val.detail.value))
},
filterNodes(node, query) {
const keyword = query.trim() // 获取搜索关键字并转换为小写
const nodes = node
// 使用递归函数过滤树形数据
const filteredNodes = []
for (const node of nodes) {
if (node.name.includes(keyword)) {
// 如果节点的标签包含关键字,将其添加到结果中
filteredNodes.push(node)
} else if (node.children && node.children.length > 0) {
// 如果节点有子节点,则递归过滤子节点
const filteredChildren = this.filterNodes(node.children, keyword)
if (filteredChildren.length > 0) {
// 如果子节点中有匹配的结果,则添加父节点
const clonedNode = { ...node, children: filteredChildren }
filteredNodes.push(clonedNode)
}
}
}
return filteredNodes
},
},
watch: {
range(list) {
this._initTree(list)
},
multiple() {
if (this.range.length) {
this._reTreeList()
}
},
selectParent() {
if (this.range.length) {
this._reTreeList()
}
},
},
mounted() {
this._initTree()
},
}
</script>
<style lang="scss" scoped>
@import './style.css';
/deep/ .uni-searchbar__box {
justify-content: left !important;
}
/deep/ .uni-input {
background: #ffffff
}
</style>

View File

@@ -0,0 +1,195 @@
.tki-tree-mask {
position: fixed;
top: 0rpx;
right: 0rpx;
bottom: 0rpx;
left: 0rpx;
z-index: 9998;
background-color: rgba(0, 0, 0, 0.6);
opacity: 0;
transition: all 0.3s ease;
visibility: hidden;
}
.tki-tree-mask.show {
visibility: visible;
opacity: 1;
}
.tki-tree-cnt {
position: fixed;
top: 0rpx;
right: 0rpx;
bottom: 0rpx;
left: 0rpx;
z-index: 9999;
top: 40%;
transition: all 0.3s ease;
transform: translateY(100%);
}
.tki-tree-cnt.show {
transform: translateY(0);
}
.tki-tree-bar {
background-color: #fff;
height: 72rpx;
padding-left: 20rpx;
padding-right: 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
border-bottom-width: 1rpx !important;
border-bottom-style: solid;
border-bottom-color: #f5f5f5;
font-size: 32rpx;
color: #757575;
line-height: 1;
}
.tki-tree-bar1 {
background-color: #fff;
}
.tki-tree-bar-confirm {
color: #07bb07;
}
.tki-tree-view {
position: absolute;
top: 0rpx;
right: 0rpx;
bottom: 0rpx;
left: 0rpx;
top: 160rpx;
background-color: #fff;
padding-top: 20rpx;
padding-right: 20rpx;
padding-bottom: 20rpx;
padding-left: 20rpx;
}
.tki-tree-view-sc {
height: 100%;
overflow: hidden;
}
.tki-tree-item {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 26rpx;
/* color: #757575; */
line-height: 1;
height: 0;
opacity: 0;
transition: 0.2s;
position: relative;
overflow: hidden;
}
.tki-tree-item.show {
height: 80rpx;
opacity: 1;
}
.tki-tree-item.showchild:before {
transform: rotate(90deg);
}
.tki-tree-item.last:before {
opacity: 0;
}
.tki-tree-icon {
width: 26rpx;
height: 26rpx;
margin-right: 8rpx;
}
.tki-tree-label {
flex: 1;
display: flex;
align-items: center;
height: 100%;
line-height: 1.2;
}
.tki-tree-check {
width: 40px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
}
.tki-tree-check-yes,
.tki-tree-check-no {
width: 20px;
height: 20px;
border-top-left-radius: 20%;
border-top-right-radius: 20%;
border-bottom-right-radius: 20%;
border-bottom-left-radius: 20%;
border-top-width: 1rpx;
border-left-width: 1rpx;
border-bottom-width: 1rpx;
border-right-width: 1rpx;
border-style: solid;
border-color: #07bb07;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
}
.tki-tree-check-yes-b {
width: 12px;
height: 12px;
border-top-left-radius: 20%;
border-top-right-radius: 20%;
border-bottom-right-radius: 20%;
border-bottom-left-radius: 20%;
background-color: #07bb07;
}
.tki-tree-check .radio {
border-top-left-radius: 50%;
border-top-right-radius: 50%;
border-bottom-right-radius: 50%;
border-bottom-left-radius: 50%;
}
.tki-tree-check .radio .tki-tree-check-yes-b {
border-top-left-radius: 50%;
border-top-right-radius: 50%;
border-bottom-right-radius: 50%;
border-bottom-left-radius: 50%;
}
.hover-c {
opacity: 0.6;
}
.search {
position: absolute;
left: 35rpx;
}
/* 基础输入框样式 */
.uni-input {
width: 95%;
height: 60rpx;
line-height: 60rpx;
border-radius: 20rpx;
/* font-size: 32rpx;
color: #333;
background: #f5f5f5;
width: 100%;
padding: 0 24rpx 0 60rpx;
box-sizing: border-box;
border: none; */
}
/* 聚焦态样式 */
.uni-input:focus {
background: #fff;
border: 2rpx solid #007aff;
}
/* 占位符样式 */
.uni-input::placeholder {
color: #999;
font-size: 28rpx;
}
/* 兼容微信小程序 */
.uni-input::-webkit-input-placeholder {
color: #999;
font-size: 28rpx;
}

View File

@@ -1,80 +1,290 @@
<template> <template>
<uni-card <uni-card :title="device.equipmentName" :sub-title="device.mac" :extra="device.isPrimaryUser == 1 ? '主设备' : '分享设备'"
:title="device.equipmentName" padding="0" @click="jump(device)" class="boxClick" :thumbnail="deviceIcon(device.runStatus)">
:sub-title="device.mac" <template v-slot:title>
:extra="device.isPrimaryUser == 1 ? '主设备' : '分享设备'" <!-- 卡片标题 -->
padding="0" <view class="uni-card__header" @click="jump(device)">
@click="jump(device)" <view class="uni-card__header-box">
:thumbnail="deviceIcon(device.runStatus)" <view class="uni-card__header-avatar">
> <view class="event-icon">
<template v-slot:title> <!-- 动态图标根据类型切换 -->
<slot name="title"></slot> <!-- <uni-icons
</template> custom-prefix="iconfont"
<view class="device-body"> :type="
<view class="device-body-item"> device.devType == 'Direct_Connected_Device'
<text>工程名称</text> ? 'icon-zaixianjianceshebei'
<text>{{ device.engineeringName }}</text> : 'icon-shebei1'
</view> "
<view class="device-body-item mt6"> :color="device.runStatus == 1 ? '#ff3b30' : '#10B981'"
<text>项目名称</text> :size="device.devType == 'Direct_Connected_Device' ? '35' : '40'"
<text>{{ device.projectName }}</text> ></uni-icons> -->
</view> <Cn-icon-device :devType="device.devType" :runStatus="device.runStatus"
<view class="device-body-item mt6" v-if="device.process == 2 || device.process == 3"> :alarmStatus="device.isAlarm ? 1 : 0"></Cn-icon-device>
<text>调试阶段</text> </view>
<text>{{ device.process == 2 ? '功能调试' : '出厂调试' }}</text> </view>
</view> <view class="uni-card__header-content">
</view> <text class="uni-card__header-content-title uni-ellipsis">
</uni-card> {{ device.equipmentName }}
</template> </text>
<script> <!-- <text class="uni-card__header-content-subtitle uni-ellipsis">
export default { {{ device.mac }}
data() { </text> -->
return {} <view class="event-desc mt4 mb8">
}, <text>
props: { 工程{{ device.engineeringName }}
device: { </text>
type: Object, <text>
default: () => {}, 项目{{ device.projectName }}
}, </text>
}, </view>
methods: {
deviceIcon(e) { <view class="tagBox">
let str = '' <text class="event-tag" :class="device.runStatus == 1 ? 'lx-tag' : 'zx-tag'">
switch (e) { {{ device.runStatus == 1 ? '离线' : '在线' }}
case 1: </text>
str = '/static/device_bad.png' <text class="event-tag"
break :class="device.devType == 'Direct_Connected_Device' ? 'zl-tag' : 'jc-tag'">
case 2: {{ device.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备' }}
str = '/static/device_success.png' </text>
break <text class="event-tag" :class="device.isPrimaryUser == 1 ? 'z-tag' : 'fx-tag'">
default: {{ device.isPrimaryUser == 1 ? '我的设备' : '他人设备' }}
str = '/static/device_success.png' </text>
break </view>
} </view>
return str </view>
}, <view class="uni-card__header-extra" style="position: relative" @click.stop>
jump() { <text class="uni-card__header-extra-text"></text>
console.log(12321,this.device); <slot name="title"></slot>
uni.navigateTo({ </view>
url: </view>
'/pages/device/APF/detail?id=' + <!-- <slot name="title"></slot> -->
this.device.equipmentId + </template>
'&isPrimaryUser=' + <!-- <view class="device-body">
this.device.isPrimaryUser + <view class="device-body-item">
'&process=' + <text>工程</text>
this.device.process + '&ndid=' + this.device.ndid, <text>{{ device.engineeringName }}</text>
}) </view>
}, <view class="device-body-item mt6">
}, <text>项目</text>
} <text>{{ device.projectName }}</text>
</script> </view>
<style lang="scss"> <view class="device-body-item mt6" v-if="device.process == 2 || device.process == 3">
.device-body { <text>调试阶段</text>
padding: 20rpx; <text>{{ device.process == 2 ? '功能调试' : '出厂调试' }}</text>
</view>
.device-body-item { </view> -->
display: flex; <view class="pinToTop" v-if="device.isTop == 1"> 置顶</view>
justify-content: space-between; </uni-card>
} </template>
} <script>
</style> export default {
data() {
return {}
},
props: {
device: {
type: Object,
default: () => {
},
},
},
methods: {
deviceIcon(e) {
let str = ''
switch (e) {
case 1:
str = '/static/device_bad.png'
break
case 2:
str = '/static/device_success.png'
break
default:
str = '/static/device_success.png'
break
}
return str
},
jump() {
if (this.device.devType == 'Direct_Connected_Device') {
uni.navigateTo({
url:
'/pages/device/APF/detail?id=' +
this.device.equipmentId +
'&isPrimaryUser=' +
this.device.isPrimaryUser +
'&process=' +
this.device.process +
'&ndid=' +
this.device.ndid +
'&device=' +
JSON.stringify(this.device),
})
} else {
if (this.device.lineList.length == 0) {
return this.$util.toast('暂无监测点!')
}
uni.navigateTo({
url: '/pages/device/realTime/index?device=' + JSON.stringify(this.device),
})
}
},
getColor(status, type) {
if (status == 1) {
return '#ff3b3020'
} else {
return '#10b98120' //type == 'Direct_Connected_Device' ? '#10b98120' : ''
}
},
},
}
</script>
<style lang="scss">
.device-body {
padding: 10rpx 20rpx 20rpx;
.device-body-item {
display: flex;
justify-content: space-between;
font-size: 28rpx;
color: #666666;
line-height: 1.2;
}
}
.uni-card {
/deep/ .uni-card__header-box {
display: flex;
flex: 1;
flex-direction: row;
align-items: center;
overflow: hidden;
}
/deep/ .uni-card__header {
display: flex;
// border-bottom: 2rpx #ebeef5 solid;
flex-direction: row;
align-items: center;
padding: 20rpx 0;
overflow: hidden;
}
}
.uni-card .uni-card__header .uni-card__header-content .uni-card__header-content-title {
font-size: 30rpx;
color: #3a3a3a;
font-weight: 700;
}
.uni-card .uni-card__header .uni-card__header-content .uni-card__header-content-subtitle {
margin-top: 15rpx;
font-size: 24rpx;
// margin-top: 5px;
color: #666666;
}
.uni-card .uni-card__header .uni-card__header-avatar .uni-card__header-avatar-image {
width: 40px;
height: 40px;
overflow: hidden;
border-radius: 5px;
margin-right: 10px;
}
.uni-card .uni-card__header .uni-card__header-content {
display: flex;
flex-direction: column;
justify-content: center;
flex: 1;
overflow: hidden;
}
.tagBox {
display: flex;
gap: 15rpx;
}
.event-icon {
position: relative;
width: 100rpx;
height: 100rpx;
border-radius: 12rpx;
display: flex;
justify-content: center;
align-items: center;
margin-right: 20rpx;
}
.event-tag {
font-size: 22rpx;
padding: 2rpx 10rpx;
border-radius: 8rpx;
margin-top: 5rpx;
// height: 38rpx;
}
// 在线
.zx-tag {
background-color: #10b98120;
color: #10b981;
}
.lx-tag {
background-color: #ff3b3020;
color: #ff3b30;
}
.z-tag {
background-color: #2563eb20;
color: #2563eb;
}
.fx-tag {
background-color: #90939920;
color: #909399;
}
.zl-tag {
// background-color: #007aff20;
// color: #007aff;
background-color: #007aff20;
color: #007aff;
}
.jc-tag {
background-color: #007aff20;
color: #007aff;
}
.pinToTop {
background-color: $uni-theme-color;
width: 100rpx;
height: 60rpx;
line-height: 90rpx;
text-align: center;
color: #fff;
font-size: 20rpx;
position: absolute;
top: 0rpx;
right: 0rpx;
position: absolute;
top: 0;
right: 0;
/* 核心:旋转成斜三角效果 */
transform: rotate(45deg) translate(50rpx, -10rpx);
transform-origin: top right;
}
.event-desc {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.event-desc text {
font-size: 24rpx;
color: #666666;
line-height: 1.2;
}
</style>

View File

@@ -0,0 +1,346 @@
<template>
<view class="nav choose">
<view class="nav-menu nav-menu1" @click="selectEngineering" v-if="showQianTree">
<view class="nav-text">
{{
select.engineeringName || select.projectName || select.deviceName || select.lineName
? [select.engineeringName, select.projectName, select.deviceName, select.lineName]
.filter((item) => item && item !== '')
.join('>')
: '全部工程'
}}
</view>
<uni-icons type="bottom" size="14"></uni-icons>
</view>
<!-- 弹框组件 -->
<Cn-qianTree
ref="qiantree"
:selectParent="true"
:multiple="false"
:range="list"
:foldAll="true"
:singleChoice="singleChoice"
@confirm="treeConfirm"
@cancel="treeCancel"
></Cn-qianTree>
<picker
mode="date"
:value="select.date"
:start="startDate"
fields="month"
:end="endDate"
@change="bindDateChange"
v-if="showDatetime"
>
<view class="nav-menu nav-menu1"
><view class="nav-text">
{{ select.date }}
</view>
<uni-icons type="bottom" size="14"></uni-icons>
</view>
</picker>
<!-- <uni-datetime-picker v-if="!showDatetime" v-model="select.range" type="daterange" :end="endDate">
<view class="nav-menu"
>{{ select.range[0] + '至' + select.range[1] }}
<uni-icons type="bottom" size="14"></uni-icons>
</view>
</uni-datetime-picker> -->
<picker
mode="date"
:value="select.range"
fields="year"
:end="endDate.slice(0, -6)"
@change="yearChange"
v-if="!showDatetime"
>
<view class="nav-menu nav-menu1"
><view class="nav-text">
{{ select.range }}
</view>
<uni-icons type="bottom" size="14"></uni-icons>
</view>
</picker>
<slot />
</view>
</template>
<script>
import { lineTree } from '@/common/api/device'
export default {
components: {},
props: {
level: { type: Number, default: 3 },
showDatetime: { type: Boolean, default: true },
singleChoice: { type: Boolean, default: false },
showQianTree: { type: Boolean, default: true },
},
data() {
const currentDate = this.getDate({
format: true,
})
const rangeDate = this.getDate({
format: true,
}).slice(0, -3)
console.log('🚀 ~ rangeDate:', rangeDate)
return {
select: {
engineeringName: '',
engineeringId: '', //工程ID
projectName: '',
projectId: '', //項目ID
deviceName: '',
deviceId: '', //设备ID
lineName: '',
lineId: '', //测点ID
date: currentDate,
range: rangeDate,
},
list: [],
}
},
created() {},
onShow() {},
mounted() {},
methods: {
getTree() {
this.clear()
lineTree().then((res) => {
let list = {}
if (this.singleChoice) {
let result = this.findFirstLevel(res.data)
console.log('🚀 ~ result:', result)
this.select.engineeringName = result.parents[0].name
this.select.engineeringId = result.parents[0].id //工程ID
this.select.projectName = result.parents[1].name
this.select.projectId = result.parents[1].id //項目ID
this.select.deviceName = result.parents[2].name
this.select.deviceId = result.parents[2].id //设备ID
this.select.lineName = result.node.name
this.select.lineId = result.node.id //测点ID
} else {
list = {
id: '',
pid: '0',
pids: '0',
name: '全部工程',
path: null,
provinceId: null,
cityId: null,
area: null,
remark: null,
sort: 0,
level: 0,
comFlag: null,
type: null,
lineType: null,
conType: null,
process: null,
isTop: 0,
children: [],
ndid: null,
}
}
this.list = this.filterTreeByLevel(this.singleChoice ? res.data : [list, ...res.data])
// this.findFirstLevel( this.list)
})
},
// 递归过滤函数去除level > 2的节点
filterTreeByLevel(tree) {
// 遍历每一个节点
return tree.map((node) => {
// 复制当前节点(避免修改原数据)
const newNode = { ...node }
// 如果当前节点有子节点并且当前节点的level <= 2因为level=2的节点的子节点是level=3需要过滤
if (newNode.children && newNode.children.length > 0) {
// 递归过滤子节点只保留子节点中level <= 2的
newNode.children = this.filterTreeByLevel(
newNode.children.filter((child) => child.level <= this.level),
)
}
return newNode
})
},
getDate(type) {
const date = new Date()
let year = date.getFullYear()
let month = date.getMonth() + 1
let day = date.getDate()
if (type === 'start') {
year = year - 10
} else if (type === 'end') {
year = year
}
month = month > 9 ? month : '0' + month
day = day > 9 ? day : '0' + day
return this.showDatetime ? `${year}-${month}` : `${year}-${month}-${day}`
},
bindDateChange(e) {
this.select.date = e.detail.value
},
yearChange(e) {
this.select.range = e.detail.value
},
selectEngineering() {
this.$refs.qiantree._show()
},
// 确定回调事件
treeConfirm(e) {
this.clear()
this.setSelect(e[0].rank, e[0].name, e[0].id)
e[0].parents.forEach((item) => {
this.setSelect(item.rank, item.name, item.id)
})
},
// 清空
clear() {
this.select.engineeringName = ''
this.select.engineeringId = '' //工程ID
this.select.projectName = ''
this.select.projectId = '' //項目ID
this.select.deviceName = ''
this.select.deviceId = '' //设备ID
this.select.lineName = ''
this.select.lineId = '' //测点ID
},
setSelect(rank, name, id) {
switch (rank) {
case 0:
this.select.engineeringId = id
this.select.engineeringName = name
break
case 1:
this.select.projectId = id
this.select.projectName = name
break
case 2:
this.select.deviceId = id
this.select.deviceName = name
break
case 3:
this.select.lineId = id
this.select.lineName = name
break
}
},
external(params) {
this.getTree()
// this.select.engineeringId = id
// this.select.engineeringName = name
this.select.engineeringName = params.engineeringName
this.select.engineeringId = params.engineeringId //工程ID
this.select.projectName = params.projectName
this.select.projectId = params.projectId //項目ID
this.select.deviceName = params.deviceName
this.select.deviceId = params.deviceId //设备ID
this.select.lineName = params.lineName
this.select.lineId = params.lineId //测点ID
},
// 取消回调事件
treeCancel(e) {
console.log(e)
},
findFirstLevel(list, parents = []) {
for (const item of list) {
// 当前就是 level=3
if (item.level === 3) {
return {
node: item, // 第一个 level=3
parents: parents, // 它的所有上级
}
}
// 递归子节点
if (item.children && item.children.length) {
const res = this.findFirstLevel(item.children, [...parents, item])
if (res) return res // 找到直接返回,不再循环
}
}
return null
},
},
computed: {
startDate() {
return this.getDate('start')
},
endDate() {
return this.getDate('end')
},
},
watch: {
select: {
handler(val, oldVal) {
if (this.loading) return
this.$emit('select', val)
},
deep: true,
immediate: true,
},
level: {
handler(val, oldVal) {
this.getTree()
},
deep: true,
immediate: true,
},
// showDatetime: {
// handler(val, oldVal) {
// if (val == false) {
// console.log("🚀 ~ this.select.range:", this.select.range)
// }
// },
// deep: true,
// },
},
}
</script>
<style lang="scss" scoped>
/deep/ .uni-date-editor {
width: 360rpx;
}
.nav-menu {
display: flex;
align-items: center;
}
// .nav-menu1 {
// max-width: calc(100vw - 150px);
// overflow: hidden !important;
// -webkit-line-clamp: 1;
// display: -webkit-box;
// -webkit-box-orient: vertical;
// text-overflow: ellipsis;
// word-break: break-all;
// white-space: nowrap;
// }
.nav-menu1 {
display: flex;
align-items: center;
max-width: calc(100vw - 150px);
}
/* 文字容器:单行溢出省略 */
.nav-text {
flex: 1;
overflow: hidden;
white-space: nowrap; /* 强制不换行 */
text-overflow: ellipsis;
// -webkit-line-clamp: 1;
// display: -webkit-box;
// -webkit-box-orient: vertical;
// text-overflow: ellipsis;
// word-break: break-all;
// white-space: nowrap;
line-height: 1;
}
</style>

View File

@@ -0,0 +1,234 @@
<template>
<view class="nav choose">
<view class="nav-menu nav-menu1" @click="selectEngineering" v-if="showQianTree">
<view class="nav-text">
{{ lineDisplayText }}
</view>
<uni-icons type="bottom" size="14"></uni-icons>
</view>
<view class="nav-menu nav-menu1" @click="selectEngineering" v-if="showQianTree">
<view class="nav-text">
{{
'指标配置'
}}
</view>
<uni-icons type="bottom" size="14"></uni-icons>
</view>
<!-- 弹框组件 -->
<Cn-MultipleTree ref="qiantree" :selectParent="true" :multiple="true" :range="list" :foldAll="true"
@confirm="treeConfirm" @cancel="treeCancel"></Cn-MultipleTree>
<slot />
</view>
</template>
<script>
import { lineTree } from '@/common/api/device'
export default {
components: {},
props: {
level: { type: Number, default: 3 },
singleChoice: { type: Boolean, default: false },
showQianTree: { type: Boolean, default: true },
},
data() {
return {
select: {
lineList: []//监测点id
},
list: [],
}
},
created() { },
onShow() { },
mounted() { },
methods: {
getTree() {
this.clear()
lineTree().then((res) => {
let list = {}
// if (this.singleChoice) {
// let result = this.findFirstLevel(res.data)
// } else {
// list = {
// id: '',
// pid: '0',
// pids: '0',
// name: '全部工程',
// path: null,
// provinceId: null,
// cityId: null,
// area: null,
// remark: null,
// sort: 0,
// level: 0,
// comFlag: null,
// type: null,
// lineType: null,
// conType: null,
// process: null,
// isTop: 0,
// children: [],
// ndid: null,
// }
// }
this.list = this.filterTreeByLevel(this.singleChoice ? res.data : [...res.data])
// this.findFirstLevel( this.list)
})
},
// 递归过滤函数去除level > 2的节点
filterTreeByLevel(tree) {
// 遍历每一个节点
return tree.map((node) => {
// 复制当前节点(避免修改原数据)
const newNode = { ...node }
// 如果当前节点有子节点并且当前节点的level <= 2因为level=2的节点的子节点是level=3需要过滤
if (newNode.children && newNode.children.length > 0) {
// 递归过滤子节点只保留子节点中level <= 2的
newNode.children = this.filterTreeByLevel(
newNode.children.filter((child) => child.level <= this.level),
)
}
return newNode
})
},
selectEngineering() {
this.$refs.qiantree._show()
},
// 确定回调事件
treeConfirm(e) {
this.select.lineList = e.filter(item => item.rank == 3)
},
// 清空
clear() {
this.select.lineList = []//监测点id
},
// 取消回调事件
treeCancel(e) {
console.log(e)
},
findFirstLevel(list, parents = []) {
for (const item of list) {
// 当前就是 level=3
if (item.level === 3) {
return {
node: item, // 第一个 level=3
parents: parents, // 它的所有上级
}
}
// 递归子节点
if (item.children && item.children.length) {
const res = this.findFirstLevel(item.children, [...parents, item])
if (res) return res // 找到直接返回,不再循环
}
}
return null
},
},
computed: {
lineDisplayText() {
const list = this.select.lineList || []
if (!list.length) {
return '筛选监测点'
}
const text = list
.map((item) => item.name)
.filter(Boolean)
.join('、')
if (text.length > 8) {
return text.slice(0, 8) + '...'
}
return text
},
},
watch: {
select: {
handler(val, oldVal) {
console.log("🚀 ~ val:", val)
if (this.loading) return
this.$emit('select', val)
},
deep: true,
immediate: true,
},
level: {
handler(val, oldVal) {
this.getTree()
},
deep: true,
immediate: true,
},
// showDatetime: {
// handler(val, oldVal) {
// if (val == false) {
// console.log("🚀 ~ this.select.range:", this.select.range)
// }
// },
// deep: true,
// },
},
}
</script>
<style lang="scss" scoped>
/deep/ .uni-date-editor {
width: 360rpx;
}
.nav-menu {
display: flex;
align-items: center;
}
// .nav-menu1 {
// max-width: calc(100vw - 150px);
// overflow: hidden !important;
// -webkit-line-clamp: 1;
// display: -webkit-box;
// -webkit-box-orient: vertical;
// text-overflow: ellipsis;
// word-break: break-all;
// white-space: nowrap;
// }
.nav-menu1 {
display: flex;
align-items: center;
max-width: calc(100vw - 150px);
}
/* 文字容器:单行溢出省略 */
.nav-text {
flex: 1;
overflow: hidden;
white-space: nowrap;
/* 强制不换行 */
text-overflow: ellipsis;
// -webkit-line-clamp: 1;
// display: -webkit-box;
// -webkit-box-orient: vertical;
// text-overflow: ellipsis;
// word-break: break-all;
// white-space: nowrap;
line-height: 1;
}
</style>

View File

@@ -0,0 +1,130 @@
<template>
<view v-html="svgHtml" class="svg-container"></view>
</template>
<script>
export default {
props: {
// 父组件传递的参数
devType: {
type: String,
default: 'Direct_Connected_Device',
},
runStatus: {
type: [String, Number],
},
alarmStatus: {
type: [String, Number],
},
},
data() {
return {
// 动态颜色
powerColor: '#10b981',
// alarmStatus==1?'#f59e0b':'#10b981': '#f59e0b', //告警
// commColor: '#10B981', //在线离线
// 动态数据
}
},
computed: {
svgHtml() {
if (this.devType == 'Direct_Connected_Device') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<!-- 设备主体 - 治理设备主题色(绿色) -->
<rect x="2" y="2" width="96" height="96" rx="6" ry="6" fill="#007aff30" stroke="#007aff" stroke-width="2"/>
<!-- 屏幕区域 -->
<rect x="6" y="6" width="88" height="52" rx="3" ry="3" fill="#FFFFFF" stroke="#007aff" stroke-width="1.5"/>
<!-- 屏幕标题栏 - 调整高度以容纳14px文字 -->
<rect x="10" y="9" width="80" height="14" rx="2" ry="2" fill="#007aff30" stroke="#CCC" stroke-width="0.8"/>
<text x="50" y="20" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#007aff" text-anchor="middle">治理设备</text>
<!-- 下降趋势折线(从高到低,拉满宽度) -->
<polyline points="14,28 22,34 30,32 38,40 46,38 54,46 62,44 70,50 78,48 86,52"
fill="none" stroke="#007aff" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
<!-- 趋势填充区域(完全覆盖屏幕下方) -->
<polygon points="14,28 22,34 30,32 38,40 46,38 54,46 62,44 70,50 78,48 86,52 86,54 14,54"
fill="#007aff15"/>
<!-- 数据节点圆点(增强数据感) -->
<circle cx="14" cy="28" r="1.5" fill="#007aff"/>
<circle cx="30" cy="32" r="1.5" fill="#007aff"/>
<circle cx="46" cy="38" r="1.5" fill="#007aff"/>
<circle cx="62" cy="44" r="1.5" fill="#007aff"/>
<circle cx="78" cy="48" r="1.5" fill="#007aff"/>
<circle cx="86" cy="52" r="1.5" fill="#007aff"/>
<!-- 下降箭头(增强趋势指向) -->
<polygon points="88,48 86,52 84,48" fill="#007aff" opacity="0.7"/>
<!-- 指示灯区域分隔线 -->
<line x1="6" y1="62" x2="94" y2="62" stroke="#999" stroke-width="1" stroke-dasharray="2,2"/>
<!-- 告警指示灯 -->
<circle cx="28" cy="70" r="6" fill="${this.alarmStatus==1?'#f59e0b':'#10b981'}" stroke="${this.alarmStatus==1?'#f59e0b':'#10b981'}" stroke-width="1"/>
<text x="28" y="92" font-family="Arial, sans-serif" font-size="13" font-weight="bold" fill="#007aff" text-anchor="middle">告警</text>
<!-- 通讯指示灯 -->
<circle cx="70" cy="70" r="6" fill="${this.runStatus == 1 ? '#ff3b30' : '#10b981'}" stroke="${this.runStatus == 1 ? '#ff3b30' : '#10b981'}" stroke-width="1"/>
<text x="70" y="92" font-family="Arial, sans-serif" font-size="13" font-weight="bold" fill="#007aff" text-anchor="middle">通讯</text>
</svg>`
} else {
return `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<style>
text { font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif; }
</style>
<!-- 设备主体 -->
<rect x="2" y="2" width="96" height="96" rx="6" ry="6" fill="#007aff30" stroke="#007aff" stroke-width="2"/>
<!-- 屏幕区域 -->
<rect x="6" y="6" width="88" height="52" rx="3" ry="3" fill="#FFFFFF" stroke="#007aff" stroke-width="1.5"/>
<!-- 屏幕标题栏 - 调整高度 -->
<rect x="10" y="9" width="80" height="14" rx="2" ry="2" fill="#007aff30" stroke="#CCC" stroke-width="0.8"/>
<text x="50" y="20" font-size="13" font-weight="bold" fill="#007aff" text-anchor="middle">监测设备</text>
<!-- 左侧电压数据 - 调整Y位置 -->
<text x="10" y="34" font-size="7" fill="#007aff">Ua: 220.5V</text>
<text x="10" y="43" font-size="7" fill="#007aff">Ub: 219.8V</text>
<text x="10" y="52" font-size="7" fill="#007aff">Uc: 220.1V</text>
<!-- 竖向分隔线 -->
<line x1="52" y1="26" x2="52" y2="55" stroke="#CCC" stroke-width="0.8" stroke-dasharray="1.5,1.5"/>
<!-- 右侧电流数据 -->
<text x="58" y="34" font-size="7" fill="#007aff">Ia: 125.3A</text>
<text x="58" y="43" font-size="7" fill="#007aff">Ib: 124.7A</text>
<text x="58" y="52" font-size="7" fill="#007aff">Ic: 125.1A</text>
<!-- 指示灯区域分隔线 -->
<line x1="6" y1="62" x2="94" y2="62" stroke="#999" stroke-width="1" stroke-dasharray="2,2"/>
<!-- 告警指示灯 -->
<circle cx="28" cy="70" r="6" fill="${this.alarmStatus==1?'#f59e0b':'#10b981'}" stroke="${this.alarmStatus==1?'#f59e0b':'#10b981'}" stroke-width="1"/>
<text x="28" y="92" font-size="13" font-weight="bold" fill="#007aff" text-anchor="middle">告警</text>
<!-- 通讯指示灯 -->
<circle cx="70" cy="70" r="6" fill="${this.runStatus == 1 ? '#ff3b30' : '#10b981'}" stroke="${this.runStatus == 1 ? '#ff3b30' : '#10b981'}" stroke-width="1"/>
<text x="70" y="92" font-size="13" font-weight="bold" fill="#007aff" text-anchor="middle">通讯</text>
</svg>
`
}
},
},
methods: {},
}
</script>
<style scoped>
.svg-container {
width: 100rpx;
display: flex;
justify-content: center;
align-items: center;
}
</style>

View File

@@ -0,0 +1,41 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<!-- 设备主体 -->
<rect x="2" y="2" width="96" height="96" rx="6" ry="6" fill="#E8E8E8" stroke="#333" stroke-width="2"/>
<!-- 屏幕区域 -->
<rect x="6" y="6" width="88" height="52" rx="3" ry="3" fill="#FFFFFF" stroke="#333" stroke-width="1.5"/>
<!-- 屏幕标题栏(代替品牌标识) -->
<rect x="10" y="9" width="80" height="10" rx="2" ry="2" fill="#F0F0F0" stroke="#CCC" stroke-width="0.8"/>
<text x="50" y="17" font-family="Arial, sans-serif" font-size="7" font-weight="bold" fill="#333" text-anchor="middle">电能质量监测</text>
<!-- 屏幕内容 - 左侧参数 -->
<text x="10" y="28" font-family="Arial, sans-serif" font-size="6" fill="#000">Ua:220.5V</text>
<text x="10" y="36" font-family="Arial, sans-serif" font-size="6" fill="#000">Ub:219.8V</text>
<text x="10" y="44" font-family="Arial, sans-serif" font-size="6" fill="#000">Uc:220.1V</text>
<text x="10" y="52" font-family="Arial, sans-serif" font-size="6" fill="#000">Hz:50.02</text>
<!-- 垂直分隔线 -->
<line x1="52" y1="22" x2="52" y2="55" stroke="#CCC" stroke-width="0.8" stroke-dasharray="1.5,1.5"/>
<!-- 右侧参数 -->
<text x="58" y="28" font-family="Arial, sans-serif" font-size="6" fill="#000">Ia:125.3A</text>
<text x="58" y="36" font-family="Arial, sans-serif" font-size="6" fill="#000">Ib:124.7A</text>
<text x="58" y="44" font-family="Arial, sans-serif" font-size="6" fill="#000">Ic:125.1A</text>
<text x="58" y="52" font-family="Arial, sans-serif" font-size="6" fill="#000">PF:0.98</text>
<!-- 指示灯区域分隔线 -->
<line x1="6" y1="62" x2="94" y2="62" stroke="#999" stroke-width="1" stroke-dasharray="2,2"/>
<!-- 电源灯 -->
<circle cx="20" cy="76" r="5" fill="#10b981" stroke="#10b981" stroke-width="1"/>
<text x="20" y="90" font-family="Arial, sans-serif" font-size="8" font-weight="bold" fill="#333" text-anchor="middle">电源</text>
<!-- 运行灯 -->
<circle cx="50" cy="76" r="5" fill="#999999" stroke="#333" stroke-width="1"/>
<text x="50" y="90" font-family="Arial, sans-serif" font-size="8" font-weight="bold" fill="#333" text-anchor="middle">运行</text>
<!-- 通讯灯(原通信灯,已改名) -->
<circle cx="80" cy="76" r="5" fill="#999999" stroke="#333" stroke-width="1"/>
<text x="80" y="90" font-family="Arial, sans-serif" font-size="8" font-weight="bold" fill="#333" text-anchor="middle">通讯</text>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,148 @@
<template>
<view v-html="svgHtml" class="svg-container"></view>
</template>
<script>
export default {
props: {
// 父组件传递的参数
name: {
type: String,
default: '',
},
},
data() {
return {}
},
computed: {
svgHtml() {
if (this.name == '电压暂降') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<path d="M8,50 L15,50 L18,38 L21,28 L24,38 L27,50 L30,62 L33,72 L36,62 L39,50 L42,38 L45,28 L48,38 L51,50 L54,56 L56,54 L58,55 L60,54 L63,56 L66,60 L68,62 L70,60 L72,56 L75,54 L77,52 L79,54 L81,56 L84,50 L87,38 L90,28 L93,38 L96,50" fill="none" stroke="#2563eb" stroke-width="4"/>
</svg>`
} else if (this.name == '电压暂升') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<path d="M8,50 L15,50 L18,38 L21,28 L24,38 L27,50 L30,62 L33,72 L36,62 L39,50 L42,38 L45,28 L48,38 L51,50 L54,43 L56,34 L58,26 L60,34 L63,43 L66,54 L68,60 L70,54 L72,43 L75,34 L77,26 L79,34 L81,43 L84,50 L87,38 L90,28 L93,38 L96,50" fill="none" stroke="#e6a23c" stroke-width="4"/>
</svg>`
} else if (this.name == '电压中断') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<path d="M8,50 L15,50 L18,38 L21,28 L24,38 L27,50 L30,62 L33,72 L36,62 L39,50 L42,38 L45,28 L48,38 L51,50 L54,50 L57,50 L60,50 L63,50 L66,50 L69,50 L72,50 L75,50 L78,50 L81,50 L84,50 L87,38 L90,28 L93,38 L96,50" fill="none" stroke="#6b7280" stroke-width="4"/>
</svg>`
} else if (this.name == '瞬态') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<path d="M8,50 L15,50 L18,38 L21,28 L24,38 L27,50 L30,62 L33,72 L36,62 L39,50 L42,38 L45,28 L48,38 L51,50 L53,50 L55,50 L57,20 L59,50 L61,50 L63,50 L66,60 L68,62 L70,60 L72,56 L75,54 L77,52 L79,54 L81,56 L84,50 L87,38 L90,28 L93,38 L96,50" fill="none" stroke="#8b5cf6" stroke-width="4"/>
</svg>`
} else if (this.name == '未知') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<path d="M8,50 L15,50 L18,38 L21,28 L24,38 L27,50 L30,62 L33,72 L36,62 L39,50 L42,38 L45,28 L48,38 L51,50 L54,56 L56,54 L58,55 L60,54 L63,56 L66,60 L68,62 L70,60 L72,56 L75,54 L77,52 L79,54 L81,56 L84,50 L87,38 L90,28 L93,38 L96,50" fill="none" stroke="#6b7280" stroke-width="4"/>
<text x="50" y="82" text-anchor="middle" font-size="18" fill="#6b7280" font-family="Arial, sans-serif" font-weight="bold">?</text>
</svg>`
} else if (this.name == '稳态越限') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<!-- Limit line -->
<line x1="5" y1="40" x2="95" y2="40" stroke="#e6a23c" stroke-width="2" stroke-dasharray="4,4"/>
<polyline points="
5,65 12,65 15,59 18,53 21,59 24,65
27,71 30,77 33,71 36,65
39,59 42,53 45,59 48,65
" fill="none" stroke="#376cf3" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
<polyline points="
51,40 54,20 57,40
" fill="none" stroke="#e6a23c" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
<polyline points="
60,65 63,71 66,77 69,71 72,65
75,59 78,53 81,59 84,65
87,71 90,77 93,71 95,65
" fill="none" stroke="#376cf3" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="48" y1="65" x2="51" y2="40" stroke="#376cf3" stroke-width="4" stroke-linecap="round"/>
<line x1="57" y1="40" x2="60" y2="65" stroke="#376cf3" stroke-width="4" stroke-linecap="round"/>
<circle cx="54" cy="18" r="2" fill="#e6a23c"/>
<defs>
<marker id="arrowRed" markerWidth="6" markerHeight="5" refX="5" refY="2.5" orient="auto">
<polygon points="0,0 6,2.5 0,5" fill="#e6a23c"/>
</marker>
</defs>
</svg>`
} else if (this.name == '运行告警') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="40" height="40">
<path d="M78.43 4H20.06C9.48 4 1.16 12.33 1.16 22.9v38.37c0 10.57 8.32 18.9 18.9 18.9h26.49v7.27H25.77v7.41h47.96v-7.41H53.96v-7.27h26.47c10.58 0 18.9-8.33 18.9-18.9V22.9c0-10.57-8.32-18.9-18.9-18.9z m11.49 57.27c0 6.33-5.14 11.49-11.49 11.49H20.06c-6.34 0-11.49-5.15-11.49-11.49V22.9c0-6.33 5.14-11.49 11.49-11.49h59.37c6.34 0 11.49 5.15 11.49 11.49v38.37z" fill="#007aff"/>
<line x1="50" y1="28" x2="50" y2="50" stroke="#007aff" stroke-width="6" stroke-linecap="round"/>
<circle cx="50" cy="62" r="4" fill="#007aff"/>
</svg>`
} else if (this.name == '治理设备') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="38" height="38">
<rect x="0" y="0" width="100" height="100" rx="8" ry="8" fill="#007aff30" stroke="#007aff" stroke-width="2"/>
<rect x="8" y="8" width="84" height="84" rx="4" ry="4" fill="#FFFFFF" stroke="#007aff" stroke-width="1.5"/>
<rect x="10" y="12" width="80" height="16" rx="2" ry="2" fill="#007aff30" stroke="#CCC" stroke-width="0.8"/>
<text x="50" y="24" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#007aff" text-anchor="middle">治理设备</text>
<polyline points="14,45 22,51 30,49 38,57 46,55 54,63 62,61 70,67 78,65 86,69"
fill="none" stroke="#007aff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
<polygon points="14,45 22,51 30,49 38,57 46,55 54,63 62,61 70,67 78,65 86,69 86,80 14,80"
fill="#007aff15"/>
<circle cx="14" cy="45" r="2" fill="#007aff"/>
<circle cx="30" cy="49" r="2" fill="#007aff"/>
<circle cx="46" cy="55" r="2" fill="#007aff"/>
<circle cx="62" cy="61" r="2" fill="#007aff"/>
<circle cx="78" cy="65" r="2" fill="#007aff"/>
<circle cx="86" cy="69" r="2" fill="#007aff"/>
<polygon points="88,65 86,70 84,65" fill="#007aff" opacity="0.7"/>
</svg>`
} else if (this.name == '监测设备') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="38" height="38">
<style>
text { font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif; }
</style>
<rect x="0" y="0" width="100" height="100" rx="6" ry="6" fill="#007aff30" stroke="#007aff" stroke-width="2"/>
<rect x="8" y="8" width="84" height="84" rx="3" ry="3" fill="#FFFFFF" stroke="#007aff" stroke-width="1.5"/>
<rect x="10" y="12" width="80" height="16" rx="2" ry="2" fill="#007aff30" stroke="#CCC" stroke-width="0.8"/>
<text x="50" y="24" font-size="14" font-weight="bold" fill="#007aff" text-anchor="middle">监测设备</text>
<text x="16" y="45" font-size="7" fill="#007aff">Ua: 220.5V</text>
<text x="16" y="55" font-size="7" fill="#007aff">Ub: 219.8V</text>
<text x="16" y="65" font-size="7" fill="#007aff">Uc: 220.1V</text>
<line x1="48" y1="38" x2="48" y2="78" stroke="#CCC" stroke-width="0.8" stroke-dasharray="2,2"/>
<text x="54" y="45" font-size="7" fill="#007aff">Ia: 125.3A</text>
<text x="54" y="55" font-size="7" fill="#007aff">Ib: 124.7A</text>
<text x="54" y="65" font-size="7" fill="#007aff">Ic: 125.1A</text>
</svg>`
} else if (this.name == '报告') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="37" height="37">
<path d="M12,12 L78,12 L88,22 L88,88 L12,88 Z" fill="none" stroke="#007aff" stroke-width="4" stroke-linejoin="round"/>
<path d="M78,12 L78,22 L88,22" fill="none" stroke="#007aff" stroke-width="4" stroke-linejoin="round"/>
<polyline points="20,50 26,50 28,46 30,42 32,46 34,50 36,54 38,58 40,54 42,50 44,46 46,42 48,46 50,50 56,50" fill="none" stroke="#007aff" stroke-width="4" stroke-linecap="round"/>
<line x1="20" y1="68" x2="52" y2="68" stroke="#007aff" stroke-width="4" opacity="0.4" stroke-linecap="round"/>
<line x1="20" y1="76" x2="42" y2="76" stroke="#007aff" stroke-width="4" opacity="0.4" stroke-linecap="round"/>
<circle cx="70" cy="68" r="9" fill="none" stroke="#007aff" stroke-width="4"/>
<line x1="76" y1="74" x2="86" y2="84" stroke="#007aff" stroke-width="4" stroke-linecap="round"/>
</svg>`
} else if (this.name == '监测点') {
return `<svg t="1779762122379" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3577" width="33" height="33"><path d="M875.17148 230.296136c30.706152 56.294611 46.059227 122.824606 46.059227 194.472293 0 107.47153-40.941535 209.825369-107.47153 286.590748 0 0 0 5.117692-5.117692 5.117692l-261.002288 286.590748c0 5.117692-5.117692 10.235384-5.117692 10.235383-15.353076 10.235384-30.706152 15.353076-46.059227 5.117692-5.117692 0-10.235384-5.117692-15.353076-10.235384v-5.117691L209.87153 716.476869s-5.117692-5.117692-5.117692-10.235384c-66.529995-76.765379-102.353838-174.001525-102.353838-281.473056C102.4 189.354601 286.636909 0 511.815354 0c81.883071 0 153.530758 25.58846 220.060752 66.529995 5.117692 0 5.117692 5.117692 10.235384 5.117692h5.117692c46.059227 35.823843 81.883071 81.883071 112.589222 133.05999 10.235384 5.117692 15.353076 15.353076 15.353076 25.588459z m-163.766141-92.118454c-5.117692 0-10.235384-5.117692-15.353076-10.235384-51.176919-35.823843-112.589222-56.294611-179.119217-56.294611-189.354601 0-337.767667 158.64845-337.767667 353.120742 0 92.118455 30.706152 174.001525 87.000762 235.413829l20.470768 20.470767 20.470768 20.470768 143.295374 153.530758L511.815354 931.41993l71.647687-76.765379 143.295373-153.530758 5.117692-5.117692 35.823844-40.941535c0-5.117692 5.117692-5.117692 10.235384-5.117692 51.176919-61.412303 81.883071-143.295374 81.88307-230.296136-5.117692-112.589222-66.529995-214.943061-148.413065-281.473056z m-199.589985 460.592273c-92.118455 0-163.766141-76.765379-163.766142-174.001526C348.049212 332.649975 419.696899 255.884596 511.815354 255.884596c92.118455 0 163.766141 76.765379 163.766141 174.001525 0 92.118455-71.647687 168.883833-163.766141 168.883834z m0-271.237672c-51.176919 0-97.236146 46.059227-97.236147 102.353838s46.059227 102.353838 97.236147 102.353839c51.176919 0 97.236146-46.059227 97.236146-102.353839s-46.059227-102.353838-97.236146-102.353838z" fill="#007aff" p-id="3578"></path></svg>`
}
},
},
methods: {},
}
</script>
<style scoped>
.svg-container {
width: 100rpx;
display: flex;
justify-content: center;
align-items: center;
}
</style>

View File

@@ -0,0 +1,41 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<!-- 设备主体 -->
<rect x="2" y="2" width="96" height="96" rx="6" ry="6" fill="#E8E8E8" stroke="#333" stroke-width="2"/>
<!-- 屏幕区域 -->
<rect x="6" y="6" width="88" height="52" rx="3" ry="3" fill="#FFFFFF" stroke="#333" stroke-width="1.5"/>
<!-- 屏幕标题栏(代替品牌标识) -->
<rect x="10" y="9" width="80" height="10" rx="2" ry="2" fill="#F0F0F0" stroke="#CCC" stroke-width="0.8"/>
<text x="50" y="17" font-family="Arial, sans-serif" font-size="7" font-weight="bold" fill="#333" text-anchor="middle">电能质量监测</text>
<!-- 屏幕内容 - 左侧参数 -->
<text x="10" y="28" font-family="Arial, sans-serif" font-size="6" fill="#000">Ua:220.5V</text>
<text x="10" y="36" font-family="Arial, sans-serif" font-size="6" fill="#000">Ub:219.8V</text>
<text x="10" y="44" font-family="Arial, sans-serif" font-size="6" fill="#000">Uc:220.1V</text>
<text x="10" y="52" font-family="Arial, sans-serif" font-size="6" fill="#000">Hz:50.02</text>
<!-- 垂直分隔线 -->
<line x1="52" y1="22" x2="52" y2="55" stroke="#CCC" stroke-width="0.8" stroke-dasharray="1.5,1.5"/>
<!-- 右侧参数 -->
<text x="58" y="28" font-family="Arial, sans-serif" font-size="6" fill="#000">Ia:125.3A</text>
<text x="58" y="36" font-family="Arial, sans-serif" font-size="6" fill="#000">Ib:124.7A</text>
<text x="58" y="44" font-family="Arial, sans-serif" font-size="6" fill="#000">Ic:125.1A</text>
<text x="58" y="52" font-family="Arial, sans-serif" font-size="6" fill="#000">PF:0.98</text>
<!-- 指示灯区域分隔线 -->
<line x1="6" y1="62" x2="94" y2="62" stroke="#999" stroke-width="1" stroke-dasharray="2,2"/>
<!-- 电源灯 -->
<circle cx="20" cy="76" r="5" fill="#10b981" stroke="#10b981" stroke-width="1"/>
<text x="20" y="90" font-family="Arial, sans-serif" font-size="8" font-weight="bold" fill="#333" text-anchor="middle">电源</text>
<!-- 运行灯 -->
<circle cx="50" cy="76" r="5" fill="#999999" stroke="#333" stroke-width="1"/>
<text x="50" y="90" font-family="Arial, sans-serif" font-size="8" font-weight="bold" fill="#333" text-anchor="middle">运行</text>
<!-- 通讯灯(原通信灯,已改名) -->
<circle cx="80" cy="76" r="5" fill="#999999" stroke="#333" stroke-width="1"/>
<text x="80" y="90" font-family="Arial, sans-serif" font-size="8" font-weight="bold" fill="#333" text-anchor="middle">通讯</text>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -1,63 +1,63 @@
<template> <template>
<view class="Cn-page" :class="{ 'no-padding': noPadding }"> <view class="Cn-page" :class="{ 'no-padding': noPadding }">
<template v-if="showLoginMsk && !login"> <template v-if="showLoginMsk && !login">
<navigator url="/pages/user/login" hover-class="none" class="page-login-btn">登录</navigator> <navigator url="/pages/user/login" hover-class="none" class="page-login-btn">登录</navigator>
</template> </template>
<template v-else> <template v-else>
<zero-loading v-if="loading" mask></zero-loading> <zero-loading v-if="loading" mask></zero-loading>
<slot name="body" v-if="beforeRender|| !loading "></slot> <slot name="body" v-if="beforeRender|| !loading "></slot>
</template> </template>
</view> </view>
</template> </template>
<script> <script>
export default { export default {
name: 'Cn-page', name: 'Cn-page',
props: { props: {
loading: { loading: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
beforeRender: { beforeRender: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
showLoginMsk: Boolean, showLoginMsk: Boolean,
noPadding: Boolean, noPadding: Boolean,
}, },
data() { data() {
return { return {
login: false, login: false,
} }
}, },
created() { created() {
this.login = uni.getStorageSync('Authorization') this.login = uni.getStorageSync('Authorization')
}, },
} }
</script> </script>
<style lang="scss"> <style lang="scss">
.Cn-page { .Cn-page {
box-sizing: border-box; box-sizing: border-box;
padding-bottom: calc(30rpx + env(safe-area-inset-bottom)); padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
} }
.no-padding { .no-padding {
padding-bottom: 0; padding-bottom: 0;
} }
.page-login-btn { .page-login-btn {
position: fixed; position: fixed;
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
height: 80rpx; height: 80rpx;
width: 200rpx; width: 200rpx;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background: #449dff; background: #449dff;
color: #fff; color: #fff;
border-radius: 4rpx; border-radius: 4rpx;
} }
</style> </style>

View File

@@ -0,0 +1,550 @@
<template xlang="wxml">
<view class="tki-tree">
<view class="tki-tree-mask" :class="{ show: showTree }" @tap="_cancel"></view>
<view class="tki-tree-cnt" :class="{ show: showTree }">
<view class="tki-tree-bar">
<view class="tki-tree-bar-cancel" :style="{ color: cancelColor }" hover-class="hover-c" @tap="_cancel"
>取消</view
>
<view class="tki-tree-bar-title" :style="{ color: titleColor }">{{ title }}</view>
<view
class="tki-tree-bar-confirm"
:style="{ color: confirmColor }"
hover-class="hover-c"
@tap="_confirm"
>确定</view
>
</view>
<view class="tki-tree-bar1">
<uni-search-bar
class="uni-input"
radius="5"
placeholder="请输入关键字搜索"
clearButton="none"
@input="input"
/>
<!-- <uni-search-bar
v-model="searchValue"
clearButton="none"
bgColor="#fff"
placeholder="请输入关键词"
@input="input"
></uni-search-bar> -->
</view>
<view class="tki-tree-view">
<scroll-view class="tki-tree-view-sc" :scroll-y="true">
<block v-for="(item, index) in treeList" :key="index">
<view
class="tki-tree-item"
:style="[
{
paddingLeft: item.rank * 15 + 'px',
zIndex: item.rank * -1 + 50,
},
]"
:class="{
border: border === true,
show: item.show,
last: item.lastRank,
showchild: item.showChild,
open: item.open,
}"
>
<view class="tki-tree-label" @tap.stop="_treeItemTap(item, index)">
<image
class="tki-tree-icon"
:src="item.lastRank ? lastIcon : item.showChild ? currentIcon : defaultIcon"
></image>
{{ item.name }}
</view>
<view
class="tki-tree-check"
@tap.stop="_treeItemSelect(item, index)"
v-if="selectParent ? true : item.lastRank"
>
<view
class="tki-tree-check-yes"
v-if="item.checked && (singleChoice ? item.rank == 3 : true)"
:class="{ radio: !multiple }"
:style="{ 'border-color': confirmColor }"
>
<view
class="tki-tree-check-yes-b"
:style="{ 'background-color': confirmColor }"
></view>
</view>
<view
class="tki-tree-check-no"
v-if="!item.checked && (singleChoice ? item.rank == 3 : true)"
:class="{ radio: !multiple }"
:style="{ 'border-color': confirmColor }"
></view>
</view>
</view>
</block>
</scroll-view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'tki-tree',
props: {
lazy: {
type: Boolean,
default: false,
},
range: {
type: Array,
default: function () {
return []
},
},
idKey: {
type: String,
default: 'id',
},
singleChoice: { type: Boolean, default: false },
rangeKey: {
type: String,
default: 'name',
},
title: {
type: String,
default: '',
},
multiple: {
// 是否可以多选
type: Boolean,
default: false,
// default: true
},
selectParent: {
//是否可以选父级
type: Boolean,
default: false,
},
foldAll: {
//折叠时关闭所有已经打开的子集,再次打开时需要一级一级打开
type: Boolean,
default: false,
},
confirmColor: {
// 确定按钮颜色
type: String,
default: '#376cf3', // #07bb07
},
cancelColor: {
// 取消按钮颜色
type: String,
default: '', // #757575
},
titleColor: {
// 标题颜色
type: String,
default: '', // #757575
},
currentIcon: {
// 展开时候的ic
type: String,
default:
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFEAAABRCAYAAACqj0o2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MEQ0QTM0MzQ1Q0RBMTFFOUE0MjY4NzI1Njc1RjI1ODIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MEQ0QTM0MzU1Q0RBMTFFOUE0MjY4NzI1Njc1RjI1ODIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowRDRBMzQzMjVDREExMUU5QTQyNjg3MjU2NzVGMjU4MiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowRDRBMzQzMzVDREExMUU5QTQyNjg3MjU2NzVGMjU4MiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PidwepsAAAK0SURBVHja7JxbTsJAFIYHww7ciStgCeoGvGxAiOsgURegoL5720AXYLiIr0aJviq3Zx3PhIEnKG3ndtr+f3KixrSUj/ZjzjClIqUUiFm2gAAQAREQEUAEREAERAQQAREQAREBREAEREBEEqa67h9RFDWllDv0awWYlqlQHmu1WjMRRMoV1QFttA12y3xRtdNczq8EsE4/f8FumX2q77ROvNXk8UGMEKdUz6tYJHljaZAbuyUH+UR1to5BEohTuqwPCeS4pAA/qY6o/kyHOAMCeRK3owJnj+rH1jjxhqpVsstaebCz6TmnHWyXyY+xHjSBWBY/bvSgadtXBj9u9KCN3rnIfkzkQVsTEEX0Y2IP2oKo/HhMICcFAThUcwVZNGU6FdbX/XURzkbVF4+ybGhjPrFdgP66QdXNurGtSdk6Xdb9nAJ8oDo3OQlsQZzkdPw41ONBo6vI5scDefRjZg+6gpg3Pxp50CXEvPjR2IOuIXL3oxUPuobI3Y9WPOgDIlc/WvOgL4iL/vqFCcD7LH0xB4hj7cfQ/fWH9qCT+FhG0tN+DBk1PzjOM0SVllixcsBT1AvYc/kAPhc0hRg/3uvxoCgKRN9+dOrBUBB9+9GpB0NC9OVH5x4MDdG1H714kANEV3705kEOEBf9dcPi/lQnsuvLg1wgSu3Ha0v7Uh4MMgUXeuG71H407a+VBy9CPQkOdw+MtB+nGbd/D+FBbhBNxo9SjwcngJjNj0E9yBFiFj8G9SBXiGn8GNyDnCEm8SMLD3KHGOdHNh7kDjHOj2w8mAeIi/5arX+c6b/fxHz9oADEdGdjR/fXCw/OOB5oVfCOgnepz8IB14PMw03jCmTE+QBx5z0gAmKSqK9OUF+hcAeIhu/QYr4Qie8rjW83hhMBERARQAREQAREBBABERCLnH8BBgA+TQI7U4t53AAAAABJRU5ErkJggg==',
},
defaultIcon: {
// 折叠时候的ic
type: String,
default:
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFEAAABRCAYAAACqj0o2AAACE0lEQVR4Xu3c200DMRCF4XEltJAOkEugA+ggpUAHoQMqiFMCdEAJUMEiS4mEELlIO7bPOeN9i6K1rG/952myyea1WiCtXmEuYBPR4RBMxInoIOCwhOtJLKVszWyXc/5y2BvNEq6I+/3+kFK6M7OHnPM7jcLKjbZAvD/uaZtzflm5P4rbWyJWgDcze1LPuzVihfxUz7sH4ilJ2bx7Isrm3RtRMu8RiHJ5j0SUyXs0okTeCIj0eSMh0uaNhkiZNyIiXd7IiDR5oyNS5M2ACJ83EyJs3myIkHkzIsLlzYwIkzc7IkTeCojD81ZCHJa3GuKQvBURu+etjNgtb3XELnlHQGyedyTEZnlHQ2ySd0RE97wjI7rlHR3RJe+JeIrbLOecD6ePpZQ6W1kn2epo4MUrPOKyLN8ppYq1+y1VStncOjIdGnFZlo+U0uOtWOeOY2TE12Ouq//pEA7xXL7XfvcufR8K0Svfv6CREN3yDYfYIt9QiK3yjYTYLF95xB75SiP2ylcZsVu+cogj8pVCHJWvEuKwfOkREfKlRkTJlxkRJl86RMR8qRBR82VChM0XHpEhX2hElnyREWnyhUNkzBcKkTVfJETafIcjKuQ7FFEl35GIMvl2R1TMtyuiar49EWXzbY5oZpv/hibXTF2h3+s60FRKeT6+3TjMS3nrA3ZFRD8xrfY3ER1kJ+JEdBBwWGKeRAfEH1wS5WFZSDB/AAAAAElFTkSuQmCC',
},
lastIcon: {
// 没有子集的ic
type: String,
default: '',
},
border: {
// 是否有分割线
type: Boolean,
default: false,
},
},
data() {
return {
showTree: false,
treeList: [],
selectIndex: -1,
returnedItem: [], //定义一个空数组
pids: [],
ancestorsIds: [],
childNums: [],
dataTree: [],
inputTimer: null, // 节流定时器标识
searchValue: '',
}
},
computed: {},
methods: {
_show() {
this.showTree = true
if (this.searchValue != '') {
this.searchValue = ''
this.input('')
}
},
_hide() {
this.showTree = false
},
_cancel() {
this._hide()
this.$emit('cancel', '')
},
_confirm() {
// 处理所选数据
let rt = [],
obj = {}
this.treeList.forEach((v, i) => {
if (this.treeList[i].checked) {
// rt.push(this.treeList[i].id)
rt.push(this.treeList[i])
}
})
this._hide()
console.log('🚀 ~ rt:', rt)
if (rt.length == 0) return
if (this.singleChoice) {
if (rt[0].rank != 3) return
}
this.$emit('confirm', rt)
},
//扁平化树结构
_renderTreeList(list = [], rank = 0, parentId = [], parents = []) {
list.forEach((item) => {
this.treeList.push({
id: item[this.idKey],
name: item[this.rangeKey],
source: item,
parentId, // 父级id数组
parents, // 父级id数组
rank, // 层级
showChild: false, //子级是否显示
open: false, //是否打开
show: rank === 0, // 自身是否显示
hideArr: [],
orChecked: item.checked ? item.checked : false,
checked: item.checked ? item.checked : false,
childNum: 0,
})
if (Array.isArray(item.children) && item.children.length > 0) {
let parentid = [...parentId],
parentArr = [...parents]
delete parentArr.children
parentid.push(item[this.idKey])
parentArr.push({
[this.idKey]: item[this.idKey],
[this.rangeKey]: item[this.rangeKey],
rank: rank,
})
// lazy
if (!this.lazy) {
this._renderTreeList(item.children, rank + 1, parentid, parentArr)
}
} else {
this.treeList[this.treeList.length - 1].lastRank = true
}
})
},
// 处理默认选择
_defaultSelect() {
this.treeList.forEach((v, i) => {
if (v.checked) {
this.treeList.forEach((v2, i2) => {
if (v.parentId.toString().indexOf(v2.parentId.toString()) >= 0) {
v2.show = true
if (v.parentId.includes(v2.id)) {
v2.showChild = true
v2.open = true
}
}
})
}
})
},
getOwn(id, arr) {
//利用foreach循环遍历
arr.forEach((item) => {
//判断递归结束条件
if (item[this.idKey] == id) {
// 存储数据到空数组
this.returnedItem = item
} else if (item.children != null) //判断chlidren是否有数据
{
//递归调用
this.getOwn(id, item.children)
}
})
return this.returnedItem
},
setShow(id, arr, isShow) {
arr.forEach((item, index) => {
if (item.parentId.includes(id)) {
this.treeList[index].showChild = isShow
this.treeList[index].show = isShow
} else if (item.children !== undefined) {
this.setShow(id, item.children, isShow)
}
})
},
// 点击
_treeItemTap(item, index) {
// console.log(item)
if (item.lastRank === true) {
//点击最后一级时触发事件
this.treeList[index].checked = !this.treeList[index].checked
this._fixMultiple(index)
return
}
let id = item.id
item.showChild = !item.showChild
// qingqian
if (item.showChild) {
// const range = this.range
const range = this.dataTree
const parentIdArr = item.parentId
// 找到当前元素
const own = this.getOwn(id, range)
const checkedChildren = own.children
// 子元素插入的索引位置
const nextIndex = this.treeList.findIndex((itemT) => itemT.id === item.id)
console.log(checkedChildren)
if (checkedChildren === undefined || checkedChildren.length < 1) {
return
}
// 子节点数量
this.treeList[index].childNum = checkedChildren.length
const newRank = item.rank + 1
checkedChildren.forEach((itemC) => {
const childObj = {
id: itemC[this.idKey],
name: itemC[this.rangeKey],
source: {},
parentId: [item.id], // 父级id数组
parents: [item], // 父级id数组
rank: newRank, // 层级
showChild: false, //子级是否显示
open: false, //是否打开
show: 1, // 自身是否显示
hideArr: [],
orChecked: this.treeList[index].checked,
checked: this.treeList[index].checked,
}
if (!this.treeList.some((itemT) => itemT.id === itemC[this.idKey])) {
this.treeList.splice(nextIndex + 1, 0, childObj)
}
})
}
// 展开/隐藏子级/孙级
let list = this.treeList
item.open = item.showChild ? true : !item.open
list.forEach((childItem, i) => {
if (item.showChild === false) {
//隐藏所有子级
if (!childItem.parentId.includes(id)) {
return
}
//TODO: 修改
if (!this.foldAll) {
if (childItem.lastRank !== true && !childItem.open) {
childItem.showChild = false
this.setShow(childItem.id, this.treeList, false)
}
// 为隐藏的内容添加一个标记
if (childItem.show) {
childItem.hideArr[item.rank] = id
}
} else {
if (childItem.lastRank !== true) {
childItem.showChild = false
// 继续隐藏子级的的子级
this.setShow(childItem.id, this.treeList, false)
}
}
if (childItem.children !== undefined) {
childItem.children.forEach((childItem1, i1) => {
if (!childItem1.parentId.includes(childItem.id)) {
return
}
childItem.children[i1].showChild = false
childItem.children[i1].show = false
})
}
childItem.show = false
} else {
// 打开子集
if (childItem.parentId[childItem.parentId.length - 1] === id) {
childItem.show = true
}
// 打开被隐藏的子集
if (childItem.parentId.includes(id) && !this.foldAll) {
// console.log(childItem.hideArr)
if (childItem.hideArr[item.rank] === id) {
childItem.show = true
if (childItem.open && childItem.showChild) {
childItem.showChild = true
} else {
childItem.showChild = false
}
childItem.hideArr[item.rank] = null
}
}
}
})
},
// 通过父id处理子级
syncChecked(trees, pid, checked) {
trees.forEach((item, index) => {
if (item.parentId.includes(pid)) {
this.treeList[index].checked = checked
this.syncChecked(trees, item.id, checked)
} else if (item.children !== undefined) {
this.syncChecked(item.children, pid, checked)
}
})
},
// 获取父级往上所有层级的id 并同步状态
setAncestors(pids, checked) {
this.treeList.forEach((item, index) => {
if (pids.includes(item.id)) {
if (checked && this.childNums[item.id] !== undefined && item.childNum === this.childNums[item.id]) {
// 子级全部选中, 父级才选中
this.treeList[index].checked = true
} else {
this.treeList[index].checked = false
}
this.setAncestors(item.parentId, checked)
}
})
},
_treeItemSelect(item, index) {
if (item.rank != 3) {
if (this.singleChoice) return
}
// if(this.singleChoice)
this.treeList[index].checked = !this.treeList[index].checked
// 选父级, 子级自动全选
this.syncChecked(this.treeList, item.id, this.treeList[index].checked)
if (item.rank > 0) {
item.parentId.forEach((pid, indexP) => {
const parent = this.treeList.filter((i) => i.id === pid)
const childNum = parent.length > 0 ? parent[0].childNum : 0
if (this.childNums[pid] === undefined) {
this.childNums[pid] = 1
} else if (this.childNums[pid] < childNum) {
this.childNums[pid]++
}
})
//子级选择/选满/取消选择, 父级往上同步状态
this.setAncestors(item.parentId, this.treeList[index].checked)
}
this._fixMultiple(index)
},
// 处理单选多选
_fixMultiple(index) {
if (!this.multiple) {
// 如果是单选
this.treeList.forEach((v, i) => {
if (i != index) {
this.treeList[i].checked = false
} else {
this.treeList[i].checked = true
}
})
}
},
// 重置数据
_reTreeList() {
this.treeList.forEach((v, i) => {
this.treeList[i].checked = v.orChecked
})
},
_initTree(range = this.range) {
this.treeList = []
this.dataTree = JSON.parse(JSON.stringify(range))
this._renderTreeList(range)
this.$nextTick(() => {
this._defaultSelect(range)
})
},
// 筛选
input(val) {
// 清除上一次的定时器,避免频繁执行
if (this.inputTimer) {
clearTimeout(this.inputTimer)
}
// 设置新的定时器,指定延迟后执行过滤逻辑
this.inputTimer = setTimeout(() => {
const keyword = val
// 执行树形过滤和初始化
this._initTree(this.filterNodes(this.range, keyword))
// 清空定时器标识
clearTimeout(this.inputTimer)
this.inputTimer = null
}, 500)
// this._initTree(this.filterNodes(this.range, val.detail.value))
},
filterNodes(node, query) {
const keyword = query.trim() // 获取搜索关键字并转换为小写
const nodes = node
// 使用递归函数过滤树形数据
const filteredNodes = []
for (const node of nodes) {
if (node.name.includes(keyword)) {
// 如果节点的标签包含关键字,将其添加到结果中
filteredNodes.push(node)
} else if (node.children && node.children.length > 0) {
// 如果节点有子节点,则递归过滤子节点
const filteredChildren = this.filterNodes(node.children, keyword)
if (filteredChildren.length > 0) {
// 如果子节点中有匹配的结果,则添加父节点
const clonedNode = { ...node, children: filteredChildren }
filteredNodes.push(clonedNode)
}
}
}
return filteredNodes
},
},
watch: {
range(list) {
this._initTree(list)
},
multiple() {
if (this.range.length) {
this._reTreeList()
}
},
selectParent() {
if (this.range.length) {
this._reTreeList()
}
},
},
mounted() {
this._initTree()
},
}
</script>
<style lang="scss" scoped>
@import './style.css';
/deep/ .uni-searchbar__box {
justify-content: left !important;
}
</style>

View File

@@ -0,0 +1,195 @@
.tki-tree-mask {
position: fixed;
top: 0rpx;
right: 0rpx;
bottom: 0rpx;
left: 0rpx;
z-index: 9998;
background-color: rgba(0, 0, 0, 0.6);
opacity: 0;
transition: all 0.3s ease;
visibility: hidden;
}
.tki-tree-mask.show {
visibility: visible;
opacity: 1;
}
.tki-tree-cnt {
position: fixed;
top: 0rpx;
right: 0rpx;
bottom: 0rpx;
left: 0rpx;
z-index: 9999;
top: 40%;
transition: all 0.3s ease;
transform: translateY(100%);
}
.tki-tree-cnt.show {
transform: translateY(0);
}
.tki-tree-bar {
background-color: #fff;
height: 72rpx;
padding-left: 20rpx;
padding-right: 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
border-bottom-width: 1rpx !important;
border-bottom-style: solid;
border-bottom-color: #f5f5f5;
font-size: 32rpx;
color: #757575;
line-height: 1;
}
.tki-tree-bar1 {
background-color: #fff;
}
.tki-tree-bar-confirm {
color: #07bb07;
}
.tki-tree-view {
position: absolute;
top: 0rpx;
right: 0rpx;
bottom: 0rpx;
left: 0rpx;
top: 160rpx;
background-color: #fff;
padding-top: 20rpx;
padding-right: 20rpx;
padding-bottom: 20rpx;
padding-left: 20rpx;
}
.tki-tree-view-sc {
height: 100%;
overflow: hidden;
}
.tki-tree-item {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 26rpx;
/* color: #757575; */
line-height: 1;
height: 0;
opacity: 0;
transition: 0.2s;
position: relative;
overflow: hidden;
}
.tki-tree-item.show {
height: 80rpx;
opacity: 1;
}
.tki-tree-item.showchild:before {
transform: rotate(90deg);
}
.tki-tree-item.last:before {
opacity: 0;
}
.tki-tree-icon {
width: 26rpx;
height: 26rpx;
margin-right: 8rpx;
}
.tki-tree-label {
flex: 1;
display: flex;
align-items: center;
height: 100%;
line-height: 1.2;
}
.tki-tree-check {
width: 40px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
}
.tki-tree-check-yes,
.tki-tree-check-no {
width: 20px;
height: 20px;
border-top-left-radius: 20%;
border-top-right-radius: 20%;
border-bottom-right-radius: 20%;
border-bottom-left-radius: 20%;
border-top-width: 1rpx;
border-left-width: 1rpx;
border-bottom-width: 1rpx;
border-right-width: 1rpx;
border-style: solid;
border-color: #07bb07;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
}
.tki-tree-check-yes-b {
width: 12px;
height: 12px;
border-top-left-radius: 20%;
border-top-right-radius: 20%;
border-bottom-right-radius: 20%;
border-bottom-left-radius: 20%;
background-color: #07bb07;
}
.tki-tree-check .radio {
border-top-left-radius: 50%;
border-top-right-radius: 50%;
border-bottom-right-radius: 50%;
border-bottom-left-radius: 50%;
}
.tki-tree-check .radio .tki-tree-check-yes-b {
border-top-left-radius: 50%;
border-top-right-radius: 50%;
border-bottom-right-radius: 50%;
border-bottom-left-radius: 50%;
}
.hover-c {
opacity: 0.6;
}
.search {
position: absolute;
left: 35rpx;
}
/* 基础输入框样式 */
.uni-input {
width: 95%;
height: 60rpx;
line-height: 60rpx;
border-radius: 20rpx;
/* font-size: 32rpx;
color: #333;
background: #f5f5f5;
width: 100%;
padding: 0 24rpx 0 60rpx;
box-sizing: border-box;
border: none; */
}
/* 聚焦态样式 */
.uni-input:focus {
background: #fff;
border: 2rpx solid #007aff;
}
/* 占位符样式 */
.uni-input::placeholder {
color: #999;
font-size: 28rpx;
}
/* 兼容微信小程序 */
.uni-input::-webkit-input-placeholder {
color: #999;
font-size: 28rpx;
}

View File

@@ -0,0 +1,177 @@
<template>
<view class="content">
<picker
mode="multiSelector"
@change="bindPickerChange"
@columnchange="handleColumnChange"
:value="multiIndex"
:range="onlyYear ? yearsArray : multiArray"
>
<view class="time-season">
<text>
<text v-if="showMonth">{{ year + '-' + season }} </text>
<text v-else-if="year">{{ year + (year ? '' : '') + (onlyYear ? '' : season) }} </text>
<text v-else class="prompt">请选择时间 </text>
</text>
</view>
</picker>
</view>
</template>
<script>
export default {
props: {
yearsMin: {
type: Number,
default: 5,
},
yearsMax: {
type: Number,
default: 0,
},
onlyYear: {
type: Boolean,
default: false,
},
showMonth: {
type: Boolean,
default: false,
},
},
data() {
const now = new Date()
this.currentYear = now.getFullYear() // 保存当前年份
this.currentMonth = now.getMonth() + 1 // 保存当前月份1-12
this.currentSeason = Math.ceil(this.currentMonth / 3) // 保存当前季度1-4
const yearArr = this.handleYear()
const seasonArr = ['一季度', '二季度', '三季度', '四季度']
const monthArr = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12']
return {
multiArray: [yearArr, this.showMonth ? monthArr : seasonArr],
multiIndex: [this.handleYear(true), 0],
yearsArray: [yearArr],
year: '',
season: '',
// 原始完整的时间数组(用于恢复)
fullMonthArr: [...monthArr],
fullSeasonArr: [...seasonArr]
}
},
created() {
const now = new Date()
this.year = now.getFullYear().toString()
const month = now.getMonth() + 1
// 初始化时就过滤当前年份的时间范围
this.updateTimeRange(this.currentYear)
if (this.showMonth) {
this.multiIndex = [5, month - 1]
this.season = month < 10 ? `0${month}` : `${month}`
} else {
let key = 0
if (month >= 1 && month <= 3) {
key = 0
this.season = '一季度'
} else if (month >= 4 && month <= 6) {
key = 1
this.season = '二季度'
} else if (month >= 7 && month <= 9) {
key = 2
this.season = '三季度'
} else {
key = 3
this.season = '四季度'
}
this.multiIndex = [5, key]
}
this.$emit('timeSeasonC', {
year: this.year,
season: this.season,
})
},
methods: {
// 处理年份
handleYear(nowYearIndex) {
let optionsArray = []
let years = new Date().getFullYear()
for (let i = years - this.yearsMin; i <= years + this.yearsMax; i++) {
optionsArray.push(i)
}
if (nowYearIndex) {
return optionsArray.indexOf(years)
}
return optionsArray
},
// 列变化事件:切换年份时动态调整时间范围
handleColumnChange(e) {
// 只有切换第一列(年份列)时才处理
if (e.detail.column === 0) {
const selectedYear = this.multiArray[0][e.detail.value]
// 更新时间范围(月份/季度)
this.updateTimeRange(selectedYear)
// 修正索引:如果当前选中的时间超出新范围,重置为最后一个选项
const timeLength = this.multiArray[1].length
if (this.multiIndex[1] >= timeLength) {
this.multiIndex[1] = timeLength - 1
}
}
},
// 核心:根据选中年份更新时间范围
updateTimeRange(selectedYear) {
if (this.onlyYear) return // 只选年份时无需处理
if (selectedYear === this.currentYear) {
// 当前年份:只显示到当前月/当前季度
if (this.showMonth) {
// 过滤月份只保留1到当前月
this.multiArray[1] = this.fullMonthArr.slice(0, this.currentMonth)
} else {
// 过滤季度只保留1到当前季度
this.multiArray[1] = this.fullSeasonArr.slice(0, this.currentSeason)
}
} else {
// 非当前年份:恢复完整的时间数组
this.multiArray[1] = this.showMonth ? [...this.fullMonthArr] : [...this.fullSeasonArr]
}
},
// 确认选择时间
bindPickerChange: function (e) {
this.multiIndex = e.detail.value
this.year = this.multiArray[0][this.multiIndex[0]]
if (this.onlyYear) {
this.$emit('timeSeasonC', { year: this.year })
} else {
this.season = this.multiArray[1][this.multiIndex[1]]
this.$emit('timeSeasonC', {
year: this.year,
season: this.season,
})
}
},
},
}
</script>
<style>
.content {
width: 100%;
height: 62rpx !important;
box-sizing: border-box;
background-color: #fff;
padding: 10rpx 20rpx;
line-height: 38rpx;
border: 1px solid #e5e5e5;
border-radius: 10rpx;
}
.time-season {
font-size: 28rpx;
}
.prompt {
font-size: 24rpx;
color: grey;
}
</style>

File diff suppressed because one or more lines are too long

44
main.js
View File

@@ -1,21 +1,23 @@
import App from './App' import App from './App'
import util from './common/js/util' import util from './common/js/util'
import request from './common/js/request' import request from './common/js/request'
import config from './common/js/config' import config from './common/js/config'
import cacheKey from './common/js/cacheKey' import cacheKey from './common/js/cacheKey'
import Vue from 'vue' import Vue from 'vue'
import share from "@/common/js/share.js"; import share from '@/common/js/share.js'
import uView from 'uview-ui'
Vue.config.productionTip = false Vue.config.productionTip = false
Vue.prototype.$request = request Vue.prototype.$request = request
Vue.prototype.$util = util Vue.prototype.$util = util
Vue.prototype.$config = config Vue.prototype.$config = config
Vue.prototype.$cacheKey = cacheKey Vue.prototype.$cacheKey = cacheKey
Vue.mixin(share); Vue.mixin(share)
App.mpType = 'app' Vue.use(uView)
const app = new Vue({ uni.$u.config.unit = 'rpx'
...App App.mpType = 'app'
}) const app = new Vue({
app.$mount() ...App,
})
app.$mount()

View File

@@ -2,8 +2,8 @@
"name" : "灿能物联", "name" : "灿能物联",
"appid" : "__UNI__88BC25B", "appid" : "__UNI__88BC25B",
"description" : "", "description" : "",
"versionName" : "1.6.81", "versionName" : "1.6.82",
"versionCode" : 169, "versionCode" : 170,
"transformPx" : false, "transformPx" : false,
"sassImplementationName" : "node-sass", "sassImplementationName" : "node-sass",
/* 5+App */ /* 5+App */
@@ -138,8 +138,9 @@
"proxy" : { "proxy" : {
"/api" : { "/api" : {
"https" : true, "https" : true,
"target" : "https://pqmcn.com:8092/api", // "target" : "https://pqmcn.com:8092/api",
// "target" : "http://192.168.1.103:10215", // "target" : "http://192.168.1.103:10215",
"target" : "http://192.168.1.103:10215",
"changOrigin" : true, "changOrigin" : true,
"pathRewrite" : { "pathRewrite" : {
"/api" : "" "/api" : ""
@@ -153,6 +154,9 @@
}, },
"unipush" : { "unipush" : {
"enable" : false "enable" : false
},
"sdkConfigs" : {
"maps" : {}
} }
}, },
"mp-toutiao" : { "mp-toutiao" : {

1611
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,30 +1,31 @@
{ {
"id": "yk-authpup", "id": "yk-authpup",
"name": "解决软件在运行时,未见向用户告知权限申请的目的,华为等上架被拒问题", "name": "解决软件在运行时,未见向用户告知权限申请的目的,华为等上架被拒问题",
"displayName": "解决软件在运行时,未见向用户告知权限申请的目的,华为等上架被拒问题", "displayName": "解决软件在运行时,未见向用户告知权限申请的目的,华为等上架被拒问题",
"version": "1.0.5", "version": "1.0.5",
"description": "解决软件在运行时,未见向用户告知权限申请的目的,华为等上架被拒问题", "description": "解决软件在运行时,未见向用户告知权限申请的目的,华为等上架被拒问题",
"keywords": [ "keywords": [
"uniapp", "uniapp",
"华为上架", "华为上架",
"权限", "权限",
"权限申请", "权限申请",
"权限判断" "权限判断"
], ],
"dcloudext": { "dcloudext": {
"category": [ "category": [
"前端组件", "前端组件",
"通用组件" "通用组件"
] ]
}, },
"dependencies": { "dependencies": {
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"echarts": "^5.6.0", "echarts": "^5.6.0",
"html2canvas": "^1.4.1", "html2canvas": "^1.4.1",
"image-tool": "^1.0.2", "image-tool": "^1.0.2",
"image-tools": "^1.4.0", "image-tools": "^1.4.0",
"jsrsasign": "^11.1.0", "jsrsasign": "^11.1.0",
"mqtt": "^3.0.0", "mqtt": "^3.0.0",
"pinyin-pro": "^3.26.0" "pinyin-pro": "^3.28.1",
} "uview-ui": "^2.0.38"
} }
}

View File

@@ -4,6 +4,7 @@
{ {
"path": "pages/index/index", "path": "pages/index/index",
"style": { "style": {
"enablePullDownRefresh": true, // 开启下拉刷新
"navigationStyle": "custom", "navigationStyle": "custom",
"pullToRefresh": { "pullToRefresh": {
"support":true, "support":true,
@@ -13,11 +14,47 @@
} }
}, },
{ {
"path": "pages/index/message", "path": "pages/index/message1",
"style": { "style": {
"navigationBarTitleText": "消息" "navigationBarTitleText": "消息",
"enablePullDownRefresh": true, // 开启下拉刷新
"pullToRefresh": {
"support":true,
"style": "circle",
"color":"#007aff"
},
"app-plus": {
"bounce": "none",
//关闭窗口回弹效果
"titleNView": {
// 窗口的标题
"titleAlign": "center",
"padding-right": "20rpx",
"buttons": [
{
"text": "一键已读",
"fontSize": "28rpx",
"select": false,
"width": "auto"
}
]
}
}
} }
}, },
{
"path": "pages/index/report",
"style": {
"navigationBarTitleText": "报表",
"enablePullDownRefresh": true, // 开启下拉刷新
"pullToRefresh": {
"support":true,
"style": "circle",
"color":"#007aff"
}
}
},
{ {
"path": "pages/index/mine", "path": "pages/index/mine",
"style": { "style": {
@@ -84,6 +121,19 @@
"navigationBarTitleText": "个性化推荐" "navigationBarTitleText": "个性化推荐"
} }
}, },
{
"path": "pages/index/comp/monitoringPoint",
"style": {
"navigationBarTitleText": "监测点电能质量信息"
}
},
{
"path": "pages/index/comp/targetInfo",
"style": {
"navigationBarTitleText": "指标详情"
}
},
{ {
"path": "pages/mine/system", "path": "pages/mine/system",
"style": { "style": {
@@ -130,7 +180,19 @@
"path": "pages/device/APF/detail", "path": "pages/device/APF/detail",
"style": { "style": {
"navigationBarTitleText": "APF 设备名称 + 型号", "navigationBarTitleText": "APF 设备名称 + 型号",
"enablePullDownRefresh": true "enablePullDownRefresh": true,
"pullToRefresh": {
"support":true,
"style": "circle",
"color":"#007aff"
}
}
},
{
"path": "pages/device/realTime/index",
"style": {
"navigationBarTitleText": "实时数据"
// "enablePullDownRefresh": true
} }
}, },
{ {
@@ -221,12 +283,36 @@
} }
} }
}, },
{
"path": "pages/message1/comp/preview",
"style": {
"navigationBarTitleText": "预览"
}
},
{ {
"path": "pages/message/messageDetail", "path": "pages/message/messageDetail",
"style": { "style": {
"navigationBarTitleText": "暂态事件详情" "navigationBarTitleText": "暂态事件详情"
} }
}, },
{
"path": "pages/message1/comp/transientDetails",
"style": {
"navigationBarTitleText": "暂态事件详情"
}
},
{
"path": "pages/message1/comp/steadyStateDetails",
"style": {
"navigationBarTitleText": "稳态事件详情"
}
},
{
"path": "pages/message1/comp/alarmDetails",
"style": {
"navigationBarTitleText": "运行告警详情"
}
},
{ {
"path": "pages/device/transfer", "path": "pages/device/transfer",
"style": { "style": {
@@ -347,12 +433,19 @@
"navigationBarTitleText": "关注工程配置" "navigationBarTitleText": "关注工程配置"
} }
}, },
{ {
"path": "pages/mine/serverSetting", "path": "pages/mine/serverSetting",
"style": { "style": {
"navigationBarTitleText": "服务内容配置" "navigationBarTitleText": "服务内容配置"
} }
}, },
{
"path": "pages/mine/transientSetting",
"style": {
"navigationBarTitleText": "暂态事件配置"
}
},
{ {
"path": "pages/user/erweima", "path": "pages/user/erweima",
"style": { "style": {
@@ -441,10 +534,16 @@
"text": "首页" "text": "首页"
}, },
{ {
"pagePath": "pages/index/message", "pagePath": "pages/index/message1",
"iconPath": "static/notice.png", "iconPath": "static/notice.png",
"selectedIconPath": "static/notice2.png", "selectedIconPath": "static/notice2.png",
"text": "消息" "text": "消息"
},
{
"pagePath": "pages/index/report",
"iconPath": "static/reportIco.png",
"selectedIconPath": "static/reportIco1.png",
"text": "报表"
}, },
{ {
"pagePath": "pages/index/mine", "pagePath": "pages/index/mine",
@@ -468,7 +567,8 @@
"easycom": { "easycom": {
"autoscan": true, "autoscan": true,
"custom": { "custom": {
"^rc-(.*)": "@/components/Cn-$1/Cn-$1.vue" "^rc-(.*)": "@/components/Cn-$1/Cn-$1.vue",
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
} }
}, },
"condition": { "condition": {

View File

@@ -1,62 +1,76 @@
<template> <template>
<Cn-page :loading="loading"> <Cn-page :loading="loading">
<view slot="body"> <view slot="body">
<view class="about"> <view class="about">
<view class="about-title">{{ deviceInfo.name }}</view> <view class="about-title">{{ deviceInfo.name }}</view>
<view class="about-text">设备类型{{ deviceInfo.devTypeName }}</view> <view class="about-text">设备类型{{ deviceInfo.devTypeName }}</view>
<view class="about-text">设备型号{{ deviceInfo.devModelName }}</view> <view class="about-text">设备型号{{ deviceInfo.devModelName }}</view>
<view class="about-text" <view class="about-text">设备接入方式{{ deviceInfo.devAccessMethod }}</view>
>设备接入方式{{ deviceInfo.devAccessMethod === 'cloud' ? 'CLD' : 'MQTT' }}</view <!-- <view class="about-text">设备注册时间永久使用</view> -->
> <view class="about-text">程序版本{{ deviceInfo.programVersionName }}</view>
<!-- <view class="about-text">设备注册时间永久使用</view> --> <view class="about-text">网络设备ID{{ deviceInfo.ndid }}</view>
<view class="about-text">程序版本{{ deviceInfo.programVersionName }}</view> </view>
<view class="about-text">网络设备ID{{ deviceInfo.ndid }}</view> </view>
</view> </Cn-page>
</view> </template>
</Cn-page> <script>
</template> import { queryDeivceById } from '@/common/api/device'
<script> import { queryByCode, queryCsDictTree, queryByid, queryEdDataPage } from '@/common/api/dictionary'
import { queryDeivceById } from '@/common/api/device' export default {
import { queryByCode, queryCsDictTree, queryByid, queryEdDataPage } from '@/common/api/dictionary' data() {
export default { return {
data() { loading: true,
return { deviceInfo: {},
loading: true, }
deviceInfo: {}, },
} methods: {},
}, onLoad(options) {
methods: {}, queryDeivceById(options.id).then((res) => {
onLoad(options) { this.deviceInfo = res.data[0]
queryDeivceById(options.id).then((res) => { if (this.deviceInfo.devAccessMethod == 'MQTT') {
console.log(res) queryByCode('Device_Type').then((res) => {
this.deviceInfo = res.data[0] Promise.all([queryCsDictTree(res.data.id), queryByid(res.data.id), queryEdDataPage()]).then(
queryByCode('Device_Type').then((res) => { (resp) => {
Promise.all([queryCsDictTree(res.data.id), queryByid(res.data.id), queryEdDataPage()]).then((resp) => { this.deviceInfo.devTypeName = resp[0].data.find(
console.log(resp) (item) => item.id === this.deviceInfo.devType,
this.deviceInfo.devTypeName = resp[0].data.find((item) => item.id === this.deviceInfo.devType)?.name )?.name
this.deviceInfo.devModelName = resp[1].data.find( this.deviceInfo.devModelName = resp[1].data.find(
(item) => item.id === this.deviceInfo.devModel, (item) => item.id === this.deviceInfo.devModel,
)?.name )?.name
this.loading = false this.loading = false
}) },
}) )
}) })
}, } else {
} queryByCode('DEV_CLD').then((res) => {
</script> this.deviceInfo.devTypeName = res.data.name
<style lang="scss"> Promise.all([queryCsDictTree(res.data.id), queryByid(res.data.id), queryEdDataPage()]).then(
.about { (resp) => {
padding: 34rpx; this.deviceInfo.devModelName = resp[1].data.find(
.about-title { (item) => item.id === this.deviceInfo.devModel,
font-size: 34rpx; )?.name
font-weight: bold; this.loading = false
color: #333333; },
margin-bottom: 34rpx; )
} })
.about-text { }
font-size: 28rpx; })
color: #666666; },
margin-bottom: 34rpx; }
} </script>
} <style lang="scss">
</style> .about {
padding: 34rpx;
.about-title {
font-size: 34rpx;
font-weight: bold;
color: #333333;
margin-bottom: 34rpx;
}
.about-text {
font-size: 28rpx;
color: #666666;
margin-bottom: 34rpx;
}
}
</style>

View File

@@ -1,151 +1,153 @@
<template> <template>
<view class="basic"> <view>
<view class="grid-card"> <uni-load-more status="loading" v-if="IOData.length == 0"></uni-load-more>
<view class="grid-card-title">温度</view> <view class="basic" v-else>
<view class="grid-card-content-4"> <view class="grid-card">
<template v-for="item in renderData"> <view class="grid-card-title">温度</view>
<view class="item item-title">{{ item[0].clDid }} <view class="grid-card-content-4">
<template v-if="item[0].clDid"> (°C)</template> <template v-for="item in renderData">
</view> <view class="item item-title">{{ item[0].clDid }}
<view class="item item-title">{{ item[1].clDid }} <template v-if="item[0].clDid"> (°C)</template>
<template v-if="item[1].clDid"> (°C)</template> </view>
</view> <view class="item item-title">{{ item[1].clDid }}
<view class="item item-title">{{ item[2].clDid }} <template v-if="item[1].clDid"> (°C)</template>
<template v-if="item[2].clDid"> (°C)</template> </view>
</view> <view class="item item-title">{{ item[2].clDid }}
<view class="item item-title">{{ item[3].clDid }} <template v-if="item[2].clDid"> (°C)</template>
<template v-if="item[3].clDid"> (°C)</template> </view>
</view> <view class="item item-title">{{ item[3].clDid }}
<view class="item">{{ item[0].clDid ? Math.round(item[0].value) || '-' : '' }}</view> <template v-if="item[3].clDid"> (°C)</template>
<view class="item">{{ item[1].clDid ? Math.round(item[1].value) || '-' : '' }}</view> </view>
<view class="item">{{ item[2].clDid ? Math.round(item[2].value) || '-' : '' }}</view> <view class="item">{{ item[0].clDid ? Math.round(item[0].value) || '-' : '' }}</view>
<view class="item">{{ item[3].clDid ? Math.round(item[3].value) || '-' : '' }}</view> <view class="item">{{ item[1].clDid ? Math.round(item[1].value) || '-' : '' }}</view>
</template> <view class="item">{{ item[2].clDid ? Math.round(item[2].value) || '-' : '' }}</view>
</view> <view class="item">{{ item[3].clDid ? Math.round(item[3].value) || '-' : '' }}</view>
</view> </template>
<!-- 运维管理员工程用户 可看 --> </view>
<view class="grid-card" v-if="userInfo.authorities=='operation_manager'||userInfo.authorities=='engineering_user'"> </view>
<view class="grid-card-title">状态</view> <!-- 运维管理员工程用户 可看 -->
<view class="grid-card-content-4"> <view class="grid-card"
<template v-for="(item, index) in moduleData"> v-if="(userInfo.authorities == 'operation_manager' || userInfo.authorities == 'engineering_user') && moduleData.length > 0">
<view class="item item-title">{{ item[0].moduleName }} <view class="grid-card-title">状态</view>
<template v-if="item[0].moduleName"></template> <view class="grid-card-content-4">
</view> <template v-for="(item, index) in moduleData">
<view class="item item-title">{{ item[1].moduleName }} <view class="item item-title">{{ item[0].moduleName }}
<template v-if="item[1].moduleName"></template> <template v-if="item[0].moduleName"></template>
</view> </view>
<view class="item item-title">{{ item[2].moduleName }} <view class="item item-title">{{ item[1].moduleName }}
<template v-if="item[2].moduleName"></template> <template v-if="item[1].moduleName"></template>
</view> </view>
<view class="item item-title">{{ item[3].moduleName }} <view class="item item-title">{{ item[2].moduleName }}
<template v-if="item[3].moduleName"></template> <template v-if="item[2].moduleName"></template>
</view> </view>
<!-- <uni-tag :text="item[0].moduleState" :type=" item[0].moduleState=='离线'?'error' : 'success'" /> --> <view class="item item-title">{{ item[3].moduleName }}
<view class="item">{{ item[0].moduleState }}</view> <template v-if="item[3].moduleName"></template>
<view class="item">{{ item[1].moduleState }}</view> </view>
<view class="item">{{ item[2].moduleState }}</view> <!-- <uni-tag :text="item[0].moduleState" :type=" item[0].moduleState=='离线'?'error' : 'success'" /> -->
<view class="item">{{ item[3].moduleState }}</view> <view class="item">{{ item[0].moduleState }}</view>
</template> <view class="item">{{ item[1].moduleState }}</view>
</view> <view class="item">{{ item[2].moduleState }}</view>
</view> <view class="item">{{ item[3].moduleState }}</view>
<!-- <view class="grid-card">--> </template>
<!-- <view class="grid-card-title">干接点</view>--> </view>
<!-- <view class="grid-card-content-4">--> </view>
<!-- <view class="item item-title">干接点1</view>--> <!-- <view class="grid-card">-->
<!-- <view class="item item-title">干接点2</view>--> <!-- <view class="grid-card-title">干接点</view>-->
<!-- <view class="item item-title"></view>--> <!-- <view class="grid-card-content-4">-->
<!-- <view class="item item-title"></view>--> <!-- <view class="item item-title">干接点1</view>-->
<!-- <view class="item">正常</view>--> <!-- <view class="item item-title">干接点2</view>-->
<!-- <view class="item">正常</view>--> <!-- <view class="item item-title"></view>-->
<!-- <view class="item"></view>--> <!-- <view class="item item-title"></view>-->
<!-- <view class="item"></view>--> <!-- <view class="item">正常</view>-->
<!-- </view>--> <!-- <view class="item">正常</view>-->
<!-- </view>--> <!-- <view class="item"></view>-->
</view> <!-- <view class="item"></view>-->
</template> <!-- </view>-->
<script> <!-- </view>-->
import { </view>
getModuleState </view>
} from '@/common/api/harmonic.js' </template>
export default { <script>
import { getModuleState } from '@/common/api/harmonic.js'
props: { export default {
IOData: { props: {
type: Array, IOData: {
default: () => { type: Array,
return [] default: () => {
}, return []
}, },
ndid: { },
type: String, ndid: {
}, type: String,
}, },
data() { },
return { data() {
list: [], return {
userInfo: {}, list: [],
flag: false userInfo: {},
} flag: false,
}, }
computed: { },
renderData() { computed: {
let arr = [] renderData() {
// 把IOData转换成每4个一组的二维数组 let arr = []
for (let i = 0; i < this.IOData.length; i += 4) {
this.IOData.slice(i, i + 4).forEach((item) => { // 把IOData转换成每4个一组的二维数组
if (Number.isInteger(item.value) || item.value == '') {} else { for (let i = 0; i < this.IOData.length; i += 4) {
item.value = (item.value - 0).toFixed(2) this.IOData.slice(i, i + 4).forEach((item) => {
} if (Number.isInteger(item.value) || item.value == '') {
}) } else {
arr.push(this.IOData.slice(i, i + 4)) item.value = (item.value - 0).toFixed(2)
} }
// 把每组的长度补齐到4 })
arr.forEach((item) => { arr.push(this.IOData.slice(i, i + 4))
if (item.length < 4) { }
let length = 4 - item.length // 把每组的长度补齐到4
for (let i = 0; i < length; i++) { arr.forEach((item) => {
item.push({}) if (item.length < 4) {
} let length = 4 - item.length
} for (let i = 0; i < length; i++) {
}) item.push({})
console.warn(arr) }
return arr }
}, })
moduleData() { return arr
let arr = [] },
// 把IOData转换成每4个一组的二维数组 moduleData() {
for (let i = 0; i < this.list.length; i += 4) { let arr = []
arr.push(this.list.slice(i, i + 4)) // 把IOData转换成每4个一组的二维数组
} for (let i = 0; i < this.list.length; i += 4) {
// 把每组的长度补齐到4 arr.push(this.list.slice(i, i + 4))
arr.forEach((item) => { }
if (item.length < 4) { // 把每组的长度补齐到4
let length = 4 - item.length arr.forEach((item) => {
for (let i = 0; i < length; i++) { if (item.length < 4) {
item.push({}) let length = 4 - item.length
} for (let i = 0; i < length; i++) {
} item.push({})
}) }
console.warn(arr) }
return arr })
}, console.warn(arr)
}, return arr
methods: { },
info() { },
getModuleState({ methods: {
id: this.ndid info() {
}).then((res) => { getModuleState({
this.list = res.data id: this.ndid,
}) }).then((res) => {
}, this.list = res.data
}, })
mounted() { },
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo) },
mounted() {
this.info() this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
},
} this.info()
</script> },
<style lang="scss"> }
.basic {} </script>
</style> <style lang="scss">
.basic {}
</style>

View File

@@ -1,172 +1,184 @@
<template> <template>
<view class="basic"> <view>
<view class="grid-card"> <uni-load-more status="loading"
<view class="grid-card-title">电网电流</view> v-if="renderData.电网电流.length == 0 || renderData.电网电压.length == 0 || renderData.负载电流.length == 0 || renderData.补偿电流.length == 0 "></uni-load-more>
<view class="grid-card-content-3"> <view class="basic" v-else>
<view class="item item-title">名称</view> <view class="grid-card">
<view class="item item-title">有效值(A)</view> <view class="grid-card-title">电网电流</view>
<view class="item item-title">畸变率(%)</view> <view class="grid-card-content-3">
<template v-for="(item, index) in renderData.电网电流"> <view class="item item-title">名称</view>
<view class="item">{{ item.phase }}</view> <view class="item item-title">有效值(A)</view>
<view class="item">{{ <view class="item item-title">畸变率(%)</view>
item['Apf_RmsI_Sys(A)'] > 0 ? item['Apf_RmsI_Sys(A)'].toFixed(2) : item['Apf_RmsI_Sys(A)'] <template v-for="(item, index) in renderData.电网电流">
}}</view> <view class="item">{{ item.phase }}</view>
<view class="item">{{ <view class="item">{{
item['Apf_ThdA_Sys(%)'] > 0 ? item['Apf_ThdA_Sys(%)'].toFixed(2) : item['Apf_ThdA_Sys(%)'] item['Apf_RmsI_Sys(A)'] > 0 ? item['Apf_RmsI_Sys(A)'].toFixed(2) : item['Apf_RmsI_Sys(A)']
}}</view> }}</view>
</template> <view class="item">{{
</view> item['Apf_ThdA_Sys(%)'] > 0 ? item['Apf_ThdA_Sys(%)'].toFixed(2) : item['Apf_ThdA_Sys(%)']
</view> }}</view>
<view class="grid-card"> </template>
<view class="grid-card-title">电网电压</view> </view>
<view class="grid-card-content-4"> </view>
<view class="item item-title">名称</view> <view class="grid-card">
<view class="item item-title">电压(V)</view> <view class="grid-card-title">网电</view>
<view class="item item-title">频率(Hz)</view> <view class="grid-card-content-4">
<view class="item item-title">畸变率(%)</view> <view class="item item-title">名称</view>
<template v-for="(item, index) in renderData.电网电压"> <view class="item item-title">电压(V)</view>
<view class="item">{{ item.phase }}</view> <view class="item item-title">频率(Hz)</view>
<view class="item">{{ <view class="item item-title">畸变率(%)</view>
item['Apf_PhV_Sys(V)'] > 0 ? item['Apf_PhV_Sys(V)'].toFixed(2) : item['Apf_PhV_Sys(V)'] <template v-for="(item, index) in renderData.电网电压">
}}</view> <view class="item">{{ item.phase }}</view>
<view class="item">{{ <view class="item">{{
item['Apf_Freq(Hz)'] > 0 ? item['Apf_Freq(Hz)'].toFixed(2) : item['Apf_Freq(Hz)'] item['Apf_PhV_Sys(V)'] > 0 ? item['Apf_PhV_Sys(V)'].toFixed(2) : item['Apf_PhV_Sys(V)']
}}</view> }}</view>
<view class="item">{{ <view class="item">{{
item['Apf_ThdU_Sys(%)'] > 0 ? item['Apf_ThdU_Sys(%)'].toFixed(2) : item['Apf_ThdU_Sys(%)'] item['Apf_Freq(Hz)'] > 0 ? item['Apf_Freq(Hz)'].toFixed(2) : item['Apf_Freq(Hz)']
}}</view> }}</view>
</template> <view class="item">{{
</view> item['Apf_ThdU_Sys(%)'] > 0 ? item['Apf_ThdU_Sys(%)'].toFixed(2) : item['Apf_ThdU_Sys(%)']
</view> }}</view>
<view class="grid-card"> </template>
<view class="grid-card-title">负载电流</view> </view>
<view class="grid-card-content-3"> </view>
<view class="item item-title">名称</view> <view class="grid-card">
<view class="item item-title">有效值(A)</view> <view class="grid-card-title">负载电流</view>
<view class="item item-title">畸变率(%)</view> <view class="grid-card-content-3">
<template v-for="(item, index) in renderData.负载电流"> <view class="item item-title">名称</view>
<view class="item">{{ item.phase }}</view> <view class="item item-title">有效值(A)</view>
<view class="item">{{ <view class="item item-title">畸变率(%)</view>
item['Apf_RmsI_Load(A)'] > 0 ? item['Apf_RmsI_Load(A)'].toFixed(2) : item['Apf_RmsI_Load(A)'] <template v-for="(item, index) in renderData.负载电流">
}}</view> <view class="item">{{ item.phase }}</view>
<view class="item">{{ <view class="item">{{
item['Apf_ThdA_Load(%)'] > 0 ? item['Apf_ThdA_Load(%)'].toFixed(2) : item['Apf_ThdA_Load(%)'] item['Apf_RmsI_Load(A)'] > 0
}}</view> ? item['Apf_RmsI_Load(A)'].toFixed(2)
</template> : item['Apf_RmsI_Load(A)']
</view> }}</view>
</view> <view class="item">{{
<view class="grid-card"> item['Apf_ThdA_Load(%)'] > 0
<view class="grid-card-title">补偿电流</view> ? item['Apf_ThdA_Load(%)'].toFixed(2)
<view class="grid-card-content-3"> : item['Apf_ThdA_Load(%)']
<view class="item item-title">名称</view> }}</view>
<view class="item item-title">有效值(A)</view> </template>
<view class="item item-title">负载率(%)</view> </view>
<template v-for="(item, index) in renderData.补偿电流"> </view>
<view class="item">{{ item.phase }}</view> <view class="grid-card">
<view class="item">{{ <view class="grid-card-title">补偿电流</view>
item['Apf_RmsI_TolOut(A)'] == 3.1415926 ? '-' : <view class="grid-card-content-3">
item['Apf_RmsI_TolOut(A)'] > 0 <view class="item item-title">名称</view>
? item['Apf_RmsI_TolOut(A)'].toFixed(2) <view class="item item-title">有效值(A)</view>
: item['Apf_RmsI_TolOut(A)'] <view class="item item-title">负载率(%)</view>
}}</view> <template v-for="(item, index) in renderData.补偿电流">
<view class="item">{{ <view class="item">{{ item.phase }}</view>
item['load_Rate'] == 3.1415926 ? '-' : item['load_Rate'] > 0 ? item['load_Rate'].toFixed(2) : <view class="item">{{
item['load_Rate'] item['Apf_RmsI_TolOut(A)'] == 3.1415926
}}</view> ? '-'
</template> : item['Apf_RmsI_TolOut(A)'] > 0
</view> ? item['Apf_RmsI_TolOut(A)'].toFixed(2)
</view> : item['Apf_RmsI_TolOut(A)']
</view> }}</view>
</template> <view class="item">{{
<script> item['load_Rate'] == 3.1415926
export default { ? '-'
data() { : item['load_Rate'] > 0
return { ? item['load_Rate'].toFixed(2)
renderData: { : item['load_Rate']
电网电流: [], }}</view>
电网电压: [], </template>
负载电流: [], </view>
补偿电流: [], </view>
未知: [], </view>
}, </view>
} </template>
}, <script>
props: { export default {
basicData: { data() {
type: Array, return {
default: () => { renderData: {
return [] 电网电流: [],
}, 电网电压: [],
}, 负载电流: [],
}, 补偿电流: [],
watch: { 未知: [],
basicData: { },
handler: function (newVal, oldVal) { }
newVal.forEach((item) => { },
if (item.phase === 'avg') { props: {
return basicData: {
} type: Array,
let key = '' default: () => {
switch (item.statisticalName) { return []
case 'Apf_RmsI_Sys(A)': },
key = '电网电流' },
break },
case 'Apf_ThdA_Sys(%)': watch: {
key = '电网电流' basicData: {
break handler: function (newVal, oldVal) {
case 'Apf_PhV_Sys(V)': newVal.forEach((item) => {
key = '电网电压' if (item.phase === 'avg') {
break return
case 'Apf_Freq(Hz)': }
key = '电网电压' let key = ''
break switch (item.statisticalName) {
case 'Apf_ThdU_Sys(%)': case 'Apf_RmsI_Sys(A)':
key = '电网电' key = '电网电'
break break
case 'Apf_RmsI_Load(A)': case 'Apf_ThdA_Sys(%)':
key = '负载电流' key = '电网电流'
break break
case 'Apf_ThdA_Load(%)': case 'Apf_PhV_Sys(V)':
key = '负载电流' key = '电网电压'
break break
case 'Apf_RmsI_TolOut(A)': case 'Apf_Freq(Hz)':
key = '补偿电流' key = '电网电压'
break break
case 'Apf_PhV_Sys(V)': case 'Apf_ThdU_Sys(%)':
key = '补偿电流' key = '电网电压'
break break
case 'Apf_PhV_Sys(V)': case 'Apf_RmsI_Load(A)':
key = '补偿电流' key = '负载电流'
break break
case 'load_Rate': case 'Apf_ThdA_Load(%)':
key = '补偿电流' key = '负载电流'
break break
default: case 'Apf_RmsI_TolOut(A)':
key = '未知' key = '补偿电流'
break break
} case 'Apf_PhV_Sys(V)':
key = '补偿电流'
let index = this.renderData[key].findIndex((item2) => { break
return item2.phase === item.phase case 'Apf_PhV_Sys(V)':
}) key = '补偿电流'
if (index > -1) { break
this.renderData[key][index][item.statisticalName] = item.statisticalData // case 'load_Rate':
} else { key = '补偿电流'
this.renderData[key].push({ break
phase: item.phase, default:
[item.statisticalName]: item.statisticalData, //, key = '未知'
}) break
} }
})
console.log(this.renderData) let index = this.renderData[key].findIndex((item2) => {
}, return item2.phase === item.phase
deep: true, })
immediate: true, if (index > -1) {
}, this.renderData[key][index][item.statisticalName] = item.statisticalData //
}, } else {
methods: {}, this.renderData[key].push({
} phase: item.phase,
</script> [item.statisticalName]: item.statisticalData, //,
<style lang="scss"> })
.basic {} }
</style> })
console.log(this.renderData)
},
deep: true,
immediate: true,
},
},
methods: {},
}
</script>
<style lang="scss">
.basic {}
</style>

View File

@@ -1,125 +1,134 @@
<template> <template>
<view class="basic"> <view>
<view class="grid-card"> <uni-load-more status="loading" v-if="renderData.电网侧.length == 0 || renderData.负载侧.length == 0"></uni-load-more>
<view class="grid-card-title">电网侧</view> <view class="basic" v-else>
<view class="grid-card-content-5"> <view class="grid-card">
<view class="item item-title">名称</view> <view class="grid-card-title">电网侧</view>
<view class="item item-title">有功功率(kW)</view> <view class="grid-card-content-5">
<view class="item item-title">无功功率(kVar)</view> <view class="item item-title">名称</view>
<view class="item item-title">视在功率(kVA)</view> <view class="item item-title">有功功率(kW)</view>
<view class="item item-title">功率因数</view> <view class="item item-title">无功功率(kVar)</view>
<template v-for="(item, index) in renderData.电网侧"> <view class="item item-title">视在功率(kVA)</view>
<view class="item">{{ item.phase }}</view> <view class="item item-title">功率因数</view>
<view class="item">{{ item['Apf_P_Sys(W)'] == '-' ? '-' : (item['Apf_P_Sys(W)'] / 1000).toFixed(2) }} <template v-for="(item, index) in renderData.电网侧">
</view> <view class="item">{{ item.phase }}</view>
<view class="item">{{ item['Apf_Q_Sys(Var)'] == '-' ? '-' : (item['Apf_Q_Sys(Var)'] / 1000).toFixed(2) }} <view class="item">{{ item['Apf_P_Sys(W)'] == '-' ? '-' : (item['Apf_P_Sys(W)'] /
</view> 1000).toFixed(2) }}
<view class="item">{{ item['Apf_S_Sys(VA)'] == '-' ? '-' : (item['Apf_S_Sys(VA)'] / 1000).toFixed(2) }} </view>
</view> <view class="item">{{ item['Apf_Q_Sys(Var)'] == '-' ? '-' : (item['Apf_Q_Sys(Var)'] /
<view class="item">{{ item['Apf_PF_Sys(null)'] || '-' }}</view> 1000).toFixed(2) }}
</template> </view>
</view> <view class="item">{{ item['Apf_S_Sys(VA)'] == '-' ? '-' : (item['Apf_S_Sys(VA)'] /
</view> 1000).toFixed(2) }}
<view class="grid-card"> </view>
<view class="grid-card-title">负载侧</view> <view class="item">{{ item['Apf_PF_Sys(null)'] || '-' }}</view>
<view class="grid-card-content-5"> </template>
<view class="item item-title">名称</view> </view>
<view class="item item-title">有功功率(kW)</view> </view>
<view class="item item-title">无功功率(kVar)</view> <view class="grid-card">
<view class="item item-title">视在功率(kVA)</view> <view class="grid-card-title">负载侧</view>
<view class="item item-title">功率因数</view> <view class="grid-card-content-5">
<template v-for="(item, index) in renderData.负载侧"> <view class="item item-title">名称</view>
<view class="item">{{ item.phase }}</view> <view class="item item-title">有功功率(kW)</view>
<view class="item">{{ item['Apf_P_Load(W)'] == '-' ? '-' : (item['Apf_P_Load(W)'] / 1000).toFixed(2) }} <view class="item item-title">无功功率(kVar)</view>
</view> <view class="item item-title">视在功率(kVA)</view>
<view class="item">{{ item['Apf_Q_Load(Var)'] == '-' ? '-' : (item['Apf_Q_Load(Var)'] / 1000).toFixed(2) <view class="item item-title">功率因数</view>
}}</view> <template v-for="(item, index) in renderData.负载侧">
<view class="item">{{ item['Apf_S_Load(VA)'] == '-' ? '-' : (item['Apf_S_Load(VA)'] / 1000).toFixed(2) }} <view class="item">{{ item.phase }}</view>
</view> <view class="item">{{ item['Apf_P_Load(W)'] == '-' ? '-' : (item['Apf_P_Load(W)'] /
<view class="item">{{ item['Apf_PF_Load(null)'] || '-' }}</view> 1000).toFixed(2) }}
</template> </view>
</view> <view class="item">{{
</view> item['Apf_Q_Load(Var)'] == '-' ? '-' : (item['Apf_Q_Load(Var)'] / 1000).toFixed(2)
</view> }}</view>
</template> <view class="item">{{ item['Apf_S_Load(VA)'] == '-' ? '-' : (item['Apf_S_Load(VA)'] /
<script> 1000).toFixed(2) }}
export default { </view>
data() { <view class="item">{{ item['Apf_PF_Load(null)'] || '-' }}</view>
return { </template>
renderData: { </view>
电网侧: [], </view>
负载侧: [], </view>
未知: [], </view>
}, </template>
} <script>
}, export default {
props: { data() {
basicData: { return {
type: Array, renderData: {
default: () => { 电网侧: [],
return [] 负载侧: [],
}, 未知: [],
}, },
}, }
watch: { },
basicData: { props: {
handler: function (newVal, oldVal) { basicData: {
newVal.forEach((item) => { type: Array,
if (item.phase === 'avg') { default: () => {
return return []
} },
let key = '' },
switch (item.statisticalName) { },
case 'Apf_P_Sys(W)': watch: {
key = '电网侧' basicData: {
break handler: function (newVal, oldVal) {
case 'Apf_Q_Sys(Var)': newVal.forEach((item) => {
key = '电网侧' if (item.phase === 'avg') {
break return
case 'Apf_S_Sys(VA)': }
key = '电网侧' let key = ''
break switch (item.statisticalName) {
case 'Apf_PF_Sys(null)': case 'Apf_P_Sys(W)':
key = '电网侧' key = '电网侧'
break break
case 'Apf_P_Load(W)': case 'Apf_Q_Sys(Var)':
key = '负载侧' key = '电网侧'
break break
case 'Apf_Q_Load(Var)': case 'Apf_S_Sys(VA)':
key = '负载侧' key = '电网侧'
break break
case 'Apf_S_Load(VA)': case 'Apf_PF_Sys(null)':
key = '负载侧' key = '电网侧'
break break
case 'Apf_PF_Load(null)': case 'Apf_P_Load(W)':
key = '负载侧' key = '负载侧'
break break
default: case 'Apf_Q_Load(Var)':
key = '未知' key = '负载侧'
break break
} case 'Apf_S_Load(VA)':
key = '负载侧'
let index = this.renderData[key].findIndex((item2) => { break
return item2.phase === item.phase case 'Apf_PF_Load(null)':
}) key = '负载侧'
if (index > -1) { break
this.renderData[key][index][item.statisticalName] = item.statisticalData || '-' default:
} else { key = '未知'
this.renderData[key].push({ break
phase: item.phase, }
[item.statisticalName]: item.statisticalData || '-',
}) let index = this.renderData[key].findIndex((item2) => {
} return item2.phase === item.phase
}) })
console.log(this.renderData) if (index > -1) {
}, this.renderData[key][index][item.statisticalName] = item.statisticalData || '-'
deep: true, } else {
immediate: true, this.renderData[key].push({
}, phase: item.phase,
}, [item.statisticalName]: item.statisticalData || '-',
methods: {}, })
} }
</script> })
<style lang="scss"> console.log(this.renderData)
.basic {} },
</style> deep: true,
immediate: true,
},
},
methods: {},
}
</script>
<style lang="scss">
.basic {}
</style>

View File

@@ -1,375 +1,385 @@
<template> <template>
<view> <view>
<div class="header-form"> <uni-load-more status="loading" v-if="basicData.length == 0"></uni-load-more>
<uni-data-select
v-model="parity" <view v-else>
:localdata="parityOption" <div class="header-form">
@change="initEcharts" <uni-data-select
style="flex: 1" v-model="parity"
:clear="false" :localdata="parityOption"
></uni-data-select> @change="initEcharts"
<!-- <uni-data-checkbox v-model="dataRadio" :localdata="dataOptions" @change="initEcharts"></uni-data-checkbox> --> style="flex: 1"
<uni-data-select :clear="false"
v-model="dataRadio" ></uni-data-select>
:localdata="dataOptions" <!-- <uni-data-checkbox v-model="dataRadio" :localdata="dataOptions" @change="initEcharts"></uni-data-checkbox> -->
@change="initEcharts" <uni-data-select
style="flex: 2; margin-left: 20rpx" v-model="dataRadio"
:clear="false" :localdata="dataOptions"
></uni-data-select> @change="initEcharts"
</div> style="flex: 2; margin-left: 20rpx"
<view class="charts-box"> :clear="false"
<!-- <view class="data-time">{{ time }}</view> --> ></uni-data-select>
<!-- <qiun-data-charts type="bar" :ontouch="true" :opts="opts" :chartData="chartData" /> --> </div>
<view style="width: 100%; height: 100%"><l-echart ref="chartRef" @finished="init"></l-echart></view> <view class="charts-box">
</view> <!-- <view class="data-time">{{ time }}</view> -->
</view> <!-- <qiun-data-charts type="bar" :ontouch="true" :opts="opts" :chartData="chartData" /> -->
</template> <view style="width: 100%; height: 100%"><l-echart ref="chartRef" @finished="init"></l-echart></view>
</view>
<script> </view>
import * as echarts from '@/uni_modules/lime-echart/static/echarts.min' </view>
export default { </template>
props: {
basicData: { <script>
type: Array, import * as echarts from '@/uni_modules/lime-echart/static/echarts.min'
default: () => [], export default {
}, props: {
dataTime: { basicData: {
type: [String, Number], type: Array,
default: '', default: () => [],
}, },
}, dataTime: {
data() { type: [String, Number],
return { default: '',
parityOption: [ },
{ },
text: '奇次', data() {
value: 2, return {
}, parityOption: [
{ {
text: '次', text: '次',
value: 1, value: 2,
}, },
], {
parity: 2, text: '偶次',
time: '', value: 1,
dataOptions: [], },
dataRadio: 0, ],
renderData: { parity: 2,
电网侧: { time: '',
Apf_HarmI: {}, dataOptions: [],
Apf_HarmUR: {}, dataRadio: 0,
}, renderData: {
负载: { 电网: {
Apf_HarmI: {}, Apf_HarmI: {},
Apf_HarmUR: {}, Apf_HarmUR: {},
}, },
}, 负载侧: {
chartData: {}, Apf_HarmI: {},
//您可以通过修改 config-ucharts.js 文件中下标为 ['column'] 的节点来配置全局默认参数,如都是默认参数,此处可以不传 opts 。实际应用过程中 opts 只需传入与全局默认参数中不一致的【某一个属性】即可实现同类型的图表显示不同的样式,达到页面简洁的需求。 Apf_HarmUR: {},
option: { },
tooltip: { },
trigger: 'axis', chartData: {},
axisPointer: { //您可以通过修改 config-ucharts.js 文件中下标为 ['column'] 的节点来配置全局默认参数,如都是默认参数,此处可以不传 opts 。实际应用过程中 opts 只需传入与全局默认参数中不一致的【某一个属性】即可实现同类型的图表显示不同的样式,达到页面简洁的需求。
type: 'shadow', option: {
}, tooltip: {
confine: true, trigger: 'axis',
}, axisPointer: {
color: [ type: 'shadow',
'#1890FF', },
'#91CB74', confine: true,
'#FAC858', },
'#EE6666', color: [
'#73C0DE', '#1890FF',
'#3CA272', '#91CB74',
'#FC8452', '#FAC858',
'#9A60B4', '#EE6666',
'#ea7ccc', '#73C0DE',
], '#3CA272',
legend: { '#FC8452',
data: ['电网侧', '负载侧'], '#9A60B4',
left: 0, '#ea7ccc',
}, ],
grid: { legend: {
left: 10, data: ['电网侧', '负载侧'],
right: 10, left: 0,
bottom: 15, },
top: 30, grid: {
containLabel: true, left: 10,
}, right: 10,
xAxis: [ bottom: 15,
{ top: 30,
type: 'value', containLabel: true,
},
axisLine: { xAxis: [
show: true, {
}, type: 'value',
minInterval: 0.5,
position: 'top', // 设置 x 轴在顶部 axisLine: {
}, show: true,
], },
yAxis: [ minInterval: 0.5,
{ position: 'top', // 设置 x 轴在顶部
type: 'category', },
axisTick: { show: false }, ],
data: [], yAxis: [
splitLine: { show: true }, {
axisLine: { type: 'category',
lineStyle: { axisTick: { show: false },
color: '#999999', data: [],
}, splitLine: { show: true },
}, axisLine: {
axisLabel: { lineStyle: {
color: '#666666', color: '#999999',
}, },
}, },
], axisLabel: {
series: [ color: '#666666',
{ },
name: '电网侧', },
type: 'bar', ],
label: { series: [
normal: { {
color: '#666', name: '电网侧',
show: true, type: 'bar',
position: 'right', label: {
fontSize: '8px', normal: {
color: '#666',
}, show: true,
}, position: 'right',
barGap: '10%', fontSize: '8px',
data: [], },
}, },
{ barGap: '10%',
name: '负载侧', data: [],
type: 'bar', },
barCateGoryGap:20, {
label: { name: '负载侧',
normal: { type: 'bar',
color: '#666', barCateGoryGap: 20,
show: true, label: {
position: 'right', normal: {
fontSize: '8px', color: '#666',
}, show: true,
}, position: 'right',
fontSize: '8px',
data: [], },
}, },
],
}, data: [],
opts: { },
// enableScroll: true, ],
dataLabel: false, },
color: [ opts: {
'#1890FF', // enableScroll: true,
'#91CB74', dataLabel: false,
'#FAC858', color: [
'#EE6666', '#1890FF',
'#73C0DE', '#91CB74',
'#3CA272', '#FAC858',
'#FC8452', '#EE6666',
'#9A60B4', '#73C0DE',
'#ea7ccc', '#3CA272',
], '#FC8452',
padding: [0, 20, 0, 0], '#9A60B4',
legend: { '#ea7ccc',
position: 'top', ],
float: 'left', padding: [0, 20, 0, 0],
}, legend: {
xAxis: { position: 'top',
// disableGrid: true, float: 'left',
boundaryGap: 'justify', },
itemCount: 8, xAxis: {
// scrollShow: true, // disableGrid: true,
data: [ boundaryGap: 'justify',
{ itemCount: 8,
min: 0, // scrollShow: true,
}, data: [
], {
min: 0, min: 0,
// max: 10, },
],
position: 'top', min: 0,
formatter: (value, index, opts) => { // max: 10,
console.log(123, value, index, opts)
}, position: 'top',
}, formatter: (value, index, opts) => {
yAxis: {}, console.log(123, value, index, opts)
extra: { },
bar: { },
type: 'group', yAxis: {},
width: 30, extra: {
meterBorde: 1, bar: {
meterFillColor: '#FFFFFF', type: 'group',
activeBgColor: '#000000', width: 30,
activeBgOpacity: 0.08, meterBorde: 1,
barBorderCircle: true, meterFillColor: '#FFFFFF',
seriesGap: 2, activeBgColor: '#000000',
categoryGap: 6, activeBgOpacity: 0.08,
}, barBorderCircle: true,
}, seriesGap: 2,
}, categoryGap: 6,
} },
}, },
watch: { },
basicData: { }
handler(newVal, oldVal) { },
console.log(this.basicData) watch: {
let basicData = JSON.parse(JSON.stringify(this.basicData)) basicData: {
// this.dataRadio = 0 handler(newVal, oldVal) {
this.renderData = { console.log(this.basicData)
电网侧: { let basicData = JSON.parse(JSON.stringify(this.basicData))
Apf_HarmI: {}, // this.dataRadio = 0
Apf_HarmUR: {}, this.renderData = {
}, 电网侧: {
负载侧: { Apf_HarmI: {},
Apf_HarmI: {}, Apf_HarmUR: {},
Apf_HarmUR: {}, },
}, 负载侧: {
} Apf_HarmI: {},
let arr = [ Apf_HarmUR: {},
{ },
name: '电网侧', }
key: 'Apf_HarmI_Sys', let arr = [
}, {
{ name: '电网侧',
name: '电网侧', key: 'Apf_HarmI_Sys',
key: 'Apf_HarmUR_Sys', },
}, {
{ name: '电网侧',
name: '负载侧', key: 'Apf_HarmUR_Sys',
key: 'Apf_HarmI_Load', },
}, {
{ name: '负载侧',
name: '负载侧', key: 'Apf_HarmI_Load',
key: 'Apf_HarmUR_Load', },
}, {
] name: '负载侧',
basicData.forEach((item) => { key: 'Apf_HarmUR_Load',
let have = arr.find((item2) => { },
return item.statisticalName.indexOf(item2.key) > -1 ]
}) basicData.forEach((item) => {
if (!have) return let have = arr.find((item2) => {
let name1 = have['name'] return item.statisticalName.indexOf(item2.key) > -1
let name2 = have.key.split('_')[0] + '_' + have.key.split('_')[1] })
if (this.renderData[name1][name2][item.phase]) { if (!have) return
this.renderData[name1][name2][item.phase][item.statisticalName] = item.statisticalData || 0 let name1 = have['name']
} else { let name2 = have.key.split('_')[0] + '_' + have.key.split('_')[1]
this.renderData[name1][name2][item.phase] = { if (this.renderData[name1][name2][item.phase]) {
[item.statisticalName]: item.statisticalData || 0, this.renderData[name1][name2][item.phase][item.statisticalName] = item.statisticalData || 0
} } else {
} this.renderData[name1][name2][item.phase] = {
}) [item.statisticalName]: item.statisticalData || 0,
console.log(this.renderData) }
let dataOptions = [] }
let type = [ })
{ console.log(this.renderData)
name: '谐波电流幅值', let dataOptions = []
key: 'Apf_HarmI', let type = [
}, {
{ name: '谐波电流幅值',
name: '谐波电压含有率', key: 'Apf_HarmI',
key: 'Apf_HarmUR', },
}, {
] name: '谐波电压含有率',
Object.keys(this.renderData['电网侧']['Apf_HarmI']).forEach((item, index) => { key: 'Apf_HarmUR',
type.forEach((item2) => { },
dataOptions.push({ ]
text: item + '相' + item2.name, Object.keys(this.renderData['电网侧']['Apf_HarmI']).forEach((item, index) => {
pointer: item2.key + '_' + item, type.forEach((item2) => {
value: dataOptions.length, dataOptions.push({
}) text: item + '相' + item2.name,
}) pointer: item2.key + '_' + item,
}) value: dataOptions.length,
this.dataOptions = dataOptions })
console.log(dataOptions) })
this.initEcharts() })
this.dataOptions = dataOptions
this.time = this.$util.parseTime(this.dataTime - 8 * 60 * 60) console.log(dataOptions)
}, this.initEcharts()
deep: true,
immediate: true, this.time = this.$util.parseTime(this.dataTime - 8 * 60 * 60)
}, },
}, deep: true,
methods: { immediate: true,
async init() { },
// chart 图表实例不能存在data里 },
const chart = await this.$refs.chartRef.init(echarts) methods: {
chart.setOption(this.option) async init() {
}, // chart 图表实例不能存在data里
initEcharts() { const chart = await this.$refs.chartRef.init(echarts)
setTimeout(() => { chart.setOption(this.option)
if(this.renderData['电网侧']['Apf_HarmI'][Object.keys(this.renderData['电网侧']['Apf_HarmI'])[0]] == undefined) return },
let obj = JSON.parse( initEcharts() {
JSON.stringify( setTimeout(() => {
this.renderData['电网侧']['Apf_HarmI'][Object.keys(this.renderData['电网侧']['Apf_HarmI'])[0]], if (
), this.renderData['电网侧']['Apf_HarmI'][Object.keys(this.renderData['电网侧']['Apf_HarmI'])[0]] ==
) undefined
let key = this.dataOptions[this.dataRadio].pointer.split('_') )
console.log(key) return
let name1 = key[0] + '_' + key[1] let obj = JSON.parse(
let name2 = key[2] JSON.stringify(
this.chartData = { this.renderData['电网侧']['Apf_HarmI'][Object.keys(this.renderData['电网侧']['Apf_HarmI'])[0]],
categories: Object.keys(obj) ),
.map((item) => { )
// Apf_HarmI_Sys_36(A) 匹配36 let key = this.dataOptions[this.dataRadio].pointer.split('_')
return Number(item.match(/\d+/)[0]) console.log(key)
}) let name1 = key[0] + '_' + key[1]
.filter((item) => { let name2 = key[2]
return item % 2 === this.parity - 1 this.chartData = {
}), categories: Object.keys(obj)
series: [ .map((item) => {
{ // Apf_HarmI_Sys_36(A) 匹配36
name: '电网侧', return Number(item.match(/\d+/)[0])
data: Object.values(this.renderData['电网侧'][name1][name2]).filter((item, index) => { })
return index % 2 === this.parity - 1 .filter((item) => {
}), return item % 2 === this.parity - 1
}, }),
{ series: [
name: '负载侧', {
data: Object.values(this.renderData['负载侧'][name1][name2]).filter((item, index) => { name: '电网侧',
return index % 2 === this.parity - 1 data: Object.values(this.renderData['电网侧'][name1][name2]).filter((item, index) => {
}), return index % 2 === this.parity - 1
}, }),
], },
} {
// /传值到echart name: '负载侧',
this.option.yAxis[0].data = Object.keys(obj) data: Object.values(this.renderData['负载侧'][name1][name2]).filter((item, index) => {
.map((item) => { return index % 2 === this.parity - 1
// Apf_HarmI_Sys_36(A) 匹配36 }),
return Number(item.match(/\d+/)[0]) },
}) ],
.filter((item) => { }
return item % 2 === this.parity - 1 // /传值到echart
}).reverse() this.option.yAxis[0].data = Object.keys(obj)
this.option.series[0].data = Object.values(this.renderData['电网侧'][name1][name2]).filter( .map((item) => {
(item, index) => { // Apf_HarmI_Sys_36(A) 匹配36
return index % 2 === this.parity - 1 return Number(item.match(/\d+/)[0])
}, })
).reverse().map(item=>item.toFixed(2)) .filter((item) => {
this.option.series[1].data = Object.values(this.renderData['负载侧'][name1][name2]).filter( return item % 2 === this.parity - 1
(item, index) => { })
return index % 2 === this.parity - 1 .reverse()
}, this.option.series[0].data = Object.values(this.renderData['电网侧'][name1][name2])
).reverse().map(item=>item.toFixed(2)) .filter((item, index) => {
this.init() return index % 2 === this.parity - 1
}, 100) })
}, .reverse()
}, .map((item) => item.toFixed(2))
} this.option.series[1].data = Object.values(this.renderData['负载侧'][name1][name2])
</script> .filter((item, index) => {
return index % 2 === this.parity - 1
<style lang="scss"> })
.charts-box { .reverse()
margin-top: 20rpx; .map((item) => item.toFixed(2))
height: 100vh; this.init()
.data-time { }, 100)
position: absolute; },
right: 20rpx; },
margin-top: 18rpx; }
font-size: 24rpx; </script>
}
} <style lang="scss">
.header-form { .charts-box {
display: flex; margin-top: 20rpx;
} height: 100vh;
</style> .data-time {
position: absolute;
right: 20rpx;
margin-top: 18rpx;
font-size: 24rpx;
}
}
.header-form {
display: flex;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -12,37 +12,24 @@
style="margin-top: 30rpx" style="margin-top: 30rpx"
> >
<view class="content-item-header-icon"> <view class="content-item-header-icon">
<image mode="aspectFill" :src="staticIcon" style="height: 60rpx; width: 60rpx"></image> <!-- <image mode="aspectFill" :src="staticIcon" style="height: 60rpx; width: 60rpx"></image> -->
<Cn-icon-transient :name="`运行告警`" />
</view> </view>
</uni-badge> </uni-badge>
<view class="content-item-header-right"> <view class="content-item-header-right">
<view class="content-item-header-right-title">{{ item.equipmentName }}</view> <view class="content-item-header-right-title">{{ item.equipmentName }}</view>
<!-- <view class="content-item-header-right-des">{{ item.engineeringName }} {{ item.projectName }}</view> -->
<view class="content-item-header-right-des">工程名称{{ item.engineeringName }}</view> <view class="content-item-header-right-des">工程{{ item.engineeringName }}</view>
<view class="content-item-header-right-des">项目名称{{ item.projectName }}</view> <view class="content-item-header-right-des">项目{{ item.projectName }}</view>
<!-- <view class="content-item-header-right-des">监测点名称{{ item.lineName }}</view> -->
<!-- <view class="content-item-header-right-des">暂态类型{{ item.showName }}</view> -->
<!-- <view class="content-item-header-right-des">{{ item.subTitle }}</view> -->
</view> </view>
<view class="ml10" v-if="type === '0' || item.status != '1'">🔍</view> <view class="ml10" v-if="type === '0' || item.status != '1'">
<uni-icons type="search" size="25" color="#376cf3"></uni-icons
></view>
</view> </view>
<view class="content-item-footer">{{ item.subTitle }}</view> <view class="content-item-footer">{{ item.subTitle }}</view>
</view> </view>
<!-- <uni-card
:title="item.equipmentName"
:extra="item.status == '1' ? '' : '未读'"
:sub-title="item.subTitle"
thumbnail="https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/unicloudlogo.png"
@click="jump(item)"
v-for="(item, index) in store.data"
:key="index"
>
<view class="term-list-bottom">
<view class="term-list-bottom-item" v-for="(item2, textIndex) in item.dataSet" :key="textIndex">
{{ item2.showName + ':' + (item2.value == 3.1415926 ? '-' : item2.value) + (item2.unit || '') }}
</view>
</view>
</uni-card> -->
<Cn-empty v-if="store.empty" style="padding-top: 400rpx"></Cn-empty> <Cn-empty v-if="store.empty" style="padding-top: 400rpx"></Cn-empty>
<uni-load-more <uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)" v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
@@ -112,8 +99,8 @@ export default {
this.store = this.DataSource('/cs-harmonic-boot/eventUser/queryEventpage') this.store = this.DataSource('/cs-harmonic-boot/eventUser/queryEventpage')
this.store.params.type = this.type this.store.params.type = this.type
this.store.params.deviceId = this.deviceId this.store.params.deviceId = this.deviceId
this.store.params.startTime = this.$util.getBeforeDays() this.store.params.startTime = this.$util.getBeforeDays()
this.store.params.endTime = this.$util.getToday() this.store.params.endTime = this.$util.getToday()
this.store.loadedCallback = () => { this.store.loadedCallback = () => {
this.store.data.forEach((item) => { this.store.data.forEach((item) => {
if (this.type === '3') { if (this.type === '3') {
@@ -141,17 +128,17 @@ export default {
this.store.reload() this.store.reload()
}, },
jump(item) { jump(item) {
if (this.type === '0') { // if (this.type === '0') {
let str = JSON.stringify(item).replace(/%/g, '百分比') let str = JSON.stringify(item).replace(/%/g, '百分比')
uni.navigateTo({ url: '/pages/message/messageDetail?detail=' + encodeURIComponent(str) }) uni.navigateTo({ url: '/pages/message/messageDetail?detail=' + encodeURIComponent(str) })
} else { // } else {
if (item.status != '1') { // if (item.status != '1') {
item.status = '1' // item.status = '1'
updateStatus({ // updateStatus({
eventIds: [item.id], // eventIds: [item.id],
}) // })
} // }
} // }
}, },
}, },
} }
@@ -176,10 +163,11 @@ export default {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 100rpx; width: 110rpx;
height: 100rpx; height: 110rpx;
border-radius: 8rpx; border-radius: 8rpx;
background: $uni-theme-color; // background: $uni-theme-color;
background-color: #376cf320;
} }
.content-item-header-right { .content-item-header-right {

View File

@@ -1,286 +1,292 @@
<template> <template>
<Cn-page :loading="loading" noPadding> <Cn-page :loading="loading" noPadding>
<view slot="body"> <view slot="body">
<view class="detail"> <view class="detail">
<view class="detail-header"> <view class="detail-header">
<view class="header"> <view class="header">
<image <image
src="http://localhost:8088/api/system-boot/file/download?filePath=topology/1aca98ceb22a1fc33b81d9101275ef1.png" src="http://localhost:8088/api/system-boot/file/download?filePath=topology/1aca98ceb22a1fc33b81d9101275ef1.png"
mode="widthFix" style="width: 100%" /> mode="widthFix" style="width: 100%" />
</view> </view>
<!-- <view class="des"> <!-- <view class="des">
<text>设备基础信息</text> <text>设备基础信息</text>
<text class="ml10">设备状态</text> <text class="ml10">设备状态</text>
</view> --> </view> -->
<view class="nav"> <view class="nav">
<view class="nav-menu" :class="{ 'nav-menu-active': navMenuActive == index }" <view class="nav-menu" :class="{ 'nav-menu-active': navMenuActive == index }"
v-for="(item, index) in navMenuList" :key="index" @click="navMenuClick(index)">{{ item.text v-for="(item, index) in navMenuList" :key="index" @click="navMenuClick(index)">{{ item.text
}} }}
</view> </view>
</view> </view>
</view> </view>
<view class="content"> <view class="content">
<DianWang v-if="navMenuActive == 0"></DianWang> <DianWang v-if="navMenuActive == 0"></DianWang>
<NiBian v-else-if="navMenuActive == 1"></NiBian> <NiBian v-else-if="navMenuActive == 1"></NiBian>
<ShuChu v-else-if="navMenuActive == 2"></ShuChu> <ShuChu v-else-if="navMenuActive == 2"></ShuChu>
<GanJieDian v-else-if="navMenuActive == 3"></GanJieDian> <GanJieDian v-else-if="navMenuActive == 3"></GanJieDian>
<ZhuangTaiLiang v-else-if="navMenuActive == 4"> </ZhuangTaiLiang> <ZhuangTaiLiang v-else-if="navMenuActive == 4"> </ZhuangTaiLiang>
<QiTa v-else-if="navMenuActive == 5"></QiTa> <QiTa v-else-if="navMenuActive == 5"></QiTa>
<view style="height: 20rpx"></view> <view style="height: 20rpx"></view>
</view> </view>
<!-- <uni-fab <!-- <uni-fab
ref="fab" ref="fab"
direction="vertical" direction="vertical"
horizontal="right" horizontal="right"
vertical="bottom" vertical="bottom"
:content="content" :content="content"
@trigger="trigger" @trigger="trigger"
/> --> /> -->
<hover-menu :btnList="content" @trigger='trigger'></hover-menu> <hover-menu :btnList="content" @trigger='trigger'></hover-menu>
</view> </view>
</view> </view>
</Cn-page> </Cn-page>
</template> </template>
<script> <script>
import DianWang from './comp/dianWang.vue' import DianWang from './comp/dianWang.vue'
import NiBian from './comp/niBian.vue' import NiBian from './comp/niBian.vue'
import ShuChu from './comp/shuChu.vue' import ShuChu from './comp/shuChu.vue'
import GanJieDian from './comp/ganJieDian.vue' import GanJieDian from './comp/ganJieDian.vue'
import ZhuangTaiLiang from './comp/zhuangTaiLiang.vue' import ZhuangTaiLiang from './comp/zhuangTaiLiang.vue'
import QiTa from './comp/qiTa.vue' import QiTa from './comp/qiTa.vue'
import { manualAccess } from '@/common/api/accessBoot' import { manualAccess } from '@/common/api/accessBoot'
import hoverMenu from '@/hover-menu/components/hover-menu/hover-menu.vue'; import hoverMenu from '@/hover-menu/components/hover-menu/hover-menu.vue';
export default { export default {
components: { components: {
DianWang, DianWang,
NiBian, NiBian,
ShuChu, ShuChu,
GanJieDian, GanJieDian,
ZhuangTaiLiang, ZhuangTaiLiang,
QiTa, QiTa,
hoverMenu hoverMenu
}, },
data() { data() {
return { return {
loading: false, loading: false,
navMenuActive: 0, navMenuActive: 0,
navHeight: 0, navHeight: 0,
pageOptions: {}, pageOptions: {},
navMenuList: [ navMenuList: [
{ {
text: '电网数据', text: '电网数据',
}, },
{ {
text: '逆变数据', text: '逆变数据',
}, },
{ {
text: '输出数据', text: '输出数据',
}, },
{ {
text: '干接点', text: '干接点',
}, },
{ {
text: '状态量', text: '状态量',
}, },
{ {
text: '其他', text: '其他',
}, },
], ],
content: [ content: [
{ {
iconPath: '/static/report.png', iconPath: '/static/tongji.png',
text: '告警', text: '事件',
}, },
{ // {
iconPath: '/static/record.png', // iconPath: '/static/record.png',
text: '记录', // text: '记录',
}, // },
{ {
iconPath: '/static/about.png', iconPath: '/static/about.png',
text: '关于', text: '关于',
}, },
{ // {
iconPath: '/static/access.png', // iconPath: '/static/access.png',
text: '接入', // text: '接入',
}, // },
], ],
} }
}, },
methods: { methods: {
trigger(e) { trigger(e) {
console.log(e) console.log(e)
if (e.text === '分享') { if (e.text === '分享') {
this.$refs.share.open() this.$refs.share.open()
} else if (e.text === '删除') { } else if (e.text === '删除') {
uni.showModal({ uni.showModal({
title: '提示', title: '提示',
content: '确定删除该设备吗?', content: '确定删除该设备吗?',
success: function (res) { success: function (res) {
if (res.confirm) { if (res.confirm) {
console.log('用户点击确定') console.log('用户点击确定')
} else if (res.cancel) { } else if (res.cancel) {
console.log('用户点击取消') console.log('用户点击取消')
} }
}, },
}) })
} else if (e.text === '下载') { } else if (e.text === '下载') {
this.$util.toast('下载成功') this.$util.toast('下载成功')
} else if (e.text === '记录') { } else if (e.text === '记录') {
uni.navigateTo({ url: '/pages/device/DVR/record' }) uni.navigateTo({ url: '/pages/device/DVR/record' })
} else if (e.text === '告警') { } else if (e.text === '事件') {
uni.navigateTo({ url: '/pages/device/DVR/report' }) uni.navigateTo({ url: '/pages/device/DVR/report' })
} else if (e.text === '关于') { } else if (e.text === '关于') {
uni.navigateTo({ url: '/pages/device/DVR/about' }) uni.navigateTo({ url: '/pages/device/DVR/about' })
} else if (e.text === '移交') { } else if (e.text === '移交') {
uni.navigateTo({ url: '/pages/device/transfer' }) uni.navigateTo({ url: '/pages/device/transfer' })
} else if (e.text === '反馈') { } else if (e.text === '反馈') {
uni.navigateTo({ url: '/pages/device/feedback' }) uni.navigateTo({ url: '/pages/device/feedback' })
} else if (e.text === '用户') { } else if (e.text === '用户') {
uni.navigateTo({ url: '/pages/device/user' }) uni.navigateTo({ url: '/pages/device/user' })
} else if (e.text === '接入') { } else if (e.text === '接入') {
manualAccess({ nDid: this.pageOptions.ndid }).then((res) => { manualAccess({ nDid: this.pageOptions.ndid }).then((res) => {
this.$util.toast(res.message) this.$util.toast(res.message)
}) })
} }
// this.$refs.fab.close() // this.$refs.fab.close()
}, },
navMenuClick(idx) { navMenuClick(idx) {
this.navMenuActive = idx this.navMenuActive = idx
uni.pageScrollTo({ scrollTop: 0, duration: 0 }) uni.pageScrollTo({ scrollTop: 0, duration: 0 })
}, },
init() { init() {
let userInfo = uni.getStorageSync(this.$cacheKey.userInfo) let userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
console.log(userInfo.authorities) console.log(userInfo.authorities)
switch (userInfo.authorities) { switch (userInfo.authorities) {
case 1: case 1:
this.content.splice( this.content.splice(
0, 0,
0, 0,
{ {
iconPath: '/static/version.png', iconPath: '/static/version.png',
text: '版本', text: '版本',
}, },
{ {
iconPath: '/static/template.png', iconPath: '/static/template.png',
text: '模版', text: '模版',
}, },
) )
break break
case 3: case 3:
this.content.splice(1, 0, { this.content.splice(1, 0, {
iconPath: '/static/transfer.png', iconPath: '/static/transfer.png',
text: '移交', text: '移交',
}) })
break break
case 4: case 4:
this.content.splice( this.content.splice(
0, 0,
0, 0,
{ {
iconPath: '/static/subordinate.png', iconPath: '/static/subordinate.png',
text: '用户', text: '用户',
}, },
{ {
iconPath: '/static/delate.png', iconPath: '/static/delate.png',
text: '删除', text: '删除',
}, },
) )
break break
case 5: case 5:
this.content.push({ this.content.push({
iconPath: '/static/feedback.png', iconPath: '/static/feedback.png',
text: '反馈', text: '反馈',
}) })
break break
default: default:
break break
} }
setTimeout(() => { if (this.userInfo.authorities === 'operation_manager') {
// 获取nav高度 this.content.push({
uni.createSelectorQuery() iconPath: '/static/access.png',
.select('.nav') text: '接入',
.boundingClientRect((rect) => { })
this.navHeight = rect.height }
}) setTimeout(() => {
.exec() // 获取nav高度
}, 1000) uni.createSelectorQuery()
}, .select('.nav')
}, .boundingClientRect((rect) => {
onLoad(options) { this.navHeight = rect.height
this.pageOptions = options })
this.init() .exec()
}, }, 1000)
} },
</script> },
<style lang="scss"> onLoad(options) {
.detail { this.pageOptions = options
this.init()
// background: $uni-theme-white; },
.header {} }
</script>
.des { <style lang="scss">
padding: 20rpx 20rpx 0; .detail {
font-size: 28rpx;
color: #999; // background: $uni-theme-white;
} .header {}
// .nav { .des {
// position: sticky; padding: 20rpx 20rpx 0;
// top: 0; font-size: 28rpx;
// left: 0; color: #999;
// padding-top: 20rpx; }
// display: flex;
// flex-wrap: wrap; // .nav {
// background: rgb(243, 244, 245); // position: sticky;
// top: 0;
// .nav-menu { // left: 0;
// padding: 10rpx 20rpx; // padding-top: 20rpx;
// margin-left: 20rpx; // display: flex;
// margin-bottom: 20rpx; // flex-wrap: wrap;
// font-size: 28rpx; // background: rgb(243, 244, 245);
// border-radius: 8rpx;
// background: $uni-theme-white; // .nav-menu {
// padding: 10rpx 20rpx;
// &-active { // margin-left: 20rpx;
// background: $uni-theme-color; // margin-bottom: 20rpx;
// color: #fff; // font-size: 28rpx;
// } // border-radius: 8rpx;
// } // background: $uni-theme-white;
// } // &-active {
// background: $uni-theme-color;
.content { // color: #fff;
box-sizing: border-box; // }
padding: 0 20rpx; // }
}
// }
.detail-header {
position: sticky; .content {
top: 0; box-sizing: border-box;
left: 0; padding: 0 20rpx;
z-index: 2; }
background: #f3f4f5;
} .detail-header {
} position: sticky;
top: 0;
/deep/ .uni-fab__circle--rightBottom { left: 0;
right: 8px !important; z-index: 2;
bottom: 8px !important; background: #f3f4f5;
} }
}
/deep/ .uni-fab--rightBottom {
right: 8px !important; /deep/ .uni-fab__circle--rightBottom {
bottom: 8px !important; right: 8px !important;
} bottom: 8px !important;
}
/deep/ .uni-fab__circle {
width: 50px; /deep/ .uni-fab--rightBottom {
height: 54px; right: 8px !important;
} bottom: 8px !important;
}
/deep/ .uni-fab__content--flexDirectionEnd {
width: 50px !important; /deep/ .uni-fab__circle {
// height: 50px !important; width: 50px;
} height: 54px;
</style> }
/deep/ .uni-fab__content--flexDirectionEnd {
width: 50px !important;
// height: 50px !important;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -1,379 +1,468 @@
<template> <template>
<Cn-page :loading="loading"> <Cn-page :loading="loading">
<template slot="body"> <template slot="body">
<view class="device"> <view class="device">
<view class="nav" :style="{ top: navTabHeight + 'px' }"> <view class="nav" :style="{ top: navTabHeight + 'px' }">
<view <view class="nav-menu" @click="selectEngineering"
class="nav-menu" >{{
:class="{ 'nav-menu-active': select.engineeringName }" select.engineeringName
@click="selectEngineering" ? select.engineeringName.length > 6
>{{ select.engineeringName || '全部工程' }} ? select.engineeringName.substring(0, 6) + '...'
<uni-icons : select.engineeringName
type="bottom" : '全部工程'
size="14" }}
:color="select.engineeringName ? '#376cf3' : '#666'" <uni-icons type="bottom" size="14"></uni-icons>
></uni-icons> </view>
</view> <picker
<picker @change="projectNameChange"
@change="projectNameChange" @cancel="select.selectProject = false"
@cancel="select.selectProject = false" :value="select.projectNameIndex"
:value="select.projectNameIndex" :range="filterProjectList"
:range="filterProjectList" range-key="text"
range-key="text" v-if="select.engineeringId"
v-if="select.engineeringId" >
> <view class="nav-menu" @click="select.selectProject = true">
<view {{
class="nav-menu" select.projectName
:class="{ 'nav-menu-active': select.projectName }" ? select.projectName.length > 6
@click="select.selectProject = true" ? select.projectName.substring(0, 6) + '...'
> : select.projectName
{{ : '全部项目'
select.projectName }}
? select.projectName.length > 6 <uni-icons type="top" size="14" v-if="select.selectProject"></uni-icons>
? select.projectName.substring(0, 6) + '...' <uni-icons type="bottom" size="14" v-else></uni-icons>
: select.projectName </view>
: '全部项目' </picker>
}} <picker
<uni-icons @change="runStatusChange"
type="top"
size="14" :value="select.runStatusIndex"
:color="select.projectName ? '#376cf3' : '#666'" :range="projectType"
v-if="select.selectProject" range-key="text"
></uni-icons> >
<uni-icons <view class="nav-menu">
type="bottom" {{
size="14" select.runStatusName
:color="select.projectName ? '#376cf3' : '#666'" ? select.runStatusName.length > 12
v-else ? select.runStatusName.substring(0, 12) + '...'
></uni-icons> : select.runStatusName
</view> : '全部状态'
</picker> }}
<picker <uni-icons type="top" size="14" v-if="select.runStatusSelect"></uni-icons>
@change="runStatusChange" <uni-icons type="bottom" size="14" v-else></uni-icons>
@cancel="select.runStatusSelect = false" </view>
:value="select.runStatusIndex" </picker>
:range="projectType" </view>
range-key="text"
> <view class="nav" style="padding: 0 10px !important">
<view <view style="flex: 1"></view>
class="nav-menu" <template v-if="transfer || share">
:class="{ 'nav-menu-active': select.runStatusName }" <view class="nav-menu nav-menu-btn" @click="cancel">取消</view>
@click="select.runStatusSelect = true" <view class="nav-menu nav-menu-btn" @click="submit">确定</view>
> </template>
{{ <template v-else-if="store.data.length">
select.runStatusName <view
? select.runStatusName.length > 4 class="nav-menu nav-menu-btn"
? select.runStatusName.substring(0, 4) + '...' @click="selectDevice('transfer')"
: select.runStatusName v-if="
: '全部状态' userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'
}} "
<uni-icons >移交
type="top" </view>
size="14" <view
:color="select.runStatusName ? '#376cf3' : '#666'" class="nav-menu nav-menu-btn"
v-if="select.runStatusSelect" @click="selectDevice('share')"
></uni-icons> v-if="userInfo.authorities === 'app_vip_user'"
<uni-icons >分享
type="bottom" </view>
size="14" </template>
:color="select.runStatusName ? '#376cf3' : '#666'" </view>
v-else
></uni-icons> <view class="content device" :style="{ minHeight: minHeight }">
</view> <uni-swipe-action>
</picker> <uni-swipe-action-item
<view style="flex: 1"></view> v-for="(item, index) in store.data"
<!-- <picker @change="runStatusChange" :value="select.projectTypeIndex" :range="projectType" range-key="text"> :threshold="0"
<view class="nav-menu" :class="{ 'nav-menu-active': select.projectType }" :right-options="item.isTop == 0 ? options1 : options12"
>{{ select.projectType || '类型' }} @click="bindClick($event, item)"
</view> >
</picker> --> <Cn-device-card :device="item" :key="index">
</view> <template v-slot:title>
<view class="content device" :style="{ minHeight: minHeight }"> <!-- 卡片标题 -->
<Cn-device-card v-for="(item, index) in store.data" :device="item" :key="index"> </Cn-device-card> <switch
<uni-load-more v-if="transfer || share"
v-if="store.status == 'loading' || (store.data && store.data.length > 0)" :checked="checkList.indexOf(item.equipmentId) > -1"
:status="store.status" style="transform: scale(0.8); position: relative; left: 20rpx"
></uni-load-more> @change="switchChange(item)"
<Cn-empty v-else></Cn-empty> />
</view> <view class="star-icon" v-else>
</view> <uni-icons type="search" size="25" color="#376cf3"></uni-icons>
</template> </view>
</Cn-page> </template>
</template> </Cn-device-card>
<script> </uni-swipe-action-item>
import { getProjectList } from '@/common/api/project' </uni-swipe-action>
import { queryDictData } from '@/common/api/dictionary' <uni-load-more
import list from '@/common/js/list' v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
export default { ></uni-load-more>
mixins: [list], <Cn-empty v-else></Cn-empty>
data() { </view>
return { </view>
loading: true, </template>
transfer: false, </Cn-page>
share: false, </template>
checkList: [], <script>
select: { import { getProjectList } from '@/common/api/project'
projectName: '', import { queryDictData } from '@/common/api/dictionary'
projectNameIndex: 0, import list from '@/common/js/list'
projectSelect: false, import { engineeringPinToTop } from '@/common/api/device'
engineeringName: '',
engineeringId: '', export default {
runStatusName: '', mixins: [list],
runStatusIndex: 0, data() {
runStatusSelect: false, return {
}, loading: true,
minHeight: 0, transfer: false,
navTabHeight: 0, share: false,
engineeringList: [], checkList: [],
projectList: [], select: {
projectType: [ projectName: '',
{ projectNameIndex: 0,
text: '全部', projectSelect: false,
value: '', engineeringName: '',
}, engineeringId: '',
{ runStatusName: '',
text: '离线', runStatusIndex: 0,
value: 1, runStatusSelect: false,
}, },
{ userInfo: {},
text: '在线', minHeight: 0,
value: 2, navTabHeight: 0,
}, engineeringList: [],
], projectList: [],
pageOptions: {}, projectType: [
} {
}, text: '全部',
watch: { value: '',
select: { },
handler(val, oldVal) { {
if (this.loading) return text: '离线',
this.store.params.projectId = value: 1,
val.projectNameIndex === 0 ? '' : this.filterProjectList[val.projectNameIndex].value },
this.store.params.runStatus = val.runStatusIndex === 0 ? '' : this.projectType[val.runStatusIndex].value {
this.store.params.engineerId = val.engineeringId || '' text: '在线',
this.store.reload() value: 2,
}, },
deep: true, ],
}, pageOptions: {},
}, options1: [
computed: { {
filterProjectList() { text: '置顶',
return this.projectList.filter( style: {
(item) => item.engineeringId === this.select.engineeringId || item.value === '-1', backgroundColor: '#376cf3',
) },
}, },
}, ],
onLoad(options) { options12: [
let engineering = uni.getStorageSync('engineering') {
this.pageOptions = options text: '取消',
switch (options.type) { style: {
case 'onLineDevs': backgroundColor: '#ccc',
this.select.runStatusIndex = 2 },
this.select.runStatusName = '在线' },
break ],
case 'offLineDevs': }
this.select.runStatusIndex = 1 },
this.select.runStatusName = '离线' watch: {
break select: {
case 'currentOnLineDevs': handler(val, oldVal) {
this.select.runStatusIndex = 2 if (this.loading) return
this.select.engineeringName = engineering.name this.store.params.projectId =
this.select.engineeringId = engineering.id val.projectNameIndex === 0 ? '' : this.filterProjectList[val.projectNameIndex].value
this.select.runStatusName = '在线' this.store.params.runStatus = val.runStatusIndex === 0 ? '' : this.projectType[val.runStatusIndex].value
break this.store.params.engineerId = val.engineeringId || ''
case 'currentOffLineDevs': this.store.reload()
this.select.runStatusIndex = 1 },
this.select.engineeringName = engineering.name deep: true,
this.select.engineeringId = engineering.id },
this.select.runStatusName = '离线' },
break computed: {
case 'allEngineering': filterProjectList() {
this.select.engineeringName = '' return this.projectList.filter(
this.select.engineeringId = '' (item) => item.engineeringId === this.select.engineeringId || item.value === '-1',
break )
case 'nowEngineering': },
this.select.engineeringName = engineering.name },
this.select.engineeringId = engineering.id created() {
break this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
default: },
break onLoad(options) {
} let engineering = uni.getStorageSync('engineering')
this.init() this.pageOptions = options
}, switch (options.type) {
onShow() { case 'onLineDevs':
let engineering = uni.getStorageSync('onceSelectEngineering') this.select.runStatusIndex = 2
if (engineering) { this.select.runStatusName = '在线'
uni.removeStorageSync('onceSelectEngineering') break
this.select.engineeringId = engineering.id case 'offLineDevs':
this.select.engineeringName = engineering.name this.select.runStatusIndex = 1
this.select.projectNameIndex = 0 this.select.runStatusName = '离线'
} break
}, case 'currentOnLineDevs':
methods: { this.select.runStatusIndex = 2
selectEngineering() { this.select.engineeringName = engineering.name
uni.navigateTo({ this.select.engineeringId = engineering.id
url: '/pages/home/selectEngineering?from=once', this.select.runStatusName = '在线'
}) break
}, case 'currentOffLineDevs':
deviceIcon(e) { this.select.runStatusIndex = 1
let str = '' this.select.engineeringName = engineering.name
switch (e) { this.select.engineeringId = engineering.id
case 1: this.select.runStatusName = '离线'
str = '/static/device_bad.png' break
break case 'allEngineering':
case 2: this.select.engineeringName = ''
str = '/static/device.png' this.select.engineeringId = ''
break break
default: case 'nowEngineering':
str = '/static/device.png' this.select.engineeringName = engineering.name
break this.select.engineeringId = engineering.id
} break
return str default:
}, break
switchChange(e) { }
console.log(e) this.init()
let index = this.checkList.indexOf(e.equipmentId) },
if (index > -1) { onShow() {
this.checkList.splice(index, 1) let engineering = uni.getStorageSync('onceSelectEngineering')
} else { if (engineering) {
this.checkList.push(e.equipmentId) uni.removeStorageSync('onceSelectEngineering')
} this.select.engineeringId = engineering.id
}, this.select.engineeringName = engineering.name
cancel() { this.select.projectNameIndex = 0
this.transfer = false this.select.projectName = ''
this.share = false this.getProjectList()
this.checkList = [] }
}, this.store && this.store.reload()
submit() { },
console.log(this.checkList) methods: {
if (this.checkList.length === 0) { bindClick(e, item) {
this.$util.toast('请选择设备') engineeringPinToTop({
return targetId: item.equipmentId,
} targetType: 1,
if (this.transfer) { userId: uni.getStorageSync(this.$cacheKey.userInfo).userIndex,
uni.navigateTo({ url: '/pages/device/transfer?id=' + this.checkList.join(',') }) }).then((res) => {
} else if (this.share) { if (res.code == 'A0000') {
uni.navigateTo({ url: '/pages/device/share?id=' + this.checkList.join(',') }) this.$util.toast('操作成功!')
} this.store.search()
this.cancel() } else {
}, this.$util.toast(res.message)
async init() { }
console.warn('init') })
this.getEngineeringList() },
this.getProjectList() selectEngineering() {
this.getDeviceList() uni.navigateTo({
}, url: '/pages/home/selectEngineering?from=once',
getDeviceList() { })
this.store = this.DataSource('/cs-device-boot/EquipmentDelivery/queryEquipmentByProject') },
this.store.params.engineerId = this.select.engineeringId deviceIcon(e) {
this.store.params.runStatus = let str = ''
this.select.runStatusIndex === 0 ? '' : this.projectType[this.select.runStatusIndex].value switch (e) {
this.store.params.pageSize = 50 case 1:
this.store.firstCallBack = (res) => { str = '/static/device_bad.png'
this.loading = false break
uni.createSelectorQuery() case 2:
.select('.uni-navbar') str = '/static/device.png'
.boundingClientRect((rect1) => { break
if (!rect1) return default:
this.navTabHeight = rect1.height str = '/static/device.png'
uni.createSelectorQuery() break
.select('.nav') }
.boundingClientRect((rect2) => { return str
if (!rect2) return },
// #ifdef H5 switchChange(e) {
this.minHeight = 'calc(100vh - ' + (this.navTabHeight + rect2.height + 50) + 'px)' console.log(e)
// #endif let index = this.checkList.indexOf(e.equipmentId)
// #ifdef APP-PLUS if (index > -1) {
this.minHeight = 'calc(100vh - ' + (this.navTabHeight + rect2.height) + 'px)' this.checkList.splice(index, 1)
console.log(this.minHeight) } else {
// #endif this.checkList.push(e.equipmentId)
}) }
.exec() },
}) cancel() {
.exec() this.transfer = false
} this.share = false
this.store.reload() this.checkList = []
}, },
getProjectList() { submit() {
this.projectList = uni.getStorageSync('projectList') console.log(this.checkList)
}, if (this.checkList.length === 0) {
getEngineeringList() { this.$util.toast('请选择设备')
this.engineeringList = uni.getStorageSync('engineeringList') return
}, }
queryDictData() { if (this.transfer) {
queryDictData('项目类型').then((res) => { uni.navigateTo({ url: '/pages/device/transfer?id=' + this.checkList.join(',') })
this.projectType = [ } else if (this.share) {
{ uni.navigateTo({ url: '/pages/device/share?id=' + this.checkList.join(',') })
text: '全部类型', }
value: '', this.cancel()
}, },
...res.data.map((item) => { async init() {
return { console.warn('init')
text: item.anotherName, this.getEngineeringList()
value: item.id, this.getProjectList()
} this.getDeviceList()
}), },
] getDeviceList() {
}) this.store = this.DataSource('/cs-device-boot/EquipmentDelivery/queryEquipmentByProject')
}, this.store.params.engineerId = this.select.engineeringId
submitFeedBack() { this.store.params.runStatus =
uni.navigateTo({ url: '/pages/home/feedback' }) this.select.runStatusIndex === 0 ? '' : this.projectType[this.select.runStatusIndex].value
}, this.store.params.pageSize = 50
runStatusChange(e) { this.store.firstCallBack = (res) => {
this.select.runStatusSelect = false this.loading = false
this.select.runStatusIndex = e.detail.value uni.createSelectorQuery()
if (e.detail.value === 0) { .select('.uni-navbar')
this.select.runStatusName = '' .boundingClientRect((rect1) => {
return if (!rect1) return
} this.navTabHeight = rect1.height
this.select.runStatusName = this.projectType[e.detail.value].text uni.createSelectorQuery()
}, .select('.nav')
projectNameChange(e) { .boundingClientRect((rect2) => {
this.select.selectProject = false if (!rect2) return
console.log(e) // #ifdef H5
this.select.projectNameIndex = e.detail.value this.minHeight = 'calc(100vh - ' + (this.navTabHeight + rect2.height + 50) + 'px)'
if (e.detail.value === 0) { // #endif
this.select.projectName = '' // #ifdef APP-PLUS
return this.minHeight = 'calc(100vh - ' + (this.navTabHeight + rect2.height) + 'px)'
} console.log(this.minHeight)
this.select.projectName = this.projectList[e.detail.value].text // #endif
}, })
registerDevice() { .exec()
uni.showModal({ })
title: '提示', .exec()
content: '请选择设备类型', }
confirmText: '直连设备', this.store.reload()
cancelText: '网关接入', },
cancelColor: '#007aff',
success: ({ confirm, cancel }) => { getProjectList() {
if (confirm) { getProjectList({
uni.navigateTo({ pageNum: 1,
url: '/pages/device/new', pageSize: 9999,
}) engineeringId: this.select.engineeringId,
} else if (cancel) { }).then((res) => {
uni.navigateTo({ console.log(res)
url: '/pages/gateway/list', let arr = [
}) {
} text: '全部项目',
}, value: '-1',
}) },
}, ...res.data.records.map((item) => {
registerGateway() { return {
uni.navigateTo({ text: item.name,
url: '/pages/gateway/new', value: item.id,
}) ...item,
}, }
navMenuClick(index) { }),
this.navMenuActive = index ]
}, this.projectList = arr
jump(item) { uni.setStorageSync('projectList', arr)
console.log(12321,item); })
uni.navigateTo({ },
url: '/pages/device/APF/detail?id=' + item.equipmentId + '&isPrimaryUser=' + item.isPrimaryUser + '&ndid=' + item.ndid, getEngineeringList() {
}) this.engineeringList = uni.getStorageSync('engineeringList')
}, },
}, queryDictData() {
} queryDictData('项目类型').then((res) => {
</script> this.projectType = [
<style lang="scss"></style> {
text: '全部类型',
value: '',
},
...res.data.map((item) => {
return {
text: item.anotherName,
value: item.id,
}
}),
]
})
},
submitFeedBack() {
uni.navigateTo({ url: '/pages/home/feedback' })
},
runStatusChange(e) {
this.select.runStatusSelect = false
this.select.runStatusIndex = e.detail.value
if (e.detail.value === 0) {
this.select.runStatusName = ''
return
}
this.select.runStatusName = this.projectType[e.detail.value].text
},
projectNameChange(e) {
this.select.selectProject = false
console.log(e)
this.select.projectNameIndex = e.detail.value
if (e.detail.value === 0) {
this.select.projectName = ''
return
}
this.select.projectName = this.projectList[e.detail.value].text
},
registerDevice() {
uni.showModal({
title: '提示',
content: '请选择设备类型',
confirmText: '直连设备',
cancelText: '网关接入',
cancelColor: '#007aff',
success: ({ confirm, cancel }) => {
if (confirm) {
uni.navigateTo({
url: '/pages/device/new',
})
} else if (cancel) {
uni.navigateTo({
url: '/pages/gateway/list',
})
}
},
})
},
registerGateway() {
uni.navigateTo({
url: '/pages/gateway/new',
})
},
navMenuClick(index) {
this.navMenuActive = index
},
jump(item) {
console.log(12321, item)
uni.navigateTo({
url:
'/pages/device/APF/detail?id=' +
item.equipmentId +
'&isPrimaryUser=' +
item.isPrimaryUser +
'&ndid=' +
item.ndid,
})
},
selectDevice(type) {
if (this.store.data.findIndex((item) => item.isPrimaryUser === '1') === -1) {
this.$util.toast('没有可操作的设备')
} else {
this[type] = true
}
}
},
}
</script>
<style lang="scss">
/deep/ .button-group--right {
padding: 0 0 20rpx;
}
</style>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,273 +1,280 @@
<template> <template>
<Cn-page :loading="loading" noPadding> <Cn-page :loading="loading" noPadding>
<view slot="body"> <view slot="body">
<view class="detail"> <view class="detail">
<view class="header"> <view class="header">
<view class="header-title" <view class="header-title"
>{{ engineering.name }} >{{ engineering.name }}
<!-- <view class="header-title-extra">用能</view> --> <!-- <view class="header-title-extra">用能</view> -->
</view> </view>
<view class="header-des-mini mb10" <view class="header-des-mini mb10"
>{{ engineering.provinceName + engineering.cityName }} {{ engineering.createTime }}</view >{{ engineering.provinceName + engineering.cityName }} {{ engineering.createTime }}</view
> >
<view class="header-des">工程描述{{ engineering.description }} </view> <view class="header-des">工程描述{{ engineering.description }} </view>
</view> </view>
<view class="nav"> <view class="nav">
<view <view
class="nav-menu" class="nav-menu"
:class="{ 'nav-menu-active': navMenuActive == index }" :class="{ 'nav-menu-active': navMenuActive == index }"
v-for="(item, index) in navMenuList" v-for="(item, index) in navMenuList"
:key="index" :key="index"
@click="navMenuClick(index)" @click="navMenuClick(index)"
>{{ item.text }} >{{ item.text }}
</view> </view>
</view> </view>
<view class="content" :style="{ minHeight: 'calc(100vh - ' + navHeight + 'px)' }"> <view class="content" :style="{ minHeight: 'calc(100vh - ' + navHeight + 'px)' }">
<view v-show="navMenuActive == 0"> <view v-show="navMenuActive == 0">
<uni-card <!-- extra="🔍" -->
:title="item.name" <uni-card
extra="🔍" :title="item.name"
@click="jumpProject(item)"
v-for="(item, index) in store.data" @click="jumpProject(item)"
:key="index" v-for="(item, index) in store.data"
> :key="index"
<view class="term-list-bottom"> >
<view class="term-list-bottom-item"> <view class="term-list-bottom">
<view>设备个数</view> <view class="term-list-bottom-item">
<view>{{ item.devNum }}</view> <view>设备个数</view>
</view> <view>{{ item.devNum }}</view>
<view class="term-list-bottom-item"> </view>
<view>创建时间</view> <view class="term-list-bottom-item">
<view>{{ item.createTime }}</view> <view>创建时间</view>
</view> <view>{{ item.createTime }}</view>
</view> </view>
</uni-card> </view>
<Cn-empty v-if="store.empty"></Cn-empty> </uni-card>
<uni-load-more <Cn-empty v-if="store.empty"></Cn-empty>
v-if="store.status == 'loading' || (store.data && store.data.length > 0)" <uni-load-more
:status="store.status" v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
></uni-load-more> :status="store.status"
</view> ></uni-load-more>
<view style="padding: 0 20rpx" v-show="navMenuActive == 2"> </view>
<image <view style="padding: 0 20rpx" v-show="navMenuActive == 2">
class="gplot gplot-box" <image
mode="aspectFill" class="gplot gplot-box"
src="/static/test2.pic.png" mode="aspectFill"
v-for="(item, key) in 3" src="/static/test2.pic.png"
:key="key" v-for="(item, key) in 3"
/> :key="key"
</view> />
</view> </view>
<uni-fab </view>
ref="fab" <uni-fab
direction="vertical" ref="fab"
horizontal="right" direction="vertical"
vertical="bottom" horizontal="right"
:content="content" vertical="bottom"
@trigger="trigger" :content="content"
v-if="content.length" @trigger="trigger"
/> v-if="content.length"
<uni-popup ref="share" type="share" background-color="#fff"> />
<uni-popup-share title="分享到"></uni-popup-share> <uni-popup ref="share" type="share" background-color="#fff">
</uni-popup> <uni-popup-share title="分享到"></uni-popup-share>
</view> </uni-popup>
</view> </view>
</Cn-page> </view>
</template> </Cn-page>
<script> </template>
import list from '../../common/js/list' <script>
import { deleteEngineering } from '../../common/api/engineering' import list from '../../common/js/list'
import { deleteEngineering } from '../../common/api/engineering'
export default {
mixins: [list], export default {
data() { mixins: [list],
return { data() {
loading: false, return {
engineering: '', loading: false,
navMenuList: [ engineering: '',
{ navMenuList: [
text: '项目', {
}, text: '项目',
// { },
// text: '拓扑图', // {
// }, // text: '拓扑图',
], // },
content: [ ],
// { content: [
// iconPath: '/static/share.png', // {
// text: '编辑', // iconPath: '/static/share.png',
// }, // text: '编辑',
// { // },
// iconPath: '/static/delate.png', // {
// text: '删除', // iconPath: '/static/delate.png',
// }, // text: '删除',
], // },
navHeight: 0, ],
navMenuActive: 0, navHeight: 0,
} navMenuActive: 0,
}, }
methods: { },
trigger(e) { methods: {
console.log(this.$refs) trigger(e) {
if (e.item.text == '移交') { console.log(this.$refs)
uni.navigateTo({ if (e.item.text == '移交') {
url: '/pages/gc/transfer', uni.navigateTo({
}) url: '/pages/gc/transfer',
} else if (e.item.text == '分享') { })
this.$refs.share.open() } else if (e.item.text == '分享') {
} else if (e.item.text == '编辑') { this.$refs.share.open()
uni.navigateTo({ } else if (e.item.text == '编辑') {
url: '/pages/engineering/new?engineering=' + encodeURIComponent(JSON.stringify(this.engineering)), uni.navigateTo({
}) url: '/pages/engineering/new?engineering=' + encodeURIComponent(JSON.stringify(this.engineering)),
} else if (e.item.text == '删除') { })
uni.showModal({ } else if (e.item.text == '删除') {
title: '提示', uni.showModal({
content: '删除工程后不可恢复,是否继续?', title: '提示',
success: (res) => { content: '删除工程后不可恢复,是否继续?',
if (res.confirm) { success: (res) => {
deleteEngineering(this.engineering.id).then((res) => { if (res.confirm) {
this.$util.toast('删除成功') deleteEngineering(this.engineering.id).then((res) => {
this.$util.refreshPrePage() this.$util.toast('删除成功')
}) this.$util.refreshPrePage()
} else if (res.cancel) { })
console.log('用户点击取消') } else if (res.cancel) {
} console.log('用户点击取消')
}, }
}) },
} })
}, }
navMenuClick(index) { },
this.navMenuActive = index navMenuClick(index) {
}, this.navMenuActive = index
goUserDetail() { },
uni.navigateTo({ goUserDetail() {
url: '/pages/mine/userDetail', uni.navigateTo({
}) url: '/pages/mine/userDetail',
}, })
del() { },
console.log('del') del() {
uni.showModal({ console.log('del')
title: '提示', uni.showModal({
content: '确定要移除该成员吗?', title: '提示',
success: function (res) { content: '确定要移除该成员吗?',
if (res.confirm) { success: function (res) {
console.log('用户点击确定') if (res.confirm) {
} else if (res.cancel) { console.log('用户点击确定')
console.log('用户点击取消') } else if (res.cancel) {
} console.log('用户点击取消')
}, }
}) },
}, })
goDevice() { },
uni.navigateTo({ goDevice() {
url: '/pages/device/APF/detail', uni.navigateTo({
}) url: '/pages/device/APF/detail',
}, })
jumpProject(item) { },
uni.navigateTo({ jumpProject(item) {
url: '/pages/project/detail?project=' + encodeURIComponent(JSON.stringify(item)), uni.navigateTo({
}) url: '/pages/project/detail?project=' + encodeURIComponent(JSON.stringify(item)),
}, })
init() { },
this.store = this.DataSource('/cs-device-boot/project/queryProject') init() {
this.store.params.engineeringId = this.engineering.id this.store = this.DataSource('/cs-device-boot/project/queryProject')
this.store.reload() this.store.params.engineeringId = this.engineering.id
}, this.store.reload()
}, },
onLoad(option) { },
this.engineering = JSON.parse(decodeURIComponent(option.engineering)) onLoad(option) {
let userInfo = uni.getStorageSync('userInfo') this.engineering = JSON.parse(decodeURIComponent(option.engineering))
if (userInfo.authorities == 'engineering_user' || userInfo.authorities == 'app_vip_user') { let userInfo = uni.getStorageSync('userInfo')
this.content.push( if (userInfo.authorities == 'engineering_user' || userInfo.authorities == 'app_vip_user') {
{ this.content.push(
iconPath: '/static/share.png', {
text: '编辑', iconPath: '/static/share.png',
}, text: '编辑',
{ },
iconPath: '/static/delate.png', {
text: '删除', iconPath: '/static/delate.png',
}, text: '删除',
) },
} )
setTimeout(() => { }
// 获取nav高度 setTimeout(() => {
uni.createSelectorQuery() // 获取nav高度
.select('.nav') uni.createSelectorQuery()
.boundingClientRect((rect) => { .select('.nav')
this.navHeight = rect.height .boundingClientRect((rect) => {
}) this.navHeight = rect.height
.exec() })
}, 1000) .exec()
this.init() }, 1000)
// uni.setNavigationBarTitle({ title: this.engineering }) this.init()
}, // uni.setNavigationBarTitle({ title: this.engineering })
} },
</script> }
<style lang="scss"> </script>
.detail { <style lang="scss">
.content { .detail {
box-sizing: border-box; .content {
padding-bottom: 20rpx; box-sizing: border-box;
} padding-bottom: 20rpx;
}
.header {
padding: 20rpx 20rpx 0; .header {
padding: 20rpx 20rpx 0;
.header-title {
display: flex; .header-title {
justify-content: space-between; display: flex;
align-items: center; justify-content: space-between;
font-size: 40rpx; align-items: center;
margin-bottom: 10rpx; font-size: 40rpx;
margin-bottom: 10rpx;
.header-title-extra {
font-size: 24rpx; .header-title-extra {
color: #666; font-size: 24rpx;
padding-right: 10rpx; color: #666;
} padding-right: 10rpx;
} }
}
.header-des {
font-size: 28rpx; .header-des {
color: #666; font-size: 28rpx;
} color: #666;
.header-des-mini { }
font-size: 24rpx; .header-des-mini {
color: #999; font-size: 24rpx;
} color: #999;
} }
}
.footer-btn {
padding: 0 20rpx; .footer-btn {
height: 50rpx; padding: 0 20rpx;
background-color: #007aff; height: 50rpx;
font-size: 24rpx; background-color: #007aff;
color: #fff; font-size: 24rpx;
text-align: center; color: #fff;
line-height: 50rpx; text-align: center;
border-radius: 10rpx; line-height: 50rpx;
} border-radius: 10rpx;
} }
}
.gplot {
position: relative; .gplot {
width: 100%; position: relative;
border: 8rpx solid #ccc; width: 100%;
} border: 8rpx solid #ccc;
}
.term-list-bottom {
.term-list-bottom-item { .term-list-bottom {
font-size: 28rpx; .term-list-bottom-item {
margin-bottom: 20rpx; font-size: 28rpx;
display: flex; // margin-bottom: 20rpx;
justify-content: space-between; display: flex;
// view:first-of-type{ justify-content: space-between;
// color: #111; // view:first-of-type{
// } // color: #111;
} // }
}
.term-list-bottom-item:last-of-type {
margin-bottom: 0; .term-list-bottom-item:last-of-type {
} margin-bottom: 0;
} }
</style> }
/deep/ .uni-card__content {
padding: 5px 10px 10px !important;
}
/deep/ .uni-card__header-content-title {
font-weight: 700;
}
</style>

View File

@@ -1,188 +1,245 @@
<template> <template>
<view :loading="loading"> <view :loading="loading">
<!-- <uni-nav-bar left-icon="left" right-icon="cart" title="标题" /> --> <!-- <uni-nav-bar left-icon="left" right-icon="cart" title="标题" /> -->
<uni-nav-bar <uni-nav-bar dark :fixed="true" status-bar left-icon="left" :rightIcon="userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'
dark ? 'plusempty'
:fixed="true" : ''
status-bar " background-color="#fff" color="#111" title="工程管理" @clickLeft="back" @clickRight="add" />
left-icon="left" <uni-search-bar v-model="store.params.name" clearButton="none" bgColor="#fff" placeholder="请输入关键词"
:rightIcon=" @input="store.search()"></uni-search-bar>
userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user' <view class="message">
? 'plusempty'
: ''
" <uni-swipe-action>
background-color="#fff" <uni-swipe-action-item v-for="(item, index) in store.data"
color="#111" :style="{ marginTop: index === 0 ? '0' : '' }" :key="index" :threshold="0"
title="工程管理" :right-options="item.isTop == 0 ? options1 : options12" @click="bindClick($event, item)">
@clickLeft="back" <!-- extra="🔍" -->
@clickRight="add" <uni-card class="boxClick" :title="item.name" @click="jump(item)">
/> <view class="term-list-bottom">
<uni-search-bar <view class="term-list-bottom-item">
v-model="store.params.name" <view>区域</view>
clearButton="none" <view>{{ item.provinceName + item.cityName }}</view>
bgColor="#fff" </view>
placeholder="请输入关键词" <view class="term-list-bottom-item">
@input="store.search()" <view>创建时间</view>
></uni-search-bar> <view>{{ item.createTime }}</view>
<view class="message"> </view>
<uni-card </view>
:title="item.name" <view class="pinToTop" v-if="item.isTop == 1"> 置顶 </view>
extra="🔍" </uni-card>
@click="jump(item)" </uni-swipe-action-item>
v-for="(item, index) in store.data" </uni-swipe-action>
:style="{ marginTop: index === 0 ? '0' : '' }"
:key="index"
>
<view class="term-list-bottom">
<view class="term-list-bottom-item"> <Cn-empty v-if="store.empty" style="padding-top: 400rpx"></Cn-empty>
<view>区域</view> <uni-load-more v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
<view>{{ item.provinceName + item.cityName }}</view> :status="store.status"></uni-load-more>
</view> </view>
<view class="term-list-bottom-item"> </view>
<view>创建时间</view> </template>
<view>{{ item.createTime }}</view>
</view> <script>
</view> import list from '../../common/js/list'
</uni-card> import { engineeringPinToTop } from '@/common/api/device'
<Cn-empty v-if="store.empty" style="padding-top: 400rpx"></Cn-empty>
<uni-load-more export default {
v-if="store.status == 'loading' || (store.data && store.data.length > 0)" mixins: [list],
:status="store.status" data() {
></uni-load-more> return {
</view> loading: true,
</view> userInfo: {},
</template> options1: [
{
<script> text: '置顶',
import list from '../../common/js/list' style: {
backgroundColor: '#376cf3',
export default { },
mixins: [list], },
data() { ],
return { options12: [
loading: true, {
userInfo: {}, text: '取消',
} style: {
}, backgroundColor: '#ccc',
methods: { },
init() { },
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo) ],
this.store = this.DataSource('/cs-device-boot/engineering/queryEngineeringPage') }
this.store.params.name = '' },
this.store.reload() methods: {
this.store.firstCallBack = (res) => { bindClick(e, item) {
let engineering = uni.getStorageSync('engineering') engineeringPinToTop({
if (!engineering) { targetId: item.id,
uni.setStorageSync('engineering', this.store.data[0]) targetType: 2,
} else { userId: uni.getStorageSync(this.$cacheKey.userInfo).userIndex,
this.store.data.forEach((item) => { }).then((res) => {
if (item.id == engineering.id) { if (res.code == 'A0000') {
uni.setStorageSync('engineering', item) this.$util.toast('操作成功!')
} this.store.search()
}) } else {
} this.$util.toast(res.message)
} }
}, })
back() { },
uni.navigateBack() init() {
}, this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
add() { this.store = this.DataSource('/cs-device-boot/engineering/queryEngineeringPage')
if (this.userInfo.authorities === 'app_vip_user' || this.userInfo.authorities === 'engineering_user') { this.store.params.name = ''
uni.navigateTo({ this.store.reload()
url: `/pages/engineering/new`, this.store.firstCallBack = (res) => {
}) let engineering = uni.getStorageSync('engineering')
} if (!engineering) {
}, uni.setStorageSync('engineering', this.store.data[0])
upgrade(code) { } else {
console.log(code) this.store.data.forEach((item) => {
uni.showToast({ if (item.id == engineering.id) {
title: '升级成功', uni.setStorageSync('engineering', item)
icon: 'none', }
}) })
}, }
jump(engineering) { }
uni.navigateTo({ },
url: `/pages/engineering/detail?engineering=${encodeURIComponent(JSON.stringify(engineering))}`, back() {
}) uni.navigateBack()
}, },
}, add() {
if (this.userInfo.authorities === 'app_vip_user' || this.userInfo.authorities === 'engineering_user') {
onLoad() { uni.navigateTo({
this.init() url: `/pages/engineering/new`,
}, })
} }
</script> },
upgrade(code) {
<style lang="scss"> console.log(code)
.message { uni.showToast({
.message-header { title: '升级成功',
padding: 200rpx 34rpx 34rpx; icon: 'none',
display: flex; })
align-items: center; },
background: $uni-theme-white; jump(engineering) {
margin-bottom: 20rpx; uni.navigateTo({
box-shadow: 0 4rpx 8rpx #e7e7e74c; url: `/pages/engineering/detail?engineering=${encodeURIComponent(JSON.stringify(engineering))}`,
})
.message-header-head { },
margin-right: 30rpx; },
height: 128rpx;
width: 128rpx; onLoad() {
border-radius: $uni-theme-radius; this.init()
overflow: hidden; },
} }
</script>
.message-header-name {
margin-right: 30rpx; <style lang="scss">
flex: 1; .message {
font-size: 36rpx; .message-header {
color: #111; padding: 200rpx 34rpx 34rpx;
font-weight: 700; display: flex;
align-items: center;
.tag { background: $uni-theme-white;
margin-top: 10rpx; margin-bottom: 20rpx;
font-size: 24rpx; box-shadow: 0 4rpx 8rpx #e7e7e74c;
color: #aaa;
} .message-header-head {
} margin-right: 30rpx;
} height: 128rpx;
width: 128rpx;
.message-nav { border-radius: $uni-theme-radius;
padding: 34rpx; overflow: hidden;
display: flex; }
align-items: center;
background: $uni-theme-white; .message-header-name {
border-bottom: 1rpx solid #e8e8e8; margin-right: 30rpx;
flex: 1;
&-icon { font-size: 36rpx;
margin-right: 30rpx; color: #111;
height: 44rpx; font-weight: 700;
width: 44rpx;
border-radius: $uni-theme-radius; .tag {
overflow: hidden; margin-top: 10rpx;
} font-size: 24rpx;
color: #aaa;
&-label { }
margin-right: 30rpx; }
flex: 1; }
font-size: 28rpx;
color: #111; .message-nav {
} padding: 34rpx;
} display: flex;
} align-items: center;
background: $uni-theme-white;
.term-list-bottom { border-bottom: 1rpx solid #e8e8e8;
.term-list-bottom-item {
font-size: 28rpx; &-icon {
margin-bottom: 20rpx; margin-right: 30rpx;
display: flex; height: 44rpx;
justify-content: space-between; width: 44rpx;
// view:first-of-type{ border-radius: $uni-theme-radius;
// color: #111; overflow: hidden;
// } }
}
&-label {
.term-list-bottom-item:last-of-type { margin-right: 30rpx;
margin-bottom: 0; flex: 1;
} font-size: 28rpx;
} color: #111;
</style> }
}
}
.term-list-bottom {
.term-list-bottom-item {
font-size: 28rpx;
// margin-bottom: 20rpx;
display: flex;
justify-content: space-between;
// view:first-of-type{
// color: #111;
// }
}
.term-list-bottom-item:last-of-type {
margin-bottom: 0;
}
}
/deep/ .uni-card--border {
margin: 0 10px !important;
padding-bottom: 10px;
}
/deep/ .uni-swipe {
margin-bottom: 10px;
}
.pinToTop {
background-color: $uni-theme-color;
width: 100rpx;
height: 60rpx;
line-height: 90rpx;
text-align: center;
color: #fff;
font-size: 20rpx;
position: absolute;
top: 0rpx;
right: 0rpx;
position: absolute;
top: 0;
right: 0;
/* 核心:旋转成斜三角效果 */
transform: rotate(45deg) translate(50rpx, -10rpx);
transform-origin: top right;
}
/deep/ .uni-card__content {
padding: 5px 10px 10px !important;
}
/deep/ .uni-card__header-content-title {
font-weight: 700;
}
</style>

View File

@@ -1,224 +1,225 @@
<template> <template>
<view :loading="loading"> <view :loading="loading">
<uni-search-bar v-model="keyWord" bgColor="#fff" placeholder="请输入关键词"></uni-search-bar> <uni-search-bar v-model="keyWord" bgColor="#fff" placeholder="请输入关键词"></uni-search-bar>
<view class="message"> <view class="message">
<!-- <uni-card <!-- <uni-card
:title="item.engineerName" :title="item.engineerName"
:extra="item.mac" :extra="item.mac"
@click="jump(item)" @click="jump(item)"
v-for="(item, index) in list" v-for="(item, index) in list"
:key="index" :key="index"
> >
<view class="term-list-bottom"> <view class="term-list-bottom">
<view class="term-list-bottom-item"> <view class="term-list-bottom-item">
<view>区域</view> <view>区域</view>
<view>{{ item.provinceName + item.cityName }}</view> <view>{{ item.provinceName + item.cityName }}</view>
</view> </view>
<view class="term-list-bottom-item"> <view class="term-list-bottom-item">
<view>创建时间</view> <view>创建时间</view>
<view>{{ item.createTime }}</view> <view>{{ item.createTime }}</view>
</view> </view>
</view> </view>
</uni-card> --> </uni-card> -->
<uni-list> <uni-list>
<uni-list-item @click="jump(item)" v-for="(item, index) in filterList" :key="index"> <uni-list-item @click="jump(item)" v-for="(item, index) in filterList" :key="index">
<template v-slot:header> <template v-slot:header>
<view class="slot-box"> <view class="slot-box">
<view class="slot-box-left hide-txt mr20">{{ item.engineerName }}</view> <view class="slot-box-left hide-txt mr20">{{ item.engineerName }}</view>
<switch <switch
:checked="selectList.indexOf(item.engineerId) > -1" :checked="selectList.indexOf(item.engineerId) > -1"
style="transform: scale(0.8)" style="transform: scale(0.8)"
@change="switchChange(item)" @change="switchChange(item)"
/> />
</view> </view>
</template> </template>
</uni-list-item> </uni-list-item>
</uni-list> </uni-list>
<uni-load-more v-if="list && list.length > 0" status="nomore"></uni-load-more> <uni-load-more v-if="list && list.length > 0" status="nomore"></uni-load-more>
<Cn-empty v-else style="padding-top: 300rpx"></Cn-empty> <Cn-empty v-else style="padding-top: 300rpx"></Cn-empty>
</view> </view>
</view> </view>
</template> </template>
<script> <script>
import list from '../../common/js/list' import list from '../../common/js/list'
import {queryAllEnginner, csMarketDataAdd, queryEngineering} from '@/common/api/engineering' import { queryAllEnginner, csMarketDataAdd, queryEngineering } from '@/common/api/engineering'
export default { export default {
data() { data() {
return { return {
loading: true, loading: true,
userInfo: {}, userInfo: {},
list: [], list: [],
selectList: [], selectList: [],
keyWord: '', keyWord: '',
} }
}, },
computed: { computed: {
filterList() { filterList() {
return this.list.filter((item) => { return this.list.filter((item) => {
return item.engineerName.indexOf(this.keyWord) > -1 return item.engineerName.indexOf(this.keyWord) > -1
}) })
}, },
}, },
methods: { methods: {
switchChange(e) { switchChange(e) {
console.log(e) console.log(e)
let index = this.selectList.indexOf(e.engineerId) let index = this.selectList.indexOf(e.engineerId)
if (index > -1) { if (index > -1) {
this.selectList.splice(index, 1) this.selectList.splice(index, 1)
} else { } else {
this.selectList.push(e.engineerId) this.selectList.push(e.engineerId)
} }
},
csMarketDataAdd({ init() {
engineerIds: this.selectList, this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
}).then((res) => { queryAllEnginner().then((res) => {
console.log(res) this.list = res.data
}) console.log(this.list)
}, this.selectList = res.data.filter((item) => item.isSelect === '1').map((item) => item.engineerId)
init() { console.log(this.selectList)
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo) this.loading = false
queryAllEnginner().then((res) => { })
this.list = res.data },
console.log(this.list) back() {
this.selectList = res.data.filter((item) => item.isSelect === '1').map((item) => item.engineerId) uni.navigateBack()
console.log(this.selectList) },
this.loading = false add() {
}) uni.navigateTo({
}, url: `/pages/engineering/new`,
back() { })
uni.navigateBack() },
}, upgrade(code) {
add() { console.log(code)
uni.navigateTo({ uni.showToast({
url: `/pages/engineering/new`, title: '升级成功',
}) icon: 'none',
}, })
upgrade(code) { },
console.log(code) jump(engineering) {
uni.showToast({ uni.navigateTo({
title: '升级成功', url: `/pages/engineering/detail?engineering=${encodeURIComponent(JSON.stringify(engineering))}`,
icon: 'none', })
}) },
}, },
jump(engineering) { onUnload() {
uni.navigateTo({ csMarketDataAdd({
url: `/pages/engineering/detail?engineering=${encodeURIComponent(JSON.stringify(engineering))}`, engineerIds: this.selectList,
}) }).then((res) => {
}, console.log(res)
}, })
onBackPress() { },
console.log('onBackPress') onBackPress() {
let engineering = uni.getStorageSync('engineering') console.log('onBackPress')
queryEngineering().then(res => { let engineering = uni.getStorageSync('engineering')
if (res.data.length === 0) { queryEngineering().then((res) => {
uni.removeStorage({ if (res.data.length === 0) {
key: this.$cacheKey.engineering, uni.removeStorage({
}) key: this.$cacheKey.engineering,
} else if (engineering && !res.data.some(item => item.id = engineering.id)) { })
uni.removeStorage({ } else if (engineering && !res.data.some((item) => (item.id = engineering.id))) {
key: this.$cacheKey.engineering, uni.removeStorage({
}) key: this.$cacheKey.engineering,
} else { })
uni.setStorage({ } else {
key: this.$cacheKey.engineering, uni.setStorage({
data: res.data[0], key: this.$cacheKey.engineering,
}) data: res.data[0],
} })
}) }
}, })
onLoad() { },
this.init() onLoad() {
}, this.init()
} },
</script> }
</script>
<style lang="scss">
.message { <style lang="scss">
/deep/ .slot-box { .message {
width: 100%; /deep/ .slot-box {
display: flex; width: 100%;
align-items: center; display: flex;
align-items: center;
&-left {
flex: 1; &-left {
margin-right: 20rpx; flex: 1;
} margin-right: 20rpx;
} }
}
/deep/ .uni-list-item__content {
padding-right: 0; /deep/ .uni-list-item__content {
} padding-right: 0;
}
.message-header {
padding: 200rpx 34rpx 34rpx; .message-header {
display: flex; padding: 200rpx 34rpx 34rpx;
align-items: center; display: flex;
background: $uni-theme-white; align-items: center;
margin-bottom: 20rpx; background: $uni-theme-white;
box-shadow: 0 4rpx 8rpx #e7e7e74c; margin-bottom: 20rpx;
box-shadow: 0 4rpx 8rpx #e7e7e74c;
.message-header-head {
margin-right: 30rpx; .message-header-head {
height: 128rpx; margin-right: 30rpx;
width: 128rpx; height: 128rpx;
border-radius: $uni-theme-radius; width: 128rpx;
overflow: hidden; border-radius: $uni-theme-radius;
} overflow: hidden;
}
.message-header-name {
margin-right: 30rpx; .message-header-name {
flex: 1; margin-right: 30rpx;
font-size: 36rpx; flex: 1;
color: #111; font-size: 36rpx;
font-weight: 700; color: #111;
font-weight: 700;
.tag {
margin-top: 10rpx; .tag {
font-size: 24rpx; margin-top: 10rpx;
color: #aaa; font-size: 24rpx;
} color: #aaa;
} }
} }
}
.message-nav {
padding: 34rpx; .message-nav {
display: flex; padding: 34rpx;
align-items: center; display: flex;
background: $uni-theme-white; align-items: center;
border-bottom: 1rpx solid #e8e8e8; background: $uni-theme-white;
border-bottom: 1rpx solid #e8e8e8;
&-icon {
margin-right: 30rpx; &-icon {
height: 44rpx; margin-right: 30rpx;
width: 44rpx; height: 44rpx;
border-radius: $uni-theme-radius; width: 44rpx;
overflow: hidden; border-radius: $uni-theme-radius;
} overflow: hidden;
}
&-label {
margin-right: 30rpx; &-label {
flex: 1; margin-right: 30rpx;
font-size: 28rpx; flex: 1;
color: #111; font-size: 28rpx;
} color: #111;
} }
} }
}
.term-list-bottom {
.term-list-bottom-item { .term-list-bottom {
font-size: 28rpx; .term-list-bottom-item {
margin-bottom: 20rpx; font-size: 28rpx;
display: flex; margin-bottom: 20rpx;
justify-content: space-between; display: flex;
// view:first-of-type{ justify-content: space-between;
// color: #111; // view:first-of-type{
// } // color: #111;
} // }
}
.term-list-bottom-item:last-of-type {
margin-bottom: 0; .term-list-bottom-item:last-of-type {
} margin-bottom: 0;
} }
</style> }
</style>

View File

@@ -1,113 +1,113 @@
<template> <template>
<Cn-page :loading='loading' noPadding> <Cn-page :loading='loading' noPadding>
<view slot='body'> <view slot='body'>
<view class='detail device'> <view class='detail device'>
<view class="header"> <view class="header">
<image src="/static/test2.pic.png" mode="widthFix" style="width: 100%;" /> <image src="/static/test2.pic.png" mode="widthFix" style="width: 100%;" />
</view> </view>
<view class="title">基本信息</view> <view class="title">基本信息</view>
<view class="des"> <view class="des">
<text>名称监测网关</text> <text>名称监测网关</text>
<text class="ml20">项目XXX项目1</text> <text class="ml20">项目XXX项目1</text>
</view> </view>
<view class="des"> <view class="des">
<text>设备型号PQS-882</text> <text>设备型号PQS-882</text>
<text class="ml20">版本号v1.0.0</text> <text class="ml20">版本号v1.0.0</text>
</view> </view>
<view class="title mb20 m340">设备列表 <view class="title mb20 m340">设备列表
<view class="footer-btn" v-if="userInfo.authorities != '2' && userInfo.authorities != '5'" @click="newDevice">注册设备 <view class="footer-btn" v-if="userInfo.authorities != '2' && userInfo.authorities != '5'" @click="newDevice">注册设备
</view> </view>
</view> </view>
<uni-card :title="'设备' + item" :sub-title="'XXX项目1'" extra="用能" v-for="item in 2" :key="item" <uni-card :title="'设备' + item" :sub-title="'XXX项目1'" extra="用能" v-for="item in 2" :key="item"
@click="goDevice" padding="0" thumbnail="/static/device.png"> @click="goDevice" padding="0" thumbnail="/static/device.png">
</uni-card> </uni-card>
<uni-load-more status="nomore"></uni-load-more> <uni-load-more status="nomore"></uni-load-more>
<view style="height:20rpx"></view> <view style="height:20rpx"></view>
</view> </view>
</view> </view>
</Cn-page> </Cn-page>
</template> </template>
<script> <script>
export default { export default {
data () { data () {
return { return {
loading: false, loading: false,
userInfo: {}, userInfo: {},
deviceList: [ deviceList: [
{ {
name: '设备1', name: '设备1',
des: '设备描述1', des: '设备描述1',
type: 'APF', type: 'APF',
project: '监测', project: '监测',
}, },
{ {
name: '设备2', name: '设备2',
des: '设备描述2', des: '设备描述2',
type: 'DVR', type: 'DVR',
project: '监测' project: '监测'
}, },
] ]
} }
}, },
methods: { methods: {
newDevice () { newDevice () {
uni.navigateTo({ uni.navigateTo({
url: '/pages/gateway/newDevice' url: '/pages/gateway/newDevice'
}) })
}, },
goDevice (item) { goDevice (item) {
uni.navigateTo({ uni.navigateTo({
url: `/pages/device/${item.type}/detail` url: `/pages/device/${item.type}/detail`
}) })
} }
}, },
onLoad (options) { onLoad (options) {
this.userInfo = uni.getStorageSync('userInfo') this.userInfo = uni.getStorageSync('userInfo')
}, },
} }
</script> </script>
<style lang='scss'> <style lang='scss'>
.detail { .detail {
// background: $uni-theme-white; // background: $uni-theme-white;
.header { .header {
position: relative; position: relative;
} }
.title { .title {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
padding: 20rpx 20rpx 0; padding: 20rpx 20rpx 0;
font-size: 36rpx; font-size: 36rpx;
color: #111; color: #111;
font-weight: 700; font-weight: 700;
.footer-btn { .footer-btn {
padding: 0 20rpx; padding: 0 20rpx;
height: 50rpx; height: 50rpx;
background-color: #007aff; background-color: #007aff;
font-size: 24rpx; font-size: 24rpx;
color: #fff; color: #fff;
text-align: center; text-align: center;
line-height: 50rpx; line-height: 50rpx;
border-radius: 10rpx; border-radius: 10rpx;
} }
} }
.des { .des {
padding: 20rpx 20rpx 0; padding: 20rpx 20rpx 0;
font-size: 28rpx; font-size: 28rpx;
color: #333; color: #333;
} }
.content { .content {
box-sizing: border-box; box-sizing: border-box;
} }
} }
</style> </style>

View File

@@ -1,97 +1,160 @@
<template> <template>
<Cn-page :loading="loading"> <Cn-page :loading="loading">
<view slot="body"> <view slot="body">
<view class="select-enineering"> <view class="select-enineering">
<uni-indexed-list <view class="all" @click="all">全部工程</view>
:options="engineeringListFilter" <uni-indexed-list
:showSelect="false" :style="{ top: showAll ? '110rpx' : '0' }"
@click="confirm" :options="engineeringListFilter"
></uni-indexed-list> :showSelect="false"
</view> @click="confirm"
</view> >
</Cn-page> </uni-indexed-list>
</template> </view>
<script> </view>
import { pinyin } from 'pinyin-pro' </Cn-page>
import { queryEngineering } from '@/common/api/engineering' </template>
<script>
export default { import { pinyin } from 'pinyin-pro'
data() { import { queryEngineering } from '@/common/api/engineering'
return {
loading: false, export default {
engineeringList: [], props: {},
options: {}, data() {
} return {
}, loading: false,
computed: { engineeringList: [],
engineeringListFilter() { options: {},
let result = [] showAll: true,
this.engineeringList.forEach((item) => { }
let arr = pinyin(item.name[0], { toneType: 'none', type: 'array' }) },
let letter = arr[0][0].toUpperCase() computed: {
console.log(letter) engineeringListFilter() {
let index = result.findIndex((item) => item.letter === letter) let result = []
if (index === -1) { this.engineeringList.forEach((item) => {
result.push({ let arr = pinyin(item.name[0], { toneType: 'none', type: 'array' })
letter, let letter = arr[0][0].toUpperCase()
data: [item.name], // console.log(letter)
}) let index = result.findIndex((item) => item.letter === letter)
} else { if (index === -1) {
result[index].data.push(item.name) result.push({
} letter,
}) data: [item.name],
return result })
}, } else {
}, result[index].data.push(item.name)
onLoad(options) { }
this.options = options })
this.engineeringList = uni.getStorageSync('engineeringList') return result
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo) },
if (!(this.userInfo.authorities === 'app_vip_user' || this.userInfo.authorities === 'engineering_user')) { },
// 修改buttons onLoad(options) {
// #ifdef APP-PLUS this.options = options
var webView = this.$mp.page.$getAppWebview() this.showAll = this.options.showAll ? true : false
// 修改buttons this.engineeringList = uni.getStorageSync('engineeringList')
webView.setTitleNViewButtonStyle(0, { this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
width: '0', if (!(this.userInfo.authorities === 'app_vip_user' || this.userInfo.authorities === 'engineering_user')) {
}) // 修改buttons
// #endif // #ifdef APP-PLUS
} var webView = this.$mp.page.$getAppWebview()
}, // 修改buttons
onShow() { webView.setTitleNViewButtonStyle(0, {
queryEngineering().then((res) => { width: '0',
this.engineeringList = res.data })
}) // #endif
}, }
onNavigationBarButtonTap(e) { },
if (this.userInfo.authorities === 'app_vip_user' || this.userInfo.authorities === 'engineering_user') { onShow() {
uni.navigateTo({ queryEngineering().then((res) => {
url: `/pages/engineering/new`, this.engineeringList = this.sortByFirstLetter(res.data)
}) })
} else { },
uni.showToast({ onNavigationBarButtonTap(e) {
title: '暂无权限', if (this.userInfo.authorities === 'app_vip_user' || this.userInfo.authorities === 'engineering_user') {
icon: 'none', uni.navigateTo({
}) url: `/pages/engineering/new`,
} })
}, } else {
methods: { uni.showToast({
confirm(e) { title: '暂无权限',
console.log(e) icon: 'none',
let engineering = this.engineeringList.find((item) => item.name === e.item.name) })
if (this.options.from === 'once') { }
// 创建项目的时候选择工程 用完即删 },
uni.setStorageSync('onceSelectEngineering', engineering) methods: {
} else { // 处理函数
uni.setStorageSync('engineering', engineering) sortByFirstLetter(data) {
} // 1. 添加首字母字段
uni.navigateBack() const withLetter = data.map((item) => {
}, let letter = '#'
}, const firstChar = item.name?.charAt(0) || ''
}
</script> if (/[A-Za-z]/.test(firstChar)) {
<style lang="scss"> letter = firstChar.toUpperCase()
.index { } else if (/[0-9]/.test(firstChar)) {
padding: 34rpx; letter = '#'
} } else {
</style> const py = pinyin(firstChar, { pattern: 'first', toneType: 'none' })
letter = py ? py.toUpperCase() : '#'
}
return { ...item, letter }
})
// 2. 排序
return withLetter.sort((a, b) => {
if (a.letter === '#') return 1
if (b.letter === '#') return -1
return a.letter.localeCompare(b.letter)
})
},
all() {
uni.setStorageSync('onceSelectEngineering', {
createBy: '',
createTime: '',
updateBy: '',
updateTime: '',
id: '',
name: '',
userId: null,
province: '',
provinceName: '',
city: '',
cityName: '',
description: '',
status: '1',
})
uni.navigateBack()
},
confirm(e) {
console.log(e)
let engineering = this.engineeringList.find((item) => item.name === e.item.name)
if (this.options.from === 'once') {
// 创建项目的时候选择工程 用完即删
uni.setStorageSync('onceSelectEngineering', engineering)
} else {
uni.setStorageSync('engineering', engineering)
}
uni.navigateBack()
},
},
}
</script>
<style lang="scss">
.index {
padding: 34rpx;
}
.all {
padding-left: 30rpx;
display: flex;
align-items: center;
cursor: pointer;
height: 50px;
border-bottom-style: solid;
border-bottom-width: 1px;
border-bottom-color: #dedede;
background-color: #ffffff;
}
</style>

View File

@@ -0,0 +1,144 @@
<template>
<Cn-page :loading="loading">
<view slot="body">
<view class="select-enineering">
<view class="all" @click="all">全部工程</view>
<uni-indexed-list
:style="{ top: showAll ? '110rpx' : '0' }"
:options="engineeringListFilter"
:showSelect="false"
@click="confirm"
>
</uni-indexed-list>
</view>
</view>
</Cn-page>
</template>
<script>
import { pinyin } from 'pinyin-pro'
import { queryEngineering } from '@/common/api/engineering'
export default {
props: {},
data() {
return {
loading: false,
engineeringList: [],
options: {},
showAll: true,
}
},
computed: {
engineeringListFilter() {
let result = []
this.engineeringList.forEach((item) => {
let arr = pinyin(item.name[0], { toneType: 'none', type: 'array' })
let letter = arr[0][0].toUpperCase()
// console.log(letter)
let index = result.findIndex((item) => item.letter === letter)
if (index === -1) {
result.push({
letter,
data: [item.name],
})
} else {
result[index].data.push(item.name)
}
})
return result
},
},
onLoad(options) {
this.options = options
this.showAll = this.options.showAll ? true : false
this.engineeringList = uni.getStorageSync('engineeringList')
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
if (!(this.userInfo.authorities === 'app_vip_user' || this.userInfo.authorities === 'engineering_user')) {
// 修改buttons
// #ifdef APP-PLUS
var webView = this.$mp.page.$getAppWebview()
// 修改buttons
webView.setTitleNViewButtonStyle(0, {
width: '0',
})
// #endif
}
},
onShow() {
queryEngineering().then((res) => {
this.engineeringList = res.data.sort((a, b) => {
const nameA = a.name
const nameB = b.name
const isANumber = /^\d/.test(nameA)
const isBNumber = /^\d/.test(nameB)
if (isANumber !== isBNumber) {
return isANumber ? 1 : -1
}
return nameA.localeCompare(nameB, 'zh', { sensitivity: 'accent' })
})
})
},
onNavigationBarButtonTap(e) {
if (this.userInfo.authorities === 'app_vip_user' || this.userInfo.authorities === 'engineering_user') {
uni.navigateTo({
url: `/pages/engineering/new`,
})
} else {
uni.showToast({
title: '暂无权限',
icon: 'none',
})
}
},
methods: {
all() {
uni.setStorageSync('onceSelectEngineering', {
createBy: '',
createTime: '',
updateBy: '',
updateTime: '',
id: '',
name: '',
userId: null,
province: '',
provinceName: '',
city: '',
cityName: '',
description: '',
status: '1',
})
uni.navigateBack()
},
confirm(e) {
console.log(e)
let engineering = this.engineeringList.find((item) => item.name === e.item.name)
if (this.options.from === 'once') {
// 创建项目的时候选择工程 用完即删
uni.setStorageSync('onceSelectEngineering', engineering)
} else {
uni.setStorageSync('engineering', engineering)
}
uni.navigateBack()
},
},
}
</script>
<style lang="scss">
.index {
padding: 34rpx;
}
.all {
padding-left: 30rpx;
display: flex;
align-items: center;
cursor: pointer;
height: 50px;
border-bottom-style: solid;
border-bottom-width: 1px;
border-bottom-color: #dedede;
background-color: #ffffff;
}
</style>

375
pages/index/comp/apply.vue Normal file
View File

@@ -0,0 +1,375 @@
<template>
<view>
<view class="filterCriteria">
<!-- 筛选条件 -->
<Cn-filterCriteria @select="select" :singleChoice="true" :showDatetime="true"> </Cn-filterCriteria>
<!-- <view class="choose1">
<view class="nav-menu nav-menu-btn" @click="selectDevice">申请报告 </view>
</view> -->
</view>
<view class="smallLabel mt20">
<view class="boxCenter">
<view>
<checkbox-group @change="changeBox" class="boxCenter"
><checkbox value="true" :checked="checkedAll" />全选 
</checkbox-group></view
>
已选择 {{ checkedTotal }} 条事件
</view>
<view class="nav-menu nav-menu-btn" @click="selectDevice">申请报告 </view>
<!-- <view style="width: 180rpx">
<picker @change="bindPickerChange" :value="sort" :range="array">
<view class="uni-input"
>{{ array[sort] }}排序
<uni-icons custom-prefix="iconfont" type="icon-paixu1" size="10" color="#2563EB"></uni-icons>
</view>
</picker>
</view> -->
</view>
<!-- 卡片 -->
<scroll-view
scroll-y="true"
@scrolltolower="scrolltolower"
class="event-list"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }"
>
<!-- 循环渲染事件项 -->
<uni-card
class="event-item"
:class="judgment(item.showName).type"
v-for="(item, index) in store.data"
:key="index"
@click="clackCard(item)"
>
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view class="event-icon">
<!-- 动态图标根据类型切换 -->
<!-- <uni-icons
:custom-prefix="judgment(item.showName) == 'interrupt' ? 'custom-icon' : 'iconfont'"
:type="judgment(item.showName).icon"
:color="judgment(item.showName).color"
:size="judgment(item.showName).size"
></uni-icons> -->
<Cn-icon-transient :name="item.showName" />
</view>
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.lineName }}</text>
<text class="event-tag" :class="`${judgment(item.showName).type}-tag`">{{
item.showName
}}</text>
</view>
<view class="event-desc">
<text>工程{{ item.engineeringName }}</text>
<text>项目{{ item.projectName }}</text>
<text>设备{{ item.equipmentName }}</text>
</view>
</view>
<view class="event-action" @click="handleWrapperClick(item, !item.wavePath)">
<!-- 选择 -->
<checkbox-group @change="changeChild($event, item)"
><checkbox value="true" :disabled="!item.wavePath" :checked="item.checked" />
</checkbox-group>
</view>
</view>
<!-- 详情区域 -->
<view class="event-detail">
<text>
{{ item.startTime ? '发生时间:' + item.startTime : '' }}
{{
item.evtParamVVaDepth != null && item.evtParamVVaDepth !== ''
? ',幅值:' + item.evtParamVVaDepth + '%'
: ''
}}
{{
item.evtParamTm != null && item.evtParamTm !== ''
? ',持续时间:' + item.evtParamTm + 's'
: ''
}}
{{
item.evtParamPhase != null && item.evtParamPhase !== ''
? ',相别:' + item.evtParamPhase
: ''
}}
{{
item.landPoint != null && item.landPoint !== ''
? ',落点区域:' + item.landPoint
: ''
}}
</text>
</view>
</uni-card>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty>
</scroll-view>
</view>
</template>
<script>
import list from '@/common/js/list'
import { applicationReport } from '@/common/api/report.js'
export default {
components: {},
props: {
navHeight: {
type: Number,
default: 0,
},
},
mixins: [list],
data() {
return {
selectValue: {},
height: 0,
checkedAll: false,
checkedTotal: 0,
sort: 0,
array: ['发生时间', '暂降深度', '持续时间'],
}
},
mounted() {},
methods: {
setHeight() {
uni.createSelectorQuery()
.select('.filterCriteria')
.boundingClientRect((rect) => {
//
// #ifdef H5
this.height = rect?.height + 170 || 0
// #endif
// #ifdef APP-PLUS
this.height = rect?.height + 110 || 0
// #endif
})
.exec()
},
async select(val) {
this.selectValue = val
await this.init()
setTimeout(() => {
this.setHeight()
}, 200)
},
init() {
this.store = this.DataSource('/cs-harmonic-boot/eventUser/queryEventpage')
this.store.params.type = 0
// this.store.params.pageSize = 10000
this.store.params.sortField = this.sort
this.store.params.engineeringid = this.selectValue.engineeringId
this.store.params.projectId = this.selectValue.projectId
this.store.params.deviceId = this.selectValue.deviceId
this.store.params.lineId = this.selectValue.lineId
this.store.params.target = ['Evt_Sys_DipStr']
this.store.params.startTime = this.$util.getMonthFirstAndLastDay(this.selectValue.date).firstDay
this.store.params.endTime = this.$util.getMonthFirstAndLastDay(this.selectValue.date).lastDay
// this.store.params.startTime = this.selectValue.range[0]
// this.store.params.endTime = this.selectValue.range[1]
this.store.loadedCallback = () => {
this.checkedTotal = 0
this.store.data = this.store.data.map((item) => {
item.checked = false
return item
})
}
this.store.reload()
},
// 全选
changeBox(e) {
this.checkedAll = !this.checkedAll
if (e.target.value.length > 0) {
let total = 0
this.store.data = this.store.data.map((item) => {
if (item.wavePath != null) {
item.checked = true
total += 1
} else {
item.checked = false
}
return item
})
this.checkedTotal = total
} else {
this.store.data = this.store.data.map((item) => {
item.checked = false
return item
})
this.checkedTotal = 0
}
},
changeChild(e, item) {
item.checked = !item.checked
this.checkedAll = this.store.data.every((item) => item.checked === true)
this.checkedTotal = this.store.data.filter((item) => item.checked === true).length
},
handleWrapperClick(e, flag) {
if (flag) {
return uni.showToast({
title: '当前事件没有波形,不支持生成报告!',
icon: 'none',
})
}
},
// 点击卡片
clackCard() {},
// 切换排序
bindPickerChange(e) {
this.sort = e.detail.value
this.init()
},
judgment(val, key) {
switch (val) {
case '电压暂降':
return {
type: 'sag',
icon: 'icon-a-svg4',
color: '#2563eb',
size: '25',
}
case '电压暂升':
return {
type: 'swell',
icon: 'icon-a-svg5',
color: '#e6a23c',
size: '25',
}
case '电压中断':
return {
type: 'interrupt',
icon: 'icon-zhongduan2',
color: '#6b7280',
size: '35',
}
case '瞬态':
return {
type: 'transient',
icon: 'icon-shuntaishijian',
color: '#8b5cf6',
size: '40',
}
case '未知':
return {
type: 'unknown',
icon: 'icon-wenhao',
color: '#6b7280',
size: '45',
}
}
},
// 申请
selectDevice() {
if (this.checkedTotal == 0) {
return uni.showToast({
title: '请选择事件!',
icon: 'none',
})
} else {
uni.showLoading({
title: '申请中,请稍等...',
mask: true,
})
let list = this.store.data.filter((item) => item.checked === true)
applicationReport({
list: list.map((item) => item.id),
lineId: list[0].lineId,
startTime: this.$util.getMonthFirstAndLastDay(this.selectValue.date).firstDay,
endTime: this.$util.getMonthFirstAndLastDay(this.selectValue.date).lastDay,
}).then((res) => {
this.checkedAll = false
this.store.reload()
uni.showToast({
icon: 'success',
mask: true,
title: '申请报告,成功!',
})
})
}
},
isAllLineIdSame(data) {
// 获取第一个元素的lineId作为基准
const baseLineId = data[0].lineId
// 遍历数组检查每个元素的lineId是否和基准一致
for (let item of data) {
// 兼容元素可能没有lineId的情况
if (!item || item.lineId !== baseLineId) {
return false
}
}
return true
},
// 下拉
refresherrefresh() {
this.triggered = true
uni.startPullDownRefresh()
setTimeout(() => {
this.triggered = false
}, 500)
},
// 上拉
scrolltolower() {
if (this.store.status != 'noMore') {
this.store.next && this.store.next()
}
},
},
computed: {},
watch: {},
}
</script>
<style lang="scss" scoped>
@import '@/pages/message1/index.scss';
.filterCriteria {
.nav {
background-color: #fff;
}
.choose1 {
background-color: #fff;
padding: 0 20rpx;
display: flex;
justify-content: flex-end;
/deep/ .uni-checkbox-input {
width: 30rpx;
height: 30rpx;
}
font-size: 26rpx;
}
}
.nav-menu {
height: 40rpx;
padding: 6rpx 20rpx;
// margin-left: 20rpx;
// margin-bottom: 20rpx;
line-height: 40rpx;
font-size: 24rpx;
border-radius: 8rpx;
background: #ebeaec;
color: #666;
&-active {
background: #dfe5f7;
color: $uni-theme-color;
}
&-btn {
background: $uni-theme-color;
color: #fff;
}
}
/deep/.uni-card__content {
padding: 20rpx !important;
}
.smallLabel {
justify-content: space-between;
font-size: 26rpx !important;
}
.boxCenter {
display: flex !important;
align-items: center !important;
}
</style>

View File

@@ -44,13 +44,13 @@
class="nav-menu nav-menu-btn" class="nav-menu nav-menu-btn"
@click="selectDevice('transfer')" @click="selectDevice('transfer')"
v-if="userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'" v-if="userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'"
>移交 >移交
</view> </view>
<view <view
class="nav-menu nav-menu-btn" class="nav-menu nav-menu-btn"
@click="selectDevice('share')" @click="selectDevice('share')"
v-if="userInfo.authorities === 'app_vip_user'" v-if="userInfo.authorities === 'app_vip_user'"
>分享 >分享
</view> </view>
</template> </template>
<!-- <picker @change="projectTypeChange" :value="select.projectTypeIndex" :range="projectType" range-key="text"> <!-- <picker @change="projectTypeChange" :value="select.projectTypeIndex" :range="projectType" range-key="text">
@@ -60,37 +60,29 @@
</picker> --> </picker> -->
</view> </view>
<view class="content device" :style="{ minHeight: minHeight }"> <view class="content device" :style="{ minHeight: minHeight }">
<Cn-device-card v-for="(item, index) in deviceListFilter" :device="item" :key="index"> <uni-swipe-action>
<template v-slot:title v-if="transfer || share"> <uni-swipe-action-item
<!-- 卡片标题 --> v-for="(item, index) in deviceListFilter"
<view class="uni-card__header"> :threshold="0"
<view class="uni-card__header-box"> :right-options="item.isTop == 0 ? options1 : options12"
<view class="uni-card__header-avatar"> @click="bindClick($event, item)"
<image >
class="uni-card__header-avatar-image" <Cn-device-card :device="item" :key="index">
:src="deviceIcon(item.runStatus)" <template v-slot:title>
mode="aspectFit" <!-- 卡片标题 -->
/>
</view>
<view class="uni-card__header-content">
<text class="uni-card__header-content-title uni-ellipsis">
{{ item.equipmentName }}
</text>
<text class="uni-card__header-content-subtitle uni-ellipsis">
{{ item.mac }}
</text>
</view>
</view>
<view class="uni-card__header-extra" style="position: relative">
<switch <switch
v-if="transfer || share"
:checked="checkList.indexOf(item.equipmentId) > -1" :checked="checkList.indexOf(item.equipmentId) > -1"
style="transform: scale(0.8); position: relative; left: 20rpx" style="transform: scale(0.8); position: relative; left: 20rpx"
@change="switchChange(item)" @change="switchChange(item)"
/> />
</view> <view class="star-icon" v-else>
</view> <uni-icons type="search" size="25" color="#376cf3"></uni-icons>
</template> </view>
</Cn-device-card> </template>
</Cn-device-card>
</uni-swipe-action-item>
</uni-swipe-action>
<uni-load-more <uni-load-more
v-if="store.status == 'loading' || deviceListFilter.length > 0" v-if="store.status == 'loading' || deviceListFilter.length > 0"
:status="store.status" :status="store.status"
@@ -102,6 +94,7 @@
<script> <script>
import { getProjectList } from '@/common/api/project' import { getProjectList } from '@/common/api/project'
import { queryDictData } from '@/common/api/dictionary' import { queryDictData } from '@/common/api/dictionary'
import { engineeringPinToTop } from '@/common/api/device'
export default { export default {
props: { props: {
@@ -129,11 +122,27 @@ export default {
projectType: [], projectType: [],
userInfo: {}, userInfo: {},
selectProject: false, selectProject: false,
options1: [
{
text: '置顶',
style: {
backgroundColor: '#376cf3',
},
},
],
options12: [
{
text: '取消',
style: {
backgroundColor: '#ccc',
},
},
],
} }
}, },
computed: { computed: {
deviceListFilter() { deviceListFilter() {
let arr = this.store.data.filter((item) => { let arr = this.store.data.filter((item) => {
if (this.select.projectName && this.select.projectType) { if (this.select.projectName && this.select.projectType) {
return item.project === this.select.projectName && item.type === this.select.projectType return item.project === this.select.projectName && item.type === this.select.projectType
@@ -145,9 +154,8 @@ export default {
return true return true
} }
}) })
if (this.transfer || this.share) { if (this.transfer || this.share) {
return arr.filter((item) => { return arr.filter((item) => {
return item.isPrimaryUser === '1' //&& item.process == 4 return item.isPrimaryUser === '1' //&& item.process == 4
}) })
@@ -159,8 +167,24 @@ export default {
created() { created() {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo) this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
}, },
mounted() {}, mounted() {
},
methods: { methods: {
bindClick(e, item) {
engineeringPinToTop({
targetId: item.equipmentId,
targetType: 1,
userId: uni.getStorageSync(this.$cacheKey.userInfo).userIndex,
}).then((res) => {
if (res.code == 'A0000') {
this.$util.toast('操作成功!')
this.store.search()
} else {
this.$util.toast(res.message)
}
})
},
selectDevice(type) { selectDevice(type) {
if (this.deviceListFilter.findIndex((item) => item.isPrimaryUser === '1') === -1) { if (this.deviceListFilter.findIndex((item) => item.isPrimaryUser === '1') === -1) {
this.$util.toast('没有可操作的设备') this.$util.toast('没有可操作的设备')
@@ -184,7 +208,6 @@ export default {
return str return str
}, },
switchChange(e) { switchChange(e) {
console.log(e)
let index = this.checkList.indexOf(e.equipmentId) let index = this.checkList.indexOf(e.equipmentId)
if (index > -1) { if (index > -1) {
this.checkList.splice(index, 1) this.checkList.splice(index, 1)
@@ -333,18 +356,30 @@ export default {
this.navMenuActive = index this.navMenuActive = index
}, },
jump(item) { jump(item) {
uni.navigateTo({ uni.navigateTo({
url: '/pages/device/APF/detail?id=' + item.equipmentId + '&isPrimaryUser=' + item.isPrimaryUser+ '&ndid=' + item.ndid, url:
'/pages/device/APF/detail?id=' +
item.equipmentId +
'&isPrimaryUser=' +
item.isPrimaryUser +
'&ndid=' +
item.ndid,
}) })
}, },
}, },
} }
</script> </script>
<style lang="scss"> <style lang="scss">
.index-device{ .index-device {
.nav-menu { .nav-menu {
} }
} }
/deep/ .button-group--right {
padding: 0 0 20rpx;
}
.star-icon {
font-size: 40rpx;
}
</style> </style>

View File

@@ -0,0 +1,285 @@
<template>
<view class="index-device">
<view class="nav" :style="{ top: navTabHeight + 'px' }"> </view>
<view class="content device project-list" :style="{ minHeight: minHeight }">
<uni-swipe-action>
<uni-swipe-action-item
v-for="(item, index) in store.data"
:threshold="0"
:right-options="item.isTop == 0 ? options1 : options12"
@click="bindClick($event, item)"
>
<uni-card :key="index">
<view class="card-header">
<view class="project-icon">
<uni-icons
custom-prefix="iconfont"
type="icon-gongcheng"
color="#2563eb"
size="45"
></uni-icons>
</view>
<view class="project-info">
<view class="project-name">{{ item.engineeringName }}</view>
<view class="project-stats">
<view class="stat-item boxClick" @click="jump('nowEngineering', item)">
<text class="stat-value blue">{{ item.devTotal }}</text>
<text class="stat-label">设备总数</text>
</view>
<view class="stat-item boxClick" @click="jump('currentOnLineDevs', item)">
<text class="stat-value green">{{ item.onlineDevTotal }}</text>
<text class="stat-label">在线设备</text>
</view>
<view class="stat-item boxClick" @click="jump('currentOffLineDevs', item)">
<text class="stat-value red">{{ item.offlineDevTotal }}</text>
<text class="stat-label">离线设备</text>
</view>
<view class="stat-item boxClick" @click="jump('event', item)">
<text class="stat-value red">{{ item.alarmTotal }}</text>
<text class="stat-label">事件数量</text>
</view>
</view>
</view>
</view>
<view class="pinToTop" v-if="item.isTop == 1"> 置顶 </view>
</uni-card>
</uni-swipe-action-item>
</uni-swipe-action>
<uni-load-more
v-if="store.status == 'loading' || deviceListFilter.length > 0"
:status="store.status"
></uni-load-more>
<Cn-empty v-else></Cn-empty>
</view>
</view>
</template>
<script>
import { engineeringPinToTop } from '@/common/api/device'
export default {
props: {
store: {
type: Object,
default: {},
},
},
data() {
return {
loading: false,
minHeight: 0,
navTabHeight: 0,
userInfo: {},
options1: [
{
text: '置顶',
style: {
backgroundColor: '#376cf3',
},
},
],
options12: [
{
text: '取消',
style: {
backgroundColor: '#ccc',
},
},
],
}
},
computed: {
deviceListFilter() {
let arr = this.store.data
return arr
},
},
created() {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
},
mounted() {
console.log(12333, this.store)
},
methods: {
bindClick(e, item) {
engineeringPinToTop({
targetId: item.engineeringId,
targetType: 2,
userId: uni.getStorageSync(this.$cacheKey.userInfo).userIndex,
}).then((res) => {
if (res.code == 'A0000') {
this.$util.toast('操作成功!')
this.store.search()
} else {
this.$util.toast(res.message)
}
})
},
getDeviceList() {
this.store.params.pageSize = 50
this.store.firstCallBack = (res) => {
uni.createSelectorQuery()
.select('.uni-navbar')
.boundingClientRect((rect1) => {
if (!rect1) return
this.navTabHeight = rect1.height
uni.createSelectorQuery()
.select('.nav')
.boundingClientRect((rect2) => {
if (!rect2) return
// #ifdef H5
this.minHeight = 'calc(100vh - ' + (this.navTabHeight + rect2.height + 50) + 'px)'
// #endif
// #ifdef APP-PLUS
this.minHeight = 'calc(100vh - ' + (this.navTabHeight + rect2.height) + 'px)'
console.log(this.minHeight)
// #endif
})
.exec()
})
.exec()
}
this.store.reload()
},
async init() {
console.warn('init')
this.getDeviceList()
},
jump(type, item) {
if (type == 'event') {
// 存储参数
uni.setStorageSync('messageParams', {
engineeringName: item.engineeringName,
engineeringId: item.engineeringId, //工程ID
projectName: '',
projectId: '', //項目ID
deviceName: '',
deviceId: '', //设备ID
lineName: '',
lineId: '', //测点ID
type: '',
})
uni.switchTab({
url: '/pages/index/message1',
})
} else {
uni.setStorageSync('engineering', { name: item.engineeringName, id: item.engineeringId })
uni.navigateTo({
url: '/pages/device/list?type=' + type,
})
}
},
},
}
</script>
<style lang="scss" scoped>
.index-device {
/* 列表容器 */
// .project-card {
// background-color: #ffffff;
// border-radius: 16rpx;
// margin-bottom: 16rpx;
// padding: 24rpx;
// box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
// }
.card-header {
display: flex;
align-items: center;
}
.project-icon {
width: 110rpx;
height: 110rpx;
border-radius: 12rpx;
display: flex;
justify-content: center;
align-items: center;
margin-right: 20rpx;
background-color: #2563eb20;
}
.project-info {
flex: 1;
line-height: 36rpx;
}
.project-name {
font-size: 28rpx;
font-weight: 700;
color: #333333;
margin-bottom: 20rpx;
}
.project-stats {
display: flex;
// justify-content: space-between;
}
.stat-item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
border-right: 2rpx solid #ccc;
&:last-child {
border-right: none;
}
}
.stat-value {
font-size: 36rpx;
font-weight: 700;
}
.stat-label {
font-size: 26rpx;
margin-top: 5rpx;
// color: #666666;
}
.blue {
color: #007aff;
}
.green {
color: #34c759;
}
.red {
color: #ff3b30;
}
.icon-star {
color: #cccccc;
}
}
/deep/ .uni-card {
padding: 0 !important;
}
/deep/ .button-group--right {
padding: 0 0 20rpx;
}
.pinToTop {
background-color: $uni-theme-color;
width: 100rpx;
height: 60rpx;
line-height: 90rpx;
text-align: center;
color: #fff;
font-size: 20rpx;
position: absolute;
top: 0rpx;
right: 0rpx;
position: absolute;
top: 0;
right: 0;
/* 核心:旋转成斜三角效果 */
transform: rotate(45deg) translate(50rpx, -10rpx);
transform-origin: top right;
}
</style>

View File

@@ -1,24 +1,36 @@
<template> <template>
<view class="index-zhuyonghu"> <view class="index-zhuyonghu">
<template v-if="devCount.engineeringListLength > 1"> <template v-if="devCount.engineeringListLength > 0">
<view class="canneng-index-title mb20">所有工程设备统计</view> <view class="canneng-index-title mb20">所有工程设备统计</view>
<view class="header"> <view class="header">
<view class="header-item" @click="jump('allEngineering')"> <view class="header-item boxClick" @click="jump('allEngineering')">
<view class="header-item-value">{{ devCount.onLineDevCount + devCount.offLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.onLineDevCount + devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">设备总数</view> <view class="header-item-label">设备总数</view>
</view> </view>
<view class="header-item" @click="jump('onLineDevs')"> <view class="header-item boxClick" @click="jump('onLineDevs')">
<view class="header-item-value">{{ devCount.onLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.onLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view> <view class="header-item-label">在线设备</view>
</view> </view>
<view class="header-item" @click="jump('offLineDevs')"> <view class="header-item boxClick" @click="jump('offLineDevs')">
<view class="header-item-value">{{ devCount.offLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view> <view class="header-item-label">离线设备</view>
</view> </view>
</view> <view class="header-item boxClick" @click="jumpMessage(0)">
<view class="mt20"></view> <view class="header-item-value">{{ devCount.eventCount || 0 }}</view>
</template> <view class="header-item-label">暂态事件数</view>
<view class="canneng-index-title mb20">当前工程设备统计</view> </view>
<view class="header-item boxClick" @click="jumpMessage(1)">
<view class="header-item-value">{{ devCount.harmonicCount || 0 }}</view>
<view class="header-item-label">稳态事件数</view>
</view>
<view class="header-item boxClick" @click="eningerNum">
<view class="header-item-value">{{ devCount.eningerCount || 0 }}</view>
<view class="header-item-label">工程个数</view>
</view>
</view>
<!-- <view class="mt20"></view> -->
</template>
<!-- <view class="canneng-index-title mb20">当前工程设备统计</view>
<view class="header"> <view class="header">
<view class="header-item" @click="jump('nowEngineering')"> <view class="header-item" @click="jump('nowEngineering')">
<view class="header-item-value" <view class="header-item-value"
@@ -34,135 +46,163 @@
<view class="header-item-value">{{ devCount.currentOffLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.currentOffLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view> <view class="header-item-label">离线设备</view>
</view> </view>
</view> </view> -->
<view class="canneng-index-title mt20">常用功能</view> <view class="canneng-index-title mt20">常用功能</view>
<view style="padding: 20rpx 20rpx 0"> <view style="padding: 20rpx 20rpx 0">
<Cn-grid title="" :auto-fill="false"> <Cn-grid title="" :auto-fill="false">
<Cn-grid-item src="/static/device2.png" text="设备注册" @click="registerDevice(4)"></Cn-grid-item> <Cn-grid-item
<Cn-grid-item class="boxClick"
src="/static/device2.png" src="/static/device2.png"
text="功能调试" text="设备注册"
@click="registerDevice(2)" @click="registerDevice(4)"
v-if="config.feature" ></Cn-grid-item>
></Cn-grid-item> <!-- <Cn-grid-item
<Cn-grid-item src="/static/device2.png"
src="/static/device2.png" text="功能调试"
text="出厂调试" @click="registerDevice(2)"
@click="registerDevice(3)" v-if="config.feature"
v-if="config.factory" ></Cn-grid-item>
></Cn-grid-item> <Cn-grid-item
<Cn-grid-item background="#fff" v-if="!config.feature"></Cn-grid-item> src="/static/device2.png"
<Cn-grid-item background="#fff" v-if="!config.factory"></Cn-grid-item> text="出厂调试"
<Cn-grid-item background="#fff"></Cn-grid-item> @click="registerDevice(3)"
<!-- <Cn-grid-item src="/static/gateway2.png" text="网关注册" @click="registerGateway"></Cn-grid-item> --> v-if="config.factory"
<!-- <Cn-grid-item src="/static/feedback2.png" text="问题反馈" @click="submitFeedBack"></Cn-grid-item>--> ></Cn-grid-item> -->
</Cn-grid> <!-- <Cn-grid-item background="#fff" v-if="!config.feature"></Cn-grid-item>
</view> <Cn-grid-item background="#fff" v-if="!config.factory"></Cn-grid-item> -->
<uni-popup ref="popup" type="dialog" @maskClick="maskClick"> <Cn-grid-item background="#fff"></Cn-grid-item>
<uni-popup-dialog <Cn-grid-item background="#fff"></Cn-grid-item>
mode="base" <Cn-grid-item background="#fff"></Cn-grid-item>
type="info" <!-- <Cn-grid-item src="/static/gateway2.png" text="网关注册" @click="registerGateway"></Cn-grid-item> -->
content="请选择设备类型" <!-- <Cn-grid-item src="/static/feedback2.png" text="问题反馈" @click="submitFeedBack"></Cn-grid-item>-->
:duration="0" </Cn-grid>
confirmText="直连设备" </view>
cancelText="网关接入" <uni-popup ref="popup" type="dialog" @maskClick="maskClick">
cancelColor="#007aff" <uni-popup-dialog
@close="close" mode="base"
@confirm="confirm" type="info"
></uni-popup-dialog> content="请选择设备类型"
</uni-popup> :duration="0"
</view> confirmText="直连设备"
cancelText="网关接入"
cancelColor="#007aff"
@close="close"
@confirm="confirm"
></uni-popup-dialog>
</uni-popup>
</view>
</template> </template>
<script> <script>
export default { export default {
data() { data() {
return { return {
loading: true, loading: true,
config: { config: {
feature: true, feature: true,
factory: true, factory: true,
}, },
type: 0, type: 0,
} }
}, },
props: { props: {
devCount: { devCount: {
type: Object, type: Object,
default: {}, default: {},
}, },
}, },
created() { created() {
this.init() this.init()
}, },
methods: { methods: {
init() { init() {
console.log('工程init') console.log('工程init')
let serverConfig = uni.getStorageSync(this.$cacheKey.serverConfig) let serverConfig = uni.getStorageSync(this.$cacheKey.serverConfig)
serverConfig && (this.config = serverConfig) serverConfig && (this.config = serverConfig)
}, },
submitFeedBack() { submitFeedBack() {
uni.navigateTo({ url: '/pages/home/feedback' }) uni.navigateTo({ url: '/pages/home/feedback' })
}, },
registerDevice(type) { registerDevice(type) {
this.type = type this.type = type
this.$refs.popup.open() this.$refs.popup.open()
// uni.showModal({ // uni.showModal({
// title: '提示', // title: '提示',
// content: '请选择设备类型', // content: '请选择设备类型',
// confirmText: '直连设备', // confirmText: '直连设备',
// cancelText: '网关接入', // cancelText: '网关接入',
// cancelColor: '#007aff', // cancelColor: '#007aff',
// success: ({ confirm, cancel }) => { // success: ({ confirm, cancel }) => {
// if (confirm) { // if (confirm) {
// if (this.devCount.engineeringListLength > 0) { // if (this.devCount.engineeringListLength > 0) {
// uni.navigateTo({ // uni.navigateTo({
// url: '/pages/device/new?type=' + type, // url: '/pages/device/new?type=' + type,
// }) // })
// } else { // } else {
// uni.navigateTo({ // uni.navigateTo({
// url: '/pages/engineering/new?from=index&type=' + type, // url: '/pages/engineering/new?from=index&type=' + type,
// }) // })
// } // }
// } else if (cancel) { // } else if (cancel) {
// // uni.navigateTo({ // // uni.navigateTo({
// // url: '/pages/gateway/list', // // url: '/pages/gateway/list',
// // }) // // })
// this.$util.toast('功能正在开发,敬请期待') // this.$util.toast('功能正在开发,敬请期待')
// } // }
// }, // },
// }) // })
}, },
maskClick() { maskClick() {
this.$refs.popup.close() this.$refs.popup.close()
}, },
close() { close() {
this.$util.toast('功能正在开发,敬请期待') this.$util.toast('功能正在开发,敬请期待')
this.$refs.popup.close() this.$refs.popup.close()
}, },
confirm(value) { confirm(value) {
if (this.devCount.engineeringListLength > 0) { // if (this.devCount.engineeringListLength > 0) {
uni.navigateTo({ uni.navigateTo({
url: '/pages/device/new?type=' + this.type, url: '/pages/device/new?type=' + this.type,
}) })
} else { // } else {
uni.navigateTo({ // uni.navigateTo({
url: '/pages/engineering/new?from=index&type=' + this.type, // url: '/pages/engineering/new?from=index&type=' + this.type,
}) // })
} // }
this.$refs.popup.close() this.$refs.popup.close()
}, },
registerGateway() { registerGateway() {
uni.navigateTo({ uni.navigateTo({
url: '/pages/gateway/new', url: '/pages/gateway/new',
}) })
}, },
jump(type) { jump(type) {
uni.navigateTo({ uni.navigateTo({
url: '/pages/device/list?type=' + type, url: '/pages/device/list?type=' + type,
}) })
}, },
}, jumpMessage(type) {
uni.setStorageSync('messageParams', {
engineeringName: '',
engineeringId: '', //工程ID
projectName: '',
projectId: '', //項目ID
deviceName: '',
deviceId: '', //设备ID
lineName: '',
lineId: '', //测点ID
type: type,
})
uni.switchTab({
url: '/pages/index/message1',
})
},
eningerNum() {
uni.navigateTo({
url: '/pages/engineering/list',
})
},
},
} }
</script> </script>
<style lang="scss"></style> <style lang="scss"></style>

View File

@@ -1,72 +1,71 @@
<template> <template>
<view class="index-zhuyonghu"> <view class="index-zhuyonghu">
<template v-if="devCount.engineeringListLength > 1"> <template v-if="devCount.engineeringListLength > 1">
<view class="canneng-index-title mb20">所有工程设备统计</view> <view class="canneng-index-title mb20">所有工程设备统计</view>
<view class="header"> <view class="header">
<view class="header-item" @click="jump('allEngineering')"> <view class="header-item boxClick" @click="jump('allEngineering')">
<view class="header-item-value">{{ devCount.onLineDevCount + devCount.offLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.onLineDevCount + devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">设备总数</view> <view class="header-item-label">设备总数</view>
</view> </view>
<view class="header-item" @click="jump('onLineDevs')"> <view class="header-item boxClick" @click="jump('onLineDevs')">
<view class="header-item-value">{{ devCount.onLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.onLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view> <view class="header-item-label">在线设备</view>
</view> </view>
<view class="header-item" @click="jump('offLineDevs')"> <view class="header-item boxClick" @click="jump('offLineDevs')">
<view class="header-item-value">{{ devCount.offLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view> <view class="header-item-label">离线设备</view>
</view> </view>
</view> </view>
<view class="mt20"></view> <view class="mt20"></view>
</template> </template>
<view class="canneng-index-title mb20">当前工程设备统计</view> <view class="canneng-index-title mb20">当前工程设备统计</view>
<view class="header"> <view class="header">
<view class="header-item" @click="jump('nowEngineering')"> <view class="header-item boxClick" @click="jump('nowEngineering')">
<view class="header-item-value">{{ <view class="header-item-value">{{
devCount.currentOnLineDevCount + devCount.currentOffLineDevCount || 0 devCount.currentOnLineDevCount + devCount.currentOffLineDevCount || 0
}}</view> }}</view>
<view class="header-item-label">设备总数</view> <view class="header-item-label">设备总数</view>
</view> </view>
<view class="header-item" @click="jump('currentOnLineDevs')"> <view class="header-item boxClick" @click="jump('currentOnLineDevs')">
<view class="header-item-value">{{ devCount.currentOnLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.currentOnLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view> <view class="header-item-label">在线设备</view>
</view> </view>
<view class="header-item" @click="jump('currentOffLineDevs')"> <view class="header-item boxClick" @click="jump('currentOffLineDevs')">
<view class="header-item-value">{{ devCount.currentOffLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.currentOffLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view> <view class="header-item-label">离线设备</view>
</view> </view>
</view> </view>
<view style="padding: 20rpx 20rpx 0"> <!-- <view style="padding: 20rpx 20rpx 0">
<Cn-grid title=""> <Cn-grid title="">
<Cn-grid-item src="/static/device2.png" text="设备注册" @click="registerDevice"></Cn-grid-item> <Cn-grid-item src="/static/device2.png" text="设备注册" @click="registerDevice"></Cn-grid-item>
<!-- <Cn-grid-item src="/static/gateway2.png" text="网关注册" @click="registerGateway"></Cn-grid-item> --> <Cn-grid-item src="/static/feedback2.png" text="问题反馈" @click="submitFeedBack"></Cn-grid-item>
<Cn-grid-item src="/static/feedback2.png" text="问题反馈" @click="submitFeedBack"></Cn-grid-item> </Cn-grid>
</Cn-grid> </view> -->
</view>
</view>
</view> </template>
</template> <script>
<script> export default {
export default { props: {
props: { devCount: {
devCount: { type: Object,
type: Object, default: {},
default: {}, },
}, },
}, methods: {
methods: { jump(type) {
jump(type) { uni.navigateTo({
uni.navigateTo({ url:
url: '/pages/device/list?type=' + type
'/pages/device/list?type=' + type })
}) },
}, submitFeedBack() {
submitFeedBack() { uni.navigateTo({url: '/pages/home/feedback'})
uni.navigateTo({url: '/pages/home/feedback'}) },
}, registerDevice() {
registerDevice() { this.$util.toast('此功能仅对正式用户开放')
this.$util.toast('此功能仅对正式用户开放') },
}, },
}, }
} </script>
</script> <style lang="scss"></style>
<style lang="scss"></style>

View File

@@ -1,122 +1,135 @@
<template> <template>
<view class="index-zhuanzhi"> <view class="index-zhuanzhi">
<template v-if="devCount.engineeringListLength > 1"> <template v-if="devCount.engineeringListLength > 1">
<view class="canneng-index-title mb20">所有工程设备统计</view> <view class="canneng-index-title mb20">所有工程设备统计</view>
<view class="header"> <view class="header">
<view class="header-item" @click="jump('allEngineering')"> <view class="header-item boxClick" @click="jump('allEngineering')">
<view class="header-item-value">{{ devCount.onLineDevCount + devCount.offLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.onLineDevCount + devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">设备总数</view> <view class="header-item-label">设备总数</view>
</view> </view>
<view class="header-item" @click="jump('onLineDevs')"> <view class="header-item boxClick" @click="jump('onLineDevs')">
<view class="header-item-value">{{ devCount.onLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.onLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view> <view class="header-item-label">在线设备</view>
</view> </view>
<view class="header-item" @click="jump('offLineDevs')"> <view class="header-item boxClick" @click="jump('offLineDevs')">
<view class="header-item-value">{{ devCount.offLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view> <view class="header-item-label">离线设备</view>
</view> </view>
<view class="header-item" @click="jumpMessage"> <view class="header-item boxClick" @click="jumpMessage(2, false)">
<view class="header-item-value">{{ devCount.alarmCount || 0 }}</view> <view class="header-item-value">{{ devCount.alarmCount || 0 }}</view>
<view class="header-item-label">告警数量</view> <view class="header-item-label">告警数量</view>
</view> </view>
<view class="header-item" @click="jumpMessage"> <view class="header-item boxClick" @click="jumpMessage(0, false)">
<view class="header-item-value">{{ <view class="header-item-value">{{
devCount.eventCount + devCount.runCount + devCount.harmonicCount || 0 devCount.eventCount + devCount.runCount + devCount.harmonicCount || 0
}}</view> }}</view>
<view class="header-item-label">事件数量</view> <view class="header-item-label">事件数量</view>
</view> </view>
<view class="header-item" @click="eningerNum"> <view class="header-item boxClick" @click="eningerNum">
<view class="header-item-value">{{ devCount.eningerCount || 0 }}</view> <view class="header-item-value">{{ devCount.eningerCount || 0 }}</view>
<view class="header-item-label">工程个数</view> <view class="header-item-label">工程个数</view>
</view> </view>
</view> </view>
<view class="mt20"></view> <view class="mt20"></view>
</template> </template>
<view class="canneng-index-title mb20">当前工程设备统计</view> <view class="canneng-index-title mb20">当前工程设备统计</view>
<view class="header"> <view class="header">
<view class="header-item" @click="jump('nowEngineering')"> <view class="header-item boxClick" @click="jump('nowEngineering')">
<view class="header-item-value">{{ <view class="header-item-value">{{
devCount.currentOnLineDevCount + devCount.currentOffLineDevCount || 0 devCount.currentOnLineDevCount + devCount.currentOffLineDevCount || 0
}}</view> }}</view>
<view class="header-item-label">设备总数</view> <view class="header-item-label">设备总数</view>
</view> </view>
<view class="header-item" @click="jump('currentOnLineDevs')"> <view class="header-item boxClick" @click="jump('currentOnLineDevs')">
<view class="header-item-value">{{ devCount.currentOnLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.currentOnLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view> <view class="header-item-label">在线设备</view>
</view> </view>
<view class="header-item" @click="jump('currentOffLineDevs')"> <view class="header-item boxClick" @click="jump('currentOffLineDevs')">
<view class="header-item-value">{{ devCount.currentOffLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.currentOffLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view> <view class="header-item-label">离线设备</view>
</view> </view>
<view class="header-item" @click="jumpMessage"> <view class="header-item boxClick" @click="jumpMessage(2, true)">
<view class="header-item-value">{{ devCount.currentAlarmCount || 0 }}</view> <view class="header-item-value">{{ devCount.currentAlarmCount || 0 }}</view>
<view class="header-item-label">告警数量</view> <view class="header-item-label">告警数量</view>
</view> </view>
<view class="header-item" @click="jumpMessage"> <view class="header-item boxClick" @click="jumpMessage(0, true)">
<view class="header-item-value">{{ <view class="header-item-value">{{
devCount.currentEventCount + devCount.currentRunCount + devCount.currentHarmonicCount || 0 devCount.currentEventCount + devCount.currentRunCount + devCount.currentHarmonicCount || 0
}}</view> }}</view>
<view class="header-item-label">事件数量</view> <view class="header-item-label">事件数量</view>
</view> </view>
<view class="header-item" @click="projectNum(true)"> <view class="header-item boxClick" @click="projectNum(true)">
<view class="header-item-value">{{ devCount.currentProjectCount || 0 }}</view> <view class="header-item-value">{{ devCount.currentProjectCount || 0 }}</view>
<view class="header-item-label">项目个数</view> <view class="header-item-label">项目个数</view>
</view> </view>
</view> </view>
</view> </view>
</template> </template>
<script> <script>
export default { export default {
data() { data() {
return { return {
loading: false, loading: false,
} }
}, },
props: { props: {
devCount: { devCount: {
type: Object, type: Object,
default: {}, default: {},
}, },
}, },
methods: { methods: {
jumpMessage(){ jumpMessage(type, flag) {
uni.switchTab({ uni.setStorageSync('messageParams', {
url: '/pages/index/message', // name: flag ? uni.getStorageSync('engineering').name : '',
}) // id: flag ? uni.getStorageSync('engineering').id : '',
}, engineeringName: flag ? uni.getStorageSync('engineering').name : '',
eningerNum(){ engineeringId: flag ? uni.getStorageSync('engineering').id : '', //工程ID
uni.navigateTo({ projectName: '',
url: '/pages/engineering/list', projectId: '', //項目ID
}) deviceName: '',
}, deviceId: '', //设备ID
projectWarning() { lineName: '',
uni.navigateTo({ lineId: '', //测点ID
url: '/pages/zhuanzhi/warning', type: type,
}) })
}, uni.switchTab({
projectNum() { url: '/pages/index/message1',
console.log(now) })
if (now) { },
let engineering = uni.getStorageSync('engineering') eningerNum() {
uni.navigateTo({ uni.navigateTo({
url: '/pages/project/list?engineeringName=' + engineering.name + '&engineeringId=' + engineering.id, url: '/pages/engineering/list',
}) })
} else { },
uni.navigateTo({ projectWarning() {
url: '/pages/project/list', uni.navigateTo({
}) url: '/pages/zhuanzhi/warning',
} })
}, },
jump(type) { projectNum(now) {
uni.navigateTo({ console.log(now)
url: '/pages/device/list?type=' + type, if (now) {
}) let engineering = uni.getStorageSync('engineering')
}, uni.navigateTo({
}, url: '/pages/project/list?engineeringName=' + engineering.name + '&engineeringId=' + engineering.id,
created() {}, })
} } else {
</script> uni.navigateTo({
<style lang="scss"> url: '/pages/project/list',
.index-zhuanzhi { })
} }
</style> },
jump(type) {
uni.navigateTo({
url: '/pages/device/list?type=' + type,
})
},
},
created() {},
}
</script>
<style lang="scss">
.index-zhuanzhi {
}
</style>

View File

@@ -1,143 +1,174 @@
<template> <template>
<view class="index-zhuyonghu"> <view class="index-zhuyonghu">
<template v-if="devCount.engineeringListLength > 1"> <template v-if="devCount.engineeringListLength > 1">
<view class="canneng-index-title mb20">所有工程设备统计</view> <view class="canneng-index-title mb20">所有工程设备统计</view>
<view class="header"> <view class="header">
<view class="header-item" @click="jump('allEngineering')"> <view class="header-item boxClick" @click="jump('allEngineering')">
<view class="header-item-value">{{ devCount.onLineDevCount + devCount.offLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.onLineDevCount + devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">设备总数</view> <view class="header-item-label">设备总数</view>
</view> </view>
<view class="header-item" @click="jump('onLineDevs')"> <view class="header-item boxClick" @click="jump('onLineDevs')">
<view class="header-item-value">{{ devCount.onLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.onLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view> <view class="header-item-label">在线设备</view>
</view> </view>
<view class="header-item" @click="jump('offLineDevs')"> <view class="header-item boxClick" @click="jump('offLineDevs')">
<view class="header-item-value">{{ devCount.offLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view> <view class="header-item-label">离线设备</view>
</view> </view>
</view> </view>
<view class="mt20"></view> <view class="mt20"></view>
</template> </template>
<view class="canneng-index-title mb20">当前工程设备统计</view> <view class="canneng-index-title mb20">当前工程设备统计</view>
<view class="header"> <view class="header">
<view class="header-item" @click="jump('nowEngineering')"> <view class="header-item boxClick" @click="jump('nowEngineering')">
<view class="header-item-value" <view class="header-item-value"
>{{ devCount.currentOnLineDevCount + devCount.currentOffLineDevCount || 0 }} >{{ devCount.currentOnLineDevCount + devCount.currentOffLineDevCount || 0 }}
</view> </view>
<view class="header-item-label">设备总数</view> <view class="header-item-label">设备总数</view>
</view> </view>
<view class="header-item" @click="jump('currentOnLineDevs')"> <view class="header-item boxClick" @click="jump('currentOnLineDevs')">
<view class="header-item-value">{{ devCount.currentOnLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.currentOnLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view> <view class="header-item-label">在线设备</view>
</view> </view>
<view class="header-item" @click="jump('currentOffLineDevs')"> <view class="header-item boxClick" @click="jump('currentOffLineDevs')">
<view class="header-item-value">{{ devCount.currentOffLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.currentOffLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view> <view class="header-item-label">离线设备</view>
</view> </view>
</view> <view class="header-item boxClick" @click="jumpMessage('0')">
<view class="canneng-index-title mt20">常用功能</view> <view class="header-item-value">{{ devCount.currentEventCount || 0 }}</view>
<view style="padding: 20rpx 20rpx 0"> <view class="header-item-label">暂态事件数</view>
<Cn-grid title=""> </view>
<Cn-grid-item src="/static/device2.png" text="设备注册" @click="registerDevice"></Cn-grid-item> <view class="header-item boxClick" @click="jumpMessage('1')">
<!-- <Cn-grid-item src="/static/gateway2.png" text="网关注册" @click="registerGateway"></Cn-grid-item> --> <view class="header-item-value">{{ devCount.currentHarmonicCount || 0 }}</view>
<Cn-grid-item src="/static/feedback2.png" text="问题反馈" @click="submitFeedBack"></Cn-grid-item> <view class="header-item-label">稳态事件数</view>
</Cn-grid> </view>
</view> </view>
<uni-popup ref="popup" type="dialog" @maskClick='maskClick'> <view class="canneng-index-title mt20">常用功能</view>
<uni-popup-dialog <view style="padding: 20rpx 20rpx 0">
mode="base" <Cn-grid title="">
type="info" <Cn-grid-item
content="请选择设备类型" src="/static/device2.png"
:duration="0" class="boxClick"
confirmText="直连设备" text="设备注册"
cancelText="网关接入" @click="registerDevice"
cancelColor= '#007aff' ></Cn-grid-item>
@close="close" <!-- <Cn-grid-item src="/static/gateway2.png" text="网关注册" @click="registerGateway"></Cn-grid-item> -->
@confirm="confirm" <Cn-grid-item
></uni-popup-dialog> src="/static/feedback2.png"
class="boxClick"
</uni-popup> text="问题反馈"
</view> @click="submitFeedBack"
></Cn-grid-item>
</Cn-grid>
</view>
<uni-popup ref="popup" type="dialog" @maskClick="maskClick">
<uni-popup-dialog
mode="base"
type="info"
content="请选择设备类型"
:duration="0"
confirmText="直连设备"
cancelText="网关接入"
cancelColor="#007aff"
@close="close"
@confirm="confirm"
></uni-popup-dialog>
</uni-popup>
</view>
</template> </template>
<script> <script>
export default { export default {
data() { data() {
return { return {
loading: false, loading: false,
} }
}, },
props: { props: {
devCount: { devCount: {
type: Object, type: Object,
default: {}, default: {},
}, },
}, },
methods: { methods: {
submitFeedBack() { submitFeedBack() {
uni.navigateTo({ url: '/pages/home/feedback' }) uni.navigateTo({ url: '/pages/home/feedback' })
}, },
registerDevice() { registerDevice() {
this.$refs.popup.open() this.$refs.popup.open()
// uni.showModal({ // uni.showModal({
// title: '提示', // title: '提示',
// content: '请选择设备类型', // content: '请选择设备类型',
// confirmText: '直连设备', // confirmText: '直连设备',
// cancelText: '网关接入', // cancelText: '网关接入',
// cancelColor: '#007aff', // cancelColor: '#007aff',
// success: ({confirm, cancel}) => { // success: ({confirm, cancel}) => {
// if (confirm) { // if (confirm) {
// if (this.devCount.engineeringListLength > 0) { // if (this.devCount.engineeringListLength > 0) {
// uni.navigateTo({ // uni.navigateTo({
// url: '/pages/device/new?type=4', // url: '/pages/device/new?type=4',
// }) // })
// } else { // } else {
// uni.navigateTo({ // uni.navigateTo({
// url: '/pages/engineering/new?from=index' // url: '/pages/engineering/new?from=index'
// }) // })
// } // }
// } else if (cancel) { // } else if (cancel) {
// // uni.navigateTo({ // // uni.navigateTo({
// // url: '/pages/gateway/list', // // url: '/pages/gateway/list',
// // }) // // })
// this.$util.toast('功能正在开发,敬请期待') // this.$util.toast('功能正在开发,敬请期待')
// } // }
// }, // },
// }) // })
}, },
maskClick(){ maskClick() {
this.$refs.popup.close() this.$refs.popup.close()
}, },
close() { close() {
this.$util.toast('功能正在开发,敬请期待') this.$util.toast('功能正在开发,敬请期待')
this.$refs.popup.close() this.$refs.popup.close()
}, },
confirm(value) { confirm(value) {
// if (this.devCount.engineeringListLength > 0) {
if (this.devCount.engineeringListLength > 0) { uni.navigateTo({
uni.navigateTo({ url: '/pages/device/new?type=4',
url: '/pages/device/new?type=4', })
}) // } else {
} else { // uni.navigateTo({
uni.navigateTo({ // url: '/pages/engineering/new?from=index',
url: '/pages/engineering/new?from=index' // })
}) // }
}
this.$refs.popup.close()
},
this.$refs.popup.close() registerGateway() {
}, uni.navigateTo({
registerGateway() { url: '/pages/gateway/new',
uni.navigateTo({ })
url: '/pages/gateway/new', },
}) jump(type) {
}, uni.navigateTo({
jump(type) { url: '/pages/device/list?type=' + type,
uni.navigateTo({ })
url: '/pages/device/list?type=' + type, },
}) jumpMessage(type) {
}, uni.setStorageSync('messageParams', {
}, engineeringName: '',
engineeringId: '', //工程ID
projectName: '',
projectId: '', //項目ID
deviceName: '',
deviceId: '', //设备ID
lineName: '',
lineId: '', //测点ID
type: type,
})
uni.switchTab({
url: '/pages/index/message1',
})
},
},
} }
</script> </script>
<style lang="scss"></style> <style lang="scss"></style>

View File

@@ -1,122 +1,131 @@
<template> <template>
<view class="index-zhuanzhi"> <view class="index-zhuanzhi">
<template v-if="devCount.engineeringListLength > 1"> <template v-if="devCount.engineeringListLength > 1">
<view class="canneng-index-title mb20">所有工程设备统计</view> <view class="canneng-index-title mb20">所有工程设备统计</view>
<view class="header"> <view class="header">
<view class="header-item" @click="jump('allEngineering')"> <view class="header-item boxClick" @click="jump('allEngineering')">
<view class="header-item-value">{{ devCount.onLineDevCount + devCount.offLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.onLineDevCount + devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">设备总数</view> <view class="header-item-label">设备总数</view>
</view> </view>
<view class="header-item" @click="jump('onLineDevs')"> <view class="header-item boxClick" @click="jump('onLineDevs')">
<view class="header-item-value">{{ devCount.onLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.onLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view> <view class="header-item-label">在线设备</view>
</view> </view>
<view class="header-item" @click="jump('offLineDevs')"> <view class="header-item boxClick" @click="jump('offLineDevs')">
<view class="header-item-value">{{ devCount.offLineDevCount || 0 }}</view> <view class="header-item-value">{{ devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view> <view class="header-item-label">离线设备</view>
</view> </view>
<view class="header-item" @click="jumpMessage"> <view class="header-item boxClick" @click="jumpMessage(0, false)">
<view class="header-item-value">{{ devCount.alarmCount || 0 }}</view> <view class="header-item-value">{{ devCount.eventCount || 0 }}</view>
<view class="header-item-label">告警数量</view> <view class="header-item-label">暂态事件数</view>
</view> </view>
<view class="header-item" @click="jumpMessage"> <view class="header-item boxClick" @click="jumpMessage(1, false)">
<view class="header-item-value">{{ <view class="header-item-value">{{ devCount.harmonicCount || 0 }}</view>
devCount.eventCount + devCount.runCount + devCount.harmonicCount || 0 <view class="header-item-label">稳态事件数</view>
}}</view> </view>
<view class="header-item-label">事件数量</view> <view class="header-item boxClick" @click="eningerNum">
</view> <view class="header-item-value">{{ devCount.eningerCount || 0 }}</view>
<view class="header-item" @click="eningerNum"> <view class="header-item-label">工程个数</view>
<view class="header-item-value">{{ devCount.eningerCount || 0 }}</view> </view>
<view class="header-item-label">工程个数</view> </view>
</view> <view class="mt20"></view>
</view> </template>
<view class="mt20"></view> <view class="canneng-index-title mb20">当前工程设备统计</view>
</template> <view class="header">
<view class="canneng-index-title mb20">当前工程设备统计</view> <view class="header-item boxClick" @click="jump('nowEngineering')">
<view class="header"> <view class="header-item-value"
<view class="header-item" @click="jump('nowEngineering')"> >{{ devCount.currentOnLineDevCount + devCount.currentOffLineDevCount || 0 }}
<view class="header-item-value" </view>
>{{ devCount.currentOnLineDevCount + devCount.currentOffLineDevCount || 0 }} <view class="header-item-label">设备总数</view>
</view> </view>
<view class="header-item-label">设备总数</view> <view class="header-item boxClick" @click="jump('currentOnLineDevs')">
</view> <view class="header-item-value">{{ devCount.currentOnLineDevCount || 0 }}</view>
<view class="header-item" @click="jump('currentOnLineDevs')"> <view class="header-item-label">在线设备</view>
<view class="header-item-value">{{ devCount.currentOnLineDevCount || 0 }}</view> </view>
<view class="header-item-label">在线设备</view> <view class="header-item boxClick" @click="jump('currentOffLineDevs')">
</view> <view class="header-item-value">{{ devCount.currentOffLineDevCount || 0 }}</view>
<view class="header-item" @click="jump('currentOffLineDevs')"> <view class="header-item-label">离线设备</view>
<view class="header-item-value">{{ devCount.currentOffLineDevCount || 0 }}</view> </view>
<view class="header-item-label">离线设备</view> <view class="header-item boxClick" @click="jumpMessage(0, true)">
</view> <view class="header-item-value">{{ devCount.currentEventCount || 0 }}</view>
<view class="header-item" @click="jumpMessage"> <view class="header-item-label">暂态事件数</view>
<view class="header-item-value">{{ devCount.currentAlarmCount || 0 }}</view> </view>
<view class="header-item-label">告警数量</view> <view class="header-item boxClick" @click="jumpMessage(1, true)">
</view> <view class="header-item-value">{{ devCount.currentHarmonicCount || 0 }}</view>
<view class="header-item" @click="jumpMessage"> <view class="header-item-label">稳态事件数</view>
<view class="header-item-value">{{ </view>
devCount.currentEventCount + devCount.currentRunCount + devCount.currentHarmonicCount || 0 <view class="header-item boxClick" @click="projectNum(true)">
}}</view> <view class="header-item-value">{{ devCount.currentProjectCount || 0 }}</view>
<view class="header-item-label">事件数量</view> <view class="header-item-label">项目个数</view>
</view> </view>
<view class="header-item" @click="projectNum(true)"> </view>
<view class="header-item-value">{{ devCount.currentProjectCount || 0 }}</view> </view>
<view class="header-item-label">项目个数</view> </template>
</view> <script>
</view> export default {
</view> data() {
</template> return {
<script> loading: false,
export default { }
data() { },
return { props: {
loading: false, devCount: {
} type: Object,
}, default: {},
props: { },
devCount: { },
type: Object, methods: {
default: {}, projectWarning() {
}, uni.navigateTo({
}, url: '/pages/zhuanzhi/warning',
methods: { })
projectWarning() { },
uni.navigateTo({ eningerNum() {
url: '/pages/zhuanzhi/warning', uni.navigateTo({
}) url: '/pages/engineering/list',
}, })
eningerNum() { },
uni.navigateTo({ jumpMessage(type, flag) {
url: '/pages/engineering/list', uni.setStorageSync('messageParams', {
}) // name: flag ? uni.getStorageSync('engineering').name : '',
}, // id: flag ? uni.getStorageSync('engineering').id : '',
jumpMessage(){ engineeringName: flag ? uni.getStorageSync('engineering').name : '',
uni.switchTab({ engineeringId: flag ? uni.getStorageSync('engineering').id : '', //工程ID
url: '/pages/index/message', projectName: '',
}) projectId: '', //項目ID
}, deviceName: '',
projectNum(now) { deviceId: '', //设备ID
console.log(now) lineName: '',
if (now) { lineId: '', //测点ID
let engineering = uni.getStorageSync('engineering') type: type,
uni.navigateTo({ })
url: '/pages/project/list?engineeringName=' + engineering.name + '&engineeringId=' + engineering.id, uni.switchTab({
}) url: '/pages/index/message1',
} else { })
uni.navigateTo({ },
url: '/pages/project/list', projectNum(now) {
}) console.log(now)
} if (now) {
}, let engineering = uni.getStorageSync('engineering')
jump(type) { uni.navigateTo({
uni.navigateTo({ url: '/pages/project/list?engineeringName=' + engineering.name + '&engineeringId=' + engineering.id,
url: '/pages/device/list?type=' + type, })
}) } else {
}, uni.navigateTo({
}, url: '/pages/project/list',
created() {}, })
} }
</script> },
<style lang="scss"> jump(type) {
.index-zhuanzhi { uni.navigateTo({
} url: '/pages/device/list?type=' + type,
</style> })
},
},
created() {},
}
</script>
<style lang="scss">
.index-zhuanzhi {
}
</style>

View File

@@ -0,0 +1,663 @@
<template>
<view class="itic2-page">
<scroll-view class="itic2-scroll" scroll-y :show-scrollbar="false">
<view class="project-header card">
<view class="project-title-row">
<view class="project-title-left">
<uni-icons custom-prefix="iconfont" type="icon-gongcheng" size="22" color="#376cf3" />
<text class="project-name">{{ engineeringName }}</text>
</view>
<view class="switch-btn" @click="switchEngineering">
<uni-icons type="loop" size="14" color="#376cf3" />
<text>切换工程</text>
</view>
</view>
<view class="stats-row">
<view class="stats-item" v-for="(item, idx) in summaryStats" :key="idx">
<text class="stats-num">{{ item.value }}</text>
<text class="stats-label">{{ item.label }}</text>
</view>
</view>
</view>
<view class="monitor-section-header">
<view class="section-title-row section-title-row--no-mb">
<uni-icons type="settings" size="18" color="#376cf3" />
<text class="section-title">已选展示指标</text>
</view>
</view>
<view class="indicators-card card">
<view class="indicator-tags">
<view
v-for="(tag, idx) in selectedIndicators"
:key="tag"
class="indicator-tag indicator-tag--active"
@click="removeIndicator(idx)"
>
<text class="indicator-tag-text">{{ formatIndicatorTag(tag) }}</text>
<uni-icons type="closeempty" size="12" color="#376cf3" />
</view>
<view class="indicator-tag indicator-tag--add" @click="openIndicatorPopup">
<text>+添加指标</text>
</view>
</view>
</view>
<view class="monitor-section">
<view class="monitor-section-header">
<view class="section-title-row section-title-row--no-mb">
<uni-icons type="map-pin-ellipse" size="20" color="#376cf3" />
<text class="section-title">监测点信息</text>
</view>
<view class="legend-row">
<view class="legend-item" v-for="phase in phaseColors" :key="phase.name">
<view class="legend-dot" :style="{ background: phase.color }" />
<text class="legend-text">{{ phase.name }}</text>
</view>
</view>
</view>
<view class="monitor-list">
<view class="monitor-card card" v-for="(point, idx) in monitoringPoints" :key="idx">
<view class="card-header">
<view class="event-icon">
<Cn-icon-transient name="监测点" />
</view>
<view class="card-header-info">
<text class="point-name ellipsis">{{ point.pointName }}</text>
<view class="meta-row">
<text class="meta-item ellipsis">项目{{ point.projectName }}</text>
<text class="meta-item ellipsis">设备{{ point.deviceName }}</text>
</view>
<text class="meta-time ellipsis">最新数据时间{{ point.dataTime || '-' }}</text>
</view>
</view>
<view class="params-section">
<view
v-for="(rowItems, rowIdx) in chunkedChildren(getDisplayChildren(point))"
:key="rowIdx"
class="double-row"
>
<view v-for="(child, childIdx) in rowItems" :key="childIdx" class="param-group">
<view class="param-title">
<text>{{ child.name }}</text>
</view>
<view class="phase-vertical">
<view class="phase-item-vertical">
<text class="phase-value-vertical" :style="{ color: phaseColors[0].color }">{{ child.A }}</text>
</view>
<view class="phase-divider" />
<view class="phase-item-vertical">
<text class="phase-value-vertical" :style="{ color: phaseColors[1].color }">{{ child.B }}</text>
</view>
<view class="phase-divider" />
<view class="phase-item-vertical">
<text class="phase-value-vertical" :style="{ color: phaseColors[2].color }">{{ child.C }}</text>
</view>
</view>
</view>
</view>
</view>
<view class="more-btn" @click="onMoreIndicators(point)">
<uni-icons type="list" size="16" color="#376cf3" />
<text>更多指标</text>
</view>
</view>
</view>
</view>
</scroll-view>
<uni-popup ref="indicatorPopup" type="bottom">
<view class="indicator-popup">
<view class="indicator-popup-header">
<text class="indicator-popup-cancel" @click="closeIndicatorPopup">取消</text>
<text class="indicator-popup-confirm" @click="confirmIndicatorPopup">确定</text>
</view>
<scroll-view class="indicator-popup-list" scroll-y>
<view v-if="targetLists.length === 0" class="indicator-popup-empty">
<text>暂无指标数据</text>
</view>
<view
v-for="item in targetLists"
:key="item.id || item.name"
class="indicator-popup-item"
:class="{ 'indicator-popup-item--active': popupSelectedIndicators.includes(item.name) }"
@click="togglePopupIndicator(item.name)"
>
<text>{{ item.name }}</text>
<uni-icons
v-if="popupSelectedIndicators.includes(item.name)"
type="checkmarkempty"
size="18"
color="#376cf3"
/>
</view>
</scroll-view>
</view>
</uni-popup>
</view>
</template>
<script>
import { queryByCode, queryCsDictTree } from '@/common/api/dictionary'
const DEFAULT_INDICATOR_CODES = ['Key_Power_Quality_V', 'Key_Power_Quality_I']
export default {
data() {
return {
targetLists: [],
popupSelectedIndicators: [],
engineeringName: '',
summaryStats: [
{ label: '项目总数', value: 10 },
{ label: '设备总数', value: 8 },
{ label: '监测点总数', value: 12 },
],
selectedIndicators: [],
phaseColors: [
{ name: 'A相', color: '#F1B22E' },
{ name: 'B相', color: '#2BA471' },
{ name: 'C相', color: '#D54941' },
],
monitoringPoints: [
{
pointName: '测试监测点',
projectName: '测试项目',
deviceName: '测试设备',
dataTime: '2026-05-29 12:00:00',
children: [
{ name: '电压总有效值', A: '10.52', B: '10.52', C: '10.52' },
{ name: '电流总有效值', A: '10.52', B: '10.52', C: '10.52' },
{ name: '基波电压幅值', A: '10.52', B: '10.52', C: '10.52' },
{ name: '基波电流幅值', A: '10.52', B: '10.52', C: '10.52' },
],
},
],
}
},
// 页面显示时同步工程名称
onShow() {
const engineering = uni.getStorageSync('engineering')
if (engineering?.name) {
this.engineeringName = engineering.name
}
},
// 加载电能质量指标字典
created() {
queryByCode('Key_Power_Quality').then((res) => {
queryCsDictTree(res.data.id).then((resp) => {
this.targetLists = (resp.data || []).slice().reverse()
this.initDefaultIndicators()
})
})
},
methods: {
// 指标名称超过6个字截断显示
formatIndicatorTag(name) {
if (!name || name.length <= 6) return name
return `${name.slice(0, 6)}...`
},
// 判断指标名称是否匹配(兼容括号后缀)
matchIndicator(name, selected) {
const base = (name || '').replace(/\(.*\)/, '')
return base.indexOf(selected) === 0 || selected.indexOf(base) === 0
},
// 初始化默认勾选指标
initDefaultIndicators() {
if (this.selectedIndicators.length) return
this.selectedIndicators = this.targetLists
.filter((item) => DEFAULT_INDICATOR_CODES.includes(item.code) && item.name)
.map((item) => item.name)
},
// 跳转切换工程
switchEngineering() {
uni.navigateTo({ url: '/pages/home/selectEngineering' })
},
// 移除已选指标
removeIndicator(idx) {
if (this.selectedIndicators.length <= 1) {
uni.showToast({ title: '至少保留一个指标', icon: 'none' })
return
}
this.selectedIndicators.splice(idx, 1)
},
// 打开指标选择弹窗
openIndicatorPopup() {
if (!this.targetLists.length) {
uni.showToast({ title: '暂无指标数据', icon: 'none' })
return
}
this.popupSelectedIndicators = this.targetLists
.filter((item) => this.selectedIndicators.some((name) => this.matchIndicator(item.name, name)))
.map((item) => item.name)
this.$refs.indicatorPopup.open()
},
// 关闭指标选择弹窗
closeIndicatorPopup() {
this.$refs.indicatorPopup.close()
this.popupSelectedIndicators = []
},
// 切换弹窗内指标勾选状态
togglePopupIndicator(name) {
const idx = this.popupSelectedIndicators.indexOf(name)
if (idx > -1) {
this.popupSelectedIndicators.splice(idx, 1)
} else {
this.popupSelectedIndicators.push(name)
}
},
// 确认指标选择
confirmIndicatorPopup() {
if (!this.popupSelectedIndicators.length) {
uni.showToast({ title: '至少保留一个指标', icon: 'none' })
return
}
this.selectedIndicators = [...this.popupSelectedIndicators]
this.closeIndicatorPopup()
},
// 查看更多指标
onMoreIndicators(point) {
const params = encodeURIComponent(
JSON.stringify({
...point,
engineeringName: this.engineeringName,
selectedIndicators: this.selectedIndicators,
}),
)
uni.navigateTo({
url: `/pages/index/comp/targetInfo?point=${params}`,
})
},
// 获取监测点当前展示的指标数据
getDisplayChildren(point) {
return (point.children || []).filter((child) =>
this.selectedIndicators.some((name) => this.matchIndicator(child.name, name)),
)
},
// 将指标列表按每行两个分组
chunkedChildren(children) {
const result = []
for (let i = 0; i < children.length; i += 2) {
result.push(children.slice(i, i + 2))
}
return result
},
},
}
</script>
<style lang="scss" scoped>
.itic2-page {
min-height: 100vh;
background: #f7f8fa;
}
.itic2-scroll {
height: 100vh;
padding-top: 20rpx;
box-sizing: border-box;
}
.card {
background: #ffffff;
border-radius: 10px;
box-shadow: rgba(0, 0, 0, 0.08) 0px 0px 3px 1px;
margin: 0 10px 10px;
overflow: hidden;
}
.project-header {
padding: 20rpx;
// margin-top: 20rpx;
}
.project-title-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20rpx;
}
.project-title-left {
display: flex;
align-items: center;
gap: 12rpx;
flex: 1;
min-width: 0;
}
.project-name {
font-size: 32rpx;
font-weight: 700;
color: #333333;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.switch-btn {
display: flex;
align-items: center;
gap: 6rpx;
padding: 8rpx 20rpx;
border: 1rpx solid #376cf380;
background-color: #266FFF10;
border-radius: 16rpx;
flex-shrink: 0;
text {
font-size: 24rpx;
color: #376cf3;
}
}
.stats-row {
display: flex;
gap: 20rpx;
}
.stats-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 4rpx;
padding: 16rpx 12rpx;
background: #376cf3;
border-radius: 16rpx;
color: #ffffff;
}
.stats-num {
font-size: 44rpx;
font-weight: 700;
line-height: 1.2;
}
.stats-label {
font-size: 26rpx;
}
.indicators-card {
padding: 24rpx;
}
.section-title-row {
display: flex;
align-items: center;
gap: 10rpx;
margin-bottom: 20rpx;
&--no-mb {
margin-bottom: 0;
}
}
.section-title {
font-size: 30rpx;
font-weight: 600;
color: #333333;
}
.indicator-tags {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
}
.indicator-tag {
display: flex;
align-items: center;
gap: 8rpx;
padding: 6rpx 16rpx;
border-radius: 16rpx;
font-size: 26rpx;
max-width: 100%;
.indicator-tag-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&--active {
background: #376cf315;
color: #376cf3;
}
&--add {
background: #f5f5f5;
color: #666666;
border: 1rpx dashed #dcdfe6;
}
}
.monitor-section-header {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12rpx;
padding: 0 10px 16rpx;
}
.legend-row {
display: flex;
gap: 20rpx;
align-items: center;
}
.legend-item {
display: flex;
align-items: center;
gap: 8rpx;
}
.legend-dot {
width: 16rpx;
height: 16rpx;
border-radius: 50%;
}
.legend-text {
font-size: 24rpx;
color: #666666;
}
.monitor-list {
display: flex;
flex-direction: column;
padding-bottom: 40rpx;
}
.monitor-card {
border: 1rpx solid #eef2f6;
box-shadow: rgba(0, 0, 0, 0.08) 0px 0px 3px 1px;
}
.card-header {
padding: 20rpx 20rpx 12rpx;
display: flex;
align-items: center;
border-bottom: 1rpx solid #eef2f6;
}
.event-icon {
width: 90rpx;
height: 90rpx;
border-radius: 16rpx;
display: flex;
justify-content: center;
align-items: center;
margin-right: 20rpx;
background-color: #376cf320;
flex-shrink: 0;
}
.card-header-info {
flex: 1;
min-width: 0;
}
.point-name {
display: block;
font-size: 30rpx;
font-weight: 700;
color: #333333;
margin-bottom: 8rpx;
}
.meta-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 6rpx 12rpx;
}
.meta-item {
font-size: 26rpx;
color: #666666;
line-height: 1.3;
}
.meta-time {
display: block;
margin-top: 8rpx;
font-size: 26rpx;
color: #666666;
line-height: 1.3;
}
.params-section {
padding: 20rpx 16rpx;
}
.double-row {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16rpx;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
}
.param-group {
min-width: 0;
background: #f3f3f3;
border-radius: 16rpx;
padding: 16rpx 8rpx 12rpx;
}
.param-title {
font-size: 24rpx;
color: #666666;
margin-bottom: 8rpx;
padding-left: 4rpx;
}
.phase-vertical {
display: flex;
align-items: stretch;
}
.phase-item-vertical {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding: 4rpx;
}
.phase-value-vertical {
font-size: 28rpx;
font-weight: 700;
}
.phase-divider {
width: 1px;
background: #d2d2d2;
margin: 8rpx 0;
}
.more-btn {
margin: 0 20rpx 20rpx;
height: 72rpx;
line-height: 72rpx;
text-align: center;
border: 1rpx solid #376cf380;
background-color: #266FFF10;
border-radius: 16rpx;
text {
font-size: 28rpx;
color: #376cf3;
font-weight: 500;
}
}
.ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.indicator-popup {
background: #ffffff;
overflow: hidden;
}
.indicator-popup-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 18rpx 32rpx;
border-bottom: 1rpx solid #eef2f6;
}
.indicator-popup-cancel {
font-size: 27rpx;
color: #666666;
min-width: 80rpx;
}
.indicator-popup-confirm {
font-size: 28rpx;
color: #376cf3;
min-width: 80rpx;
text-align: right;
}
.indicator-popup-list {
max-height: 60vh;
padding: 16rpx 0;
box-sizing: border-box;
}
.indicator-popup-empty {
padding: 80rpx 0;
text-align: center;
font-size: 28rpx;
color: #999999;
}
.indicator-popup-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 28rpx 32rpx;
font-size: 28rpx;
color: #333333;
&--active {
color: #376cf3;
background: #376cf310;
}
}
</style>

View File

@@ -0,0 +1,348 @@
<template>
<view class="dateReport">
<!-- {{ height }} -->
<view class="pd20">
<uni-segmented-control
:current="curSub"
class="subsection"
active-color="#376cf3"
:values="subsectionList"
@clickItem="sectionChange"
/>
</view>
<view class="filterCriteria">
<!-- 筛选条件 -->
<Cn-filterCriteria @select="select" :singleChoice="true" :showDatetime="curSub == 0"> </Cn-filterCriteria>
</view>
<!-- 卡片 -->
<scroll-view
scroll-y="true"
@refresherrefresh="refresherrefresh"
:refresher-triggered="triggered"
refresher-enabled="true"
class="event-list mt20"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }"
>
<!-- 循环渲染事件项 -->
<uni-card class="event-item" :class="item.type" v-for="(item, index) in store.data" :key="index">
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view class="event-icon">
<!-- 动态图标根据类型切换 -->
<!-- <uni-icons
custom-prefix="iconfont"
type="icon-kouanjiancedian"
size="40"
color="#E6A23C"
></uni-icons> -->
<Cn-icon-transient :name="`报告`" />
<view class="badge1" v-if="item.isRead == 0"> </view>
</view>
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.lineName }}</text>
<!-- <view class="event-tags"
>{{ selectValue.report == 0 ? item.startTime : item.startTime + '至' + item.endTime }}
</view> -->
</view>
<view class="event-desc">
<text
>统计时间{{
curSub == 0 ? item.startTime : item.startTime + ' 至 ' + item.endTime
}}</text
>
</view>
</view>
<view class="event-action" v-if="curSub == 0 ? monthFlag : item.endTime != thisMonth01">
<view class="iconText boxClick" @click="download(item)"
><uni-icons type="arrow-down" color="#fff" size="16"></uni-icons>
</view>
</view>
</view>
<!-- 详情区域 -->
<view class="event-detail textBox" @touchmove.stop>
<text v-if="curSub == 0 ? monthFlag : item.endTime != thisMonth01">{{
item.overLimitDesc == '' ? '该监测点暂无指标越限' : item.overLimitDesc
}}</text>
<text v-else>数据未生成暂不支持下载</text>
</view>
<!-- <view class="downloadReport" @click="download">
<uni-icons type="download" size="16" color="#376cf3"></uni-icons>下载报告
</view> -->
</uni-card>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty>
</scroll-view>
</view>
</template>
<script>
import list from '@/common/js/list'
import { downloadHarmonicReport } from '@/common/api/report.js'
export default {
components: {},
props: {
indexList: {
type: Array,
default: () => [],
},
total: {
type: Number,
default: 0,
},
navHeight: {
type: Number,
default: 0,
},
},
mixins: [list],
data() {
return {
status: 'noMore',
curSub: 0,
subsectionList: ['周报', '月报'],
thisSelectValue: {},
triggered: true,
height: 0,
thisMonth01: '',
monthFlag: true,
}
},
created() {},
mounted() {
this.thisMonth01 = this.$util.getToday().slice(0, -3) + '-01'
this.monthFlag = this.$util.getToday() != this.$util.getToday().slice(0, -3) + '-01'
// this.setHeight()
},
methods: {
setHeight() {
uni.createSelectorQuery()
.select('.filterCriteria')
.boundingClientRect((rect) => {
//
// #ifdef H5
this.height = rect?.height + 140 || 0
// #endif
// #ifdef APP-PLUS
this.height = rect?.height + 75 || 0
// #endif
})
.exec()
},
sectionChange(index) {
this.curSub = index.currentIndex
this.init()
},
init() {
if (this.selectValue.lineId == '') return
this.store = this.DataSource('/cs-report-boot/csAppReport/reportList')
// this.store.params.pageSize = 10000
this.store.params.timeType = this.curSub //this.selectValue.report
this.store.params.engineerId = this.selectValue.engineeringId
this.store.params.projectId = this.selectValue.projectId
this.store.params.devId = this.selectValue.deviceId
this.store.params.lineId = this.selectValue.lineId
if (this.curSub == 0) {
this.store.params.time = this.selectValue.date
} else {
this.store.params.time = this.selectValue.range + '-01'
}
// this.store.params.startTime = this.selectValue.range[0]
// this.store.params.endTime = this.selectValue.range[1]
this.store.loadedCallback = () => {}
this.store.reload()
},
select(value) {
this.selectValue = value
setTimeout(() => {
this.setHeight()
}, 200)
this.init()
},
// 下载
download(item) {
uni.showLoading({
title: '下载中,请稍等...',
mask: true,
})
downloadHarmonicReport({
devId: this.selectValue.deviceId,
endTime: item.endTime,
engineerId: this.selectValue.engineeringId,
lineId: this.selectValue.lineId,
list: [],
projectId: this.selectValue.projectId,
startTime: item.startTime,
time: '',
timeType: this.selectValue.report,
})
.then((res) => {
// 下载文件资源到本地
uni.downloadFile({
url: res.data, // 后端返回的线上文件路径
success: function (res) {
if (res.statusCode === 200) {
// 文件到本地
uni.saveFile({
tempFilePath: res.tempFilePath, //临时路径
success: function (data) {
var savedFilePath = data.savedFilePath
// 在app端执行
// #ifdef APP-PLUS
let osname = plus.os.name
// 如果是安卓的话弹出提示
uni.showToast({
icon: 'success',
mask: true,
title: '下载成功!',
duration: 1000,
})
// #endif
//ios手机直接打开文件手动存储文件到手机Android手机从根目录创建文件夹保存文件并改名
setTimeout(() => {
//打开文档查看
uni.openDocument({
filePath: data.savedFilePath,
success: function (ress) {
console.log('成功打开文件')
},
fail() {
console.log('打开文件失败')
},
})
}, 500)
},
})
console.log('下载成功')
} else {
uni.showToast({
icon: 'none',
mask: true,
title: '下载失败!',
duration: 1000,
})
}
},
fail: function (res) {},
})
})
.catch((err) => {
uni.showToast({
icon: 'none',
mask: true,
title: err.message,
duration: 1000,
})
})
},
// 下拉
refresherrefresh() {
this.triggered = true
uni.startPullDownRefresh()
setTimeout(() => {
this.triggered = false
}, 500)
},
},
computed: {},
watch: {},
}
</script>
<style lang="scss" scoped>
@import '@/pages/message1/index.scss';
.event-title {
justify-content: space-between;
}
.event-tags {
display: flex;
font-size: 27rpx !important ;
line-height: 50rpx;
}
.event-detail {
// font-size: 25rpx !important;
// display: grid;
// grid-template-columns: 1fr 1fr;
}
.downloadReport {
width: 100%;
background: #376cf320;
height: 60rpx;
line-height: 60rpx;
color: #376cf3;
font-weight: 600;
border-radius: 15rpx;
margin-top: 10rpx;
display: flex;
justify-content: center;
}
.filterCriteria {
.nav {
background-color: #fff;
}
.choose1 {
background-color: #fff;
padding: 0 20rpx;
display: flex;
justify-content: space-between;
/deep/ .uni-checkbox-input {
width: 30rpx;
height: 30rpx;
}
font-size: 26rpx;
}
}
/deep/ .uni-scroll-view-refresher {
display: none;
}
.iconText {
width: 45rpx;
height: 45rpx;
border-radius: 50%;
background-color: $uni-theme-color;
text-align: center;
line-height: 40rpx;
}
.segmented-control {
flex: 1;
margin-right: 24rpx;
height: 60rpx;
}
/* 列表容器 */
.event-list {
/* 头部:图标 + 信息 + 操作 */
.event-header {
display: flex;
align-items: center;
margin-bottom: 10rpx;
}
/* 图标区域(按类型区分背景色) */
.event-icon {
background-color: #376cf320;
width: 90rpx;
height: 90rpx;
}
.event-tags {
font-size: 24rpx;
}
}
.textBox {
// @touchmove.stop
max-height: 110rpx;
overflow-y: auto;
}
</style>

View File

@@ -0,0 +1,245 @@
<template>
<view class="target-info-page">
<scroll-view class="target-info-scroll" scroll-y :show-scrollbar="false">
<view class="monitor-card card">
<view class="card-header">
<view class="event-icon">
<Cn-icon-transient name="监测点" />
</view>
<view class="card-header-info">
<text class="point-name ellipsis">{{ pointInfo.pointName }}</text>
<view class="meta-row">
<text class="meta-item ellipsis">项目{{ pointInfo.projectName }}</text>
<text class="meta-item ellipsis">设备{{ pointInfo.deviceName }}</text>
</view>
<text class="meta-time ellipsis">最新数据时间{{ pointInfo.dataTime || '-' }}</text>
</view>
</view>
<view class="legend-row">
<view class="legend-item" v-for="phase in phaseColors" :key="phase.name">
<view class="legend-dot" :style="{ background: phase.color }" />
<text class="legend-text">{{ phase.name }}</text>
</view>
</view>
<view class="params-section">
<view
v-for="(rowItems, rowIdx) in chunkedChildren(pointInfo.children || [])"
:key="rowIdx"
class="double-row"
>
<view v-for="(child, childIdx) in rowItems" :key="childIdx" class="param-group">
<view class="param-title">
<text>{{ child.name }}</text>
</view>
<view class="phase-vertical">
<view class="phase-item-vertical">
<text class="phase-value-vertical" :style="{ color: phaseColors[0].color }">{{ child.A }}</text>
</view>
<view class="phase-divider" />
<view class="phase-item-vertical">
<text class="phase-value-vertical" :style="{ color: phaseColors[1].color }">{{ child.B }}</text>
</view>
<view class="phase-divider" />
<view class="phase-item-vertical">
<text class="phase-value-vertical" :style="{ color: phaseColors[2].color }">{{ child.C }}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
export default {
data() {
return {
pointInfo: {},
phaseColors: [
{ name: 'A相', color: '#F1B22E' },
{ name: 'B相', color: '#2BA471' },
{ name: 'C相', color: '#D54941' },
],
}
},
onLoad(options) {
if (options.point) {
this.pointInfo = JSON.parse(decodeURIComponent(options.point))
}
},
methods: {
// 将指标列表按每行两个分组
chunkedChildren(children) {
const result = []
for (let i = 0; i < children.length; i += 2) {
result.push(children.slice(i, i + 2))
}
return result
},
},
}
</script>
<style lang="scss" scoped>
.target-info-page {
min-height: 100vh;
background: #f7f8fa;
}
.target-info-scroll {
height: 100vh;
box-sizing: border-box;
padding: 20rpx 0 40rpx;
}
.card {
background: #ffffff;
border-radius: 10px;
box-shadow: rgba(0, 0, 0, 0.08) 0px 0px 1px 1px;
margin: 0 10px;
overflow: hidden;
}
.monitor-card {
border: 1rpx solid #eef2f6;
}
.card-header {
padding: 20rpx 20rpx 12rpx;
display: flex;
align-items: center;
border-bottom: 1rpx solid #eef2f6;
}
.event-icon {
width: 90rpx;
height: 90rpx;
border-radius: 16rpx;
display: flex;
justify-content: center;
align-items: center;
margin-right: 20rpx;
background-color: #376cf320;
flex-shrink: 0;
}
.card-header-info {
flex: 1;
min-width: 0;
}
.point-name {
display: block;
font-size: 30rpx;
font-weight: 700;
color: #333333;
margin-bottom: 8rpx;
}
.meta-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 6rpx 12rpx;
}
.meta-item {
font-size: 26rpx;
color: #666666;
line-height: 1.3;
}
.meta-time {
display: block;
margin-top: 8rpx;
font-size: 26rpx;
color: #666666;
line-height: 1.3;
}
.legend-row {
display: flex;
gap: 20rpx;
align-items: center;
padding: 16rpx 20rpx;
}
.legend-item {
display: flex;
align-items: center;
gap: 8rpx;
}
.legend-dot {
width: 16rpx;
height: 16rpx;
border-radius: 50%;
}
.legend-text {
font-size: 24rpx;
color: #666666;
}
.params-section {
padding: 0 16rpx 20rpx;
}
.double-row {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16rpx;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
}
.param-group {
min-width: 0;
background: #f9fafb;
border-radius: 16rpx;
padding: 16rpx 8rpx 12rpx;
}
.param-title {
font-size: 26rpx;
color: #666666;
margin-bottom: 8rpx;
padding-left: 4rpx;
}
.phase-vertical {
display: flex;
align-items: stretch;
}
.phase-item-vertical {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding: 4rpx;
}
.phase-value-vertical {
font-size: 28rpx;
font-weight: 700;
}
.phase-divider {
width: 1px;
background: #d2d2d2;
margin: 8rpx 0;
}
.ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

View File

@@ -0,0 +1,386 @@
<template>
<view class="dateReport">
<view class="pd20">
<uni-segmented-control :current="curSub" class="subsection" active-color="#376cf3" :values="subsectionList"
@clickItem="sectionChange" />
</view>
<!-- 申请报告 -->
<view v-show="curSub == 0">
<!-- apply -->
<Apply ref="applyRef" :navHeight="navHeight" />
</view>
<!-- 申请记录 -->
<view v-if="curSub == 1">
<view class="filterCriteria">
<!-- 筛选条件 -->
<Cn-filterCriteria @select="select" :showQianTree="false"> </Cn-filterCriteria>
</view>
<scroll-view scroll-y="true" @refresherrefresh="refresherrefresh" @scrolltolower="scrolltolower"
:refresher-triggered="triggered" refresher-enabled="true" class="record event-list mt20"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }">
<uni-card class="event-item" :class="item.type" v-for="(item, index) in store.data" :key="index">
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view class="event-icon">
<!-- :style="{ backgroundColor: item.isComplete == 1 ? '#10b98120' : '#FF000020' }" -->
<!-- 动态图标根据类型切换 -->
<!-- <uni-icons
custom-prefix="iconfont"
type="icon-baogaoguanli"
size="40"
:color="item.isComplete == 1 ? '#10b981' : '#FF0000'"
></uni-icons> -->
<Cn-icon-transient :name="`报告`" />
</view>
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.lineName }}</text>
</view>
<view class="event-desc">
<text>工程{{ item.engineeringName }}</text>
<text>项目{{ item.projectName }}</text>
<text>设备{{ item.deviceName }}</text>
<!-- <text>申请时间{{ item.time }}</text>
<text>事件数{{ item.eventNums }}</text> -->
</view>
</view>
<view class="event-action">
<view class="iconText boxClick" v-if="item.isComplete == 1" @click="download(item)">
<uni-icons type="arrow-down" color="#fff" size="16"></uni-icons>
</view>
<view class="nav-menu nav-menu-btn boxClick"
v-else-if="userInfo.authorities === 'operation_manager'" @click="generate(item)">生成报告
</view>
</view>
</view>
<!-- 详情区域 -->
<view class="event-detail">
<!-- <view class="device-body"> -->
<view class="device-body-item">
<text>申请人</text>
<text>{{ item.applyUser }}</text>
</view>
<view class="device-body-item">
<text>报告状态</text>
<text :style="{ color: item.isComplete == 1 ? '#10b981' : '#FF0000' }">{{
item.isComplete == 1 ? '已完成' : '未完成'
}}</text>
</view>
<view class="device-body-item">
<text>申请时间</text>
<text>{{ item.time }}</text>
</view>
<view class="device-body-item">
<text>暂降事件</text>
<text>{{ item.eventNums }}</text>
</view>
<!-- <view class="device-body-item">
<text>申请时间</text>
<text>{{ item.time }}</text>
</view> -->
</view>
<!-- </view> -->
</uni-card>
<uni-load-more v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"></uni-load-more>
<Cn-empty v-else style="top: 30%"></Cn-empty>
</scroll-view>
</view>
</view>
</template>
<script>
import Apply from './apply.vue'
import list from '@/common/js/list'
import { createEventReport, downloadEventReport } from '@/common/api/report.js'
export default {
components: { Apply },
props: {
indexList: {
type: Array,
default: () => [],
},
total: {
type: Number,
default: 0,
},
// status: {
// type: String,
// default: 'more',
// },
navHeight: {
type: Number,
default: 0,
},
},
mixins: [list],
data() {
return {
value: ['0'],
content: 123,
curSub: 0,
subsectionList: ['申请报告', '申请记录'],
form: {
type: 0,
lindId: '',
},
triggered: true,
userInfo: {},
height: 0,
selectValue: {},
}
},
created() { },
mounted() {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
},
computed: {},
methods: {
setHeight() {
uni.createSelectorQuery()
.select('.filterCriteria')
.boundingClientRect((rect) => {
//
// #ifdef H5
this.height = rect?.height + 180 || 0
// #endif
// #ifdef APP-PLUS
this.height = rect?.height + 110 || 0
// #endif
})
.exec()
},
init() {
this.store = this.DataSource('/cs-report-boot/csAppReport/getApplicationReport')
this.store.params.startTime = this.$util.getMonthFirstAndLastDay(this.selectValue.date).firstDay
this.store.params.endTime = this.$util.getMonthFirstAndLastDay(this.selectValue.date).lastDay
this.store.loadedCallback = () => {
this.setHeight()
}
this.store.reload()
},
async select(val) {
this.selectValue = val
await this.init()
},
sectionChange(index) {
this.curSub = index.currentIndex
},
// 生成报告
generate(item) {
uni.showLoading({
title: '生成中,请稍等...',
mask: true,
})
createEventReport({
id: item.eventId,
}).then((res) => {
uni.showToast({
icon: 'success',
mask: true,
title: '生成事件报告成功!',
duration: 1000,
})
this.store.reload()
})
},
// 下载报告
download(item) {
uni.showLoading({
title: '下载中,请稍等...',
mask: true,
})
downloadEventReport({
id: item.eventId,
})
.then((res) => {
// 下载文件资源到本地
uni.downloadFile({
url: res.data, // 后端返回的线上文件路径
success: function (res) {
if (res.statusCode === 200) {
// 文件到本地
uni.saveFile({
tempFilePath: res.tempFilePath, //临时路径
success: function (data) {
var savedFilePath = data.savedFilePath
// 在app端执行
// #ifdef APP-PLUS
let osname = plus.os.name
// 如果是安卓的话弹出提示
uni.showToast({
icon: 'success',
mask: true,
title: '下载成功!',
duration: 1000,
})
// #endif
//ios手机直接打开文件手动存储文件到手机Android手机从根目录创建文件夹保存文件并改名
setTimeout(() => {
//打开文档查看
uni.openDocument({
filePath: data.savedFilePath,
success: function (ress) {
console.log('成功打开文件')
},
fail() {
console.log('打开文件失败')
},
})
}, 500)
},
})
console.log('下载成功')
} else {
uni.showToast({
icon: 'none',
mask: true,
title: '下载失败!',
duration: 1000,
})
}
},
fail: function (res) { },
})
})
.catch((err) => {
uni.showToast({
icon: 'none',
mask: true,
title: err.message,
duration: 1000,
})
})
},
// 刷新
reload() {
switch (this.curSub) {
case 0:
this.$refs.applyRef.store.reload()
break
case 1:
this.store && this.store.reload()
break
}
},
// 下拉
refresherrefresh() {
this.triggered = true
uni.startPullDownRefresh()
setTimeout(() => {
this.triggered = false
}, 500)
},
// 上拉
scrolltolower() {
if (this.store.status != 'noMore') {
this.store.next && this.store.next()
}
},
},
watch: {},
}
</script>
<style lang="scss" scoped>
@import '@/pages/message1/index.scss';
.event-detail {
display: grid;
grid-template-columns: 1.6fr 1fr;
}
// /deep/ .record {
// .uni-card__content {
// padding: 55rpx 20rpx 20rpx !important;
// }
// }
.filterCriteria {
.nav {
background-color: #fff;
}
.choose1 {
background-color: #fff;
padding: 0 20rpx;
display: flex;
justify-content: space-between;
/deep/ .uni-checkbox-input {
width: 30rpx;
height: 30rpx;
}
font-size: 26rpx;
}
}
// .device-body {
// padding: 10rpx 20rpx 20rpx;
.device-body-item {
display: flex;
// justify-content: space-between;
font-size: 26rpx;
color: #666666;
line-height: 1.5;
}
// }
.iconText {
display: flex;
width: 45rpx;
height: 45rpx;
border-radius: 50%;
background-color: $uni-theme-color;
justify-content: center;
align-items: center;
}
.nav-menu {
height: 40rpx;
padding: 6rpx 20rpx;
font-size: 24rpx;
border-radius: 8rpx;
line-height: 40rpx;
background: #ebeaec;
color: #666;
&-active {
background: #dfe5f7;
color: $uni-theme-color;
}
&-btn {
background: $uni-theme-color;
color: #fff;
}
}
.event-list {
/* 图标区域(按类型区分背景色) */
.event-icon {
background-color: #376cf320;
}
}
.segmented-control {
flex: 1;
margin-right: 24rpx;
height: 60rpx;
}
/deep/ .uni-scroll-view-refresher {
display: none;
}
</style>

View File

@@ -1,39 +1,44 @@
<template> <template>
<Cn-page :loading="loading" noPadding> <Cn-page :loading="loading" noPadding>
<view slot="body" class="canneng-index"> <view slot="body" class="canneng-index">
<uni-nav-bar <uni-nav-bar rightWidth="300rpx" leftWidth="300rpx" dark :fixed="true" status-bar background-color="#fff"
rightWidth="300rpx" color="#111" @clickRight="selectEngineering">
leftWidth="300rpx"
dark
:fixed="true"
status-bar
background-color="#fff"
color="#111"
@clickRight="selectEngineering"
>
<template slot="left"> <template slot="left">
<text style="font-size: 32rpx; font-weight: 500">灿能物联</text> <text style="font-size: 32rpx; font-weight: 500">灿能物联</text>
</template> </template>
<template slot="right"> <template slot="right">
<text class="hide-txt mr5" style="font-size: 28rpx" <text class="hide-txt mr5" style="font-size: 28rpx">{{
>{{ select.engineeringName || emptyEngineeringName }} userInfo.authorities === 'engineering_user'
? '创建工程'
: select.engineeringName || emptyEngineeringName
}}
</text> </text>
<uni-icons type="bottom" size="16" color="#111" v-if="select.engineeringName"></uni-icons> <uni-icons type="bottom" size="16" color="#111"
v-if="select.engineeringName && userInfo.authorities != 'engineering_user'"></uni-icons>
</template> </template>
</uni-nav-bar> </uni-nav-bar>
<view class="index"> <view class="index">
<!-- 运维 --> <!-- 运维 -->
<YunWei :devCount="devCount" v-if="userInfo.authorities === 'operation_manager'" /> <YunWei :devCount="devCount" v-if="userInfo.authorities === 'operation_manager'" />
<!-- 专职 --> <!-- 营销 -->
<ZhuanZhi :devCount="devCount" v-if="userInfo.authorities === 'market_user'" /> <ZhuanZhi :devCount="devCount" v-if="userInfo.authorities === 'market_user'" />
<!-- 工程 --> <!-- 工程 -->
<GongCheng ref="gongCheng" :devCount="devCount" v-if="userInfo.authorities === 'engineering_user'" /> <GongCheng ref="gongCheng" :devCount="devCount" v-if="userInfo.authorities === 'engineering_user'" />
<!-- 主用户 --> <!-- 正式 -->
<ZhuYongHu :devCount="devCount" v-if="userInfo.authorities === 'app_vip_user'" /> <ZhuYongHu :devCount="devCount" v-if="userInfo.authorities === 'app_vip_user'" />
<!-- 游客 --> <!-- 游客 -->
<YouKe :devCount="devCount" v-if="userInfo.authorities === 'tourist'"></YouKe> <YouKe :devCount="devCount" v-if="userInfo.authorities === 'tourist'"></YouKe>
<template v-show="engineeringList.length"> <!-- 工程列表 -->
<view class="canneng-index-title mt20">设备列表</view> <template v-show="engineeringList.length" v-if="userInfo.authorities === 'engineering_user'">
<view class="canneng-index-title mt20">工程列表</view>
<Engineering ref="engineering" :store="store" @refresh="store.search()" />
</template>
<!-- 设备列表 -->
<template v-else v-show="engineeringList.length">
<view class="canneng-index-title mt20">
<view>设备列表</view>
<view class="nav-menu nav-menu-btn boxClick" @click="jump">关键指标概览 </view>
</view>
<Device ref="device" :store="store" /> <Device ref="device" :store="store" />
</template> </template>
</view> </view>
@@ -47,6 +52,7 @@ import ZhuYongHu from './comp/indexZhuYongHu.vue'
import ZhuanZhi from './comp/indexZhuanZhi.vue' import ZhuanZhi from './comp/indexZhuanZhi.vue'
import YouKe from './comp/indexYouKe.vue' import YouKe from './comp/indexYouKe.vue'
import Device from './comp/device.vue' import Device from './comp/device.vue'
import Engineering from './comp/engineering.vue'
import list from '../../common/js/list' import list from '../../common/js/list'
import { getDevCount } from '../../common/api/device.js' import { getDevCount } from '../../common/api/device.js'
import { queryEngineering } from '@/common/api/engineering.js' import { queryEngineering } from '@/common/api/engineering.js'
@@ -60,6 +66,7 @@ export default {
ZhuanZhi, ZhuanZhi,
YouKe, YouKe,
Device, Device,
Engineering,
}, },
data() { data() {
return { return {
@@ -88,7 +95,11 @@ export default {
}, },
methods: { methods: {
selectEngineering() { selectEngineering() {
if (this.select.engineeringName) { if (this.userInfo.authorities === 'engineering_user') {
uni.navigateTo({
url: '/pages/engineering/new',
})
} else if (this.select.engineeringName) {
uni.navigateTo({ uni.navigateTo({
url: '/pages/home/selectEngineering', url: '/pages/home/selectEngineering',
}) })
@@ -140,6 +151,7 @@ export default {
console.log(this.$refs.device, 'this.$refs.device') console.log(this.$refs.device, 'this.$refs.device')
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.device && this.$refs.device.init() this.$refs.device && this.$refs.device.init()
this.$refs.engineering && this.$refs.engineering.init()
}) })
} }
this.$refs.gongCheng?.init() this.$refs.gongCheng?.init()
@@ -154,10 +166,10 @@ export default {
// console.log(`12312`,res) // console.log(`12312`,res)
// Object.assign(this.devCount, res.data) // Object.assign(this.devCount, res.data)
this.devCount = res.data this.devCount = res.data
this.devCount.currentOffLineDevs.forEach((item) => { this.devCount.currentOffLineDevs?.forEach((item) => {
item.runStatus = 1 item.runStatus = 1
}) })
this.devCount.offLineDevs.forEach((item) => { this.devCount.offLineDevs?.forEach((item) => {
item.runStatus = 1 item.runStatus = 1
}) })
this.devCount.engineeringListLength = this.engineeringList.length this.devCount.engineeringListLength = this.engineeringList.length
@@ -165,17 +177,24 @@ export default {
key: this.$cacheKey.messageCount, key: this.$cacheKey.messageCount,
data: this.devCount, data: this.devCount,
}) })
// let messagePage =
// this.devCount.runCount +
// this.devCount.eventCount +
// this.devCount.alarmCount +
// this.devCount.harmonicCount
let messagePage = let messagePage =
this.devCount.runCount +
this.devCount.eventCount + this.devCount.eventCount +
this.devCount.alarmCount + this.devCount.harmonicCount +
this.devCount.harmonicCount (uni.getStorageSync(this.$cacheKey.userInfo).authorities == 'operation_manager'
? this.devCount.alarmCount + this.devCount.runCount
: 0)
// console.log('🚀 ~ messagePage:', messagePage)
let minePage = this.devCount.feedBackCount let minePage = this.devCount.feedBackCount
if (messagePage) { if (messagePage) {
uni.setTabBarBadge({ uni.setTabBarBadge({
index: 1, index: 1,
text:messagePage ? (messagePage > 99 ? '99+' : messagePage + '') : '', text: messagePage ? (messagePage > 99 ? '99+' : messagePage + '') : '',
}) })
} else { } else {
uni.removeTabBarBadge({ uni.removeTabBarBadge({
@@ -197,8 +216,15 @@ export default {
// #endif // #endif
}) })
}, },
// 动态配置导航栏按钮
jump() {
uni.navigateTo({
url: `/pages/index/comp/monitoringPoint`,
})
}
}, },
onLoad() { onLoad() {
// 页面加载时,动态配置导航栏按钮
if (!uni.getStorageSync(this.$cacheKey.access_token)) { if (!uni.getStorageSync(this.$cacheKey.access_token)) {
uni.reLaunch({ uni.reLaunch({
url: '/pages/user/login', url: '/pages/user/login',
@@ -216,7 +242,11 @@ export default {
}, 1000) }, 1000)
} }
this.timer = setInterval(this.getDevCount, 1000 * 60) // 定时请求 this.timer = setInterval(this.getDevCount, 1000 * 60) // 定时请求
this.store = this.DataSource('/cs-device-boot/EquipmentDelivery/queryEquipmentByProject')
this.store =
uni.getStorageSync(this.$cacheKey.userInfo).authorities === 'engineering_user'
? this.DataSource('/cs-harmonic-boot/homePage/getEngineeringHomePage')
: this.DataSource('/cs-device-boot/EquipmentDelivery/queryEquipmentByProject')
// #ifdef APP-PLUS // #ifdef APP-PLUS
setTimeout(() => { setTimeout(() => {
// 获取nav高度 // 获取nav高度
@@ -243,6 +273,22 @@ export default {
this.init() this.init()
} }
}, },
mounted() {
uni.setTabBarItem({
index: 2,
visible: true,
})
if (uni.getStorageSync(this.$cacheKey.userInfo).authorities === 'tourist') {
uni.setTabBarItem({
index: 2,
visible: false,
})
uni.showToast({
title: '已同步设备历史数据',
icon: 'none',
})
}
},
} }
</script> </script>
<style lang="scss"> <style lang="scss">
@@ -256,8 +302,8 @@ export default {
.canneng-index-title { .canneng-index-title {
padding: 0 20rpx; padding: 0 20rpx;
font-size: 28rpx;
font-weight: 500; font-weight: 500;
display: flex;
} }
/deep/ .uni-card { /deep/ .uni-card {
@@ -267,4 +313,28 @@ export default {
/deep/ .uni-drawer__content { /deep/ .uni-drawer__content {
width: 100vw !important; width: 100vw !important;
} }
.nav-menu {
height: 40rpx;
padding: 4rpx 20rpx;
// margin-left: 20rpx;
// margin-bottom: 20rpx;
line-height: 38rpx;
font-size: 24rpx;
border-radius: 8rpx;
background: #ebeaec;
color: #666;
&-active {
background: #dfe5f7;
color: $uni-theme-color;
}
&-btn {
background: $uni-theme-color;
color: #fff;
}
margin-left: auto;
}
</style> </style>

346
pages/index/message1.vue Normal file
View File

@@ -0,0 +1,346 @@
<template>
<Cn-page :loading="loading" class="messageBox" style="padding-top: 10px">
<view slot="body" class="message">
<view class="tabsBox">
<uni-segmented-control :current="current" :values="items" style-type="text" active-color="#376cf3"
@clickItem="onClickItem" />
<!-- 角标 -->
<view class="badge-container">
<span v-for="(item, index) in items" :key="index" class="badge">
<uni-badge :text="badgeCounts[index] > 99 ? '99+' : badgeCounts[index]" />
<!-- {{ badgeCounts[index] > 99 ? '99+' : badgeCounts[index] }} -->
</span>
</view>
<!-- 筛选条件 -->
<Cn-filterCriteria ref="cnFilterCriteria" :level="current === 0 ? 3 : current === 1 ? 3 : 2"
@select="select">
<picker v-if="current === 0" @change="bindPickerChange" :value="sortIndex" :range="sortOptions">
<view class="nav-menu nav-menu1">
<view class="nav-text">
{{ sortOptions[sortIndex] }}排序
</view>
<uni-icons type="bottom" size="14"></uni-icons>
</view>
</picker>
</Cn-filterCriteria>
</view>
<view class="content">
<Transient ref="TransientRef" v-if="current === 0" :navHeight="navHeight" :selectValue="selectValue"
:sortIndex="sortIndex" @getDevCount="getDevCount" />
<SteadyState ref="SteadyStateRef" v-if="current === 1" :navHeight="navHeight" :selectValue="selectValue"
@getDevCount="getDevCount" />
<Alarm ref="AlarmRef" v-if="current === 2" :navHeight="navHeight" :selectValue="selectValue"
@getDevCount="getDevCount" />
<Run ref="RunRef" v-if="current === 3" :navHeight="navHeight" :selectValue="selectValue"
@getDevCount="getDevCount" />
</view>
</view>
</Cn-page>
</template>
<script>
import Transient from '@/pages/message1/transient.vue'
import SteadyState from '@/pages/message1/steadyState.vue'
import Alarm from '@/pages/message1/alarm.vue'
import Run from '@/pages/message1/run.vue'
import { getDevCount } from '../../common/api/device.js'
import { updateStatus } from '@/common/api/message'
export default {
components: { Transient, SteadyState, Alarm, Run },
props: {},
data() {
return {
items: ['暂态事件', '稳态事件'], //'运行告警', '运行事件'
badgeCounts: [0, 0, 0, 0],
current: 0,
colorIndex: 0,
item: '',
loading: false,
width: 0,
navHeight: 0,
selectValue: {},
devCount: [],
sortIndex: 0,
sortOptions: ['发生时间', '暂降深度', '持续时间'],
}
},
onLoad() { },
mounted() {
this.setHeight()
},
onPullDownRefresh() {
this.refresh()
},
onNavigationBarButtonTap(e) {
uni.showModal({
title: '提示',
content: '确定要全部标记为已读吗?',
success: (res) => {
if (res.confirm) {
updateStatus({
// '暂态事件', 0
// '稳态事件', 1
// '运行告警', 3
// '运行事件' 2
type: this.current == 2 ? 3 : this.current == 3 ? 2 : this.current,
eventIds: [],
}).then(() => {
this.refresh()
this.getDevCount()
})
}
},
})
},
onShow() {
if (uni.getStorageSync(this.$cacheKey.userInfo).authorities === 'operation_manager') {
this.items = ['暂态事件', '稳态事件', '运行告警', '运行事件']
}
const params = uni.getStorageSync('messageParams')
this.getDevCount()
this.$nextTick(() => {
if (params.type !== '') {
this.current = params.type - 0
}
if (params.engineeringName != '') {
this.$refs.cnFilterCriteria && this.$refs.cnFilterCriteria.external(params)
}
})
},
// 页面销毁
onHide() {
uni.setStorageSync('messageParams', {
engineeringName: '',
engineeringId: '', //工程ID
projectName: '',
projectId: '', //項目ID
deviceName: '',
deviceId: '', //设备ID
lineName: '',
lineId: '', //测点ID
type: '',
})
},
methods: {
setHeight() {
uni.createSelectorQuery()
.select('.tabsBox')
.boundingClientRect((rect) => {
this.width = rect.width
//
// #ifdef H5
this.navHeight = rect.height + 75
// #endif
// #ifdef APP-PLUS
this.navHeight = rect.height + 20
// #endif
})
.exec()
},
refresh() {
switch (this.current) {
case 0:
this.$refs.TransientRef.store.reload()
break
case 1:
this.$refs.SteadyStateRef.store.reload()
break
case 2:
this.$refs.AlarmRef.store.reload()
break
case 3:
this.$refs.RunRef.store.reload()
break
}
},
onClickItem(e) {
if (this.current !== e.currentIndex) {
this.current = e.currentIndex
}
},
select(value) {
this.selectValue = value
setTimeout(() => {
this.setHeight()
}, 100)
},
bindPickerChange(e) {
this.sortIndex = e.detail.value
setTimeout(() => {
if (this.$refs.TransientRef) {
this.$refs.TransientRef.init()
}
}, 0)
},
// 设置角标
getDevCount() {
if (uni.getStorageSync('projectList')[1] != undefined) {
getDevCount(uni.getStorageSync('projectList')[1].engineeringId).then((res) => {
this.devCount = res.data
this.badgeCounts = [
this.devCount.eventCount,
this.devCount.harmonicCount,
this.devCount.alarmCount,
this.devCount.runCount,
]
uni.setStorage({
key: this.$cacheKey.messageCount,
data: this.devCount,
})
let messagePage =
this.devCount.eventCount +
this.devCount.harmonicCount +
(uni.getStorageSync(this.$cacheKey.userInfo).authorities == 'operation_manager'
? this.devCount.alarmCount + this.devCount.runCount
: 0)
let minePage = this.devCount.feedBackCount
if (messagePage) {
uni.setTabBarBadge({
index: 1,
text: messagePage ? (messagePage > 99 ? '99+' : messagePage + '') : '',
})
} else {
uni.removeTabBarBadge({
index: 1,
})
}
if (minePage) {
uni.setTabBarBadge({
index: 2,
text: minePage + '',
})
} else {
uni.removeTabBarBadge({
index: 2,
})
}
// #ifdef APP-PLUS
plus.runtime.setBadgeNumber(messagePage + minePage)
// #endif
})
}
},
// 根据索引动态计算右侧偏移位置,使徽章对准每个标签的右上角
getBadgeRightPosition(index) {
if (this.items == 4) {
return (index + 1) * (this.width / 4) + 'px'
} else {
return (index + 0) * (this.width / 2) + 'px'
}
},
},
computed: {},
}
</script>
<style lang="scss">
.messageBox {
overflow: hidden;
/deep/.tabsBox {
position: relative;
background-color: #fff;
.segmented-control {
// height: 40px;
background-color: #fff;
border-bottom: 1px solid #cccccc70;
.segmented-control__item {
align-items: baseline;
margin-top: 5px;
}
}
.segmented-control__text {
font-size: 30rpx !important;
color: rgb(96, 98, 102);
}
.segmented-control__item--text {
font-weight: bold;
padding: 0 0 5rpx;
}
.choose {
// padding: 20rpx;
// display: flex;
// justify-content: space-between;
// align-items: center;
background: #fff;
}
}
.subsection {
width: 90%;
margin: 20rpx auto;
}
.badge-container {
position: absolute;
top: -10rpx;
/* 徽章向上偏移,与控件重叠 */
display: flex;
justify-content: space-around;
right: 0;
width: 100%;
height: 0;
pointer-events: none;
/* 确保徽章不干扰点击事件 */
}
/deep/ .uni-badge--error {
background-color: #ff3b30;
}
.badge {
flex: 1;
text-align: center;
.uni-badge--x {
left: 70rpx;
}
}
.sort-picker {
font-size: 24rpx;
color: #2563eb;
display: flex;
align-items: center;
white-space: nowrap;
}
}
.nav-menu {
display: flex;
align-items: center;
}
.nav-menu1 {
display: flex;
align-items: center;
max-width: calc(100vw - 150px);
}
/* 文字容器:单行溢出省略 */
.nav-text {
flex: 1;
overflow: hidden;
white-space: nowrap;
/* 强制不换行 */
text-overflow: ellipsis;
// -webkit-line-clamp: 1;
// display: -webkit-box;
// -webkit-box-orient: vertical;
// text-overflow: ellipsis;
// word-break: break-all;
// white-space: nowrap;
line-height: 1;
}
</style>

View File

@@ -1,382 +1,381 @@
<template> <template>
<view :loading="loading"> <view :loading="loading">
<view class="mine"> <view class="mine">
<view class="mine-header" @click="jump('basic')"> <view class="mine-header" @click="jump('basic')">
<image mode="aspectFill" class="mine-header-head" :src="userInfo.avatar" v-if="userInfo.avatar" /> <image mode="aspectFill" class="mine-header-head" :src="userInfo.avatar" v-if="userInfo.avatar" />
<image mode="aspectFill" class="mine-header-head" src="/static/head.png" v-else /> <image mode="aspectFill" class="mine-header-head" src="/static/head.png" v-else />
<view class="mine-header-name hide-txt"> <view class="mine-header-name hide-txt">
<view>{{ userInfo.nickname }}</view> <view>{{ userInfo.nickname }}</view>
<view></view> <view></view>
<view class="tag">{{ roleName }}</view> <view class="tag">{{ roleName }}</view>
</view> </view>
<image <image
src="/static/erweima.png" src="/static/erweima.png"
style="height: 50rpx; width: 50rpx; border-radius: 12rpx" style="height: 50rpx; width: 50rpx; border-radius: 12rpx"
mode="scaleToFill" mode="scaleToFill"
/> />
<uni-icons type="forward" color="#aaa" size="16"></uni-icons> <uni-icons type="forward" color="#aaa" size="16"></uni-icons>
</view> </view>
<view class="mine-nav" v-if="userInfo.authorities === 'tourist'" @click="jump('upgrade')"> <view class="mine-nav" v-if="userInfo.authorities === 'tourist'" @click="jump('upgrade')">
<image mode="aspectFill" class="mine-nav-icon" src="/static/server.png" /> <image mode="aspectFill" class="mine-nav-icon" src="/static/server.png" />
<view class="mine-nav-label">角色升级</view> <view class="mine-nav-label">角色升级</view>
<uni-icons type="forward" color="#aaa" size="20"></uni-icons> <uni-icons type="forward" color="#aaa" size="20"></uni-icons>
</view> </view>
<!-- <view class="mine-nav" @click="jump('audit')" v-if="userInfo.authorities === 'app_vip_user'"> <!-- <view class="mine-nav" @click="jump('audit')" v-if="userInfo.authorities === 'app_vip_user'">
<image mode="aspectFill" class="mine-nav-icon" src="/static/server.png" /> <image mode="aspectFill" class="mine-nav-icon" src="/static/server.png" />
<view class="mine-nav-label">角色审核</view> <view class="mine-nav-label">角色审核</view>
<uni-icons type="forward" color="#aaa" size="20"></uni-icons> <uni-icons type="forward" color="#aaa" size="20"></uni-icons>
</view> --> </view> -->
<!-- <view class="mine-nav" @click="jump('user')" v-if="userInfo.authorities === 'app_vip_user'"> <!-- <view class="mine-nav" @click="jump('user')" v-if="userInfo.authorities === 'app_vip_user'">
<image mode="aspectFill" class="mine-nav-icon" src="/static/subordinate.png" /> <image mode="aspectFill" class="mine-nav-icon" src="/static/subordinate.png" />
<view class="mine-nav-label">分享用户列表</view> <view class="mine-nav-label">分享用户列表</view>
<uni-icons type="forward" color="#aaa" size="20"></uni-icons> <uni-icons type="forward" color="#aaa" size="20"></uni-icons>
</view> --> </view> -->
<view <view
class="mine-nav" class="mine-nav"
@click="jump('scan')" @click="jump('scan')"
v-if="userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'" v-if="userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'"
> >
<image mode="aspectFill" class="mine-nav-icon" src="/static/scan.png" /> <image mode="aspectFill" class="mine-nav-icon" src="/static/scan.png" />
<view class="mine-nav-label">扫一扫</view> <view class="mine-nav-label">扫一扫</view>
<uni-icons type="forward" color="#aaa" size="20"></uni-icons> <uni-icons type="forward" color="#aaa" size="20"></uni-icons>
</view> </view>
<view class="mine-nav" @click="jump('engineering')"> <view class="mine-nav" @click="jump('engineering')" v-if="userInfo.authorities !== 'tourist'">
<image mode="aspectFill" class="mine-nav-icon" src="/static/gongcheng.png" /> <image mode="aspectFill" class="mine-nav-icon" src="/static/gongcheng.png" />
<view class="mine-nav-label">工程管理</view> <view class="mine-nav-label">工程管理</view>
<uni-icons type="forward" color="#aaa" size="20"></uni-icons> <uni-icons type="forward" color="#aaa" size="20"></uni-icons>
</view> </view>
<view class="mine-nav" @click="jump('project')"> <view class="mine-nav" @click="jump('project')" v-if="userInfo.authorities !== 'tourist'">
<image mode="aspectFill" class="mine-nav-icon" src="/static/project.png" /> <image mode="aspectFill" class="mine-nav-icon" src="/static/project.png" />
<view class="mine-nav-label">项目管理</view> <view class="mine-nav-label">项目管理</view>
<uni-icons type="forward" color="#aaa" size="20"></uni-icons> <uni-icons type="forward" color="#aaa" size="20"></uni-icons>
</view> </view>
<view class="mine-nav" @click="jump('feedback')">
<image mode="aspectFill" class="mine-nav-icon" src="/static/feedback.png" /> <view class="mine-nav" @click="jump('feedback')" v-if="userInfo.authorities !== 'tourist'">
<view class="mine-nav-label">反馈列表</view> <image mode="aspectFill" class="mine-nav-icon" src="/static/feedback.png" />
<uni-badge :text="messageCount.feedBackCount"></uni-badge> <view class="mine-nav-label">反馈列表</view>
<uni-icons type="forward" color="#aaa" size="20"></uni-icons> <uni-badge :text="messageCount.feedBackCount"></uni-badge>
</view> <uni-icons type="forward" color="#aaa" size="20"></uni-icons>
<!-- <view </view>
class="mine-nav" <!-- <view
@click="jump('gateway')" class="mine-nav"
style="border-bottom: none; box-shadow: 0 4rpx 8rpx #e7e7e74c" @click="jump('gateway')"
> style="border-bottom: none; box-shadow: 0 4rpx 8rpx #e7e7e74c"
<image mode="aspectFill" class="mine-nav-icon" src="/static/gateway.png" /> >
<view class="mine-nav-label">网关列表</view> <image mode="aspectFill" class="mine-nav-icon" src="/static/gateway.png" />
<uni-icons type="forward" color="#aaa" size="20"></uni-icons> <view class="mine-nav-label">网关列表</view>
</view> --> <uni-icons type="forward" color="#aaa" size="20"></uni-icons>
<view class="mine-nav" @click="jump('setupMessage')"> </view> -->
<image mode="aspectFill" class="mine-nav-icon" src="/static/message4.png" /> <view class="mine-nav" @click="jump('setupMessage')" v-if="userInfo.authorities !== 'tourist'">
<view class="mine-nav-label">推送通知设置</view> <image mode="aspectFill" class="mine-nav-icon" src="/static/message4.png" />
<uni-icons type="forward" color="#aaa" size="20"></uni-icons> <view class="mine-nav-label">推送通知配置</view>
</view> <uni-icons type="forward" color="#aaa" size="20"></uni-icons>
<view </view>
class="mine-nav" <view
@click="jump('engineering/setting')" class="mine-nav"
v-if="userInfo.authorities === 'engineering_user'" @click="jump('engineering/setting')"
> v-if="userInfo.authorities === 'engineering_user' || userInfo.authorities == 'operation_manager'"
<image mode="aspectFill" class="mine-nav-icon" src="/static/like.png" /> >
<view class="mine-nav-label">关注工程配置</view> <image mode="aspectFill" class="mine-nav-icon" src="/static/like.png" />
<uni-icons type="forward" color="#aaa" size="20"></uni-icons> <view class="mine-nav-label">关注工程配置</view>
</view> <uni-icons type="forward" color="#aaa" size="20"></uni-icons>
<view class="mine-nav" @click="jump('serverSetting')" v-if="userInfo.authorities === 'engineering_user'"> </view>
<image mode="aspectFill" class="mine-nav-icon" src="/static/server2.png" /> <!-- <view class="mine-nav" @click="jump('transientSetting')" v-if="userInfo.authorities !== 'tourist'">
<view class="mine-nav-label">调试内容配置</view> <image mode="aspectFill" class="mine-nav-icon" src="/static/tongji.png" />
<uni-icons type="forward" color="#aaa" size="20"></uni-icons> <view class="mine-nav-label">暂态统计配置</view>
</view> <uni-icons type="forward" color="#aaa" size="20"></uni-icons>
<view class="mine-nav" @click="jump('setup')" style="border-bottom: none"> </view> -->
<image mode="aspectFill" class="mine-nav-icon" src="/static/setup.png" /> <view class="mine-nav" @click="jump('setup')" style="border-bottom: none">
<view class="mine-nav-label">设置</view> <image mode="aspectFill" class="mine-nav-icon" src="/static/setup.png" />
<uni-icons type="forward" color="#aaa" size="20"></uni-icons> <view class="mine-nav-label">设置</view>
</view> <uni-icons type="forward" color="#aaa" size="20"></uni-icons>
<uni-popup ref="inputDialog" type="dialog"> </view>
<uni-popup-dialog <uni-popup ref="inputDialog" type="dialog">
ref="inputClose" <uni-popup-dialog
mode="input" ref="inputClose"
title="角色升级" mode="input"
placeholder="请输入六位邀请码" title="角色升级"
@confirm="upgrade" placeholder="请输入六位邀请码"
></uni-popup-dialog> @confirm="upgrade"
</uni-popup> ></uni-popup-dialog>
</view> </uni-popup>
</view>
<uni-popup ref="alertDialog" type="dialog">
<uni-popup-dialog <uni-popup ref="alertDialog" type="dialog">
style="width: 90%; margin: 5%" <uni-popup-dialog
type="info" style="width: 90%; margin: 5%"
cancelText="禁止" type="info"
confirmText="允许" cancelText="禁止"
title="权限说明" confirmText="允许"
content='是否允许"灿能物联"使用相机?' title="权限说明"
@confirm="handleScon('camera')" content='是否允许"灿能物联"使用相机?'
@close="dialogClose" @confirm="handleScon('camera')"
></uni-popup-dialog> @close="dialogClose"
</uni-popup> ></uni-popup-dialog>
<uni-popup ref="message" type="message"> </uni-popup>
<uni-popup-message type="info" :duration="0" style="width: 90%; margin: 5%"> <uni-popup ref="message" type="message">
<view style="color: #909399; font-style: 16px">相机权限使用说明:</view> <uni-popup-message type="info" :duration="0" style="width: 90%; margin: 5%">
<view style="color: #6c6c6c; margin-top: 3rpx; "> 用于相机扫描二维码!</view> <view style="color: #909399; font-style: 16px">相机权限使用说明:</view>
</uni-popup-message> <view style="color: #6c6c6c; margin-top: 3rpx"> 用于相机扫描二维码!</view>
</uni-popup> </uni-popup-message>
<yk-authpup ref="authpup" type="top" @changeAuth="changeAuth" permissionID="CAMERA"></yk-authpup> </uni-popup>
<yk-authpup ref="authpup" type="top" @changeAuth="changeAuth" permissionID="CAMERA"></yk-authpup>
</view> </view>
</template> </template>
<script> <script>
import { roleUpdate, autoLogin } from '@/common/api/user' import { roleUpdate, autoLogin } from '@/common/api/user'
import { transferDevice, shareDevice } from '@/common/api/device' import { transferDevice, shareDevice } from '@/common/api/device'
import ykAuthpup from "@/components/yk-authpup/yk-authpup"; import ykAuthpup from '@/components/yk-authpup/yk-authpup'
export default { export default {
components: { components: {
ykAuthpup ykAuthpup,
}, },
data() { data() {
return { return {
loading: true, loading: true,
userInfo: {}, userInfo: {},
messageCount: {}, messageCount: {},
timer: null, timer: null,
} }
}, },
computed: { computed: {
roleName() { roleName() {
let roleName = '' let roleName = ''
switch (this.userInfo.authorities) { switch (this.userInfo.authorities) {
case 'tourist': case 'tourist':
roleName = '游客' roleName = '游客'
break break
case 'engineering_user': case 'engineering_user':
roleName = '工程用户' roleName = '工程用户'
break break
case 'app_vip_user': case 'app_vip_user':
roleName = '正式用户' roleName = '正式用户'
break break
case 'market_user': case 'market_user':
roleName = '营销用户' roleName = '营销用户'
break break
case 'operation_manager': case 'operation_manager':
roleName = '运维管理员' roleName = '运维管理员'
break break
} }
return roleName return roleName
}, },
}, },
onLoad(options) { onLoad(options) {
this.init() this.init()
}, },
methods: { methods: {
init() {}, init() {},
upgrade(code) { upgrade(code) {
console.log(code) console.log(code)
roleUpdate({ roleUpdate({
referralCode: code, referralCode: code,
userId: this.userInfo.userIndex, userId: this.userInfo.userIndex,
}).then((res) => { }).then((res) => {
uni.showToast({ uni.showToast({
title: '升级成功', title: '升级成功',
icon: 'none', icon: 'none',
}) })
uni.removeStorageSync('access_token') uni.removeStorageSync('access_token')
// 直接登录 // 直接登录
autoLogin(this.userInfo.user_name).then((res) => { autoLogin(this.userInfo.user_name).then((res) => {
this.$util.loginSuccess(res.data).then((userInfo) => { this.$util.loginSuccess(res.data).then((userInfo) => {
this.userInfo = userInfo this.userInfo = userInfo
}) })
}) })
}) })
}, },
changeAuth(){ changeAuth() {
//这里是权限通过后执行自己的代码逻辑 //这里是权限通过后执行自己的代码逻辑
console.log('权限已授权,可执行自己的代码逻辑了'); console.log('权限已授权,可执行自己的代码逻辑了')
// this.handleScon() // this.handleScon()
this.handleScon() this.handleScon()
}, },
jump(type) { jump(type) {
switch (type) { switch (type) {
case 'scan': case 'scan':
if ( if (
plus.os.name == 'Android' plus.os.name == 'Android'
// && plus.navigator.checkPermission('android.permission.CAMERA') === 'undetermined' // && plus.navigator.checkPermission('android.permission.CAMERA') === 'undetermined'
) { ) {
//未授权 //未授权
// this.$refs.alertDialog.open('bottom') // this.$refs.alertDialog.open('bottom')
this.$refs['authpup'].open() this.$refs['authpup'].open()
// this.$refs.message.open() // this.$refs.message.open()
} else {
} else { console.log(2)
console.log(2) this.handleScon()
this.handleScon() }
}
break
case 'login':
break uni.navigateTo({
case 'login': url: `/pages/user/login`,
uni.navigateTo({ })
url: `/pages/user/login`, break
}) case 'gateway':
break uni.navigateTo({
case 'gateway': url: `/pages/gateway/list`,
uni.navigateTo({ })
url: `/pages/gateway/list`, break
}) case 'upgrade':
break this.$refs.inputDialog.open()
case 'upgrade': break
this.$refs.inputDialog.open() case 'basic':
break uni.navigateTo({
case 'basic': url: `/pages/user/basic`,
uni.navigateTo({ })
url: `/pages/user/basic`, break
}) case 'project':
break uni.navigateTo({
case 'project': url: `/pages/project/list`,
uni.navigateTo({ })
url: `/pages/project/list`, break
}) case 'engineering':
break uni.navigateTo({
case 'engineering': url: `/pages/engineering/list`,
uni.navigateTo({ })
url: `/pages/engineering/list`, break
}) case 'engineering/setting':
break uni.navigateTo({
case 'engineering/setting': url: `/pages/engineering/setting`,
uni.navigateTo({ })
url: `/pages/engineering/setting`, break
}) case 'feedback':
break uni.navigateTo({
case 'feedback': url: `/pages/message/feedback`,
uni.navigateTo({ })
url: `/pages/message/feedback`, break
}) default:
break uni.navigateTo({
default: url: `/pages/mine/${type}`,
uni.navigateTo({ })
url: `/pages/mine/${type}`, break
}) }
break },
} handleScon() {
}, this.$refs.message.close()
handleScon(){ uni.scanCode({
this.$refs.message.close() onlyFromCamera: true,
uni.scanCode({ success: (res) => {
onlyFromCamera:true, console.log('条码类型:' + res.scanType)
success: (res) => { console.log('条码内容:' + res.result)
console.log('条码类型:' + res.scanType) let content = JSON.parse(res.result)
console.log('条码内容:' + res.result) switch (content.type) {
let content = JSON.parse(res.result) case 'transferDevice':
switch (content.type) { this.transferDevice(content.id.split(','))
case 'transferDevice': break
this.transferDevice(content.id.split(',')) case 'shareDevice':
break this.shareDevice(content.id.split(','))
case 'shareDevice': break
this.shareDevice(content.id.split(',')) default:
break this.$util.toast('无效二维码')
default: break
this.$util.toast('无效二维码') }
break },
} })
}, },
}) dialogClose() {
}, this.$refs.message.close()
dialogClose(){this.$refs.message.close()}, },
transferDevice(id) { transferDevice(id) {
transferDevice(id).then((res) => { transferDevice(id).then((res) => {
uni.navigateTo({ url: '/pages/mine/result?type=transferDevice&id=' + id }) uni.navigateTo({ url: '/pages/mine/result?type=transferDevice&id=' + id })
}) })
}, },
shareDevice(id) { shareDevice(id) {
shareDevice(id).then((res) => { shareDevice(id).then((res) => {
uni.navigateTo({ url: '/pages/mine/result?type=shareDevice&id=' + id }) uni.navigateTo({ url: '/pages/mine/result?type=shareDevice&id=' + id })
}) })
}, },
}, },
onShow() { onShow() {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo) this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
this.loading = false this.loading = false
this.messageCount = uni.getStorageSync(this.$cacheKey.messageCount) || {} this.messageCount = uni.getStorageSync(this.$cacheKey.messageCount) || {}
this.timer = setInterval(() => { this.timer = setInterval(() => {
this.messageCount = uni.getStorageSync(this.$cacheKey.messageCount) || {} this.messageCount = uni.getStorageSync(this.$cacheKey.messageCount) || {}
}, 1000) // 定时请求 }, 1000) // 定时请求
}, },
onHide() { onHide() {
clearInterval(this.timer) clearInterval(this.timer)
}, },
} }
</script> </script>
<style lang="scss"> <style lang="scss">
.mine { .mine {
.mine-header { .mine-header {
padding: 200rpx 34rpx 34rpx; padding: 200rpx 34rpx 34rpx;
display: flex; display: flex;
align-items: center; align-items: center;
background: $uni-theme-white; background: $uni-theme-white;
margin-bottom: 20rpx; margin-bottom: 20rpx;
box-shadow: 0 4rpx 8rpx #e7e7e74c; box-shadow: 0 4rpx 8rpx #e7e7e74c;
.mine-header-head { .mine-header-head {
margin-right: 30rpx; margin-right: 30rpx;
height: 128rpx; height: 128rpx;
width: 128rpx; width: 128rpx;
border-radius: $uni-theme-radius; border-radius: $uni-theme-radius;
overflow: hidden; overflow: hidden;
} }
.mine-header-name { .mine-header-name {
margin-right: 30rpx; margin-right: 30rpx;
flex: 1; flex: 1;
font-size: 36rpx; font-size: 36rpx;
color: #111; color: #111;
font-weight: 700; font-weight: 700;
.tag { .tag {
display: flex; display: flex;
align-items: center; align-items: center;
margin-top: 10rpx; margin-top: 10rpx;
font-size: 24rpx; font-size: 24rpx;
color: #aaa; color: #aaa;
.engineering-button { .engineering-button {
margin-left: 10rpx; margin-left: 10rpx;
font-size: 24rpx; font-size: 24rpx;
padding: 5rpx 12rpx; padding: 5rpx 12rpx;
color: #fff; color: #fff;
font-weight: 400; font-weight: 400;
border-radius: 16rpx; border-radius: 16rpx;
background: $uni-theme-color; background: $uni-theme-color;
} }
} }
} }
} }
.mine-nav { .mine-nav {
padding: 34rpx; padding: 34rpx;
display: flex; display: flex;
align-items: center; align-items: center;
background: $uni-theme-white; background: $uni-theme-white;
border-bottom: 1rpx solid #e8e8e8; border-bottom: 1rpx solid #e8e8e8;
&-icon { &-icon {
margin-right: 30rpx; margin-right: 30rpx;
height: 44rpx; height: 44rpx;
width: 44rpx; width: 44rpx;
border-radius: $uni-theme-radius; border-radius: $uni-theme-radius;
overflow: hidden; overflow: hidden;
} }
&-label { &-label {
margin-right: 30rpx; margin-right: 30rpx;
flex: 1; flex: 1;
font-size: 28rpx; font-size: 28rpx;
color: #111; color: #111;
} }
} }
} }
/deep/ .uni-popup-message__box { /deep/ .uni-popup-message__box {
border-radius: 10rpx !important; border-radius: 10rpx !important;
background-color: #fff; background-color: #fff;
} }
</style> </style>
</style>

154
pages/index/report.vue Normal file
View File

@@ -0,0 +1,154 @@
<template>
<view :loading="loading" class="report" style="padding-top: 10px">
<view class="navReport">
<view class="tabsBox">
<uni-segmented-control
:current="curTabs"
:values="items"
style-type="text"
active-color="#376cf3"
@clickItem="onClickItem"
/>
</view>
</view>
<!-- 稳态报表 -->
<SteadyState
v-if="curTabs == 0"
ref="SteadyStateRef"
:indexList="indexList"
:total="total"
:status="status"
:navHeight="navHeight"
@scrolltolower="scrolltolower"
/>
<!-- 暂态报表 -->
<Transient
v-if="curTabs == 1"
ref="TransientRef"
:indexList="indexList"
:total="total"
:status="status"
:navHeight="navHeight"
@scrolltolower="scrolltolower"
/>
</view>
</template>
<script>
import SteadyState from './comp/steadyState.vue'
import Transient from './comp/transient.vue'
export default {
components: {
SteadyState,
Transient,
},
props: {},
data() {
return {
curTabs: 0,
total: 6,
loading: false,
items: ['稳态报表', '暂降报告'],
status: 'more', //more加载前 loading加载中 noMore加载后
navHeight: 0,
indexList: [],
}
},
created() {},
onPullDownRefresh() {
this.refresh()
},
mounted() {
uni.createSelectorQuery()
.select('.navReport')
.boundingClientRect((rect) => {
//
this.navHeight = rect.height
// // #ifdef H5
// // #endif
// // #ifdef APP-PLUS
// this.navHeight = rect.height
// // #endif
})
.exec()
},
methods: {
onClickItem(e) {
if (this.curTabs !== e.currentIndex) {
this.curTabs = e.currentIndex
}
},
scrolltolower() {
if (this.total != this.indexList.length) {
this.status = 'loading'
this.info()
} else {
this.status = 'noMore'
}
},
info() {
setTimeout(() => {
this.status = 'more'
}, 1000)
},
refresh() {
switch (this.curTabs) {
case 0:
this.$refs.SteadyStateRef.store.reload()
break
case 1:
this.$refs.TransientRef.reload()
break
}
},
},
computed: {},
watch: {},
}
</script>
<style lang="scss">
.report {
overflow: hidden;
/deep/ .u-tabs__wrapper__nav {
background: #fff;
}
/deep/ .u-tabs__wrapper__nav__item {
flex: 1;
}
/deep/ .u-tabs__wrapper__nav__line {
left: 80rpx;
}
/deep/ .u-u-subsection {
width: 80% !important;
}
/deep/.tabsBox {
.segmented-control {
// height: 40px;
background-color: #fff;
border-bottom: 1px solid #cccccc70;
.segmented-control__item {
align-items: baseline;
margin-top: 5px;
}
}
.segmented-control__text {
font-size: 30rpx !important;
color: rgb(96, 98, 102);
}
.segmented-control__item--text {
font-weight: bold;
padding: 0 0 5rpx;
}
}
}
</style>

View File

@@ -1,147 +1,147 @@
<template> <template>
<Cn-page :loading='loading'> <Cn-page :loading='loading'>
<view slot='body'> <view slot='body'>
<view class='detail'> <view class='detail'>
<view class="detail-content "> <view class="detail-content ">
<view class="detail-content-title mb20">{{ pageData.title }}</view> <view class="detail-content-title mb20">{{ pageData.title }}</view>
<view> {{ pageData.createTime }}</view> <view> {{ pageData.createTime }}</view>
<view class="mt10 mb10">{{ pageData.description }}</view> <view class="mt10 mb10">{{ pageData.description }}</view>
<uni-file-picker readonly v-model="imageValue" mode="grid"/> <uni-file-picker readonly v-model="imageValue" mode="grid"/>
</view> </view>
<view class="detail-content " style="margin-bottom:0"> <view class="detail-content " style="margin-bottom:0">
<view class="detail-content-title "> <view class="detail-content-title ">
<view class="title">进度</view> <view class="title">进度</view>
<!-- <template v-if="pageData.status === '1'">--> <!-- <template v-if="pageData.status === '1'">-->
<!-- <view class="title-btn mr10" @click="updateFeedBackStatus('2')">解决</view>--> <!-- <view class="title-btn mr10" @click="updateFeedBackStatus('2')">解决</view>-->
<!-- <view class="title-btn mr10" @click="updateFeedBackStatus('0')">关闭</view>--> <!-- <view class="title-btn mr10" @click="updateFeedBackStatus('0')">关闭</view>-->
<!-- </template>--> <!-- </template>-->
<!-- <template v-if="pageData.status === '2'">--> <!-- <template v-if="pageData.status === '2'">-->
<!-- <view class="title-btn mr10" @click="updateFeedBackStatus('0')">关闭</view>--> <!-- <view class="title-btn mr10" @click="updateFeedBackStatus('0')">关闭</view>-->
<!-- </template>--> <!-- </template>-->
<!-- <view class="title-btn" @click="open">回复</view>--> <!-- <view class="title-btn" @click="open">回复</view>-->
</view> </view>
</view> </view>
<uni-list> <uni-list>
<uni-list-item :title="item.userName" :note="item.chatContent" :rightText="item.createTime" <uni-list-item :title="item.userName" :note="item.chatContent" :rightText="item.createTime"
v-for="(item, index) in pageData.csFeedbackChatPOList" :key="index"/> v-for="(item, index) in pageData.csFeedbackChatPOList" :key="index"/>
<Cn-empty <Cn-empty
v-if="pageData.csFeedbackChatPOList && pageData.csFeedbackChatPOList.length == 0"></Cn-empty> v-if="pageData.csFeedbackChatPOList && pageData.csFeedbackChatPOList.length == 0"></Cn-empty>
</uni-list> </uni-list>
<!-- 输入框示例 --> <!-- 输入框示例 -->
<uni-popup ref="inputDialog" type="dialog"> <uni-popup ref="inputDialog" type="dialog">
<uni-popup-dialog ref="inputClose" type="info" mode="input" title="输入内容" <uni-popup-dialog ref="inputClose" type="info" mode="input" title="输入内容"
value="对话框预置提示内容!" value="对话框预置提示内容!"
placeholder="请输入内容" @confirm="dialogInputConfirm"> placeholder="请输入内容" @confirm="dialogInputConfirm">
<uni-easyinput type="textarea" :maxlength="250" autoHeight v-model="chatContent" <uni-easyinput type="textarea" :maxlength="250" autoHeight v-model="chatContent"
placeholder="请输入内容"></uni-easyinput> placeholder="请输入内容"></uni-easyinput>
</uni-popup-dialog> </uni-popup-dialog>
</uni-popup> </uni-popup>
</view> </view>
</view> </view>
</Cn-page> </Cn-page>
</template> </template>
<script> <script>
import {queryFeedBackDetail, AddFeedbackChat, updateChatStatus, updateFeedBackStatus} from '../../common/api/feedback' import {queryFeedBackDetail, AddFeedbackChat, updateChatStatus, updateFeedBackStatus} from '../../common/api/feedback'
export default { export default {
data() { data() {
return { return {
loading: false, loading: false,
chatContent: "", chatContent: "",
imageValue: [ imageValue: [
{ {
"name": "file.png", "name": "file.png",
"extname": "png", "extname": "png",
"url": "/static/logo.png", "url": "/static/logo.png",
} }
], ],
pageData: {}, pageData: {},
pageOption: {} pageOption: {}
} }
}, },
onLoad(o) { onLoad(o) {
this.pageOption = o this.pageOption = o
this.init() this.init()
updateChatStatus({ updateChatStatus({
id: o.id, id: o.id,
}) })
}, },
methods: { methods: {
updateFeedBackStatus(status) { updateFeedBackStatus(status) {
updateFeedBackStatus({ updateFeedBackStatus({
id: this.pageOption.id, id: this.pageOption.id,
status: status status: status
}).then(res => { }).then(res => {
this.init() this.init()
}) })
}, },
init() { init() {
this.loading = true this.loading = true
queryFeedBackDetail(this.pageOption.id).then(res => { queryFeedBackDetail(this.pageOption.id).then(res => {
// 反转数组 // 反转数组
res.data.csFeedbackChatPOList.reverse() res.data.csFeedbackChatPOList.reverse()
this.pageData = res.data this.pageData = res.data
this.imageValue = res.data.imageUrls.map(item => { this.imageValue = res.data.imageUrls.map(item => {
return { return {
"name": item, "name": item,
"extname": item.split('.')[1], "extname": item.split('.')[1],
"url": this.$config.static + item, "url": this.$config.static + item,
} }
}) })
this.loading = false this.loading = false
console.log(res); console.log(res);
}) })
}, },
dialogInputConfirm() { dialogInputConfirm() {
AddFeedbackChat({chatContent: this.chatContent, id: this.pageOption.id}).then(res => { AddFeedbackChat({chatContent: this.chatContent, id: this.pageOption.id}).then(res => {
console.log(res); console.log(res);
this.$util.toast('回复成功') this.$util.toast('回复成功')
this.init() this.init()
this.chatContent = '' this.chatContent = ''
}) })
}, },
open() { open() {
this.$refs.inputDialog.open() this.$refs.inputDialog.open()
}, },
over() { over() {
}, },
close() { close() {
}, },
} }
} }
</script> </script>
<style lang='scss'> <style lang='scss'>
.detail { .detail {
padding: 0 0 20rpx; padding: 0 0 20rpx;
.detail-content { .detail-content {
padding: 20rpx 30rpx; padding: 20rpx 30rpx;
background: #fff; background: #fff;
margin-bottom: 20rpx; margin-bottom: 20rpx;
font-size: 26rpx; font-size: 26rpx;
.detail-content-title { .detail-content-title {
font-size: 32rpx; font-size: 28rpx;
color: #111; color: #111;
font-weight: 700; font-weight: 700;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
.title { .title {
flex: 1; flex: 1;
} }
.title-btn { .title-btn {
padding: 0 20rpx; padding: 0 20rpx;
height: 50rpx; height: 50rpx;
background-color: #007aff; background-color: #007aff;
font-size: 24rpx; font-size: 24rpx;
color: #fff; color: #fff;
text-align: center; text-align: center;
line-height: 50rpx; line-height: 50rpx;
border-radius: 10rpx; border-radius: 10rpx;
} }
} }
} }
} }
</style> </style>

View File

@@ -18,17 +18,21 @@
<view class="content-item-header-right"> <view class="content-item-header-right">
<view class="content-item-header-right-title">{{ item.equipmentName }}</view> <view class="content-item-header-right-title">{{ item.equipmentName }}</view>
<!-- <view class="content-item-header-right-des">{{ item.engineeringName }} {{ item.projectName }}</view> --> <!-- <view class="content-item-header-right-des">{{ item.engineeringName }} {{ item.projectName }}</view> -->
<view class="content-item-header-right-des">工程名称{{ item.engineeringName }}</view> <view class="content-item-header-right-des">工程{{ item.engineeringName }}</view>
<view class="content-item-header-right-des">项目名称{{ item.projectName }}</view> <view class="content-item-header-right-des">项目{{ item.projectName }}</view>
<view class="content-item-header-right-des" v-if="type == '0' || type == '1'" <view class="content-item-header-right-des" v-if="type == '0' || type == '1'"
>监测点名称{{ item.lineName }}</view >监测点{{ item.lineName }}
</view
> >
<view class="content-item-header-right-des" v-if="type == '0'" <view class="content-item-header-right-des" v-if="type == '0'"
>暂态类型{{ item.showName }}</view >暂态类型{{ item.showName }}
</view
> >
<!-- <view class="content-item-header-right-des">{{ item.subTitle }}</view> --> <!-- <view class="content-item-header-right-des">{{ item.subTitle }}</view> -->
</view> </view>
<view class="ml10" v-if="type === '0' || item.status != '1'">🔍</view> <view class="ml10" v-if="type === '0' || item.status != '1'">
<uni-icons type="search" size="25" color="#376cf3"></uni-icons>
</view>
</view> </view>
<view class="content-item-footer">{{ item.subTitle }}</view> <view class="content-item-footer">{{ item.subTitle }}</view>
</view> </view>

View File

@@ -1,91 +1,91 @@
<template> <template>
<Cn-page :loading="loading"> <Cn-page :loading="loading">
<view class="detail" slot="body"> <view class="detail" slot="body">
<view class="detail-content" style="font-size: 32rpx"> <view class="detail-content" style="font-size: 32rpx">
<!-- <view class="detail-content-title mb20">发生时间</view> --> <!-- <view class="detail-content-title mb20">发生时间</view> -->
<view>{{ detail.startTime }}</view> <view>{{ detail.startTime }}</view>
</view> </view>
<view class="detail-content"> <view class="detail-content">
<view class="detail-content-title mb20">基础信息</view> <view class="detail-content-title mb20">基础信息</view>
<view class="mb5"> 设备名称{{ detail.equipmentName }}</view> <view class="mb5"> 设备{{ detail.equipmentName }}</view>
<view class="mb5"> 项目名称{{ detail.projectName }} </view> <view class="mb5"> 项目{{ detail.projectName }} </view>
<view class="mb5"> 工程名称{{ detail.engineeringName }} </view> <view class="mb5"> 工程{{ detail.engineeringName }} </view>
<view class="mb5"> 事件名称{{ detail.showName }}</view> <view class="mb5"> 事件{{ detail.showName }}</view>
<view class="mb5" v-for="(item, textIndex) in detail.dataSet" :key="textIndex"> <view class="mb5" v-for="(item, textIndex) in detail.dataSet" :key="textIndex">
{{ item.showName + '' + (item.value == 3.1415926 ? '-' : item.value) + (item.unit || '') }} {{ item.showName + '' + (item.value == 3.1415926 ? '-' : item.value) + (item.unit || '') }}
</view> </view>
</view> </view>
<view class="detail-content"> <view class="detail-content">
<view class="detail-content-title mb20">瞬时波形图</view> <view class="detail-content-title mb20">瞬时波形图</view>
<image <image
style="width: 100%" style="width: 100%"
:src="detail.instantPics" :src="detail.instantPics"
mode="widthFix" mode="widthFix"
v-if="detail.instantPics" v-if="detail.instantPics"
@click="previewImage(detail.instantPics)" @click="previewImage(detail.instantPics)"
/> />
<text v-else>暂无</text> <text v-else>暂无</text>
</view> </view>
<view class="detail-content"> <view class="detail-content">
<view class="detail-content-title mb20">RMS波形图</view> <view class="detail-content-title mb20">RMS波形图</view>
<image <image
style="width: 100%" style="width: 100%"
:src="detail.rmsPics" :src="detail.rmsPics"
mode="widthFix" mode="widthFix"
v-if="detail.rmsPics" v-if="detail.rmsPics"
@click="previewImage(detail.rmsPics)" @click="previewImage(detail.rmsPics)"
/> />
<text v-else>暂无</text> <text v-else>暂无</text>
</view> </view>
</view> </view>
</Cn-page> </Cn-page>
</template> </template>
<script> <script>
import { updateStatus } from '@/common/api/message' import { updateStatus } from '@/common/api/message'
export default { export default {
data() { data() {
return { return {
loading: true, loading: true,
detail: {}, detail: {},
} }
}, },
onLoad(options) { onLoad(options) {
console.log(options.detail) console.log(options.detail)
this.detail = JSON.parse(decodeURIComponent(options.detail).replace(/百分比/g, '%')) this.detail = JSON.parse(decodeURIComponent(options.detail).replace(/百分比/g, '%'))
this.detail.rmsPics && (this.detail.rmsPics = this.$config.static + this.detail.rmsPics) this.detail.rmsPics && (this.detail.rmsPics = this.$config.static + this.detail.rmsPics)
this.detail.instantPics && (this.detail.instantPics = this.$config.static + this.detail.instantPics) this.detail.instantPics && (this.detail.instantPics = this.$config.static + this.detail.instantPics)
this.loading = false this.loading = false
if (this.detail.status != 1) { if (this.detail.status != 1) {
updateStatus({ updateStatus({
eventIds: [this.detail.id], eventIds: [this.detail.id],
}) })
} }
}, },
methods: { methods: {
previewImage(url) { previewImage(url) {
uni.previewImage({ uni.previewImage({
urls: [url], urls: [url],
}) })
}, },
}, },
} }
</script> </script>
<style lang="scss"> <style lang="scss">
.detail { .detail {
padding: 20rpx 0; padding: 20rpx 0;
.detail-content { .detail-content {
padding: 20rpx; padding: 20rpx;
background: #fff; background: #fff;
margin-bottom: 20rpx; margin-bottom: 20rpx;
font-size: 26rpx; font-size: 26rpx;
.detail-content-title { .detail-content-title {
font-size: 32rpx; font-size: 28rpx;
color: #111; color: #111;
font-weight: 700; font-weight: 700;
} }
} }
} }
</style> </style>

162
pages/message1/alarm.vue Normal file
View File

@@ -0,0 +1,162 @@
<template>
<view style="position: relative">
<!-- 运行告警 -->
<!-- 卡片 -->
<scroll-view scroll-y="true" @refresherrefresh="refresherrefresh" @scrolltolower="scrolltolower"
:refresher-triggered="triggered" refresher-enabled="true" class="event-list"
:style="{ height: 'calc(100vh - ' + (navHeight + 10) + 'px)', overflow: 'auto' }">
<!-- 循环渲染事件项 -->
<uni-card class="event-item boxClick" :class="item.type" v-for="(item, index) in this.store.data"
:key="index" @click="jump(item)">
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view class="event-icon">
<!-- 动态图标根据类型切换 -->
<!-- <uni-icons
custom-prefix="iconfont"
type="icon-terminal-box-fill"
size="30"
color="#376cf3"
></uni-icons> -->
<Cn-icon-transient :name="`运行告警`" />
<view class="badge1" v-if="item.isRead == 0"></view>
</view>
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.date }}</text>
</view>
<view class="event-desc">
<text>告警终端总数{{ item.warnNums }}</text>
<text v-if="item.onlineRateIsWarn">在线率偏低</text>
<text v-if="item.integrityIsWarn">完整性偏低</text>
<text v-if="item.warnCounts > 0">事件触发终端告警{{ item.warnCounts }}</text>
</view>
</view>
<view class="event-action">
<uni-icons type="search" size="25" color="#376cf3"></uni-icons>
</view>
</view>
<!-- <view class="event-detail">
<text> 告警终端总数{{ item.warnNums }} </text>
</view> -->
</uni-card>
<uni-load-more v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty>
</scroll-view>
</view>
</template>
<script>
import list from '@/common/js/list'
export default {
components: {},
props: {
navHeight: {
type: Number,
default: 0,
},
selectValue: {
type: Object,
// default: () => {},
},
},
mixins: [list],
data() {
return {
triggered: true,
status: 'noMore', //more加载前 loading加载中 noMore加载后
}
},
mounted() {
},
methods: {
init() {
this.store = this.DataSource('/cs-harmonic-boot/csAlarm/queryAlarmList')
// this.store.params.pageSize = 10000
this.store.params.engineerId = this.selectValue.engineeringId
this.store.params.projectId = this.selectValue.projectId
this.store.params.devId = this.selectValue.deviceId
this.store.params.lineId = this.selectValue.lineId
this.store.params.time = this.selectValue.date
this.store.loadedCallback = () => {
this.loading = false
}
this.store.reload()
},
jump(item) {
let str = JSON.stringify(item).replace(/%/g, '百分比')
uni.navigateTo({ url: '/pages/message1/comp/alarmDetails?detail=' + encodeURIComponent(str) })
item.isRead = 1
},
// 下拉
refresherrefresh() {
this.triggered = true
uni.startPullDownRefresh()
setTimeout(() => {
this.triggered = false
}, 500)
},
// 上拉
scrolltolower() {
if (this.store.status != 'noMore') {
this.store.next && this.store.next()
}
},
},
computed: {},
watch: {
selectValue: {
handler(val, oldVal) {
if (Object.keys(val).length === 0) return
this.init()
},
deep: true,
immediate: true,
},
},
}
</script>
<style lang="scss" scoped>
@import './index.scss';
/* 列表容器 */
.event-list {
margin-top: 20rpx;
/* 头部:图标 + 信息 + 操作 */
// .event-header {
// margin-bottom: 0rpx;
// }
// .event-title {
// margin-bottom: 0rpx;
// }
/* 图标区域(按类型区分背景色) */
.event-icon {
// width: 80rpx;
// height: 80rpx;
background-color: #376cf320;
}
/* 信息区域 */
.event-info {
flex: 1;
}
}
/deep/ .uni-scroll-view-refresher {
display: none;
}
.event-header {
margin-bottom: 0rpx !important;
}
</style>

249
pages/message1/comp/F47.vue Normal file
View File

@@ -0,0 +1,249 @@
<template>
<!-- ITIC -->
<view>
<l-echart v-if="status != 'loading'" ref="echartRef" @finished="initChart"></l-echart>
<uni-load-more v-else :status="status"></uni-load-more>
</view>
</template>
<script>
const echarts = require('../../../uni_modules/lime-echart/static/echarts.min')
export default {
components: {},
props: {
store: {
type: [Object],
},
},
data() {
return {
option: {
backgroundColor: '#fff',
grid: {
left: '10px',
right: '40rpx',
bottom: '40rpx',
top: '10px',
containLabel: true,
},
legend: {
data: ['分割线', '可容忍事件', '不可容忍事件'],
right: '10px',
bottom: '10px',
textStyle: {
fontSize: 10,
},
itemWidth: 10,
itemHeight: 10,
itemGap: 8,
padding: [5, 5, 5, 10],
},
yAxis: {
type: 'log',
min: '0.001',
max: '1000',
name: 's',
inverse: true,
axisLabel: {
rotate: -90,
},
splitLine: { show: false },
},
xAxis: {
type: 'value',
splitNumber: 10,
minInterval: 20,
position: 'top',
rotate: 90,
max: 140,
axisLabel: {
rotate: -90,
},
name: '%',
},
series: [
{
name: '分割线',
type: 'line',
data: [
[0, 0.05],
[50, 0.05],
[50, 0.2],
[70, 0.2],
[70, 0.5],
[80, 0.5],
[80, 10],
[80, 1000],
],
showSymbol: false,
tooltips: {
show: false,
},
color: '#DAA520',
},
{
name: '可容忍事件',
type: 'scatter',
symbol: 'circle',
// data: this.pointF,
data: [],
color: 'green',
},
{
name: '不可容忍事件',
type: 'scatter',
symbol: 'circle',
// data: this.pointFun,
data: [],
color: 'red',
},
],
},
status: 'loading',
echartRef: null,
pointF: [],
pointFun: [],
data: [],
maxXAxis: 140,
}
},
mounted() {
// this.initChart()
// console.log('🚀 ~ props.data:', this.props.data)
},
methods: {
init() {},
async initChart() {
if (!this.$refs.echartRef) return
try {
this.echartRef = await this.$refs.echartRef.init(echarts)
this.bindChartClickEvent()
this.echartRef.setOption(this.option, true)
} catch (error) {
console.error('图表初始化失败:', error)
}
},
gongfunction() {
var standF = 0
var unstandF = 0
this.pointF = []
this.pointFun = []
var total = 0
let dataList = [0]
total = this.data.length
if (total == 0) {
} else {
for (var i = 0; i < this.data.length; i++) {
var point = []
var xx = this.data[i].evtParamTm.replace(/s/g, '')
var yy = this.data[i].evtParamVVaDepth.replace(/%/g, '')
var time = this.data[i].startTime.replace('T', ' ')
dataList.push(yy)
point = [yy, xx, time, this.data[i]]
if (xx < 0.05) {
standF++
this.pointF.push({
value: point,
itemStyle: { normal: { color: 'green' } },
})
} else if (xx < 0.2) {
if (yy > 50) {
standF++
this.pointF.push({
value: point,
itemStyle: { normal: { color: 'green' } },
})
} else {
unstandF++
this.pointFun.push({
value: point,
itemStyle: { normal: { color: 'red' } },
})
}
} else if (xx < 0.5) {
if (yy > 70) {
standF++
this.pointF.push({
value: point,
itemStyle: { normal: { color: 'green' } },
})
} else {
unstandF++
this.pointFun.push({
value: point,
itemStyle: { normal: { color: 'red' } },
})
}
} else {
if (yy > 80) {
standF++
this.pointF.push({
value: point,
itemStyle: { normal: { color: 'green' } },
})
} else {
unstandF++
this.pointFun.push({
value: point,
itemStyle: { normal: { color: 'red' } },
})
}
}
}
}
this.option.xAxis.max = Math.max(
140,
Math.ceil(
Math.max(
...dataList
.filter((item) => {
return item !== '-' && !isNaN(Number(item))
})
.map((item) => Number(item)),
) / 10,
) * 10,
) //this.maxXAxis
this.option.series[1].data = this.pointF
this.option.series[2].data = this.pointFun
if (this.echartRef) {
this.echartRef.setOption(this.option, true)
} else {
this.initChart()
}
},
bindChartClickEvent() {
if (!this.echartRef) return
this.echartRef.on('click', (params) => {
// 点击查看详情
let item = params.value[3]
let str = JSON.stringify(item).replace(/%/g, '百分比')
// uni.navigateTo({ url: '/pages/message1/comp/transientDetails?detail=' + encodeURIComponent(str) })
})
},
},
computed: {},
watch: {
store: {
handler(val, oldVal) {
this.status = val.status
this.data = (val.data || [])
this.gongfunction()
},
deep: true,
immediate: true,
},
},
}
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,241 @@
<template>
<!-- ITIC -->
<view>
<l-echart v-if="status != 'loading'" ref="echartRef" @finished="initChart"></l-echart>
<uni-load-more v-else :status="status"></uni-load-more>
</view>
</template>
<script>
const echarts = require('../../../uni_modules/lime-echart/static/echarts.min')
export default {
components: {},
props: {
store: {
type: [Object],
},
},
data() {
return {
option: {
backgroundColor: '#fff',
grid: {
left: '10px',
right: '40rpx',
bottom: '40rpx',
top: '10px',
containLabel: true,
},
legend: {
data: ['上限', '下限', '可容忍事件', '不可容忍事件'],
right: '10px',
bottom: '10px',
textStyle: {
fontSize: 10,
},
itemWidth: 10,
itemHeight: 10,
itemGap: 8,
padding: [5, 5, 5, 10],
},
color: ['#FF8C00', '#00BFFF', 'green', 'red'],
yAxis: {
type: 'log',
min: '0.001',
max: '1000',
name: 's',
inverse: true,
axisLabel: {
rotate: -90,
},
splitLine: { show: false },
},
xAxis: {
type: 'value',
splitNumber: 10,
minInterval: 3,
position: 'top',
rotate: 90,
axisLabel: {
rotate: 90,
},
name: '%',
},
series: [
{
name: '上限',
type: 'line',
data: [
[200, 0.001],
[140, 0.003],
[120, 0.003],
[120, 0.5],
[110, 0.5],
[110, 10],
[110, 1000],
],
showSymbol: false,
tooltips: {
show: false,
},
color: '#FF8C00',
},
{
name: '下限',
type: 'line',
data: [
[0, 0.02],
[70, 0.02],
[70, 0.5],
[80, 0.5],
[80, 10],
[90, 10],
[90, 1000],
],
showSymbol: false,
tooltips: {
show: false,
},
color: '#00BFFF',
},
{
name: '可容忍事件',
type: 'scatter',
symbol: 'circle',
// data: this.pointI,
data: [],
color: 'green',
},
{
name: '不可容忍事件',
type: 'scatter',
symbol: 'circle',
// data: this.pointIun,
data: [],
color: 'red',
},
],
},
status: 'loading',
echartRef: null,
pointI: [],
pointIun: [],
data: [],
}
},
mounted() {
// this.initChart()
// console.log('🚀 ~ props.data:', this.props.data)
},
methods: {
init() {},
async initChart() {
if (!this.$refs.echartRef) return
try {
this.echartRef = await this.$refs.echartRef.init(echarts)
this.bindChartClickEvent()
this.echartRef.setOption(this.option, true)
} catch (error) {
console.error('图表初始化失败:', error)
}
},
gongfunction() {
// 初始化计数与数据数组
let normalCount = 0
let abnormalCount = 0
this.normalPoints = []
this.abnormalPoints = []
if (!this.data || this.data.length === 0) {
this.updateChartOption()
return
}
// 缓存长度,遍历数据
const len = this.data.length
for (let i = 0; i < len; i++) {
const item = this.data[i]
// 建议确认正则意图,/s/g 仅移除字母 s若去空格应为 /\s/g
const xx = parseFloat(item.evtParamTm.replace(/s/g, ''))
const yy = parseFloat(item.evtParamVVaDepth.replace(/%/g, ''))
const time = item.startTime.replace('T', ' ')
const pointData = [yy, xx, time, item]
const isNormal = this.checkPointStatus(xx, yy)
const pointObj = {
value: pointData,
itemStyle: { normal: { color: isNormal ? 'green' : 'red' } },
}
if (isNormal) {
normalCount++
this.normalPoints.push(pointObj)
} else {
abnormalCount++
this.abnormalPoints.push(pointObj)
}
}
this.updateChartOption()
},
// 提取判断逻辑为独立方法
checkPointStatus(xx, yy) {
if (xx <= 0.003) {
const line = 230 - 30000 * xx
return yy <= line
} else if (xx <= 0.02) {
return yy <= 120
} else if (xx <= 0.5) {
return yy > 70 && yy < 120
} else if (xx <= 10) {
return yy > 80 && yy < 110
} else {
return yy > 90 && yy < 110
}
},
updateChartOption() {
// 建议避免硬编码 series 索引,可通过 seriesName 查找
this.option.series[2].data = this.normalPoints
this.option.series[3].data = this.abnormalPoints
if (this.echartRef) {
this.echartRef.setOption(this.option, true)
} else {
this.initChart()
}
},
bindChartClickEvent() {
if (!this.echartRef) return
this.echartRef.on('click', (params) => {
console.log('🚀 ~ params:', params.value[3])
// 点击查看详情
let item = params.value[3]
let str = JSON.stringify(item).replace(/%/g, '百分比')
// uni.navigateTo({ url: '/pages/message1/comp/transientDetails?detail=' + encodeURIComponent(str) })
})
},
},
computed: {},
watch: {
store: {
handler(val, oldVal) {
this.status = val.status
this.data = (val.data || [])
this.gongfunction()
},
deep: true,
immediate: true,
},
},
}
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,244 @@
<template>
<Cn-page :loading="loading">
<view class="detail" slot="body">
<view class="detail-content" style="font-size: 32rpx">
<!-- <view class="detail-content-title mb20">发生时间</view> -->
<view>{{ detail.date }}</view>
</view>
<view class="detail-content" style="padding: 0px">
<view class="detail-content-title pb20 pt20 pl20">终端告警列表</view>
</view>
<view class="event-list">
<uni-card class="event-item" :class="item.type" v-for="(item, index) in list" :key="index">
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view class="event-icon"
:class="item.devType == 'Direct_Connected_Device' ? 'zl-bgc' : 'jc-bgc'">
<!-- 动态图标根据类型切换 -->
<!-- <uni-icons
custom-prefix="iconfont"
type="icon-terminal-box-fill"
size="35"
color="#FF0000"
></uni-icons> -->
<!-- <Cn-icon-transient :name="`运行告警`" /> -->
<Cn-icon-transient :name="item.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备'" />
<view class="badge1" v-if="item.status == 0"> </view>
</view>
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.devName }}</text>
<text class="event-tag"
:class="item.devType == 'Direct_Connected_Device' ? 'zl-tag' : 'jc-tag'">{{
item.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备' }}</text>
</view>
<view class="event-desc">
<text>工程{{ item.engineeringName }}</text>
<text>项目{{ item.projectName }}</text>
<!-- <text v-if="item.dataDetails.onlineRate.isAbnormal">在线率{{
item.dataDetails.onlineRate.value }}% 限值{{ item.dataDetails.onlineRate.threshold
}}% </text> -->
<!-- <text>事件时间{{ item.startTime }}</text> -->
</view>
</view>
</view>
<!-- 详情区域 -->
<view class="event-detail">
<view v-if="item.dataDetails.onlineRate.isAbnormal">
<text>在线率
{{item.dataDetails.onlineRate.value }}% 
</text>
</view>
<view v-if="hasIntegrityAbnormal(item)" class="mt10">
数据完整性
<view class="data-table">
<view class="table-header">
<text>监测点</text>
<text>完整性</text>
</view>
<view class="table-row"
v-for="value in item.dataDetails.integrity.monitorPoints.filter((p) => p.isAbnormal === true)">
<text>{{ value.monitorName }}</text>
<text>{{ value.value }}%</text>
</view>
</view>
</view>
<view v-if="item.warnCounts" class="mt10">
终端告警 {{ item.warnCounts }} 详情如下
<view class="textBox">
<view v-for="val in item.warnDetails" class="textBox mb5">
{{ val.warnEventTime + '发生' + val.warnEventDesc }}
</view>
</view>
</view>
</view>
</uni-card>
</view>
</view>
</Cn-page>
</template>
<script>
import { updateStatus, queryAlarmDetail } from '@/common/api/message'
export default {
data() {
return {
loading: true,
detail: {},
limit: '',
collapseValue: '0',
list: [],
}
},
onLoad(options) {
this.loading = true
this.detail = JSON.parse(decodeURIComponent(options.detail).replace(/百分比/g, '%'))
this.init()
if (this.detail.isRead != 1) {
updateStatus({
eventIds: [this.detail.eventId],
})
}
},
methods: {
hasIntegrityAbnormal(item) {
const points = item?.dataDetails?.integrity?.monitorPoints
if (!Array.isArray(points) || !points.length) return false
return points.every((p) => p.isAbnormal === true)
},
init() {
queryAlarmDetail({
devList: this.detail.devIds,
time: this.detail.date,
})
.then((res) => {
this.list = res.data
this.loading = false
})
.catch(() => {
this.loading = false
})
},
},
}
</script>
<style lang="scss" scoped>
@import '../index.scss';
.detail {
padding: 20rpx 0;
.detail-content {
padding: 20rpx;
background: #fff;
margin-bottom: 20rpx;
font-size: 28rpx;
.detail-content-title {
font-size: 30rpx;
color: #111;
font-weight: 700;
}
}
.collapseTop {
padding: 10rpx 0;
margin-left: 15px;
.name {
font-size: 28rpx;
font-weight: 700;
color: #333333;
}
}
.frequency {
display: flex;
font-size: 28rpx;
// color: #666666;
}
}
.textBox {
// border-bottom: 1px solid #eee;
font-size: 28rpx;
color: #666666;
text-indent: 2em;
}
.event-list {
// background: #fff;
padding-bottom: 10rpx;
// .event-icon {
// background-color: #376cf320;
// }
.zl-bgc {
background-color: #376cf320;
}
.jc-bgc {
background-color: #376cf320;
}
.zl-tag {
background-color: #007aff20;
color: #007aff;
}
.jc-tag {
background-color: #007aff20;
color: #007aff;
}
}
/deep/ .uni-collapse-item__title-box {
padding: 0 15px 0 0;
height: 56rpx;
line-height: 56rpx;
font-size: 26rpx !important;
color: #666666;
span {
font-size: 26rpx !important;
}
}
.textBox {
max-height: 120rpx;
overflow-y: auto;
}
.data-table {
margin-top: 10rpx;
background-color: #fff;
overflow: hidden;
.table-header,
.table-row {
display: flex;
justify-content: space-between;
padding: 15rpx 0rpx;
border-bottom: 1rpx solid #eee;
height: 20px;
text {
text-align: center;
font-size: 28rpx;
flex: 1;
}
}
.table-header {
padding: 0rpx;
padding-bottom: 10rpx;
}
}
</style>

View File

@@ -0,0 +1,431 @@
<template>
<view class="preview-container">
<!-- 右上角按钮组 -->
<view class="btn-group">
<!-- 缩小按钮 -->
<!-- <view class="btn zoom-out-btn" @click="zoomOut">
<text class="btn-icon"></text>
</view> -->
<!-- 放大按钮 -->
<!-- <view class="btn zoom-in-btn" @click="zoomIn">
<text class="btn-icon">+</text>
</view> -->
<!-- 下载按钮 -->
<view class="btn download-btn" @click="downloadImage">
<text class="btn-icon"></text>
</view>
</view>
<!-- 图片预览区域使用movable-area和movable-view实现缩放移动 -->
<movable-area class="movable-area" :style="{ width: '100vw', height: '100vh' }">
<movable-view
class="movable-view"
direction="all"
:scale="true"
:scale-min="0.2"
:scale-max="0.5"
:scale-value="scaleValue"
@touchstart="onTouchStart"
@touchend="onTouchEnd"
:x="x"
:y="y"
:animation="true"
:animation-duration="300"
:style="{
width: rotatedWidth + 'px',
height: rotatedHeight + 'px',
}"
>
<view
class="image-wrapper"
:style="{
width: imgWidth + 'px',
height: imgHeight + 'px',
transform: 'rotate(90deg)',
transformOrigin: 'center center',
}"
>
<image
:src="imageUrl"
class="preview-img"
mode="aspectFill"
:style="{
width: imgWidth + 'px',
height: imgHeight + 'px',
}"
@load="onImageLoad"
></image>
</view>
</movable-view>
</movable-area>
</view>
</template>
<script>
export default {
onLoad(options) {
this.imageUrl = decodeURIComponent(options.url) // 接收传递的图片URL需要解码
},
data() {
return {
imageUrl: '',
// 缩放相关 - 默认0.5
scaleValue: 0.2,
x: 0,
y: 0,
// 图片原始尺寸
imgWidth: 0,
imgHeight: 0,
// 旋转后的尺寸(交换宽高)
rotatedWidth: 0,
rotatedHeight: 0,
// 提示显示控制
showScaleTip: false,
tipTimer: null,
// 屏幕尺寸
windowWidth: 0,
windowHeight: 0,
// 缩放步长
zoomStep: 0.1,
// 动画控制
isTouching: false,
animationTimer: null
}
},
mounted() {
// 获取屏幕尺寸
const systemInfo = uni.getSystemInfoSync()
this.windowWidth = systemInfo.windowWidth
this.windowHeight = systemInfo.windowHeight
},
methods: {
// 图片加载完成后获取尺寸
onImageLoad(e) {
const { width, height } = e.detail
// 保存原始尺寸
this.imgWidth = width
this.imgHeight = height
// 旋转90度后宽度和高度互换
this.rotatedWidth = height // 旋转后宽度 = 原高度
this.rotatedHeight = width // 旋转后高度 = 原宽度
// 计算初始位置居中考虑0.5缩放)
this.resetPosition()
},
// 重置位置到中心(考虑当前缩放比例)
resetPosition() {
// 计算居中的偏移量,考虑缩放比例
const displayWidth = this.rotatedWidth * this.scaleValue
const displayHeight = this.rotatedHeight * this.scaleValue
this.x = (this.windowWidth - displayWidth) / 2
this.y = (this.windowHeight - displayHeight) / 2
},
// 触摸开始
onTouchStart() {
this.isTouching = true
},
// 触摸结束
onTouchEnd() {
this.isTouching = false
},
// 缩放事件处理
onScale(e) {
this.scaleValue = e.detail.scale
// 显示缩放提示
this.showScaleTip = true
if (this.tipTimer) {
clearTimeout(this.tipTimer)
}
this.tipTimer = setTimeout(() => {
this.showScaleTip = false
}, 1500)
},
// 放大
zoomIn() {
// 计算新的缩放值,不超过最大值
const newScale = Math.min(this.scaleValue + this.zoomStep, 0.5)
this.setScaleWithAnimation(newScale)
},
// 缩小
zoomOut() {
// 计算新的缩放值,不低于最小值
const newScale = Math.max(this.scaleValue - this.zoomStep, 0.2)
this.setScaleWithAnimation(newScale)
},
// 带动画的设置缩放值
setScaleWithAnimation(newScale) {
// 保存旧的缩放值用于动画
const oldScale = this.scaleValue
// 计算缩放中心点(屏幕中心)
const centerX = this.windowWidth / 2
const centerY = this.windowHeight / 2
// 计算当前图片中心点
const oldDisplayWidth = this.rotatedWidth * oldScale
const oldDisplayHeight = this.rotatedHeight * oldScale
const oldCenterX = this.x + oldDisplayWidth / 2
const oldCenterY = this.y + oldDisplayHeight / 2
// 计算偏移量,使缩放后图片中心保持在屏幕中心
const newDisplayWidth = this.rotatedWidth * newScale
const newDisplayHeight = this.rotatedHeight * newScale
const newX = centerX - newDisplayWidth / 2
const newY = centerY - newDisplayHeight / 2
// 更新缩放值和位置
this.scaleValue = newScale
this.x = newX
this.y = newY
// 显示缩放提示
this.showScaleTip = true
if (this.tipTimer) {
clearTimeout(this.tipTimer)
}
this.tipTimer = setTimeout(() => {
this.showScaleTip = false
}, 1500)
console.log('缩放:', {oldScale, newScale, x: this.x, y: this.y})
},
// 下载图片
downloadImage() {
uni.showLoading({
title: '下载中,请稍等...',
mask: true,
})
// 先获取图片信息(如果是网络图片需要先下载)
uni.downloadFile({
url: this.imageUrl,
success: (res) => {
if (res.statusCode === 200) {
// 保存图片到相册
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
uni.hideLoading()
uni.showToast({
title: '保存成功',
icon: 'success',
})
},
fail: (err) => {
uni.hideLoading()
console.error('保存失败', err)
// 处理用户拒绝权限的情况
if (err.errMsg.includes('auth deny')) {
uni.showModal({
title: '提示',
content: '需要您授权保存图片到相册',
success: (res) => {
if (res.confirm) {
uni.openSetting({
success: (settingRes) => {
console.log('打开设置页面', settingRes)
},
})
}
},
})
} else {
uni.showToast({
title: '保存失败',
icon: 'none',
})
}
},
})
} else {
uni.hideLoading()
uni.showToast({
title: '下载失败',
icon: 'none',
})
}
},
fail: (err) => {
uni.hideLoading()
console.error('下载失败', err)
uni.showToast({
title: '下载失败',
icon: 'none',
})
},
})
},
},
// 页面返回前清理定时器
onUnload() {
if (this.tipTimer) {
clearTimeout(this.tipTimer)
}
if (this.animationTimer) {
cancelAnimationFrame(this.animationTimer)
}
},
}
</script>
<style lang="scss" scoped>
.preview-container {
position: relative;
width: 100vw;
height: 100vh;
background: #000;
overflow: hidden;
}
.movable-area {
width: 100vw;
height: 100vh;
background: #000;
}
.movable-view {
display: flex;
align-items: center;
justify-content: center;
// 添加硬件加速
transform: translateZ(0);
will-change: transform;
}
.image-wrapper {
display: flex;
align-items: center;
justify-content: center;
// 添加硬件加速
transform: translateZ(0) rotate(90deg);
will-change: transform;
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
transition: transform 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
}
.preview-img {
display: block;
// 添加硬件加速
transform: translateZ(0);
will-change: transform;
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
}
// 按钮组
.btn-group {
position: fixed;
top: 30rpx;
right: 30rpx;
display: flex;
flex-direction: row;
gap: 20rpx;
z-index: 1000;
}
// 通用按钮样式
.btn {
width: 70rpx;
height: 70rpx;
background: rgba(0, 0, 0, 0.5);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
// 按钮不参与动画
transform: translateZ(0);
transition: background-color 0.2s ease;
&:active {
background: rgba(0, 0, 0, 0.8);
transform: scale(0.95);
}
.btn-icon {
color: #fff;
font-size: 40rpx;
line-height: 1;
font-weight: bold;
}
}
// 缩小按钮
.zoom-out-btn {
.btn-icon {
font-size: 50rpx;
}
}
// 放大按钮
.zoom-in-btn {
.btn-icon {
font-size: 40rpx;
}
}
// 下载按钮
.download-btn {
.btn-icon {
font-size: 35rpx;
}
}
// 缩放提示
.scale-tip {
position: fixed;
bottom: 100rpx;
left: 50%;
transform: translateX(-50%) translateZ(0);
background: rgba(0, 0, 0, 0.6);
color: #fff;
padding: 10rpx 30rpx;
border-radius: 40rpx;
font-size: 28rpx;
z-index: 1000;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
animation: fadeInOut 1.5s ease;
// 提示不参与动画
will-change: opacity;
}
@keyframes fadeInOut {
0% {
opacity: 0;
}
15% {
opacity: 1;
}
85% {
opacity: 1;
}
100% {
opacity: 0;
}
}
</style>

View File

@@ -0,0 +1,170 @@
<template>
<Cn-page :loading="loading">
<view class="detail" slot="body">
<view class="detail-content" style="font-size: 32rpx">
<!-- <view class="detail-content-title mb20">发生时间</view> -->
<view>{{ detail.statisticsDate }}</view>
</view>
<view class="detail-content">
<view class="detail-content-title mb20">基础信息</view>
<view class="mb5"> 工程{{ detail.engineeringName }} </view>
<view class="mb5"> 项目{{ detail.projectName }} </view>
<view class="mb5"> 设备{{ detail.devName }} </view>
<view class="mb5"> 监测点{{ detail.lineName }}</view>
<view class="mb5" style="display: flex">
越限详情
<view style="flex: 1" class="details">{{ detail.overLimitDesc }}</view>
</view>
</view>
<view class="detail-content">
<view class="detail-content-title mb20">指标越限详情<text class="prompt">仅显示最严重的10组数据</text></view>
<uni-collapse accordion v-model="collapseValue">
<uni-collapse-item :title="item.targetName" v-for="item in list">
<view class="data-table">
<view class="table-header">
<text>时间</text>
<text>数据类型</text>
<text v-if="!item.harmDetailList[0].hasT">A相</text>
<text v-if="!item.harmDetailList[0].hasT">B相</text>
<text v-if="!item.harmDetailList[0].hasT">C相</text>
<text v-if="item.harmDetailList[0].hasT">总相</text>
<text>限值</text>
</view>
<view class="table-row" v-for="value in item.harmDetailList">
<text>{{ value.statisticsTime }}</text>
<text>{{ value.valueType || '/' }}</text>
<text v-if="!value.hasT">{{ value.dataA }}</text>
<text v-if="!value.hasT">{{ value.dataB }}</text>
<text v-if="!value.hasT">{{ value.dataC }}</text>
<text v-if="value.hasT">{{ value.dataT }}</text>
<text>{{ value.overLimitData }}</text>
</view>
</view>
</uni-collapse-item>
</uni-collapse>
</view>
</view>
</Cn-page>
</template>
<script>
import { updateStatus, queryHarmonicDetail } from '@/common/api/message'
export default {
data() {
return {
loading: true,
detail: {},
list: [],
collapseValue: '0',
}
},
onLoad(options) {
// console.log(options.detail)
this.detail = JSON.parse(decodeURIComponent(options.detail).replace(/百分比/g, '%'))
this.init()
if (this.detail.isRead != 1) {
updateStatus({
eventIds: [this.detail.eventId],
})
}
},
methods: {
init() {
queryHarmonicDetail({
lineId: this.detail.lineId,
time: this.detail.statisticsDate,
})
.then((res) => {
this.list = res.data
this.loading = false
})
.catch(() => {
this.loading = false
})
// }
},
},
}
</script>
<style lang="scss">
.detail {
padding: 20rpx 0;
.detail-content {
padding: 20rpx;
background: #fff;
margin-bottom: 20rpx;
font-size: 28rpx;
.detail-content-title {
font-size: 30rpx;
color: #111;
font-weight: 700;
}
}
.limit {
display: flex;
align-items: center;
justify-content: end;
width: 450rpx;
margin-left: auto;
}
.prompt {
font-size: 24rpx;
color: #111;
font-weight: 500;
}
}
.data-table {
margin-top: 20rpx;
background-color: #fff;
overflow: hidden;
color: #666;
.table-header,
.table-row {
display: flex;
justify-content: space-between;
padding: 15rpx 0rpx;
height: 20px;
border-bottom: 1rpx solid #eee;
text {
width: 100rpx;
text-align: center;
font-size: 28rpx;
// color: #333;
&:nth-child(1) {
flex: 1;
}
&:nth-child(2) {
flex: 1;
}
}
}
.table-header {
padding: 0rpx;
padding-bottom: 10rpx;
}
}
/deep/ .uni-collapse-item__title-text {
font-weight: 700;
span {
font-size: 28rpx;
}
}
.details {
max-height: 70px;
overflow-y: auto;
}
</style>

View File

@@ -0,0 +1,220 @@
<template>
<Cn-page :loading="loading">
<view class="detail" slot="body">
<view class="detail-content" style="font-size: 32rpx">
<view>{{ detail.startTime }}</view>
</view>
<view class="detail-content">
<view class="detail-content-title mb20">基础信息</view>
<view class="mb5"> 工程{{ detail.engineeringName }} </view>
<view class="mb5"> 项目{{ detail.projectName }} </view>
<view class="mb5"> 设备{{ detail.equipmentName }}</view>
<view class="mb5"> 监测点{{ detail.lineName }}</view>
<view class="mb5"> 暂态类型{{ detail.showName }}</view>
<view class="mb5" v-if="detail.evtParamTm"> 持续时间{{ detail.evtParamTm }}s</view>
<view class="mb5" v-if="detail.evtParamVVaDepth"> 幅值{{ detail.evtParamVVaDepth }}%</view>
<view class="mb5" v-if="detail.evtParamPhase"> 相别{{ detail.evtParamPhase }}</view>
<view class="mb5" v-if="detail.landPoint"> 落点区域{{ detail.landPoint }}</view>
</view>
<view class="detail-tabs">
<uni-segmented-control :current="detailTab" active-color="#376cf3" :values="['波形图', 'ITIC', 'F47']"
@clickItem="onDetailTabChange" />
</view>
<view v-if="detailTab == 0">
<view class="detail-content">
<view class="detail-content-title mb20">瞬时波形图</view>
<!-- <image style="width: 100%" :src="detail.instantPics" mode="widthFix" v-if="detail.instantPics"
@click="previewImage(detail.instantPics)" />
<text v-else>暂无</text> -->
<view v-if="listWaveData.length > 0">
<waveform v-for="(value, ind) in listWaveData" :index="ind" :unit="unit" :data="value"
style="height: 150px;" />
</view>
<text v-else>暂无</text>
</view>
<view class="detail-content">
<view class="detail-content-title mb20">RMS波形图</view>
<!-- <image style="width: 100%" :src="detail.rmsPics" mode="widthFix" v-if="detail.rmsPics"
@click="previewImage(detail.rmsPics)" />
<text v-else>暂无</text> -->
<view v-if="listRmsData.length > 0">
<waveform v-for="(value, ind) in listRmsData" :index="ind" :unit="unit" :data="value"
style="height: 150px;" />
</view>
<text v-else>暂无</text>
</view>
</view>
<view v-if="detailTab == 1" class="chart-wrapper">
<ITIC :store="eventStore" style="height: calc(100vh - 360px);" />
</view>
<view v-if="detailTab == 2" class="chart-wrapper">
<F47 :store="eventStore" style="height: calc(100vh - 360px);" />
</view>
</view>
</Cn-page>
</template>
<script>
import { updateStatus } from '@/common/api/message'
import ITIC from './ITIC.vue'
import F47 from './F47.vue'
import waveform from './waveform.vue'
import { analyseWave } from '@/common/api/harmonic.js';
export default {
components: { ITIC, F47, waveform },
data() {
return {
loading: true,
detail: {},
detailTab: 0,
listWaveData: [],
listRmsData: [],
unit: [],
list: {},
}
},
computed: {
eventStore() {
const hasData = this.detail && (this.detail.id || this.detail.equipmentId)
if (!hasData) {
return { data: [], status: 'noMore' }
}
const item = {
...this.detail,
evtParamTm: this.detail.evtParamTm || '0s',
evtParamVVaDepth: this.detail.evtParamVVaDepth || '0%',
}
return {
data: [item],
status: 'noMore',
}
},
},
onLoad(options) {
console.log("🚀 ~ options:", options)
this.detail = JSON.parse(decodeURIComponent(options.detail).replace(/百分比/g, '%'))
this.detail.rmsPics && (this.detail.rmsPics = this.$config.static + this.detail.rmsPics)
this.detail.instantPics && (this.detail.instantPics = this.$config.static + this.detail.instantPics)
this.loading = false
if (this.detail.status != 1) {
updateStatus({
eventIds: [this.detail.id],
})
}
analyseWave({
eventId: this.detail.id,
isApp: true
}).then(res => {
this.list = res.data
this.uni = []
// 数据
this.listWaveData = this.bindChartClickEvent(this.list.listWaveData)
this.listRmsData = this.bindChartClickEvent(this.list.listRmsData)
// 单位
this.unit = this.list.waveTitle.slice(1).reduce((acc, _, i, arr) => {
if (i % 3 === 0) {
const group = arr.slice(i, i + 3);
const type = group[0]?.startsWith('U') ? 'kV' :
group[0]?.startsWith('I') ? 'A' : '';
acc.push(type);
}
return acc;
}, []);
})
},
methods: {
onDetailTabChange(e) {
this.detailTab = e.currentIndex
},
previewImage(url) {
uni.navigateTo({
url: `/pages/message1/comp/preview?url=${encodeURIComponent(url)}`,
})
},
bindChartClickEvent(data) {
let unit = this.list.waveTitle.slice(1).reduce((acc, _, i, arr) => {
const group = arr.slice(i, i + 3);
const type = group[0]?.startsWith('U') ? 'kV' :
group[0]?.startsWith('I') ? 'A' : '';
acc.push(type);
return acc;
}, []);
const result = [];
// 从第2列开始遍历索引1每3个一列分组
for (let i = 1; i < data[0].length; i += 3) {
const group = {
A: data.map(row => [row[0], this.calculate(row[i], unit[i])]), // 每组第1个 → A
B: data.map(row => [row[0], this.calculate(row[i + 1], unit[i])]), // 每组第2个 → B
C: data.map(row => [row[0], this.calculate(row[i + 2], unit[i])]), // 每组第3个 → C
};
result.push(group);
}
return result;
},
calculate(num, key) {
if (num === null) return null
let nums = ''
switch (key) {
case 'kV':
nums = num * Number(this.list.pt) / 1000
break
case 'A':
nums = num * Number(this.list.ct)
break
}
return nums
}
},
}
</script>
<style lang="scss">
.detail {
padding: 20rpx 0;
.detail-content {
padding: 20rpx;
background: #fff;
margin-bottom: 20rpx;
font-size: 28rpx;
.detail-content-title {
font-size: 30rpx;
color: #111;
font-weight: 700;
}
}
.detail-tabs {
padding: 0 20rpx;
margin-bottom: 20rpx;
}
.chart-container {
min-height: 600rpx;
}
.chart-wrapper {
background: #fff;
margin-bottom: 20rpx;
padding: 20rpx;
}
}
.segmented-control {
flex: 1;
margin-right: 24rpx;
height: 60rpx;
}
</style>

View File

@@ -0,0 +1,237 @@
<template>
<!-- ITIC -->
<view>
<l-echart ref="echartRef" @finished="initChart"></l-echart>
</view>
</template>
<script>
const echarts = require('../../../uni_modules/lime-echart/static/echarts.min')
export default {
components: {},
props: {
data: {
type: [Object],
},
index: {
type: [Number],
},
unit: {
type: [Array],
}
},
data() {
return {
option: {
backgroundColor: '#fff',
grid: {
left: '0px',
right: '10rpx',
bottom: '0rpx',
top: '25px',
containLabel: true,
},
legend: {
right: '10px',
top: '0px',
icon: 'rect',
itemWidth: 20,
itemHeight: 2,
itemGap: 8,
itemStyle: {
borderWidth: 0,
},
textStyle: {
fontSize: 10,
},
padding: [5, 5, 5, 10],
},
xAxis: {
type: 'category',
boundaryGap: false,
splitLine: { show: false },
axisLine: { show: true },
axisTick: { show: false },
axisLabel: {
fontSize: 10,
interval: 0,
},
},
yAxis: {
type: 'value',
name: '',
nameLocation: 'end',
nameGap: 10,
minInterval: 1,
nameTextStyle: {
fontSize: 12,
padding: [28, 10, 0, 0],
},
axisLine: {
show: true,
},
axisTick: {
show: true,
},
},
series: [
{
name: 'A相',
type: 'line',
data: [
],
showSymbol: false,
smooth: true,
tooltips: {
show: false,
},
color: '#DAA520',
},
{
name: 'B相',
type: 'line',
data: [
],
showSymbol: false,
smooth: true,
tooltips: {
show: false,
},
color: '#2E8B57',
},
{
name: 'C相',
type: 'line',
data: [
],
showSymbol: false,
smooth: true,
tooltips: {
show: false,
},
color: '#A52a2a',
},
],
},
status: 'loading',
echartRef: null,
pointI: [],
xLabelShowIndices: new Set(),
}
},
mounted() {
// this.initChart()
// console.log('🚀 ~ props.data:', this.props.data)
},
methods: {
init() { },
async initChart() {
if (!this.$refs.echartRef) return
try {
this.echartRef = await this.$refs.echartRef.init(echarts)
this.setOption()
this.echartRef.setOption(this.option, true)
} catch (error) {
console.error('图表初始化失败:', error)
}
},
formatXAxisLabel(val, index) {
return this.xLabelShowIndices.has(index) ? String(val) : ''
},
getYAxisRange() {
const values = []
;['A', 'B', 'C'].forEach((key) => {
; (this.data[key] || []).forEach((p) => {
const v = p[1]
if (v !== null && v !== undefined && !Number.isNaN(Number(v))) {
values.push(Number(v))
}
})
})
if (!values.length) return {}
const dataMax = Math.max(...values)
const dataMin = Math.min(...values)
let min = 0
let max = 0
if (dataMin > 0) {
min = Math.floor(dataMin / 1.3)
} else {
min = Math.floor(dataMin * 1.3)
}
if (dataMax > 0) {
max = Math.ceil(dataMax * 1.3)
} else {
max = Math.ceil(dataMax / 1.3)
}
if (min === max) {
min -= 1
max += 1
}
return { min, max }
},
buildXLabelShowIndices(xLabels) {
const len = xLabels.length
if (len === 0) return new Set()
const showIndices = new Set([0, len - 1])
const zeroIdx = xLabels.findIndex((x) => Number(x) === 0)
if (zeroIdx >= 0) {
showIndices.add(zeroIdx)
} else if (len > 2) {
showIndices.add(Math.floor((len - 1) / 2))
}
return showIndices
},
setOption() {
if (!this.data) return
if (this.index == 0) {
this.option.legend.show = true
} else {
this.option.legend.show = false
}
this.option.yAxis.name = this.unit[this.index]
const points = this.data.A || []
const xLabels = points.map((p) => p[0])
this.xLabelShowIndices = this.buildXLabelShowIndices(xLabels)
this.option.xAxis.data = xLabels
this.option.xAxis.axisLabel.formatter = (val, index) => this.formatXAxisLabel(val, index)
this.option.series[0].data = points.map((p) => p[1])
this.option.series[1].data = (this.data.B || []).map((p) => p[1])
this.option.series[2].data = (this.data.C || []).map((p) => p[1])
const { min, max } = this.getYAxisRange()
this.option.yAxis.min = min
this.option.yAxis.max = max
},
},
computed: {},
watch: {
},
}
</script>
<style lang="scss" scoped></style>

198
pages/message1/index.scss Normal file
View File

@@ -0,0 +1,198 @@
/* 整体容器:横向排列,间距均匀 */
.statistics {
display: flex;
gap: 20rpx; /* 盒子之间的间距 */
/* 通用盒子样式 */
.box {
flex: 1; /* 四个盒子等分宽度 */
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 130rpx;
background-color: #ffffff;
border-radius: 16rpx;
}
/* 第一个盒子的特殊样式(蓝色背景) */
.box:first-child {
flex: 1.7;
}
.boxClick1 {
background-color: $uni-theme-color;
color: #ffffff;
}
/* 数字样式 */
.num {
font-size: 38rpx;
font-weight: 600;
line-height: 1.2;
margin-bottom: 8rpx;
}
/* 标签文字样式 */
.label {
font-size: 24rpx;
color: inherit; /* 继承父元素颜色,适配蓝色背景 */
}
}
/* 列表容器 */
.event-list {
background-color: #f5f7fa;
box-sizing: border-box;
/* 通用项样式 */
/deep/ .uni-card:first-of-type {
margin-top: 0 !important;
}
/deep/ .uni-card {
padding: 0 !important;
}
/* 头部:图标 + 信息 + 操作 */
.event-header {
display: flex;
align-items: center;
margin-bottom: 10rpx;
}
/* 图标区域(按类型区分背景色) */
.event-icon {
position: relative;
width: 110rpx;
height: 110rpx;
border-radius: 12rpx;
display: flex;
justify-content: center;
align-items: center;
margin-right: 20rpx;
}
.badge1 {
position: absolute;
top: -10rpx;
right: -10rpx;
width: 20rpx;
height: 20rpx;
background-color: #ff3b30; /* 红色徽章 */
border-radius: 20rpx;
}
/* 电压暂降 - 蓝色系 */
.sag .event-icon {
background-color: #2563eb20;
}
/* 电压暂升 - 橙色系 */
.swell .event-icon {
background-color: #e6a23c20;
}
.interrupt .event-icon {
background-color: #00000020;
}
.transient .event-icon {
background-color: #8b5cf620;
}
.unknown .event-icon {
background-color: #6b728020;
}
.event-icon image {
width: 48rpx;
height: 48rpx;
}
/* 信息区域 */
.event-info {
flex: 1;
}
.event-title {
display: flex;
align-items: center;
margin-bottom: 5rpx;
flex-wrap: wrap; /* 适配小屏,防止文字溢出 */
}
.event-id {
font-size: 30rpx;
font-weight: 700;
color: #333333;
margin-right: 16rpx;
}
/* 标签样式(按类型区分) */
.event-tag {
font-size: 20rpx;
padding: 0rpx 10rpx;
border-radius: 8rpx;
color: #ffffff;
height: 34rpx;
line-height: 38rpx;
}
.sag-tag {
background-color: #2563eb20;
color: #2563eb;
}
.swell-tag {
background-color: #e6a23c20;
color: #e6a23c;
}
.interrupt-tag {
background-color: #6b728020;
color: #6b7280;
}
.transient-tag {
background-color: #8b5cf620;
color: #8b5cf6;
}
.unknown-tag {
background-color: #6b728020;
color: #6b7280;
}
/* 描述文本 */
.event-desc {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.event-desc text {
font-size: 24rpx;
color: #666666;
line-height: 1.2;
}
/* 操作按钮 */
.event-action {
display: flex;
justify-content: center;
align-items: center;
color: #999999;
font-size: 40rpx;
/* 点击反馈 */
touch-action: manipulation;
}
.event-action:active {
color: #376cf3;
transform: scale(0.95);
}
/* 详情文本 */
.event-detail {
font-size: 26rpx;
color: #666666;
line-height: 1.5;
padding-top: 10rpx;
border-top: 1rpx solid #f0f0f0;
word-wrap: break-word; /* 自动换行,防止长文本溢出 */
}
}
.smallLabel {
padding: 0 20rpx 20rpx 20rpx;
display: flex;
align-items: center;
justify-content: flex-end;
.segmented-control {
flex: 1;
margin-right: 20rpx;
height: 58rpx;
}
.uni-input {
font-size: 24rpx;
color: #2563eb;
margin-right: 10rpx;
}
}

159
pages/message1/run.vue Normal file
View File

@@ -0,0 +1,159 @@
<template>
<view style="position: relative">
<!-- 运行事件 -->
<!-- 卡片 -->
<scroll-view scroll-y="true" @refresherrefresh="refresherrefresh" @scrolltolower="scrolltolower"
:refresher-triggered="triggered" refresher-enabled="true" class="event-list"
:style="{ height: 'calc(100vh - ' + (navHeight + 10) + 'px)', overflow: 'auto' }">
<!-- 循环渲染事件项 -->
<uni-card class="event-item " :class="item.type" v-for="(item, index) in store.data" :key="index"
@click="jump(item)">
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view class="event-icon" :class="item.devType == 'Direct_Connected_Device' ? 'zl-bgc' : 'jc-bgc'">
<!-- 动态图标根据类型切换 -->
<!-- <uni-icons custom-prefix="iconfont" type="icon-shebei3" size="35" color="#376cf3"></uni-icons> -->
<Cn-icon-transient :name="item.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备'" />
<view class="badge1" v-if="item.status == 0"> </view>
</view>
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.equipmentName }}</text>
<text class="event-tag"
:class="item.devType == 'Direct_Connected_Device' ? 'zl-tag' : 'jc-tag'">{{ item.devType
== 'Direct_Connected_Device' ? '治理设备' : '监测设备' }}</text>
</view>
<view class="event-desc">
<text>工程{{ item.engineeringName }}</text>
<text>项目{{ item.projectName }}</text>
<text>事件时间{{ item.startTime2 }}</text>
</view>
</view>
</view>
<!-- 详情区域 -->
<view class="event-detail">
<text> {{ item.showName }} </text>
</view>
</uni-card>
<uni-load-more v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty>
</scroll-view>
</view>
</template>
<script>
import list from '@/common/js/list'
import { updateStatus } from '@/common/api/message'
export default {
components: {},
props: {
navHeight: {
type: Number,
default: 0,
},
selectValue: {
type: Object,
// default: () => {},
},
},
mixins: [list],
data() {
return {
triggered: true,
}
},
mounted() { },
methods: {
// 查詢
init() {
this.store = this.DataSource('/cs-harmonic-boot/eventUser/queryEventpage')
this.store.params.type = 2
// this.store.params.pageSize = 10000
this.store.params.sortField = this.sort
this.store.params.engineeringid = this.selectValue.engineeringId
this.store.params.projectId = this.selectValue.projectId
this.store.params.deviceId = this.selectValue.deviceId
this.store.params.lineId = this.selectValue.lineId
this.store.params.startTime = this.$util.getMonthFirstAndLastDay(this.selectValue.date).firstDay
this.store.params.endTime = this.$util.getMonthFirstAndLastDay(this.selectValue.date).lastDay
this.store.loadedCallback = () => {
this.loading = false
}
this.store.reload()
},
jump(item) {
if (item.status != '1') {
item.status = '1'
updateStatus({
eventIds: [item.id],
})
this.$emit('getDevCount')
}
},
// 下拉
refresherrefresh() {
this.triggered = true
uni.startPullDownRefresh()
setTimeout(() => {
this.triggered = false
}, 500)
},
// 上拉
scrolltolower() {
if (this.store.status != 'noMore') {
this.store.next && this.store.next()
}
},
},
computed: {},
watch: {
selectValue: {
handler(val, oldVal) {
if (Object.keys(val).length === 0) return
this.init()
},
deep: true,
immediate: true,
},
},
}
</script>
<style lang="scss" scoped>
@import './index.scss';
/* 列表容器 */
.event-list {
margin-top: 20rpx;
/* 头部:图标 + 信息 + 操作 */
/* 图标区域(按类型区分背景色) */
.zl-bgc {
background-color: #376cf320;
}
.jc-bgc {
background-color: #376cf320;
}
.zl-tag {
background-color: #007aff20;
color: #007aff;
}
.jc-tag {
background-color: #007aff20;
color: #007aff;
}
}
/deep/ .uni-scroll-view-refresher {
display: none;
}
</style>

View File

@@ -0,0 +1,391 @@
<template>
<view style="position: relative">
<!-- 稳态 -->
<view class="transientBox">
<view class="statistics pd20">
<view
class="box boxClick"
:class="{ boxClick1: item.label == filterValue }"
v-for="item in list"
@click="
filterValue = item.label
init()
"
>
<text class="num">{{ item.value }}</text>
<text class="label">{{ item.label }}</text>
</view>
</view>
</view>
<!-- 越限数量 -->
<scroll-view
v-if="filterValue == '越限数量'"
scroll-y="true"
@refresherrefresh="refresherrefresh"
@scrolltolower="scrolltolower"
:refresher-triggered="triggered"
refresher-enabled="true"
class="event-list"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }"
>
<!-- 循环渲染事件项 -->
<uni-card
class="event-item boxClick"
:class="item.type"
v-for="(item, index) in store.data"
:key="index"
@click="jump(item)"
>
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view class="event-icon">
<!-- 动态图标根据类型切换 -->
<!-- <uni-icons
custom-prefix="iconfont"
type="icon-kouanjiancedian"
size="40"
color="#E6A23C"
></uni-icons> -->
<Cn-icon-transient :name="`稳态越限`" />
<view class="badge1" v-if="item.isRead == 0"></view>
</view>
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.lineName }}</text>
</view>
<view class="event-desc">
<text>工程{{ item.engineeringName }}</text>
<text>项目{{ item.projectName }}</text>
<text>设备{{ item.devName }}</text>
<!-- <text>统计日期{{ item.statisticsDate }}</text> -->
</view>
</view>
<view class="event-action">
<uni-icons type="search" size="25" color="#376cf3"></uni-icons>
</view>
</view>
<!-- 详情区域 -->
<view class="event-detail textBox" @touchmove.stop>
<text>{{ item.statisticsDate }}发生 {{ item.overLimitDesc }}</text>
</view>
</uni-card>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty>
</scroll-view>
<!-- 越限天数 -->
<view v-if="filterValue == '越限天数'">
<uni-calendar
:insert="true"
:lunar="false"
:date="startData"
:selected="selected"
:start-date="startData"
:end-date="endData"
/>
</view>
<!-- 越限测点数 -->
<scroll-view
v-if="filterValue == '越限测点数'"
scroll-y="true"
@refresherrefresh="refresherrefresh"
@scrolltolower="scrolltolower"
:refresher-triggered="triggered"
refresher-enabled="true"
class="event-list"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }"
>
<!-- 循环渲染事件项 -->
<uni-card class="event-item" :class="item.type" v-for="(item, index) in store.data" :key="index">
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view class="event-icon">
<!-- 动态图标根据类型切换 -->
<!-- <uni-icons
custom-prefix="iconfont"
type="icon-kouanjiancedian"
size="40"
color="#E6A23C"
></uni-icons> -->
<Cn-icon-transient :name="`稳态越限`" />
</view>
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.lineName }}</text>
</view>
<view class="event-desc">
<text>工程{{ item.engineeringName }}</text>
<text>项目{{ item.projectName }}</text>
<text>设备{{ item.devName }}</text>
<!-- <text>统计日期{{ item.statisticsDate }}</text> -->
</view>
</view>
</view>
<!-- 详情区域 -->
<view class="event-detail">
<uni-calendar
:insert="true"
:lunar="false"
:date="startData"
:selected="item.timeList.map((date) => ({ date, info: '' }))"
:start-date="startData"
:end-date="endData"
/>
</view>
</uni-card>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty>
</scroll-view>
</view>
</template>
<script>
import list from '@/common/js/list'
import { queryAppHarmonicCounts, queryAppHarmonicLine } from '../../common/api/harmonic.js'
export default {
components: {},
props: {
navHeight: {
type: Number,
default: 0,
},
selectValue: {
type: Object,
// default: () => {},
},
},
mixins: [list],
data() {
return {
height: 0,
filterValue: '越限数量',
list: [
{ value: 0, label: '越限数量' },
{ value: 0, label: '越限天数' },
{ value: 0, label: '越限测点数' },
],
startData: '',
endData: '',
selected: [
// { date: '2026-04-10', info: '' },
// { date: '2026-04-11', info: '' },
// { date: '2026-04-12', info: '' },
],
triggered: true,
status: 'noMore', //more加载前 loading加载中 noMore加载后
}
},
mounted() {
uni.createSelectorQuery()
.select('.transientBox')
.boundingClientRect((rect) => {
//
// #ifdef H5
this.height = rect.height
// #endif
// #ifdef APP-PLUS
this.height = rect.height
// #endif
})
.exec()
},
methods: {
// "devId": "",
// "engineerId": "",
// "lineId": "",
// "projectId": "",
// "time": ""
// 查詢
init() {
if (this.filterValue == '越限测点数') {
this.store = this.DataSource('/cs-harmonic-boot/csHarmonic/queryAppHarmonicLine')
} else {
this.store = this.DataSource('/cs-harmonic-boot/csHarmonic/queryHarmonicList')
}
// this.store.params.pageSize = 10000
this.store.params.engineerId = this.selectValue.engineeringId
this.store.params.projectId = this.selectValue.projectId
this.store.params.devId = this.selectValue.deviceId
this.store.params.lineId = this.selectValue.lineId
this.store.params.time = this.selectValue.date
this.store.loadedCallback = () => {
this.loading = false
this.startData = this.$util.getMonthFirstAndLastDay(this.selectValue.date).firstDay
this.endData = this.$util.getMonthFirstAndLastDay(this.selectValue.date).lastDay
// 查询越限日期
queryAppHarmonicCounts(this.store.params).then((res) => {
this.list[0].value = res.data.harmonicNums
this.list[1].value = res.data.overDays
this.list[2].value = res.data.overLineNums
this.selected = res.data.overDaysList.map((date) => ({ date, info: '' }))
})
}
this.store.reload()
},
jump(item) {
let str = JSON.stringify(item).replace(/%/g, '百分比')
item.isRead = '1'
uni.navigateTo({ url: '/pages/message1/comp/steadyStateDetails?detail=' + encodeURIComponent(str) })
},
// 下拉
refresherrefresh() {
this.triggered = true
uni.startPullDownRefresh()
setTimeout(() => {
this.triggered = false
}, 500)
},
// 上拉
scrolltolower() {
if (this.store.status != 'noMore') {
this.store.next && this.store.next()
}
},
},
computed: {},
watch: {
selectValue: {
handler(val, oldVal) {
if (Object.keys(val).length === 0) return
this.init()
},
deep: true,
immediate: true,
},
},
}
</script>
<style lang="scss" scoped>
@import './index.scss';
.box:first-child {
flex: 1.3 !important;
}
/* 列表容器 */
.event-list {
/* 头部:图标 + 信息 + 操作 */
.event-header {
display: flex;
align-items: center;
margin-bottom: 10rpx;
}
/* 图标区域(按类型区分背景色) */
.event-icon {
background-color: #376cf320;
}
.event-tags {
font-size: 24rpx;
}
}
/deep/ .uni-scroll-view-refresher {
display: none;
}
.textBox {
max-height: 110rpx;
overflow-y: auto;
// overflow: hidden;
/* 下面是溢出显示省略号关键样式 */
// display: -webkit-box;
// -webkit-line-clamp: 3; /* 控制最多显示几行,你可以改 2/3/4 */
// -webkit-box-orient: vertical;
// text-overflow: ellipsis;
// word-break: break-all;
}
/deep/ .uni-calendar-item--checked {
background-color: #ffffff00;
color: #000000e6;
opacity: 1;
}
/deep/ .uni-calendar-item--isDay {
background-color: #ffffff00;
color: #000000e6;
opacity: 1;
.uni-calendar-item__weeks-lunar-text {
background-color: #ffffff00;
color: #000000e6;
opacity: 1;
}
}
/deep/ .uni-calendar-item__weeks-box-text {
z-index: 1;
}
/deep/ .uni-calendar-item--isDay-text {
color: #333 !important; /* 改成你想要的颜色 */
}
/deep/ .uni-calendar-item__weeks-box-circle {
position: absolute;
top: 7px;
right: 6px;
width: 39px;
height: 39px;
border-radius: 50%;
z-index: 0;
background-color: #e6a23c;
}
/* 核心:选中圆圈下的 子元素(日期数字) */
/deep/ .uni-calendar-item__weeks-box-circle + .uni-calendar-item__weeks-box-text {
color: #fff !important; /* 改成你想要的颜色 */
}
/deep/ .uni-calendar__backtoday,
/deep/ .uni-calendar__header-btn-box {
display: none;
}
/deep/ .uni-calendar-item__weeks-lunar-text {
display: none;
}
/deep/ .uni-calendar__header {
pointer-events: none !important;
}
.event-detail {
/deep/ .uni-calendar__header {
display: none !important;
}
/deep/ .uni-calendar__weeks-day {
height: 35px;
}
/deep/ .uni-calendar-item__weeks-box-item {
height: 40px;
}
/deep/ .uni-calendar-item__weeks-box-circle {
position: absolute;
top: 3px;
right: 8px;
width: 35px;
height: 35px;
}
}
</style>

View File

@@ -0,0 +1,276 @@
<template>
<view style="position: relative">
<!-- 暂态 -->
<view class="transientBox">
<view class="statistics pd20">
<view
class="box boxClick"
:class="{ boxClick1: filterValue == index }"
v-for="(item, index) in dataList"
@click="
filterValue = index
init()
"
>
<!-- <text class="num">{{ item.value }}</text> -->
<text class="num">{{ item.value }}</text>
<text class="label">{{ item.label }}</text>
</view>
</view>
<!-- <view class="smallLabel"> </view> -->
</view>
<!-- 卡片 -->
<scroll-view
scroll-y="true"
@refresherrefresh="refresherrefresh"
@scrolltolower="scrolltolower"
:refresher-triggered="triggered"
refresher-enabled="true"
class="event-list"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }"
>
<!-- 循环渲染事件项 -->
<uni-card
class="event-item boxClick"
:class="judgment(item.showName).type"
v-for="(item, index) in store.data || []"
:key="index"
@click="jump(item)"
>
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view class="event-icon">
<!-- 动态图标根据类型切换 -->
<!-- <uni-icons
:custom-prefix="'iconfont'"
:type="judgment(item.showName).icon"
:color="judgment(item.showName).color"
:size="judgment(item.showName).size"
></uni-icons> -->
<Cn-icon-transient :name="item.showName" />
<!-- 0未读 1已读 -->
<view class="badge1" v-if="item.status == 0"> </view>
</view>
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.lineName }}</text>
<text class="event-tag" :class="`${judgment(item.showName).type}-tag`">{{
item.showName
}}</text>
</view>
<view class="event-desc">
<text>工程{{ item.engineeringName }}</text>
<text>项目{{ item.projectName }}</text>
<text>设备{{ item.equipmentName }}</text>
</view>
</view>
<view class="event-action">
<uni-icons type="search" size="25" color="#376cf3"></uni-icons>
</view>
</view>
<!-- 详情区域 -->
<view class="event-detail">
<text>
{{ item.startTime ? '发生时间:' + item.startTime : '' }}
{{
item.evtParamVVaDepth != null && item.evtParamVVaDepth !== ''
? ',幅值:' + item.evtParamVVaDepth + '%'
: ''
}}
{{
item.evtParamTm != null && item.evtParamTm !== ''
? ',持续时间:' + item.evtParamTm + 's'
: ''
}}
{{
item.evtParamPhase != null && item.evtParamPhase !== ''
? ',相别:' + item.evtParamPhase
: ''
}} {{
item.landPoint != null && item.landPoint !== ''
? ',落点区域:' + item.landPoint
: ''
}}
</text>
</view>
</uni-card>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty>
</scroll-view>
</view>
</template>
<script>
import list from '@/common/js/list'
import { queryAppEventCounts } from '../../common/api/harmonic.js'
export default {
props: {
navHeight: {
type: Number,
default: 0,
},
selectValue: {
type: Object,
// default: () => {},
},
sortIndex: {
type: [Number,String],
// default: () => {},
},
},
mixins: [list],
data() {
return {
height: 0,
filterValue: 0,
dataList: [
{ value: 0, label: '暂态数量', key: '' },
{ value: 0, label: '暂降', key: '电压暂降' },
{ value: 0, label: '中断', key: '电压中断' },
{ value: 0, label: '暂升', key: '电压暂升' },
],
status: 'noMore', //more加载前 loading加载中 noMore加载后
sort: 0,
triggered: true,
}
},
methods: {
getHeight() {
uni.createSelectorQuery()
.select('.transientBox')
.boundingClientRect((rect) => {
//
// #ifdef H5
this.height = rect?.height || 0
// #endif
// #ifdef APP-PLUS
this.height = rect?.height || 0
// #endif
})
.exec()
},
// 查詢
init() {
this.store = this.DataSource('/cs-harmonic-boot/eventUser/queryEventpage')
this.store.params.type = 0
// this.store.params.pageSize = 10000
this.store.params.sortField = this.sortIndex
this.store.params.engineeringid = this.selectValue.engineeringId
this.store.params.projectId = this.selectValue.projectId
this.store.params.deviceId = this.selectValue.deviceId
this.store.params.lineId = this.selectValue.lineId
this.store.params.target =
this.filterValue == 0
? []
: this.filterValue == 1
? ['Evt_Sys_DipStr']
: this.filterValue == 2
? ['Evt_Sys_IntrStr']
: ['Evt_Sys_SwlStr']
this.store.params.startTime = this.$util.getMonthFirstAndLastDay(this.selectValue.date).firstDay
this.store.params.endTime = this.$util.getMonthFirstAndLastDay(this.selectValue.date).lastDay
this.store.loadedCallback = () => {
this.getHeight()
this.loading = false
queryAppEventCounts(this.store.params).then((res) => {
this.dataList[0].value = res.data.allNum
this.dataList[1].value = res.data.eventDown
this.dataList[2].value = res.data.eventOff
this.dataList[3].value = res.data.eventUp
})
}
this.store.reload()
},
judgment(val, key) {
switch (val) {
case '电压暂降':
return {
type: 'sag',
icon: 'icon-a-svg4',
color: '#2563eb',
size: '25',
}
case '电压暂升':
return {
type: 'swell',
icon: 'icon-a-svg5',
color: '#e6a23c',
size: '25',
}
case '电压中断':
return {
type: 'interrupt',
icon: 'icon-zhongduan2',
color: '#6b7280',
size: '35',
}
case '瞬态':
return {
type: 'transient',
icon: 'icon-shuntaishijian',
color: '#8b5cf6',
size: '40',
}
case '未知':
return {
type: 'unknown',
icon: 'icon-wenhao',
color: '#6b7280',
size: '45',
}
}
},
// 点击查看详情
jump(item) {
let str = JSON.stringify(item).replace(/%/g, '百分比')
item.status = '1'
uni.navigateTo({ url: '/pages/message1/comp/transientDetails?detail=' + encodeURIComponent(str) })
},
setSort(index) {
console.log(123,this.sortIndex);
// this.sort = index
this.init()
},
// 下拉
refresherrefresh() {
this.triggered = true
uni.startPullDownRefresh()
setTimeout(() => {
this.triggered = false
}, 500)
},
// 上拉
scrolltolower() {
if (this.store.status != 'noMore') {
this.store.next && this.store.next()
}
},
},
computed: {},
watch: {
selectValue: {
handler(val, oldVal) {
if (Object.keys(val).length === 0) return
this.init()
},
deep: true,
immediate: true,
},
},
}
</script>
<style lang="scss" scoped>
@import './index.scss';
/deep/ .uni-scroll-view-refresher {
display: none;
}
</style>

View File

@@ -1,123 +1,123 @@
<template> <template>
<Cn-page :loading="loading"> <Cn-page :loading="loading">
<view class="mine" slot="body"> <view class="mine" slot="body">
<view class="mine-nav" style="margin-top: 20rpx"> <view class="mine-nav" style="margin-top: 20rpx">
<view class="mine-nav-label">功能调试</view> <view class="mine-nav-label">功能调试</view>
<switch <switch
style="transform: scale(0.8)" style="transform: scale(0.8)"
color="#376cf3" color="#376cf3"
@change="change('feature')" @change="change('feature')"
:checked="config.feature" :checked="config.feature"
/> />
</view> </view>
<view class="mine-nav" style="border-bottom: none"> <view class="mine-nav" style="border-bottom: none">
<view class="mine-nav-label">出厂调试</view> <view class="mine-nav-label">出厂调试</view>
<switch <switch
style="transform: scale(0.8)" style="transform: scale(0.8)"
color="#376cf3" color="#376cf3"
@change="change('factory')" @change="change('factory')"
:checked="config.factory" :checked="config.factory"
/> />
</view> </view>
</view> </view>
</Cn-page> </Cn-page>
</template> </template>
<script> <script>
export default { export default {
data() { data() {
return { return {
loading: true, loading: true,
config: { config: {
feature: true, feature: true,
factory: true, factory: true,
}, },
} }
}, },
methods: { methods: {
init() { init() {
let serverConfig = uni.getStorageSync(this.$cacheKey.serverConfig) let serverConfig = uni.getStorageSync(this.$cacheKey.serverConfig)
serverConfig && (this.config = serverConfig) serverConfig && (this.config = serverConfig)
this.loading = false this.loading = false
}, },
change(type) { change(type) {
this.config[type] = !this.config[type] this.config[type] = !this.config[type]
let str = '' let str = ''
switch (type) { switch (type) {
case 'feature': case 'feature':
str = '功能调试' str = '功能调试'
break break
case 'factory': case 'factory':
str = '出厂调试' str = '出厂调试'
break break
} }
this.$util.toast(`${str}首页入口${this.config[type] ? '开启' : '关闭'}`, 2500) this.$util.toast(`${str}首页入口${this.config[type] ? '开启' : '关闭'}`, 2500)
uni.setStorage({ uni.setStorage({
key: this.$cacheKey.serverConfig, key: this.$cacheKey.serverConfig,
data: this.config, data: this.config,
}) })
}, },
}, },
onLoad() { onLoad() {
this.init() this.init()
}, },
} }
</script> </script>
<style lang="scss"> <style lang="scss">
.mine { .mine {
.title { .title {
padding: 0 20rpx; padding: 0 20rpx;
font-size: 28rpx; font-size: 28rpx;
font-weight: 500; font-weight: 500;
} }
.mine-header { .mine-header {
padding: 200rpx 34rpx 34rpx; padding: 200rpx 34rpx 34rpx;
display: flex; display: flex;
align-items: center; align-items: center;
background: $uni-theme-white; background: $uni-theme-white;
margin-bottom: 20rpx; margin-bottom: 20rpx;
box-shadow: 0 4rpx 8rpx #e7e7e74c; box-shadow: 0 4rpx 8rpx #e7e7e74c;
.mine-header-head { .mine-header-head {
margin-right: 30rpx; margin-right: 30rpx;
height: 128rpx; height: 128rpx;
width: 128rpx; width: 128rpx;
border-radius: $uni-theme-radius; border-radius: $uni-theme-radius;
overflow: hidden; overflow: hidden;
} }
.mine-header-name { .mine-header-name {
margin-right: 30rpx; margin-right: 30rpx;
flex: 1; flex: 1;
font-size: 36rpx; font-size: 36rpx;
color: #111; color: #111;
font-weight: 700; font-weight: 700;
} }
} }
.mine-nav { .mine-nav {
padding: 34rpx; padding: 34rpx;
display: flex; display: flex;
align-items: center; align-items: center;
background: $uni-theme-white; background: $uni-theme-white;
border-bottom: 1rpx solid #e8e8e8; border-bottom: 1rpx solid #e8e8e8;
&-icon { &-icon {
margin-right: 30rpx; margin-right: 30rpx;
height: 44rpx; height: 44rpx;
width: 44rpx; width: 44rpx;
border-radius: $uni-theme-radius; border-radius: $uni-theme-radius;
overflow: hidden; overflow: hidden;
} }
&-label { &-label {
margin-right: 30rpx; margin-right: 30rpx;
flex: 1; flex: 1;
font-size: 28rpx; font-size: 28rpx;
color: #111; color: #111;
} }
} }
} }
</style> </style>

View File

@@ -48,7 +48,7 @@
<!-- @click="jump('about')" --> <!-- @click="jump('about')" -->
<view class="mine-nav" style="border-bottom: none"> <view class="mine-nav" style="border-bottom: none">
<view class="mine-nav-label">版本信息</view> <view class="mine-nav-label">版本信息</view>
<view style="color: #828282; font-size: 14rpx">当前版本V<1.6.7</view> <view style="color: #828282; font-size: 14rpx">当前版本V{{ version }}</view>
<!-- <uni-icons type="forward" color="#aaa" size="20"></uni-icons> --> <!-- <uni-icons type="forward" color="#aaa" size="20"></uni-icons> -->
</view> </view>
<view class="mine-nav" @click="jump('layout')" style="margin-top: 20rpx; border-bottom: none"> <view class="mine-nav" @click="jump('layout')" style="margin-top: 20rpx; border-bottom: none">
@@ -64,10 +64,19 @@ export default {
data() { data() {
return { return {
loading: false, loading: false,
version: '1.0.0',
} }
}, },
methods: { methods: {
async init() {}, async init() {
const isDev = process.env.NODE_ENV === 'development'
if (isDev) {
return console.log('开发环境,不执行更新检查')
}
plus.runtime.getProperty(plus.runtime.appid, (info) => {
this.version = info.version // 当前本地版本号
})
},
jump(type) { jump(type) {
switch (type) { switch (type) {
case 'changePwd': case 'changePwd':

View File

@@ -1,147 +1,170 @@
<template> <template>
<Cn-page :loading="loading"> <Cn-page :loading="loading">
<view class="mine" slot="body"> <view class="mine" slot="body">
<view class="mine-nav" style="margin-top: 20rpx"> <view class="mine-nav mt20" style="border-bottom: none">
<view class="mine-nav-label">运行事件</view> <view class="mine-nav-label">暂态事件</view>
<switch style="transform: scale(0.8)" color="#376cf3" @change="change('runInfo')" :checked="config.runInfo === 1"/> <switch
</view> style="transform: scale(0.8)"
<view class="mine-nav" style="border-bottom: none"> color="#376cf3"
<view class="mine-nav-label">暂态事件</view> @change="change('eventInfo')"
<switch style="transform: scale(0.8)" color="#376cf3" @change="change('eventInfo')" :checked="config.eventInfo === 1"/> :checked="config.eventInfo === 1"
</view> />
<view class="mine-nav" style="border-bottom: none"> </view>
<view class="mine-nav-label">稳态事件</view> <view class="mine-nav" style="border-bottom: none">
<switch style="transform: scale(0.8)" color="#376cf3" @change="change('harmonicInfo')" :checked="config.harmonicInfo === 1"/> <view class="mine-nav-label">稳态事件</view>
</view> <switch
<view class="mine-nav" style="border-bottom: none"> style="transform: scale(0.8)"
<view class="mine-nav-label">设备告警</view> color="#376cf3"
<switch style="transform: scale(0.8)" color="#376cf3" @change="change('alarmInfo')" :checked="config.alarmInfo === 1"/> @change="change('harmonicInfo')"
</view> :checked="config.harmonicInfo === 1"
</view> />
</Cn-page> </view>
</template> <view class="mine-nav" style="border-bottom: none">
<view class="mine-nav-label">运行告警</view>
<script> <switch
import {queryUserPushConfig, updatePushConfig} from '@/common/api/mine' style="transform: scale(0.8)"
color="#376cf3"
export default { @change="change('alarmInfo')"
data() { :checked="config.alarmInfo === 1"
return { />
loading: true, </view>
config: {}, <view class="mine-nav" >
} <view class="mine-nav-label">运行事件</view>
}, <switch
methods: { style="transform: scale(0.8)"
init() { color="#376cf3"
queryUserPushConfig().then(res => { @change="change('runInfo')"
console.log(123123,res); :checked="config.runInfo === 1"
this.config = res.data />
console.log(this.config) </view>
</view>
this.loading = false </Cn-page>
}) </template>
},
change(type) { <script>
this.config[type] = this.config[type] === 1 ? 0 : 1 import { queryUserPushConfig, updatePushConfig } from '@/common/api/mine'
updatePushConfig(this.config).then(res => {
let str = '' export default {
switch (type){ data() {
case 'runInfo': return {
str = '运行事件' loading: true,
break config: {},
case 'eventInfo': }
str = '暂态事件' },
break methods: {
case 'harmonicInfo': init() {
str = '稳态事件' queryUserPushConfig().then((res) => {
break this.config = res.data
case 'alarmInfo':
str = '设备告警' this.loading = false
break })
} },
this.$util.toast(`${str}推送${this.config[type] === 1 ? '开启' : '关闭'}成功`) change(type) {
}) this.config[type] = this.config[type] === 1 ? 0 : 1
}, // updatePushConfig(this.config).then((res) => {
jump(type) { // let str = ''
switch (type) { // switch (type) {
case 'changePwd': // case 'runInfo':
uni.navigateTo({ // str = '运行事件'
url: `/pages/user/changePwd`, // break
}) // case 'eventInfo':
break // str = '暂态事件'
case 'changePhone': // break
uni.navigateTo({ // case 'harmonicInfo':
url: `/pages/user/changePhone`, // str = '稳态事件'
}) // break
break // case 'alarmInfo':
default: // str = '设备告警'
uni.navigateTo({ // break
url: `/pages/mine/${type}`, // }
}) // this.$util.toast(`${str}推送${this.config[type] === 1 ? '开启' : '关闭'}成功`)
break // })
} },
}, jump(type) {
}, switch (type) {
onLoad() { case 'changePwd':
this.init() uni.navigateTo({
}, url: `/pages/user/changePwd`,
} })
</script> break
case 'changePhone':
<style lang="scss"> uni.navigateTo({
.mine { url: `/pages/user/changePhone`,
.title { })
padding: 0 20rpx; break
font-size: 28rpx; default:
font-weight: 500; uni.navigateTo({
} url: `/pages/mine/${type}`,
})
.mine-header { break
padding: 200rpx 34rpx 34rpx; }
display: flex; },
align-items: center; onUnload() {
background: $uni-theme-white; updatePushConfig(this.config).then((res) => {
margin-bottom: 20rpx; // this.$util.toast(`配置修改成功!`)
box-shadow: 0 4rpx 8rpx #e7e7e74c; })
},
.mine-header-head { },
margin-right: 30rpx; onLoad() {
height: 128rpx; this.init()
width: 128rpx; },
border-radius: $uni-theme-radius; }
overflow: hidden; </script>
}
<style lang="scss">
.mine-header-name { .mine {
margin-right: 30rpx; .title {
flex: 1; padding: 0 20rpx;
font-size: 36rpx; font-size: 28rpx;
color: #111; font-weight: 500;
font-weight: 700; }
}
} .mine-header {
padding: 200rpx 34rpx 34rpx;
.mine-nav { display: flex;
padding: 34rpx; align-items: center;
display: flex; background: $uni-theme-white;
align-items: center; margin-bottom: 20rpx;
background: $uni-theme-white; box-shadow: 0 4rpx 8rpx #e7e7e74c;
border-bottom: 1rpx solid #e8e8e8;
.mine-header-head {
&-icon { margin-right: 30rpx;
margin-right: 30rpx; height: 128rpx;
height: 44rpx; width: 128rpx;
width: 44rpx; border-radius: $uni-theme-radius;
border-radius: $uni-theme-radius; overflow: hidden;
overflow: hidden; }
}
.mine-header-name {
&-label { margin-right: 30rpx;
margin-right: 30rpx; flex: 1;
flex: 1; font-size: 36rpx;
font-size: 28rpx; color: #111;
color: #111; font-weight: 700;
} }
} }
}
</style> .mine-nav {
padding: 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
border-bottom: 1rpx solid #e8e8e8;
&-icon {
margin-right: 30rpx;
height: 44rpx;
width: 44rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
&-label {
margin-right: 30rpx;
flex: 1;
font-size: 28rpx;
color: #111;
}
}
}
</style>

View File

@@ -0,0 +1,129 @@
<template>
<Cn-page :loading="loading">
<view class="mine" slot="body">
<view class="mine-nav" style="margin-top: 20rpx">
<view class="mine-nav-label">ITIC</view>
<switch
style="transform: scale(0.8)"
color="#376cf3"
@change="change('iticFunction')"
:checked="config.iticFunction === 1"
/>
</view>
<view class="mine-nav" style="border-bottom: none">
<view class="mine-nav-label">F47</view>
<switch
style="transform: scale(0.8)"
color="#376cf3"
@change="change('f47Function')"
:checked="config.f47Function === 1"
/>
</view>
</view>
</Cn-page>
</template>
<script>
import { queryUserPushConfig, updatePushConfig } from '@/common/api/mine'
export default {
data() {
return {
loading: true,
config: {},
}
},
onLoad() {
this.init()
},
methods: {
init() {
queryUserPushConfig().then((res) => {
this.config = res.data
this.loading = false
})
},
change(type) {
this.config[type] = this.config[type] === 1 ? 0 : 1
// updatePushConfig(this.config).then((res) => {
// let str = ''
// switch (type) {
// case 'iticFunction':
// str = 'ITIC'
// break
// case 'f47Function':
// str = 'F47'
// break
// }
// this.$util.toast(`${str}配置${this.config[type] === 1 ? '开启' : '关闭'}成功`)
// })
},
},
onLoad() {
this.init()
},
onUnload() {
updatePushConfig(this.config).then((res) => {
// this.$util.toast(`配置修改成功!`)
})
},
}
</script>
<style lang="scss">
.mine {
.title {
padding: 0 20rpx;
font-size: 28rpx;
font-weight: 500;
}
.mine-header {
padding: 200rpx 34rpx 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
margin-bottom: 20rpx;
box-shadow: 0 4rpx 8rpx #e7e7e74c;
.mine-header-head {
margin-right: 30rpx;
height: 128rpx;
width: 128rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
.mine-header-name {
margin-right: 30rpx;
flex: 1;
font-size: 36rpx;
color: #111;
font-weight: 700;
}
}
.mine-nav {
padding: 34rpx;
display: flex;
align-items: center;
background: $uni-theme-white;
border-bottom: 1rpx solid #e8e8e8;
&-icon {
margin-right: 30rpx;
height: 44rpx;
width: 44rpx;
border-radius: $uni-theme-radius;
overflow: hidden;
}
&-label {
margin-right: 30rpx;
flex: 1;
font-size: 28rpx;
color: #111;
}
}
}
</style>

View File

@@ -1,361 +1,350 @@
<template> <template>
<Cn-page :loading="loading" noPadding> <Cn-page :loading="loading" noPadding>
<view slot="body"> <view slot="body">
<view class="detail"> <view class="detail">
<view class="header"> <view class="header">
<view class="header-title" <view class="header-title"
>{{ project.name }} >{{ project.name }}
<!-- <view class="header-title-extra">用能</view> --> <!-- <view class="header-title-extra">用能</view> -->
</view> </view>
<view class="header-des">项目描述{{ project.description }}</view> <view class="header-des">项目描述{{ project.description }}</view>
</view> </view>
<view class="nav"> <view class="nav">
<view <view
class="nav-menu" class="nav-menu"
:class="{ 'nav-menu-active': navMenuActive == index }" :class="{ 'nav-menu-active': navMenuActive == index }"
v-for="(item, index) in navMenuList" v-for="(item, index) in navMenuList"
:key="index" :key="index"
@click="navMenuClick(index)" @click="navMenuClick(index)"
>{{ item.text }} >{{ item.text }}
</view> </view>
</view> </view>
<view class="content device" :style="{ minHeight: 'calc(100vh - ' + navHeight + 'px)' }"> <view class="content device" :style="{ minHeight: 'calc(100vh - ' + navHeight + 'px)' }">
<view v-show="navMenuActive == 0"> <view v-show="navMenuActive == 0">
<!-- <uni-card <!-- <uni-card
:title="item.equipmentName" :title="item.equipmentName"
:sub-title="'创建时间' + item.createTime" :sub-title="'创建时间' + item.createTime"
:extra="item.mac" :extra="item.mac"
v-for="item in store.data" v-for="item in store.data"
:key="item.equipmentId" :key="item.equipmentId"
@click="goDevice(item)" @click="goDevice(item)"
padding="0" padding="0"
:thumbnail="deviceIcon(item.runStatus)" :thumbnail="deviceIcon(item.runStatus)"
> >
</uni-card> --> </uni-card> -->
<Cn-device-card v-for="(item, index) in store.data" :device="item" :key="index"> <Cn-device-card v-for="(item, index) in store.data" :device="item" :key="index">
</Cn-device-card> <template v-slot:title>
<Cn-empty v-if="store.empty"></Cn-empty>
<uni-load-more <view class="star-icon">
v-if="store.status == 'loading' || (store.data && store.data.length > 0)" <uni-icons type="search" size="25" color="#376cf3"></uni-icons>
:status="store.status" </view>
></uni-load-more> </template>
</view> </Cn-device-card>
<!-- <view style="padding: 0 20rpx" v-show="navMenuActive == 1">--> <Cn-empty v-if="store.empty"></Cn-empty>
<!-- <uni-list>--> <uni-load-more
<!-- <uni-list-item--> v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
<!-- title="张三"--> :status="store.status"
<!-- note="2023-02-10 14:55"--> ></uni-load-more>
<!-- thumb="/static/head.png"--> </view>
<!-- thumb-size="lg"-->
<!-- >--> <view style="padding: 0 20rpx" v-show="navMenuActive == 1">
<!-- </uni-list-item>--> <!-- <image
<!-- <uni-list-item--> class="gplot gplot-box"
<!-- title="李四"--> mode="aspectFill"
<!-- note="2023-02-10 14:55"--> :src="item.filePath"
<!-- thumb="/static/head.png"--> v-for="(item, key) in topologyDiagramPage"
<!-- thumb-size="lg"--> :key="key"
<!-- >--> /> -->
<!-- </uni-list-item>--> <uni-file-picker
<!-- </uni-list>--> ref="filePicker"
<!-- </view>--> v-model="topologyDiagramPage"
<view style="padding: 0 20rpx" v-show="navMenuActive == 1"> :sourceType="['album']"
<!-- <image :auto-upload="false"
class="gplot gplot-box" @select="addAppTopologyDiagram"
mode="aspectFill" @delete="deleteTopologyDiagramPage"
:src="item.filePath" readonly
v-for="(item, key) in topologyDiagramPage" ></uni-file-picker>
:key="key" </view>
/> --> </view>
<uni-file-picker <uni-fab
ref="filePicker" ref="fab"
v-model="topologyDiagramPage" direction="vertical"
:sourceType="['album']" horizontal="right"
:auto-upload="false" vertical="bottom"
@select="addAppTopologyDiagram" :content="content"
@delete="deleteTopologyDiagramPage" @trigger="trigger"
readonly v-if="content.length"
></uni-file-picker> />
</view> <uni-popup ref="share" type="share" background-color="#fff">
</view> <uni-popup-share title="分享到"></uni-popup-share>
<uni-fab </uni-popup>
ref="fab" </view>
direction="vertical" </view>
horizontal="right" </Cn-page>
vertical="bottom" </template>
:content="content" <script>
@trigger="trigger" import list from '../../common/js/list'
v-if="content.length" import {
/> queryTopologyDiagramPage,
<uni-popup ref="share" type="share" background-color="#fff"> deleteAppTopologyDiagram,
<uni-popup-share title="分享到"></uni-popup-share> addAppTopologyDiagram,
</uni-popup> deleteProject,
</view> } from '../../common/api/project'
</view> export default {
</Cn-page> mixins: [list],
</template> data() {
<script> return {
import list from '../../common/js/list' loading: false,
import { project: {},
queryTopologyDiagramPage, navMenuList: [
deleteAppTopologyDiagram, {
addAppTopologyDiagram, text: '设备',
deleteProject, },
} from '../../common/api/project' // {
export default { // text: '用户',
mixins: [list], // },
data() { {
return { text: '拓扑图',
loading: false, },
project: {}, ],
navMenuList: [ content: [],
{ navHeight: 0,
text: '设备', navMenuActive: 0,
}, topologyDiagramPage: [],
// { }
// text: '用户', },
// }, methods: {
{ deviceIcon(e) {
text: '拓扑图', let str = ''
}, switch (e) {
], case 1:
content: [], str = '/static/device_bad.png'
navHeight: 0, break
navMenuActive: 0, case 2:
topologyDiagramPage: [], str = '/static/device.png'
} break
}, default:
methods: { str = '/static/device.png'
deviceIcon(e) { break
let str = '' }
switch (e) { return str
case 1: },
str = '/static/device_bad.png' addAppTopologyDiagram(e) {
break console.log(e)
case 2: addAppTopologyDiagram(
str = '/static/device.png' {
break projectId: this.project.id,
default: topologyDiagramName: e.tempFiles[0].name,
str = '/static/device.png' },
break e.tempFiles[0].path,
} ).then((res) => {
return str console.log(res)
}, if (res.length > 1) {
addAppTopologyDiagram(e) { const result = JSON.parse(res[1].data)
console.log(e) console.log(result)
addAppTopologyDiagram( if (result.code === 'A0000') {
{ this.topologyDiagramPage.push({
projectId: this.project.id, name: result.name,
topologyDiagramName: e.tempFiles[0].name, extname: 'img',
}, url: result.filePath,
e.tempFiles[0].path, ...result,
).then((res) => { })
console.log(res) } else {
if (res.length > 1) { this.$refs.filePicker.clearFiles(this.topologyDiagramPage.length - 1)
const result = JSON.parse(res[1].data) uni.showToast({
console.log(result) title: result.message,
if (result.code === 'A0000') { icon: 'none',
this.topologyDiagramPage.push({ })
name: result.name, }
extname: 'img', } else {
url: result.filePath, uni.showToast({
...result, title: '上传失败',
}) icon: 'none',
} else { })
this.$refs.filePicker.clearFiles(this.topologyDiagramPage.length - 1) this.$refs.filePicker.clearFiles(this.topologyDiagramPage.length - 1)
uni.showToast({ }
title: result.message, })
icon: 'none', },
}) deleteTopologyDiagramPage(e) {
} console.log(e)
} else { deleteAppTopologyDiagram(e.tempFile.id).then((res) => {
uni.showToast({ console.log(res)
title: '上传失败', })
icon: 'none', },
}) trigger(e) {
this.$refs.filePicker.clearFiles(this.topologyDiagramPage.length - 1) console.log(this.$refs)
} if (e.item.text == '移交') {
}) uni.navigateTo({
}, url: '/pages/project/transfer',
deleteTopologyDiagramPage(e) { })
console.log(e) } else if (e.item.text == '分享') {
deleteAppTopologyDiagram(e.tempFile.id).then((res) => { this.$refs.share.open()
console.log(res) } else if (e.item.text == '编辑') {
}) uni.navigateTo({
}, url: '/pages/project/new?project=' + encodeURIComponent(JSON.stringify(this.project)),
trigger(e) { })
console.log(this.$refs) } else if (e.item.text == '删除') {
if (e.item.text == '移交') { uni.showModal({
uni.navigateTo({ title: '提示',
url: '/pages/project/transfer', content: '删除项目后不可恢复,是否继续?',
}) success: (res) => {
} else if (e.item.text == '分享') { if (res.confirm) {
this.$refs.share.open() deleteProject(this.project.id).then((res) => {
} else if (e.item.text == '编辑') { this.$util.toast('删除成功')
uni.navigateTo({ this.$util.refreshPrePage()
url: '/pages/project/new?project=' + encodeURIComponent(JSON.stringify(this.project)), })
}) } else if (res.cancel) {
} else if (e.item.text == '删除') { console.log('用户点击取消')
uni.showModal({ }
title: '提示', },
content: '删除项目后不可恢复,是否继续?', })
success: (res) => { }
if (res.confirm) { },
deleteProject(this.project.id).then((res) => { navMenuClick(index) {
this.$util.toast('删除成功') this.navMenuActive = index
this.$util.refreshPrePage() },
}) goUserDetail() {
} else if (res.cancel) { uni.navigateTo({
console.log('用户点击取消') url: '/pages/mine/userDetail',
} })
}, },
}) del() {
} console.log('del')
}, uni.showModal({
navMenuClick(index) { title: '提示',
this.navMenuActive = index content: '确定要移除该成员吗?',
}, success: function (res) {
goUserDetail() { if (res.confirm) {
uni.navigateTo({ console.log('用户点击确定')
url: '/pages/mine/userDetail', } else if (res.cancel) {
}) console.log('用户点击取消')
}, }
del() { },
console.log('del') })
uni.showModal({ },
title: '提示', goDevice(item) {
content: '确定要移除该成员吗?', uni.navigateTo({
success: function (res) { url: '/pages/device/APF/detail?id=' + item.equipmentId,
if (res.confirm) { })
console.log('用户点击确定') },
} else if (res.cancel) { init() {
console.log('用户点击取消') this.store = this.DataSource('/cs-device-boot/EquipmentDelivery/queryEquipmentByProject')
} this.store.params.projectId = this.project.id
}, this.store.reload()
})
}, queryTopologyDiagramPage({
goDevice(item) { projectId: this.project.id,
uni.navigateTo({ }).then((res) => {
url: '/pages/device/APF/detail?id=' + item.equipmentId, console.log(res)
}) this.topologyDiagramPage = res.data.records.map((item) => {
}, return {
init() { name: item.name,
this.store = this.DataSource('/cs-device-boot/EquipmentDelivery/queryEquipmentByProject') extname: 'img',
this.store.params.projectId = this.project.id url: this.$config.static + item.filePath,
this.store.reload() ...item,
}
queryTopologyDiagramPage({ })
projectId: this.project.id, })
}).then((res) => { },
console.log(res) },
this.topologyDiagramPage = res.data.records.map((item) => { onLoad(option) {
return { let userInfo = uni.getStorageSync('userInfo')
name: item.name, // this.content.push({
extname: 'img', // iconPath: '/static/share.png',
url: this.$config.static + item.filePath, // text: '编辑',
...item, // })
} // this.content.push({
}) // iconPath: '/static/delate.png',
}) // text: '删除',
}, // })
}, // this.content.push({
onLoad(option) { // iconPath: '/static/transfer.png',
let userInfo = uni.getStorageSync('userInfo') // text: '移交',
// this.content.push({ // })
// iconPath: '/static/share.png', // this.content.push({
// text: '编辑', // iconPath: '/static/share.png',
// }) // text: '分享',
// this.content.push({ // })
// iconPath: '/static/delate.png', if (userInfo.authorities == 'engineering_user' || userInfo.authorities == 'app_vip_user') {
// text: '删除', this.content.push(
// }) {
// this.content.push({ iconPath: '/static/share.png',
// iconPath: '/static/transfer.png', text: '编辑',
// text: '移交', },
// }) {
// this.content.push({ iconPath: '/static/delate.png',
// iconPath: '/static/share.png', text: '删除',
// text: '分享', },
// }) )
if (userInfo.authorities == 'engineering_user' || userInfo.authorities == 'app_vip_user') { }
this.content.push( setTimeout(() => {
{ // 获取nav高度
iconPath: '/static/share.png', uni.createSelectorQuery()
text: '编辑', .select('.nav')
}, .boundingClientRect((rect) => {
{ this.navHeight = rect.height
iconPath: '/static/delate.png', })
text: '删除', .exec()
}, }, 1000)
) console.log(option.project)
} this.project = JSON.parse(decodeURIComponent(option.project))
setTimeout(() => { this.project.topologyDiagramPaths.forEach((item) => {
// 获取nav高度 item.filePath = this.$config.static + item.filePath
uni.createSelectorQuery() })
.select('.nav') this.init()
.boundingClientRect((rect) => { // uni.setNavigationBarTitle({ title: this.project })
this.navHeight = rect.height },
}) }
.exec() </script>
}, 1000) <style lang="scss">
console.log(option.project) .detail {
this.project = JSON.parse(decodeURIComponent(option.project)) .content {
this.project.topologyDiagramPaths.forEach((item) => { box-sizing: border-box;
item.filePath = this.$config.static + item.filePath padding-bottom: 20rpx;
}) }
this.init()
// uni.setNavigationBarTitle({ title: this.project }) .header {
}, padding: 20rpx 20rpx 0;
}
</script> .header-title {
<style lang="scss"> display: flex;
.detail { justify-content: space-between;
.content { align-items: center;
box-sizing: border-box; font-size: 40rpx;
padding-bottom: 20rpx; margin-bottom: 10rpx;
}
.header-title-extra {
.header { font-size: 24rpx;
padding: 20rpx 20rpx 0; color: #666;
padding-right: 10rpx;
.header-title { }
display: flex; }
justify-content: space-between;
align-items: center; .header-des {
font-size: 40rpx; font-size: 28rpx;
margin-bottom: 10rpx; color: #666;
}
.header-title-extra { }
font-size: 24rpx;
color: #666; .footer-btn {
padding-right: 10rpx; padding: 0 20rpx;
} height: 50rpx;
} background-color: #007aff;
font-size: 24rpx;
.header-des { color: #fff;
font-size: 28rpx; text-align: center;
color: #666; line-height: 50rpx;
} border-radius: 10rpx;
} }
/deep/ .is-add {
.footer-btn { background-color: #fff;
padding: 0 20rpx; }
height: 50rpx; }
background-color: #007aff;
font-size: 24rpx; .gplot {
color: #fff; box-sizing: border-box;
text-align: center; position: relative;
line-height: 50rpx; width: 100%;
border-radius: 10rpx; border: 8rpx solid #ccc;
} }
/deep/ .is-add { </style>
background-color: #fff;
}
}
.gplot {
box-sizing: border-box;
position: relative;
width: 100%;
border: 8rpx solid #ccc;
}
</style>

View File

@@ -1,183 +1,167 @@
<template> <template>
<view :loading="loading"> <view :loading="loading">
<!-- <uni-nav-bar left-icon="left" right-icon="cart" title="标题" /> --> <!-- <uni-nav-bar left-icon="left" right-icon="cart" title="标题" /> -->
<uni-nav-bar <uni-nav-bar dark :fixed="true" status-bar left-icon="left" :rightIcon="userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'
dark ? 'plusempty'
:fixed="true" : ''
status-bar " background-color="#fff" color="#111" title="项目管理" @clickLeft="back" @clickRight="add" />
left-icon="left" <uni-search-bar v-model="store.params.searchValue" clearButton="none" bgColor="#fff" placeholder="请输入关键词"
:rightIcon=" @input="store.search()"></uni-search-bar>
userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user' <view class="message">
? 'plusempty' <!-- extra="🔍" -->
: '' <uni-card class="boxClick" :title="item.name" @click="jump(item)"
" v-for="(item, index) in store.data" :key="index" :style="{ marginTop: index === 0 ? '0' : '' }">
background-color="#fff" <view class="term-list-bottom">
color="#111" <view class="term-list-bottom-item">
title="项目管理" <view>设备个数</view>
@clickLeft="back" <view>{{ item.devNum }}</view>
@clickRight="add" </view>
/> <view class="term-list-bottom-item">
<uni-search-bar <view>所属工程</view>
v-model="store.params.searchValue" <view>{{ item.engineeringName }}</view>
clearButton="none" </view>
bgColor="#fff" </view>
placeholder="请输入关键词" </uni-card>
@input="store.search()" <Cn-empty v-if="store.empty" style="padding-top: 400rpx"></Cn-empty>
></uni-search-bar> <uni-load-more v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
<view class="message"> :status="store.status"></uni-load-more>
<uni-card </view>
:title="item.name" </view>
@click="jump(item)" </template>
extra="🔍"
v-for="(item, index) in store.data" <script>
:key="index" import list from '../../common/js/list'
:style="{ marginTop: index === 0 ? '0' : '' }"
> export default {
<view class="term-list-bottom"> mixins: [list],
<view class="term-list-bottom-item"> data() {
<view>设备个数</view> return {
<view>{{ item.devNum }}</view> loading: false,
</view> userInfo: {},
<view class="term-list-bottom-item"> }
<view>所属工程</view> },
<view>{{ item.engineeringName }}</view> methods: {
</view> init(engineeringId) {
</view> this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
</uni-card> this.store = this.DataSource('/cs-device-boot/project/queryProject')
<Cn-empty v-if="store.empty" style="padding-top: 400rpx"></Cn-empty> this.store.params.searchValue = ''
<uni-load-more this.store.params.engineeringId = engineeringId || ''
v-if="store.status == 'loading' || (store.data && store.data.length > 0)" this.store.reload()
:status="store.status" },
></uni-load-more> back() {
</view> uni.navigateBack()
</view> },
</template> add() {
if (this.userInfo.authorities === 'app_vip_user' || this.userInfo.authorities === 'engineering_user') {
<script> if (!uni.getStorageSync('engineering')) {
import list from '../../common/js/list' return uni.showToast({
title: '请先创建一个工程',
export default { icon: 'none',
mixins: [list], })
data() { }
return { uni.navigateTo({
loading: false, url: `/pages/project/new`,
userInfo: {}, })
} }
}, },
methods: { upgrade(code) {
init(engineeringId) { console.log(code)
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo) uni.showToast({
this.store = this.DataSource('/cs-device-boot/project/queryProject') title: '升级成功',
this.store.params.searchValue = '' icon: 'none',
this.store.params.engineeringId = engineeringId || '' })
this.store.reload() },
}, jump(project) {
back() { console.log(project)
uni.navigateBack() uni.navigateTo({
}, url: `/pages/project/detail?project=${encodeURIComponent(JSON.stringify(project))}`,
add() { })
if (this.userInfo.authorities === 'app_vip_user' || this.userInfo.authorities === 'engineering_user') { },
if (!uni.getStorageSync('engineering')) { },
return uni.showToast({ onLoad({ engineeringId }) {
title: '请先创建一个工程', this.init(engineeringId)
icon: 'none', },
}) }
} </script>
uni.navigateTo({
url: `/pages/project/new`, <style lang="scss">
}) .message {
} .message-header {
}, padding: 200rpx 34rpx 34rpx;
upgrade(code) { display: flex;
console.log(code) align-items: center;
uni.showToast({ background: $uni-theme-white;
title: '升级成功', margin-bottom: 20rpx;
icon: 'none', box-shadow: 0 4rpx 8rpx #e7e7e74c;
})
}, .message-header-head {
jump(project) { margin-right: 30rpx;
console.log(project) height: 128rpx;
uni.navigateTo({ width: 128rpx;
url: `/pages/project/detail?project=${encodeURIComponent(JSON.stringify(project))}`, border-radius: $uni-theme-radius;
}) overflow: hidden;
}, }
},
onLoad({ engineeringId }) { .message-header-name {
this.init(engineeringId) margin-right: 30rpx;
}, flex: 1;
} font-size: 36rpx;
</script> color: #111;
font-weight: 700;
<style lang="scss">
.message { .tag {
.message-header { margin-top: 10rpx;
padding: 200rpx 34rpx 34rpx; font-size: 24rpx;
display: flex; color: #aaa;
align-items: center; }
background: $uni-theme-white; }
margin-bottom: 20rpx; }
box-shadow: 0 4rpx 8rpx #e7e7e74c;
.message-nav {
.message-header-head { padding: 34rpx;
margin-right: 30rpx; display: flex;
height: 128rpx; align-items: center;
width: 128rpx; background: $uni-theme-white;
border-radius: $uni-theme-radius; border-bottom: 1rpx solid #e8e8e8;
overflow: hidden;
} &-icon {
margin-right: 30rpx;
.message-header-name { height: 44rpx;
margin-right: 30rpx; width: 44rpx;
flex: 1; border-radius: $uni-theme-radius;
font-size: 36rpx; overflow: hidden;
color: #111; }
font-weight: 700;
&-label {
.tag { margin-right: 30rpx;
margin-top: 10rpx; flex: 1;
font-size: 24rpx; font-size: 28rpx;
color: #aaa; color: #111;
} }
} }
} }
.message-nav { .term-list-bottom {
padding: 34rpx; .term-list-bottom-item {
display: flex; font-size: 28rpx;
align-items: center; // margin-bottom: 20rpx;
background: $uni-theme-white; display: flex;
border-bottom: 1rpx solid #e8e8e8; justify-content: space-between;
// view:first-of-type{
&-icon { // color: #111;
margin-right: 30rpx; // }
height: 44rpx; }
width: 44rpx;
border-radius: $uni-theme-radius; .term-list-bottom-item:last-of-type {
overflow: hidden; margin-bottom: 0;
} }
}
&-label {
margin-right: 30rpx; /deep/ .uni-card__content {
flex: 1; padding: 5px 10px 10px !important;
font-size: 28rpx; }
color: #111;
} /deep/ .uni-card__header-content-title {
} font-weight: 700;
} }
</style>
.term-list-bottom {
.term-list-bottom-item {
font-size: 28rpx;
margin-bottom: 20rpx;
display: flex;
justify-content: space-between;
// view:first-of-type{
// color: #111;
// }
}
.term-list-bottom-item:last-of-type {
margin-bottom: 0;
}
}
</style>

View File

@@ -1,249 +1,250 @@
<template> <template>
<Cn-page :loading="loading"> <Cn-page :loading="loading">
<view slot="body"> <view slot="body">
<view class="index"> <view class="index">
<template v-if="step == 1"> <template v-if="step == 1">
<uni-forms ref="form" :rules="rules" :modelValue="formData"> <uni-forms ref="form" :rules="rules" :modelValue="formData">
<uni-forms-item name="phone"> <uni-forms-item name="phone">
<uni-easyinput <uni-easyinput
disabled disabled
type="text" type="text"
maxlength="11" maxlength="11"
v-model="formData.phoneShow" v-model="formData.phoneShow"
placeholder="请输入手机号" placeholder="请输入手机号"
/> />
</uni-forms-item> </uni-forms-item>
<uni-forms-item name="code"> <uni-forms-item name="code">
<view class="login-box-input"> <view class="login-box-input">
<uni-easyinput type="text" v-model="formData.code" placeholder="请输入验证码" maxlength="6" /> <uni-easyinput type="text" v-model="formData.code" placeholder="请输入验证码" maxlength="6" />
<view <view
class="ml40" class="ml40"
style=" style="
margin-left: 40rpx; margin-left: 40rpx;
font-size: 28rpx; font-size: 28rpx;
color: #666; color: #666;
width: 200rpx; width: 200rpx;
text-align: center; text-align: center;
" "
v-if="waitTime > 0" v-if="waitTime > 0"
>{{ waitTime + 's后重新获取' }}</view >{{ waitTime + 's后重新获取' }}</view
> >
<button class="login-box-input-btn" v-else @click="getCode(5)" size="mini"> <button class="login-box-input-btn" v-else @click="getCode(5)" size="mini">
获取验证码 获取验证码
</button> </button>
</view> </view>
</uni-forms-item> </uni-forms-item>
</uni-forms> </uni-forms>
<button type="default" class="submit-btn" @click="firstSubmit">下一步</button> <button type="default" class="submit-btn" @click="firstSubmit">下一步</button>
</template> </template>
<template v-else> <template v-else>
<uni-forms ref="form" :rules="rules" :modelValue="formData"> <uni-forms ref="form" :rules="rules" :modelValue="formData">
<uni-forms-item name="phone"> <uni-forms-item name="phone">
<uni-easyinput <uni-easyinput
maxlength="11" maxlength="11"
type="number" type="number"
v-model="formData.phone2" v-model="formData.phone2"
placeholder="请输入新手机号" placeholder="请输入新手机号"
/> />
</uni-forms-item> </uni-forms-item>
<uni-forms-item name="code"> <uni-forms-item name="code">
<view class="login-box-input"> <view class="login-box-input">
<uni-easyinput type="text" v-model="formData.code2" placeholder="请输入验证码" maxlength="6" /> <uni-easyinput type="text" v-model="formData.code2" placeholder="请输入验证码" maxlength="6" />
<view <view
class="ml40" class="ml40"
style=" style="
margin-left: 40rpx; margin-left: 40rpx;
font-size: 28rpx; font-size: 28rpx;
color: #666; color: #666;
width: 200rpx; width: 200rpx;
text-align: center; text-align: center;
" "
v-if="waitTime > 0" v-if="waitTime > 0"
>{{ waitTime + 's后重新获取' }}</view >{{ waitTime + 's后重新获取' }}</view
> >
<button class="login-box-input-btn" v-else @click="getCode(4)" size="mini"> <button class="login-box-input-btn" v-else @click="getCode(4)" size="mini">
获取验证码 获取验证码
</button> </button>
</view> </view>
</uni-forms-item> </uni-forms-item>
</uni-forms> </uni-forms>
<button type="default" class="submit-btn" @click="secondSubmit">提交</button> <button type="default" class="submit-btn" @click="secondSubmit">提交</button>
</template> </template>
</view> </view>
</view> </view>
</Cn-page> </Cn-page>
</template> </template>
<script> <script>
import { apiGetYms, apiComfirmCode, apiRebindPhone } from '@/common/api/user' import { apiGetYms, apiComfirmCode, apiRebindPhone } from '@/common/api/user'
export default { export default {
name: 'jiaban', name: 'jiaban',
data() { data() {
return { return {
step: 1, step: 1,
loading: false, loading: false,
waitTime: 0, waitTime: 0,
// 表单数据 // 表单数据
formData: { formData: {
phone: '', phone: '',
phoneShow: '', phoneShow: '',
code: '', code: '',
phone2: '', phone2: '',
code2: '', code2: '',
}, },
rules: { rules: {
phone: { phone: {
rules: [ rules: [
{ {
required: true, required: true,
errorMessage: '请填写手机号', errorMessage: '请填写手机号',
}, },
], ],
}, },
code: { code: {
rules: [ rules: [
{ {
required: true, required: true,
errorMessage: '请填写验证码', errorMessage: '请填写验证码',
}, },
], ],
}, },
phone2: { phone2: {
rules: [ rules: [
{ {
required: true, required: true,
errorMessage: '请填写新手机号', errorMessage: '请填写新手机号',
}, },
], ],
}, },
code2: { code2: {
rules: [ rules: [
{ {
required: true, required: true,
errorMessage: '请填写验证码', errorMessage: '请填写验证码',
}, },
], ],
}, },
}, },
} }
}, },
onLoad() { onLoad() {
this.init() this.init()
}, },
methods: { methods: {
getCode(type) { getCode(type) {
if (!this.formData.phone) { if (!this.formData.phone) {
return this.$util.toast('请输入手机号!') return this.$util.toast('请输入手机号!')
} }
uni.showLoading({ uni.showLoading({
title: '请稍等', title: '请稍等...',
}) mask: true,
apiGetYms({ })
phone: type == 5 ? this.formData.phone : this.formData.phone2, apiGetYms({
type, phone: type == 5 ? this.formData.phone : this.formData.phone2,
}) type,
.then((res) => { })
uni.hideLoading() .then((res) => {
console.log(res) uni.hideLoading()
this.waitTime = 60 console.log(res)
this.inter = setInterval(() => { this.waitTime = 60
if (this.waitTime == 0) { this.inter = setInterval(() => {
clearInterval(this.inter) if (this.waitTime == 0) {
} else { clearInterval(this.inter)
this.waitTime-- } else {
} this.waitTime--
}, 1000) }
}) }, 1000)
.catch((err) => { })
uni.hideLoading() .catch((err) => {
console.log(err) uni.hideLoading()
}) console.log(err)
}, })
init() { },
// 手机号中间四位隐藏 init() {
this.formData.phone = uni.getStorageSync('userInfo').user_name // 手机号中间四位隐藏
this.formData.phoneShow = this.formData.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') this.formData.phone = uni.getStorageSync('userInfo').user_name
}, this.formData.phoneShow = this.formData.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
firstSubmit() { },
apiComfirmCode({ firstSubmit() {
phone: this.formData.phone, apiComfirmCode({
code: this.formData.code, phone: this.formData.phone,
}) code: this.formData.code,
.then((res) => { })
this.step = 2 .then((res) => {
clearInterval(this.inter) this.step = 2
this.waitTime = 0 clearInterval(this.inter)
}) this.waitTime = 0
.catch((err) => { })
console.log(err) .catch((err) => {
}) console.log(err)
}, })
secondSubmit() { },
apiRebindPhone({ secondSubmit() {
phone: this.formData.phone2, apiRebindPhone({
code: this.formData.code2, phone: this.formData.phone2,
}) code: this.formData.code2,
.then((res) => { })
this.$util.toast('绑定成功') .then((res) => {
uni.clearStorageSync() this.$util.toast('绑定成功')
setTimeout(() => { uni.clearStorageSync()
uni.redirectTo({ setTimeout(() => {
url: '/pages/user/login', uni.redirectTo({
}) url: '/pages/user/login',
}, 1500) })
}) }, 1500)
.catch((err) => { })
console.log(err) .catch((err) => {
}) console.log(err)
}, })
}, },
} },
</script> }
<style lang="scss"> </script>
.index { <style lang="scss">
padding: 20rpx; .index {
padding: 20rpx;
.submit-btn {
background: $uni-theme-color; .submit-btn {
color: #fff; background: $uni-theme-color;
} color: #fff;
}
.login-box-tips {
margin-top: 60rpx; .login-box-tips {
display: flex; margin-top: 60rpx;
justify-content: center; display: flex;
font-size: 20rpx; justify-content: center;
} font-size: 20rpx;
}
.login-box-input {
display: flex; .login-box-input {
align-items: center; display: flex;
border-bottom: 1rpx solid #f0f0f0; align-items: center;
border-bottom: 1rpx solid #f0f0f0;
.login-box-input-icon {
width: 40rpx; .login-box-input-icon {
margin-right: 40rpx; width: 40rpx;
} margin-right: 40rpx;
}
.login-box-input-main {
font-size: 28rpx; .login-box-input-main {
flex: 1; font-size: 28rpx;
height: 100rpx; flex: 1;
line-height: 100rpx; height: 100rpx;
} line-height: 100rpx;
}
.login-box-input-btn {
padding:0 40rpx; .login-box-input-btn {
margin-left: 40rpx; padding:0 40rpx;
background: $uni-theme-color; margin-left: 40rpx;
color: #fff; background: $uni-theme-color;
} color: #fff;
}
.login-box-input-img {
margin-left: 40rpx; .login-box-input-img {
background: skyblue; margin-left: 40rpx;
height: 80rpx; background: skyblue;
width: 200rpx; height: 80rpx;
} width: 200rpx;
} }
} }
</style> }
</style>

View File

@@ -1,242 +1,243 @@
<template> <template>
<Cn-page :loading="loading"> <Cn-page :loading="loading">
<view slot="body"> <view slot="body">
<view class="index"> <view class="index">
<uni-forms ref="form" :modelValue="formData" :rules="rules"> <uni-forms ref="form" :modelValue="formData" :rules="rules">
<uni-forms-item name="phone"> <uni-forms-item name="phone">
<uni-easyinput <uni-easyinput
maxlength="11" maxlength="11"
disabled disabled
type="text" type="text"
v-model="formData.showPhone" v-model="formData.showPhone"
placeholder="请输入手机号" placeholder="请输入手机号"
/> />
</uni-forms-item> </uni-forms-item>
<uni-forms-item name="code"> <uni-forms-item name="code">
<view class="login-box-input"> <view class="login-box-input">
<uni-easyinput type="number" v-model="formData.code" placeholder="请输入手机验证码" /> <uni-easyinput type="number" v-model="formData.code" placeholder="请输入手机验证码" />
<view <view
class="ml40" class="ml40"
style=" style="
margin-left: 40rpx; margin-left: 40rpx;
font-size: 28rpx; font-size: 28rpx;
color: #666; color: #666;
width: 200rpx; width: 200rpx;
text-align: center; text-align: center;
" "
v-if="waitTime > 0" v-if="waitTime > 0"
>{{ waitTime + 's后重新获取' }}</view >{{ waitTime + 's后重新获取' }}</view
> >
<button class="login-box-input-btn" v-else @click="getCode" size="mini">获取验证码</button> <button class="login-box-input-btn" v-else @click="getCode" size="mini">获取验证码</button>
</view> </view>
</uni-forms-item> </uni-forms-item>
<uni-forms-item name="password"> <uni-forms-item name="password">
<uni-easyinput type="password" v-model="formData.password" placeholder="请输入新的登录密码" /> <uni-easyinput type="password" v-model="formData.password" placeholder="请输入新的登录密码" />
</uni-forms-item> </uni-forms-item>
<uni-forms-item name="password2"> <uni-forms-item name="password2">
<uni-easyinput type="password" v-model="formData.password2" placeholder="请再次确认密码" /> <uni-easyinput type="password" v-model="formData.password2" placeholder="请再次确认密码" />
</uni-forms-item> </uni-forms-item>
</uni-forms> </uni-forms>
<button type="default" class="submit-btn" @click="submit">提交</button> <button type="default" class="submit-btn" @click="submit">提交</button>
<view class="login-box-tips"> <view class="login-box-tips">
<view style="color: #999">说明密码需要长度为8-16</view> <view style="color: #999">说明密码需要长度为8-16</view>
</view> </view>
</view> </view>
</view> </view>
</Cn-page> </Cn-page>
</template> </template>
<script> <script>
import { apiGetYms, apiModifyPsd, gongkey } from '@/common/api/user' import { apiGetYms, apiModifyPsd, gongkey } from '@/common/api/user'
import { sm2, encrypt } from '@/common/js/sm2.js' import { sm2, encrypt } from '@/common/js/sm2.js'
import { sm3Digest } from '@/common/js/sm3.js' import { sm3Digest } from '@/common/js/sm3.js'
export default { export default {
name: 'ChangePWd', name: 'ChangePWd',
data() { data() {
return { return {
loading: false, loading: false,
waitTime: 0, waitTime: 0,
// 表单数据 // 表单数据
formData: { formData: {
showPhone: '', showPhone: '',
phone: '', phone: '',
code: '', code: '',
password: '', password: '',
password2: '', password2: '',
}, },
rules: { rules: {
phone: { phone: {
rules: [ rules: [
{ {
required: true, required: true,
errorMessage: '请填写手机号', errorMessage: '请填写手机号',
}, },
], ],
}, },
code: { code: {
rules: [ rules: [
{ {
required: true, required: true,
errorMessage: '请填写验证码', errorMessage: '请填写验证码',
}, },
], ],
}, },
password: { password: {
rules: [ rules: [
{ {
required: true, required: true,
errorMessage: '请填写新密码', errorMessage: '请填写新密码',
}, },
], ],
}, },
password2: { password2: {
rules: [ rules: [
{ {
required: true, required: true,
errorMessage: '请填写确认密码', errorMessage: '请填写确认密码',
}, },
], ],
}, },
}, },
} }
}, },
onLoad() { onLoad() {
// 手机号中间四位隐藏 // 手机号中间四位隐藏
this.formData.phone = uni.getStorageSync('userInfo').user_name this.formData.phone = uni.getStorageSync('userInfo').user_name
this.formData.showPhone = this.formData.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') this.formData.showPhone = this.formData.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
}, },
methods: { methods: {
getCode() { getCode() {
uni.showLoading({ uni.showLoading({
title: '请稍等', title: '请稍等...',
}) mask: true,
apiGetYms({ })
phone: this.formData.phone, apiGetYms({
type: 2, phone: this.formData.phone,
}) type: 2,
.then((res) => { })
uni.hideLoading() .then((res) => {
console.log(res) uni.hideLoading()
this.waitTime = 60 console.log(res)
this.inter = setInterval(() => { this.waitTime = 60
if (this.waitTime == 0) { this.inter = setInterval(() => {
clearInterval(this.inter) if (this.waitTime == 0) {
} else { clearInterval(this.inter)
this.waitTime-- } else {
} this.waitTime--
}, 1000) }
}) }, 1000)
.catch((err) => { })
uni.hideLoading() .catch((err) => {
console.log(err) uni.hideLoading()
}) console.log(err)
}, })
submit() { },
this.$refs.form.validate((valid) => { submit() {
console.log(valid) this.$refs.form.validate((valid) => {
if (!valid) { console.log(valid)
if (this.formData.password != this.formData.password2) { if (!valid) {
uni.showToast({ if (this.formData.password != this.formData.password2) {
title: '两次密码不一致', uni.showToast({
icon: 'none', title: '两次密码不一致',
}) icon: 'none',
} else { })
// 密码需要长度为8-16 } else {
if (this.formData.password.length < 8 || this.formData.password.length > 16) { // 密码需要长度为8-16
uni.showToast({ if (this.formData.password.length < 8 || this.formData.password.length > 16) {
title: '密码需要长度为8-16', uni.showToast({
icon: 'none', title: '密码需要长度为8-16',
}) icon: 'none',
return })
} return
}
let loginName = encrypt(this.formData.phone)
gongkey({ loginName }).then((response) => { let loginName = encrypt(this.formData.phone)
let publicKey = response.data gongkey({ loginName }).then((response) => {
let sm3Pwd = sm3Digest(this.formData.password) let publicKey = response.data
let jiamipassword = sm2(sm3Pwd + '|' + this.formData.password, publicKey, 0) let sm3Pwd = sm3Digest(this.formData.password)
// apiPwdLogin({ let jiamipassword = sm2(sm3Pwd + '|' + this.formData.password, publicKey, 0)
// username: loginName, // apiPwdLogin({
// password: jiamipassword, // username: loginName,
// imageCode: '', // password: jiamipassword,
// grant_type: 'captcha', // imageCode: '',
// verifyCode: 0, // grant_type: 'captcha',
// }).then((res) => { // verifyCode: 0,
// this.$util.loginSuccess(res.data) // }).then((res) => {
// }) // this.$util.loginSuccess(res.data)
apiModifyPsd({ // })
phone: this.formData.phone, apiModifyPsd({
code: this.formData.code, phone: this.formData.phone,
password: jiamipassword, code: this.formData.code,
}) password: jiamipassword,
.then((res) => { })
console.log(res) .then((res) => {
uni.showToast({ console.log(res)
title: '修改成功', uni.showToast({
icon: 'none', title: '修改成功',
}) icon: 'none',
setTimeout(() => { })
uni.navigateBack({ setTimeout(() => {
delta: 1, uni.navigateBack({
}) delta: 1,
}, 1000) })
}) }, 1000)
.catch((err) => { })
console.log(err) .catch((err) => {
}) console.log(err)
}) })
} })
} }
}) }
}, })
}, },
} },
</script> }
<style lang="scss"> </script>
.index { <style lang="scss">
padding: 20rpx; .index {
padding: 20rpx;
.submit-btn {
background: $uni-theme-color; .submit-btn {
color: #fff; background: $uni-theme-color;
} color: #fff;
}
.login-box-tips {
margin-top: 60rpx; .login-box-tips {
display: flex; margin-top: 60rpx;
justify-content: center; display: flex;
font-size: 20rpx; justify-content: center;
} font-size: 20rpx;
}
.login-box-input {
display: flex; .login-box-input {
align-items: center; display: flex;
border-bottom: 1rpx solid #f0f0f0; align-items: center;
border-bottom: 1rpx solid #f0f0f0;
.login-box-input-icon {
width: 40rpx; .login-box-input-icon {
margin-right: 40rpx; width: 40rpx;
} margin-right: 40rpx;
}
.login-box-input-main {
font-size: 28rpx; .login-box-input-main {
flex: 1; font-size: 28rpx;
height: 100rpx; flex: 1;
line-height: 100rpx; height: 100rpx;
} line-height: 100rpx;
}
.login-box-input-btn {
padding:0 40rpx; .login-box-input-btn {
margin-left: 40rpx; padding: 0 40rpx;
background: $uni-theme-color; margin-left: 40rpx;
color: #fff; background: $uni-theme-color;
} color: #fff;
}
.login-box-input-img {
margin-left: 40rpx; .login-box-input-img {
background: skyblue; margin-left: 40rpx;
height: 80rpx; background: skyblue;
width: 200rpx; height: 80rpx;
} width: 200rpx;
} }
} }
</style> }
</style>

View File

@@ -114,7 +114,8 @@ export default {
return this.$util.toast('请输入手机号!') return this.$util.toast('请输入手机号!')
} }
uni.showLoading({ uni.showLoading({
title: '请稍等', title: '请稍等...',
mask: true,
}) })
apiGetYms({ apiGetYms({
phone: this.formData.phone, phone: this.formData.phone,

View File

@@ -1,147 +1,148 @@
<template> <template>
<view> <view>
<Cn-page :loading="loading"> <Cn-page :loading="loading">
<view slot="body"> <view slot="body">
<view class="head"> <view class="head">
<image class="head-img" :src="userInfo.avatar" v-if="userInfo.avatar"></image> <image class="head-img" :src="userInfo.avatar" v-if="userInfo.avatar"></image>
<image class="head-img" src="/static/head.png" v-else></image> <image class="head-img" src="/static/head.png" v-else></image>
<view class="head-setup"> <view class="head-setup">
<view class="head-setup-item" @click="take('album')">从相册选一张</view> <view class="head-setup-item" @click="take('album')">从相册选一张</view>
<view class="head-setup-item" @click="take('camera')">拍一张照片</view> <view class="head-setup-item" @click="take('camera')">拍一张照片</view>
</view> </view>
</view> </view>
</view> </view>
</Cn-page> </Cn-page>
<uni-popup ref="alertDialog" type="dialog"> <uni-popup ref="alertDialog" type="dialog">
<uni-popup-dialog <uni-popup-dialog
style="width: 90%; margin: 5%" style="width: 90%; margin: 5%"
cancelText="禁止" cancelText="禁止"
confirmText="允许" confirmText="允许"
title="权限说明" title="权限说明"
content='是否允许"灿能物联"使用相机?' content='是否允许"灿能物联"使用相机?'
@confirm="handleScon('camera')" @confirm="handleScon('camera')"
@close="dialogClose" @close="dialogClose"
></uni-popup-dialog> ></uni-popup-dialog>
</uni-popup> </uni-popup>
<uni-popup ref="message" type="message"> <uni-popup ref="message" type="message">
<uni-popup-message type="info" :duration="0" style="width: 90%; margin: 5%"> <uni-popup-message type="info" :duration="0" style="width: 90%; margin: 5%">
<view style="color: #909399; font-style: 16px">相机权限使用说明:</view> <view style="color: #909399; font-style: 16px">相机权限使用说明:</view>
<view style="color: #6c6c6c; margin-top: 3rpx"> 用于拍照上传头像!</view> <view style="color: #6c6c6c; margin-top: 3rpx"> 用于拍照上传头像!</view>
</uni-popup-message> </uni-popup-message>
</uni-popup> </uni-popup>
<yk-authpup ref="authpup" type="top" @changeAuth="changeAuth" permissionID="CAMERA"></yk-authpup> <yk-authpup ref="authpup" type="top" @changeAuth="changeAuth" permissionID="CAMERA"></yk-authpup>
<yk-authpup <yk-authpup
ref="authpup1" ref="authpup1"
type="top" type="top"
@changeAuth="changeAuth" @changeAuth="changeAuth"
permissionID="WRITE_EXTERNAL_STORAGE" permissionID="WRITE_EXTERNAL_STORAGE"
></yk-authpup> ></yk-authpup>
</view> </view>
</template> </template>
<script> <script>
import { uploadImage, getImageUrl } from '@/common/api/basic' import { uploadImage, getImageUrl } from '@/common/api/basic'
import { apiUpdateUser } from '@/common/api/user' import { apiUpdateUser } from '@/common/api/user'
import ykAuthpup from '@/components/yk-authpup/yk-authpup' import ykAuthpup from '@/components/yk-authpup/yk-authpup'
export default { export default {
components: { components: {
ykAuthpup, ykAuthpup,
}, },
data() { data() {
return { return {
loading: false, loading: false,
userInfo: {}, userInfo: {},
type: '', type: '',
} }
}, },
methods: { methods: {
take(type) { take(type) {
this.type = type this.type = type
if (type == 'camera') { if (type == 'camera') {
if (plus.os.name == 'Android') { if (plus.os.name == 'Android') {
this.$refs['authpup'].open() this.$refs['authpup'].open()
//未授权 //未授权
// this.$refs.message.open() // this.$refs.message.open()
// this.$refs.alertDialog.open('bottom') // this.$refs.alertDialog.open('bottom')
} else { } else {
this.handleScon(type) this.handleScon(type)
} }
} else { } else {
if (plus.os.name == 'Android') { if (plus.os.name == 'Android') {
this.$refs['authpup1'].open() this.$refs['authpup1'].open()
//未授权 //未授权
// this.$refs.message.open() // this.$refs.message.open()
// this.$refs.alertDialog.open('bottom') // this.$refs.alertDialog.open('bottom')
} else { } else {
this.handleScon(type) this.handleScon(type)
} }
// this.handleScon(type)、 // this.handleScon(type)、
} }
}, },
changeAuth() { changeAuth() {
//这里是权限通过后执行自己的代码逻辑 //这里是权限通过后执行自己的代码逻辑
console.log('权限已授权,可执行自己的代码逻辑了') console.log('权限已授权,可执行自己的代码逻辑了')
// this.handleScon() // this.handleScon()
this.handleScon(this.type) this.handleScon(this.type)
}, },
handleScon(type) { handleScon(type) {
this.$refs.message.close() this.$refs.message.close()
uni.chooseImage({ uni.chooseImage({
count: 1, count: 1,
sizeType: ['original', 'compressed'], sizeType: ['original', 'compressed'],
sourceType: [type], sourceType: [type],
success: (res) => { success: (res) => {
uploadImage(res.tempFilePaths[0]).then((res) => { uploadImage(res.tempFilePaths[0]).then((res) => {
console.log(res) console.log(res)
let result = JSON.parse(res[1].data) console.log("🚀 ~ res:", res)
apiUpdateUser({ let result = JSON.parse(res[1].data)
headSculpture: result.data.minFileUrl, apiUpdateUser({
}).then((res) => { headSculpture: result.data.minFileUrl,
console.log(res) }).then((res) => {
this.userInfo.headSculpture = result.data.minFileUrl console.log(res)
this.userInfo.avatar = this.$config.static + result.data.minFileUrl this.userInfo.headSculpture = result.data.minFileUrl
uni.setStorageSync(this.$cacheKey.userInfo, this.userInfo) this.userInfo.avatar = this.$config.static + result.data.minFileUrl
this.$forceUpdate() uni.setStorageSync(this.$cacheKey.userInfo, this.userInfo)
}) this.$forceUpdate()
}) })
}, })
}) },
}, })
dialogClose() { },
this.$refs.message.close() dialogClose() {
}, this.$refs.message.close()
}, },
},
onLoad(options) {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo) onLoad(options) {
}, this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
} },
</script> }
<style lang="scss"> </script>
.head { <style lang="scss">
.head-img { .head {
height: 750rpx; .head-img {
width: 750rpx; height: 750rpx;
} width: 750rpx;
}
.head-setup {
position: fixed; .head-setup {
bottom: 0; position: fixed;
left: 0; bottom: 0;
width: 750rpx; left: 0;
padding-bottom: 60rpx; width: 750rpx;
background-color: #fff; padding-bottom: 60rpx;
background-color: #fff;
.head-setup-item {
height: 100rpx; .head-setup-item {
line-height: 100rpx; height: 100rpx;
text-align: center; line-height: 100rpx;
border-top: 1rpx solid #e8e8e8; text-align: center;
} border-top: 1rpx solid #e8e8e8;
} }
} }
/deep/ .uni-popup-message__box { }
border-radius: 10rpx !important; /deep/ .uni-popup-message__box {
background-color: #fff; border-radius: 10rpx !important;
} background-color: #fff;
</style> }
</style>

View File

@@ -93,7 +93,7 @@ import { sm3Digest } from '@/common/js/sm3.js'
export default { export default {
data() { data() {
return { return {
checkbox: false, checkbox: true,
loading: false, loading: false,
loginType: 'pwd', loginType: 'pwd',
phone: '', phone: '',
@@ -121,7 +121,8 @@ export default {
return this.$util.toast('请输入手机号!') return this.$util.toast('请输入手机号!')
} }
uni.showLoading({ uni.showLoading({
title: '请稍等', title: '请稍等...',
mask: true,
}) })
apiGetYms({ apiGetYms({
phone: this.phone, phone: this.phone,

View File

@@ -77,7 +77,7 @@ export default {
name: 'jiaban', name: 'jiaban',
data() { data() {
return { return {
checkbox: false, checkbox: true,
step: 1, step: 1,
loading: false, loading: false,
waitTime: 0, waitTime: 0,
@@ -135,7 +135,8 @@ export default {
return this.$util.toast('请输入手机号!') return this.$util.toast('请输入手机号!')
} }
uni.showLoading({ uni.showLoading({
title: '请稍等', title: '请稍等...',
mask: true,
}) })
apiGetYms({ apiGetYms({
phone: this.formData.phone, phone: this.formData.phone,

View File

@@ -1,57 +1,57 @@
<template> <template>
<Cn-page :loading='loading'> <Cn-page :loading='loading'>
<view slot='body'> <view slot='body'>
<view class='index'> <view class='index'>
<view class="content device" :style="{ minHeight: minHeight }"> <view class="content device" :style="{ minHeight: minHeight }">
<uni-card :title="item.name" :sub-title="item.project" :extra="item.type" padding="0" <uni-card :title="item.name" :sub-title="item.project" :extra="item.type" padding="0"
v-for="(item, index) in deviceList" :key="index" thumbnail="/static/device.png"> v-for="(item, index) in deviceList" :key="index" thumbnail="/static/device.png">
<!-- <text>{{ item.project }} {{ item.type }}</text> --> <!-- <text>{{ item.project }} {{ item.type }}</text> -->
</uni-card> </uni-card>
<uni-load-more status="nomore"></uni-load-more> <!-- <uni-load-more status="nomore"></uni-load-more> -->
</view> </view>
</view> </view>
</view> </view>
</Cn-page> </Cn-page>
</template> </template>
<script> <script>
export default { export default {
data () { data () {
return { return {
loading: false, loading: false,
deviceList: [ deviceList: [
{ {
name: '设备APF-1', name: '设备APF-1',
des: '设备描述1', des: '设备描述1',
type: '监测', type: '监测',
project: 'XXX项目1', project: 'XXX项目1',
}, },
{ {
name: '设备APF-2', name: '设备APF-2',
des: '设备描述1', des: '设备描述1',
type: '监测', type: '监测',
project: 'XXX项目1', project: 'XXX项目1',
}, },
{ {
name: '设备APF-3', name: '设备APF-3',
des: '设备描述2', des: '设备描述2',
type: '用能', type: '用能',
project: 'XXX项目2' project: 'XXX项目2'
}, },
{ {
name: '设备DVR-1', name: '设备DVR-1',
des: '设备描述3', des: '设备描述3',
type: '监测', type: '监测',
project: 'XXX项目3' project: 'XXX项目3'
} }
] ]
} }
}, },
methods: { methods: {
} }
} }
</script> </script>
<style lang='scss'> <style lang='scss'>
.index { .index {
padding: 20rpx 0; padding: 20rpx 0;
} }
</style> </style>

826
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More