9 Commits

Author SHA1 Message Date
guanj
40899e6d55 修改测试问题 2026-07-02 09:55:30 +08:00
guanj
1d73755a43 修改测试问题 2026-06-29 11:01:44 +08:00
guanj
f008bcb4b8 优化强制更新功能 2026-06-18 16:34:25 +08:00
guanj
edc5dc55aa 联调app关键指标功能 2026-06-01 20:36:04 +08:00
guanj
236ab4aa75 全局修改卡片样式 2026-06-01 13:41:05 +08:00
guanj
43c6249530 提交代码 2026-06-01 11:32:25 +08:00
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
89 changed files with 10766 additions and 6997 deletions

View File

@@ -1,11 +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) //监听推送消息
// }) // })
@@ -72,4 +72,5 @@ export default {
// .uni-page-refresh__icon { // .uni-page-refresh__icon {
// fill: #007aff !important; /* 改成你想要的颜色,比如红色 #ff0000 */ // fill: #007aff !important; /* 改成你想要的颜色,比如红色 #ff0000 */
// } // }
</style> </style>

View File

@@ -2,14 +2,14 @@
"version" : "2", "version" : "2",
"prompt" : "template", "prompt" : "template",
"title" : "服务协议和隐私政策", "title" : "服务协议和隐私政策",
"message" : "  请你务必审慎阅读、充分理解“服务协议”和“隐私政策”各条款,包括但不限于:为了更好的向你提供服务,我们需要收集你的设备标识、操作日志等信息用于分析、优化应用性能。<br/>  你可阅读<a href=\"https://pqmcn.com:8092/#/agreement\">《服务协议》</a>和<a href=\"https://pqmcn.com:8092/#/policy\">《隐私政策》</a>了解详细信息。如果你同意,请点击下面按钮开始接受我们的服务。", "message" : "  请你务必审慎阅读、充分理解“服务协议”和“隐私政策”各条款,包括但不限于:为了更好的向你提供服务,我们需要收集你的设备标识、操作日志等信息用于分析、优化应用性能。<br/>  你可阅读<a href=\"http://www.pqmcc.com:27707/#/agreement\">《服务协议》</a>和<a href=\"http://www.pqmcc.com:27707/#/policy\">《隐私政策》</a>了解详细信息。如果你同意,请点击下面按钮开始接受我们的服务。",
"buttonAccept" : "同意并接受", "buttonAccept" : "同意并接受",
"buttonRefuse" : "暂不同意", "buttonRefuse" : "暂不同意",
"hrefLoader" : "system|default", "hrefLoader" : "system|default",
"backToExit" : "false", "backToExit" : "false",
"second" : { "second" : {
"title" : "确认提示", "title" : "确认提示",
"message" : "  进入应用前,你需先同意<a href=\"https://pqmcn.com:8092/#/agreement\">《用户协议》</a>和<a href=\"https://pqmcn.com:8092/#/policy\">《隐私政策》</a>,否则将退出应用。", "message" : "  进入应用前,你需先同意<a href=\"http://www.pqmcc.com:27707/#/agreement\">《用户协议》</a>和<a href=\"http://www.pqmcc.com:27707/#/policy\">《隐私政策》</a>,否则将退出应用。",
"buttonAccept" : "同意并继续", "buttonAccept" : "同意并继续",
"buttonRefuse" : "退出应用" "buttonRefuse" : "退出应用"
}, },

View File

@@ -39,6 +39,14 @@ export const queryCsDictTree = (pid) => {
}, },
}) })
} }
// 字典树接口
export const queryStatistical = (data) => {
return request({
url: '/system-boot/csstatisticalset/queryStatistical',
method: 'post',
data: data,
})
}
// 字典树接口通过id // 字典树接口通过id
export const queryByid = (id) => { export const queryByid = (id) => {

View File

@@ -11,6 +11,7 @@ export function addFeedBack(params) {
console.log(files.length); console.log(files.length);
let data = JSON.parse(JSON.stringify(params)); let data = JSON.parse(JSON.stringify(params));
delete data.files delete data.files
console.log("🚀 ~ addFeedBack ~ files.length:", files.length)
if (files.length) { if (files.length) {
return uni.uploadFile({ return uni.uploadFile({
url: config.domain + '/cs-system-boot/feedback/addFeedBack', //仅为示例,非真实的接口地址 url: config.domain + '/cs-system-boot/feedback/addFeedBack', //仅为示例,非真实的接口地址

View File

@@ -10,7 +10,7 @@ export function getModuleState(params) {
} }
export function getBaseRealData(id) { export function getBaseRealData(id) {
return request({ return request({
url: '/cs-harmonic-boot/realData/getBaseRealData?lineId='+id, url: '/cs-harmonic-boot/realData/getBaseRealData?lineId=' + id,
method: 'post', method: 'post',
}) })
} }
@@ -47,3 +47,19 @@ export function queryAppHarmonicLine(params) {
}, },
}) })
} }
// 暂态事件波形分析
export function analyseWave(params) {
return request({
url: '/cs-harmonic-boot/event/analyseWave',
method: 'get',
params,
})
}
// App-》工程下所有监测点数据
export function getLineDataByEngineer(params) {
return request({
url: '/cs-harmonic-boot/data/getLineDataByEngineer',
method: 'post',
params,
})
}

View File

@@ -7,4 +7,5 @@ export default {
dictData: 'dictData', // 字典数据 dictData: 'dictData', // 字典数据
messageCount: 'messageCount', // 消息数量 messageCount: 'messageCount', // 消息数量
serverConfig: 'serverConfig', // 服务内容配置 serverConfig: 'serverConfig', // 服务内容配置
monitorSelectedIndicators: 'monitorSelectedIndicators', // 监测点已选展示指标
} }

View File

@@ -1,11 +1,12 @@
const debug = true // true 是连地服务端本地false 是连接线上 const debug = false // true 是连地服务端本地false 是连接线上
const development = { const development = {
domain: 'http://192.168.1.103:10215', // domain: 'http://192.168.1.103:10215',
domain: 'http://192.168.1.102:27707/api',
} }
const production = { const production = {
domain: 'https://pqmcn.com:8092/api', domain: 'http://www.pqmcc.com:27707/api',
} }
const config = debug ? development : production const config = debug ? development : production

View File

@@ -1,5 +1,6 @@
// 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.103:8083/mqtt'//mqtt地址端口, 使用emqx时一定要加mqtt // export const MQTT_IP = '192.168.1.103:38083/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

@@ -83,7 +83,10 @@ function errHandler(res) {
break break
default: default:
uni.showToast({ uni.showToast({
title: res.message || res.msg || '网络异常,请稍后再试', title:
res.message.substring(res.message.indexOf(',') + 1) ||
res.msg.substring(msg.indexOf(',') + 1) ||
'网络异常,请稍后再试',
duration: 2000, duration: 2000,
icon: 'none', icon: 'none',
}) })

View File

@@ -1,52 +1,102 @@
import { getLastData } from '../api/user.js' import { getLastData } from '../api/user.js'
/** 规范化版本号,如 v1.6.83 → [1, 6, 83] */
const normalizeVersion = (version) => {
if (!version) return []
return String(version)
.replace(/^v/i, '')
.split('.')
.map((part) => parseInt(part, 10) || 0)
}
/**
* 比较版本号
* @returns 1 远端较新需更新 | 0 相同 | -1 本地较新
*/
const compareVersion = (remote, local) => {
const remoteParts = normalizeVersion(remote)
const localParts = normalizeVersion(local)
const len = Math.max(remoteParts.length, localParts.length)
for (let i = 0; i < len; i++) {
const rv = remoteParts[i] || 0
const lv = localParts[i] || 0
if (rv > lv) return 1
if (rv < lv) return -1
}
return 0
}
/** 自定义调试基座 / HBuilder 标准基座,不走线上更新 */
const isCustomDebugBase = (appName = '') => {
return /自定义基座|custom debug|HBuilder|DCloud/i.test(appName)
}
export const checkAppUpdate = () => { export const checkAppUpdate = () => {
// #ifndef APP-PLUS
// return
// #endif
// 开发环境跳过检查 // 开发环境跳过检查
const isDev = process.env.NODE_ENV === 'development' const isDev = process.env.NODE_ENV === 'development'
// if (isDev) { if (isDev) {
console.log('开发环境,不执行更新检查') console.log('开发环境,不执行更新检查')
return return
// } }
// 自定义基座调试,跳过更新检查
// try {
// const { appName } = uni.getSystemInfoSync()
// if (isCustomDebugBase(appName)) {
// console.log('自定义基座调试中,不执行更新检查')
// return
// }
// } catch (e) {}
// 获取当前应用信息 // 获取当前应用信息
plus.runtime.getProperty(plus.runtime.appid, (info) => { plus.runtime.getProperty(plus.runtime.appid, (info) => {
// if (isCustomDebugBase(info?.name)) {
// console.log('自定义基座调试中,不执行更新检查')
// return
// }
const currentVersion = info.version const currentVersion = info.version
getLastData() getLastData()
.then((res) => { .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
}
// let res = { // 适配新的接口返回格式,默认强制更新
// data: { const { versionName, androidPath, iosPath, forceUpdate = '1' } = res.data
// versionName: 'v1.6.83', console.log('🚀 ~ checkAppUpdate ~ versionName, currentVersion:', versionName, currentVersion)
// 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 (compareVersion(versionName, currentVersion) <= 0) {
console.log('已是最新版本')
return
}
// 版本相同则不需要更新 const isForce = forceUpdate !== '0' // 默认强制更新,'0' 为可选更新
if (versionName.includes(currentVersion)) {
console.log('已是最新版本')
return
}
const isForce = forceUpdate === '1' // 字符串 '1' 表示强制更新 const iosUrl = iosPath
const iosUrl = iosPath handleUpdate({ version: versionName, androidPath, iosUrl, isForce })
})
handleUpdate({ version: versionName, androidPath, iosUrl, isForce }) .catch((err) => {
}) console.error('获取版本接口失败', err)
.catch((err) => { })
console.error('获取版本接口失败', err)
})
}) })
} }
@@ -58,9 +108,9 @@ const handleUpdate = ({ version, androidPath, iosUrl, isForce }) => {
const isIOS = plus.os.name === 'iOS' const isIOS = plus.os.name === 'iOS'
if (isAndroid) { if (isAndroid) {
handleAndroidUpdate({ androidPath, isForce }) handleAndroidUpdate({ version, androidPath, isForce })
} else if (isIOS) { } else if (isIOS) {
handleIOSUpdate({ iosUrl, isForce }) handleIOSUpdate({ version, iosUrl, isForce })
} else { } else {
console.warn('未知操作系统') console.warn('未知操作系统')
} }
@@ -69,7 +119,7 @@ const handleUpdate = ({ version, androidPath, iosUrl, isForce }) => {
/** /**
* 处理安卓更新 * 处理安卓更新
*/ */
const handleAndroidUpdate = ({ androidPath, isForce }) => { const handleAndroidUpdate = ({ version, androidPath, isForce }) => {
if (!androidPath?.length) { if (!androidPath?.length) {
console.error('未找到安卓安装包') console.error('未找到安卓安装包')
uni.showToast({ uni.showToast({
@@ -80,18 +130,18 @@ const handleAndroidUpdate = ({ androidPath, isForce }) => {
} }
const downloadUrl = androidPath const downloadUrl = androidPath
const content = isForce ? `发现新版本 ${version},请立即更新后继续使用` : `发现新版本 ${version},是否立即更新?`
uni.showModal({ uni.showModal({
title: '更新提示', title: '更新提示',
content: '发现新版本,是否立即更新?', content,
showCancel: !isForce, // 强制更新隐藏取消按钮 showCancel: false,
confirmText: '去更新', confirmText: '去更新',
cancelText: '暂不更新',
success: (modalRes) => { success: (modalRes) => {
if (modalRes.confirm) { if (modalRes.confirm) {
downloadAndInstallApk(downloadUrl) downloadAndInstallApk(downloadUrl)
} else if (isForce) { } else if (isForce) {
// 强制更新用户取消,退出应用 // 强制更新用户按返回键关闭弹窗时退出
plus.runtime.quit() plus.runtime.quit()
} }
}, },
@@ -101,7 +151,7 @@ const handleAndroidUpdate = ({ androidPath, isForce }) => {
/** /**
* 处理iOS更新 * 处理iOS更新
*/ */
const handleIOSUpdate = ({ iosUrl, isForce }) => { const handleIOSUpdate = ({ version, iosUrl, isForce }) => {
if (!iosUrl) { if (!iosUrl) {
console.error('未找到iOS下载链接') console.error('未找到iOS下载链接')
uni.showToast({ uni.showToast({
@@ -111,22 +161,23 @@ const handleIOSUpdate = ({ iosUrl, isForce }) => {
return return
} }
const content = isForce
? `发现新版本 ${version},请前往 App Store 更新后继续使用`
: `发现新版本 ${version},请前往 App Store 更新`
uni.showModal({ uni.showModal({
title: '更新提示', title: '更新提示',
content: '发现新版本,请前往 App Store 更新', content,
showCancel: !isForce, showCancel: false,
confirmText: '去更新', confirmText: '去更新',
cancelText: '暂不更新',
success: (modalRes) => { success: (modalRes) => {
if (modalRes.confirm) { if (modalRes.confirm) {
plus.runtime.openURL(iosUrl) plus.runtime.openURL(iosUrl)
}
// 强制更新时,无论确认还是取消都退出应用
if (isForce) {
setTimeout(() => { setTimeout(() => {
plus.runtime.quit() plus.runtime.quit()
}, 300) // 给跳转留一点时间 }, 300)
} else if (isForce) {
// 强制更新且用户取消,退出应用
} }
}, },
}) })
@@ -143,14 +194,22 @@ const downloadAndInstallApk = (url) => {
close: false, // 不允许用户关闭 close: false, // 不允许用户关闭
padlock: true, // 锁定屏幕 padlock: true, // 锁定屏幕
}) })
let progressClosed = false
const closeProgress = () => {
if (progressClosed) return
progressClosed = true
progressWaiting.close()
}
const options = { const options = {
filename: '_doc/update/canneng_wulian.apk', filename: '_doc/update/canneng_wulian.apk',
timeout: 120, timeout: 300,
} }
console.log('🚀 ~ downloadAndInstallApk ~ url:', url)
const downloadTask = plus.downloader.createDownload(url, options, (downloadedFile, status) => { const downloadTask = plus.downloader.createDownload(url, options, (downloadedFile, status) => {
progressWaiting.close() closeProgress()
if (status === 200) { if (status === 200) {
installApk(downloadedFile.filename, url) installApk(downloadedFile.filename, url)
@@ -161,11 +220,12 @@ const downloadAndInstallApk = (url) => {
// // 更新进度 // // 更新进度
downloadTask.addEventListener('statechanged', (task) => { downloadTask.addEventListener('statechanged', (task) => {
if (progressClosed) return
if (task.state === 3 && task.totalSize > 0) { if (task.state === 3 && task.totalSize > 0) {
const percent = ((task.downloadedSize / task.totalSize) * 100).toFixed(0) const percent = ((task.downloadedSize / task.totalSize) * 100).toFixed(0)
console.log("🚀 ~ downloadAndInstallApk ~ percent:", percent) console.log('🚀 ~ downloadAndInstallApk ~ percent:', percent)
// 直接更新 waiting 的标题,不会闪烁 // 直接更新 waiting 的标题,不会闪烁
progressWaiting.setTitle(`正在下载更新 ${percent}%`) progressWaiting.setTitle(`正在下载更新...`)
} }
}) })
@@ -197,11 +257,13 @@ const installApk = (filePath, downloadUrl) => {
uni.showModal({ uni.showModal({
title: '安装失败', title: '安装失败',
content: `安装失败:${error.message}\n请检查是否已开启安装权限`, content: `安装失败:${error.message}\n请检查是否已开启安装权限`,
showCancel: false,
confirmText: '重试', confirmText: '重试',
cancelText: '取消',
success: (res) => { success: (res) => {
if (res.confirm) { if (res.confirm) {
downloadAndInstallApk(downloadUrl) downloadAndInstallApk(downloadUrl)
} else {
plus.runtime.quit()
} }
}, },
}) })
@@ -216,11 +278,13 @@ const handleDownloadError = (downloadUrl) => {
uni.showModal({ uni.showModal({
title: '下载失败', title: '下载失败',
content: '网络异常或下载链接失效,是否重试?', content: '网络异常或下载链接失效,是否重试?',
showCancel: false,
confirmText: '重试', confirmText: '重试',
cancelText: '取消',
success: (res) => { success: (res) => {
if (res.confirm) { if (res.confirm) {
downloadAndInstallApk(downloadUrl) downloadAndInstallApk(downloadUrl)
} else {
plus.runtime.quit()
} }
}, },
}) })

View File

@@ -183,35 +183,6 @@ const validatePhoneNumber = (phone) => {
return testReg.test(phone) return testReg.test(phone)
} }
const getUserLocation = (call) => {
uni.getLocation({
type: 'wgs84',
success: function (address) {
call(address)
},
fail: (err) => {
uni.showModal({
title: '提示',
content: '定位失败,请打开定位权限',
success: function (res) {
if (res.confirm) {
uni.openSetting({
success: (resSett) => {
if (resSett.authSetting['scope.userLocation']) {
uni.getLocation({
success: (address) => {
call && call(address)
},
})
}
},
})
}
},
})
},
})
}
// 加载用户配置 // 加载用户配置
var globalConfigIsLoading = false, var globalConfigIsLoading = false,
@@ -349,7 +320,6 @@ export default {
formatTime, formatTime,
parseTime, parseTime,
h5Helper, h5Helper,
getUserLocation,
loadConfig, loadConfig,
prePage, prePage,
loginSuccess, loginSuccess,

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,13 +1,6 @@
<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"
:extra="device.isPrimaryUser == 1 ? '主设备' : '分享设备'"
padding="0"
@click="jump(device)"
class="boxClick"
:thumbnail="deviceIcon(device.runStatus)"
>
<template v-slot:title> <template v-slot:title>
<!-- 卡片标题 --> <!-- 卡片标题 -->
<view class="uni-card__header" @click="jump(device)"> <view class="uni-card__header" @click="jump(device)">
@@ -25,34 +18,38 @@
:color="device.runStatus == 1 ? '#ff3b30' : '#10B981'" :color="device.runStatus == 1 ? '#ff3b30' : '#10B981'"
:size="device.devType == 'Direct_Connected_Device' ? '35' : '40'" :size="device.devType == 'Direct_Connected_Device' ? '35' : '40'"
></uni-icons> --> ></uni-icons> -->
<Cn-icon-device <Cn-icon-device :devType="device.devType" :runStatus="device.runStatus"
:devType="device.devType" :alarmStatus="device.isAlarm ? 1 : 0"></Cn-icon-device>
:runStatus="device.runStatus"
:alarmStatus="device.isAlarm ? 1 : 0"
></Cn-icon-device>
</view> </view>
</view> </view>
<view class="uni-card__header-content"> <view class="uni-card__header-content">
<text class="uni-card__header-content-title uni-ellipsis"> <text class="uni-card__header-content-title uni-ellipsis">
{{ device.equipmentName }} {{ device.equipmentName }}
</text> </text>
<text class="uni-card__header-content-subtitle uni-ellipsis"> <!-- <text class="uni-card__header-content-subtitle uni-ellipsis">
{{ device.mac }} {{ device.mac }}
</text> </text> -->
<view class="event-desc mt4 mb8">
<text>
工程{{ device.engineeringName }}
</text>
<text>
项目{{ device.projectName }}
</text>
</view>
<view class="tagBox"> <view class="tagBox">
<text class="event-tag" :class="device.runStatus == 1 ? 'lx-tag' : 'zx-tag'">{{ <text class="event-tag" :class="device.runStatus == 1 ? 'lx-tag' : 'zx-tag'">
device.runStatus == 1 ? '离线' : '在线' {{ device.runStatus == 1 ? '离线' : '在线' }}
}}</text> </text>
<text <text class="event-tag"
class="event-tag" :class="device.devType == 'Direct_Connected_Device' ? 'zl-tag' : 'jc-tag'">
:class="device.devType == 'Direct_Connected_Device' ? 'zl-tag' : 'jc-tag'"
>
{{ device.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备' }} {{ device.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备' }}
</text> </text>
<text class="event-tag" :class="device.isPrimaryUser == 1 ? 'z-tag' : 'fx-tag'">{{ <text class="event-tag" :class="device.isPrimaryUser == 1 ? 'z-tag' : 'fx-tag'">
device.isPrimaryUser == 1 ? '设备' : '分享设备' {{ device.isPrimaryUser == 1 ? '我的设备' : '他人设备' }}
}}</text></view </text>
> </view>
</view> </view>
</view> </view>
<view class="uni-card__header-extra" style="position: relative" @click.stop> <view class="uni-card__header-extra" style="position: relative" @click.stop>
@@ -62,21 +59,21 @@
</view> </view>
<!-- <slot name="title"></slot> --> <!-- <slot name="title"></slot> -->
</template> </template>
<view class="device-body"> <!-- <view class="device-body">
<view class="device-body-item"> <view class="device-body-item">
<text>工程名称</text> <text>工程</text>
<text>{{ device.engineeringName }}</text> <text>{{ device.engineeringName }}</text>
</view> </view>
<view class="device-body-item mt6"> <view class="device-body-item mt6">
<text>项目名称</text> <text>项目</text>
<text>{{ device.projectName }}</text> <text>{{ device.projectName }}</text>
</view> </view>
<view class="device-body-item mt6" v-if="device.process == 2 || device.process == 3"> <view class="device-body-item mt6" v-if="device.process == 2 || device.process == 3">
<text>调试阶段</text> <text>调试阶段</text>
<text>{{ device.process == 2 ? '功能调试' : '出厂调试' }}</text> <text>{{ device.process == 2 ? '功能调试' : '出厂调试' }}</text>
</view> </view>
</view> </view> -->
<view class="pinToTop" v-if="device.isTop == 1"> 置顶 </view> <view class="pinToTop" v-if="device.isTop == 1"> 置顶</view>
</uni-card> </uni-card>
</template> </template>
<script> <script>
@@ -87,7 +84,8 @@ export default {
props: { props: {
device: { device: {
type: Object, type: Object,
default: () => {}, default: () => {
},
}, },
}, },
methods: { methods: {
@@ -152,6 +150,7 @@ export default {
line-height: 1.2; line-height: 1.2;
} }
} }
.uni-card { .uni-card {
/deep/ .uni-card__header-box { /deep/ .uni-card__header-box {
display: flex; display: flex;
@@ -160,25 +159,30 @@ export default {
align-items: center; align-items: center;
overflow: hidden; overflow: hidden;
} }
/deep/ .uni-card__header { /deep/ .uni-card__header {
display: flex; display: flex;
border-bottom: 2rpx #ebeef5 solid; // border-bottom: 2rpx #ebeef5 solid;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding: 20rpx 20rpx 10rpx 0; padding: 20rpx 0;
overflow: hidden; overflow: hidden;
} }
} }
.uni-card .uni-card__header .uni-card__header-content .uni-card__header-content-title { .uni-card .uni-card__header .uni-card__header-content .uni-card__header-content-title {
font-size: 30rpx; font-size: 30rpx;
color: #3a3a3a; color: #3a3a3a;
font-weight: 700; font-weight: 700;
} }
.uni-card .uni-card__header .uni-card__header-content .uni-card__header-content-subtitle { .uni-card .uni-card__header .uni-card__header-content .uni-card__header-content-subtitle {
margin-top: 15rpx;
font-size: 24rpx; font-size: 24rpx;
// margin-top: 5px; // margin-top: 5px;
color: #666666; color: #666666;
} }
.uni-card .uni-card__header .uni-card__header-avatar .uni-card__header-avatar-image { .uni-card .uni-card__header .uni-card__header-avatar .uni-card__header-avatar-image {
width: 40px; width: 40px;
height: 40px; height: 40px;
@@ -186,6 +190,7 @@ export default {
border-radius: 5px; border-radius: 5px;
margin-right: 10px; margin-right: 10px;
} }
.uni-card .uni-card__header .uni-card__header-content { .uni-card .uni-card__header .uni-card__header-content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -193,10 +198,12 @@ export default {
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
} }
.tagBox { .tagBox {
display: flex; display: flex;
gap: 15rpx; gap: 15rpx;
} }
.event-icon { .event-icon {
position: relative; position: relative;
width: 100rpx; width: 100rpx;
@@ -207,6 +214,7 @@ export default {
align-items: center; align-items: center;
margin-right: 20rpx; margin-right: 20rpx;
} }
.event-tag { .event-tag {
font-size: 22rpx; font-size: 22rpx;
padding: 2rpx 10rpx; padding: 2rpx 10rpx;
@@ -220,28 +228,34 @@ export default {
background-color: #10b98120; background-color: #10b98120;
color: #10b981; color: #10b981;
} }
.lx-tag { .lx-tag {
background-color: #ff3b3020; background-color: #ff3b3020;
color: #ff3b30; color: #ff3b30;
} }
.z-tag { .z-tag {
background-color: #2563eb20; background-color: #2563eb20;
color: #2563eb; color: #2563eb;
} }
.fx-tag { .fx-tag {
background-color: #90939920; background-color: #90939920;
color: #909399; color: #909399;
} }
.zl-tag { .zl-tag {
// background-color: #007aff20; // background-color: #007aff20;
// color: #007aff; // color: #007aff;
background-color: #007aff20; background-color: #007aff20;
color: #007aff; color: #007aff;
} }
.jc-tag { .jc-tag {
background-color: #007aff20; background-color: #007aff20;
color: #007aff; color: #007aff;
} }
.pinToTop { .pinToTop {
background-color: $uni-theme-color; background-color: $uni-theme-color;
width: 100rpx; width: 100rpx;
@@ -261,4 +275,16 @@ export default {
transform: rotate(45deg) translate(50rpx, -10rpx); transform: rotate(45deg) translate(50rpx, -10rpx);
transform-origin: top right; 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> </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

@@ -1,45 +1,45 @@
<template> <template>
<view v-html="svgHtml" class="svg-container"></view> <view v-html="svgHtml" class="svg-container"></view>
</template> </template>
<script> <script>
export default { export default {
props: { props: {
// 父组件传递的参数 // 父组件传递的参数
name: { name: {
type: String, type: String,
default: '', default: '',
},
}, },
data() { },
return {} data() {
}, return {}
computed: { },
svgHtml() { computed: {
if (this.name == '电压暂降') { svgHtml() {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100"> 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"/> <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>` </svg>`
} else if (this.name == '电压暂升') { } else if (this.name == '暂升') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100"> 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"/> <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>` </svg>`
} else if (this.name == '电压中断') { } else if (this.name == '中断') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100"> 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"/> <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>` </svg>`
} else if (this.name == '瞬态') { } else if (this.name == '瞬态') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100"> 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"/> <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>` </svg>`
} else if (this.name == '未知') { } else if (this.name == '未知') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100"> 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"/> <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> <text x="50" y="82" text-anchor="middle" font-size="18" fill="#6b7280" font-family="Arial, sans-serif" font-weight="bold">?</text>
</svg>` </svg>`
} else if (this.name == '稳态越限') { } else if (this.name == '稳态越限') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100"> return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<!-- Limit line --> <!-- Limit line -->
<line x1="5" y1="40" x2="95" y2="40" stroke="#e6a23c" stroke-width="2" stroke-dasharray="4,4"/> <line x1="5" y1="40" x2="95" y2="40" stroke="#e6a23c" stroke-width="2" stroke-dasharray="4,4"/>
@@ -70,14 +70,14 @@ export default {
</marker> </marker>
</defs> </defs>
</svg>` </svg>`
} else if (this.name == '运行告警') { } else if (this.name == '运行告警') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="40" height="40"> 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"/> <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"/> <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"/> <circle cx="50" cy="62" r="4" fill="#007aff"/>
</svg>` </svg>`
} else if (this.name == '治理设备') { } else if (this.name == '治理设备') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="38" height="38"> 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="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="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"/> <rect x="10" y="12" width="80" height="16" rx="2" ry="2" fill="#007aff30" stroke="#CCC" stroke-width="0.8"/>
@@ -95,8 +95,8 @@ export default {
<circle cx="86" cy="69" 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"/> <polygon points="88,65 86,70 84,65" fill="#007aff" opacity="0.7"/>
</svg>` </svg>`
} else if (this.name == '监测设备') { } else if (this.name == '监测设备') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="38" height="38"> return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="38" height="38">
<style> <style>
text { font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif; } text { font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif; }
</style> </style>
@@ -119,8 +119,8 @@ export default {
<text x="54" y="65" font-size="7" fill="#007aff">Ic: 125.1A</text> <text x="54" y="65" font-size="7" fill="#007aff">Ic: 125.1A</text>
</svg>` </svg>`
} else if (this.name == '报告') { } else if (this.name == '报告1') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="47" height="47"> return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="32" height="32">
<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="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"/> <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"/> <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"/>
@@ -129,18 +129,30 @@ export default {
<circle cx="70" cy="68" r="9" fill="none" stroke="#007aff" stroke-width="4"/> <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"/> <line x1="76" y1="74" x2="86" y2="84" stroke="#007aff" stroke-width="4" stroke-linecap="round"/>
</svg>` </svg>`
} } else if (this.name == '报告') {
}, return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="45" height="45">
<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: {}, },
methods: {},
} }
</script> </script>
<style scoped> <style scoped>
.svg-container { .svg-container {
width: 100rpx; width: 100rpx;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
</style> </style>

View File

@@ -12,7 +12,7 @@
:style="{ color: confirmColor }" :style="{ color: confirmColor }"
hover-class="hover-c" hover-class="hover-c"
@tap="_confirm" @tap="_confirm"
>确定</view >完成</view
> >
</view> </view>
<view class="tki-tree-bar1"> <view class="tki-tree-bar1">

View File

@@ -4,18 +4,18 @@
<view class="mask" v-if="show" @tap="show = false" @touchmove.stop.prevent></view> <view class="mask" v-if="show" @tap="show = false" @touchmove.stop.prevent></view>
<!-- 按钮 --> <!-- 按钮 -->
<view class="major-box" :class="{ show: show }"> <view class="major-box" :class="{ show: show }">
<view <view class="click-btn" v-if="!show" @tap="show = !show" draggable="true">
class="click-btn"
v-if="!show"
@tap="show = !show"
draggable="true"
> <!-- <view>&lt;&nbsp;</view> -->
<!-- @touchstart="touchstart" <uni-icons type="left" size="26" color="#645555"></uni-icons>
@touchmove.stop.prevent="touchmove" -->
<view>&lt;&nbsp;</view>
</view> </view>
<view class="nav-box" v-if="show" style="max-width: 320px;"> <view class="nav-box" v-if="show" style="max-width: 320px;">
<view class="click-btn click-btn-right" @tap="show = !show" draggable="true">
<!-- <view>&gt;&nbsp;</view> -->
<uni-icons type="right" size="26" color="#645555"></uni-icons>
</view>
<view class="nav-box-list">
<view class="nav-btn" v-for="(btn, index) in btnList" :key="index" @tap="clickBtn(btn)"> <view class="nav-btn" v-for="(btn, index) in btnList" :key="index" @tap="clickBtn(btn)">
<view class="nav-icon"> <view class="nav-icon">
<image class="icon" :src="btn.iconPath"></image> <image class="icon" :src="btn.iconPath"></image>
@@ -23,6 +23,7 @@
<view class="nav-text">{{ btn.text }}</view> <view class="nav-text">{{ btn.text }}</view>
</view> </view>
</view> </view>
</view>
</view> </view>
</view> </view>
</template> </template>
@@ -40,7 +41,7 @@ export default {
show: false, // 是否显示 show: false, // 是否显示
deviationTop: 0, // 偏移量 deviationTop: 0, // 偏移量
windowHeight: uni.getSystemInfoSync().windowHeight, // 视图高度 windowHeight: uni.getSystemInfoSync().windowHeight, // 视图高度
// btnList: [ // btnList1: [
// // 所有按钮 // // 所有按钮
// { // {
// text: '首页', // text: '首页',
@@ -84,7 +85,7 @@ export default {
// 点击按钮 // 点击按钮
clickBtn: function (type) { clickBtn: function (type) {
// console.log(`123`, type) // console.log(`123`, type)
this.$emit('trigger',type) this.$emit('trigger', type)
}, },
// 拖动开始,记录一下偏移量 // 拖动开始,记录一下偏移量
touchstart: function (e) { touchstart: function (e) {
@@ -142,51 +143,71 @@ export default {
.nav-box { .nav-box {
background-color: #fff; background-color: #fff;
border-radius: 0 0 0 5px; border-radius: 0 0 0 5px;
padding: 5px 0;
} }
.click-btn { .click-btn {
width: 20px; display: flex;
height: 40px; align-items: center;
background-color: #999; justify-content: center;
width: 30px;
min-height: 40px;
height: 100%;
background-color: #d8d7d7;
color: #fff; color: #fff;
opacity: 0.8; opacity: 0.8;
text-align: center; text-align: center;
border-radius: 50px 0 0 50px; border-radius: 50px 0 0 50px;
padding: 6px 0; padding: 6px 0;
font-weight: 700;
} }
.click-btn uni-view { .click-btn uni-view {
line-height: 40px; line-height: 40px;
font-size: 12px; font-size: 15px;
} }
.click-btn view { .click-btn view {
padding-left: 8px; padding-left: 8px;
} }
.click-btn-right {
background-color: #d8d7d7;
margin-left: 5px;
}
/* 按钮盒子 */ /* 按钮盒子 */
.nav-box { .nav-box {
display: flex; display: flex;
flex-wrap: wrap;
text-align: center; text-align: center;
padding-left: 20px; align-items: center;
/* justify-content: center; */
background-color: #d8d7d7; background-color: #d8d7d7;
color: #000; color: #000;
font-size: 12rpx; font-size: 12rpx;
/* opacity: 0.8; */
text-align: center; text-align: center;
border-radius: 50px 0 0 50px; border-radius: 50px 0 0 50px;
}
/* border-width: 0px; */ .nav-box-list{
display: flex;
flex-wrap: wrap;
text-align: center;
align-items: center;
gap: 8px 0;
background-color: #d8d7d7;
color: #000;
font-size: 12rpx;
text-align: center;
} }
.nav-btn { .nav-btn {
/* flex: 1; */ /* flex: 1; */
border: 0px #000 solid; border: 0px #000 solid;
min-width: 63px; min-width: 55px;
padding: 5px 0 5px 0;
} }
.icon { .icon {

View File

@@ -2,8 +2,8 @@
"name" : "灿能物联", "name" : "灿能物联",
"appid" : "__UNI__88BC25B", "appid" : "__UNI__88BC25B",
"description" : "", "description" : "",
"versionName" : "1.6.82", "versionName" : "2.0.1",
"versionCode" : 170, "versionCode" : 176,
"transformPx" : false, "transformPx" : false,
"sassImplementationName" : "node-sass", "sassImplementationName" : "node-sass",
/* 5+App */ /* 5+App */
@@ -46,6 +46,7 @@
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>", "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>", "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.INTERNET\"/>", "<uses-permission android:name=\"android.permission.INTERNET\"/>",
"<uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>", "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>", "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>", "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
@@ -124,7 +125,10 @@
"setting" : { "setting" : {
"urlCheck" : false "urlCheck" : false
}, },
"usingComponents" : true "usingComponents" : true,
"unipush" : {
"enable" : false
}
}, },
"mp-alipay" : { "mp-alipay" : {
"usingComponents" : true "usingComponents" : true
@@ -138,8 +142,9 @@
"proxy" : { "proxy" : {
"/api" : { "/api" : {
"https" : true, "https" : true,
// "target" : "https://pqmcn.com:8092/api", "target" : "http://www.pqmcc.com:27707/api",
"target" : "http://192.168.1.103:10215", // "target" : "http://192.168.1.102:27707/api",
// "target" : "http://192.168.1.103:10215",
"changOrigin" : true, "changOrigin" : true,
"pathRewrite" : { "pathRewrite" : {
"/api" : "" "/api" : ""
@@ -152,7 +157,7 @@
"base" : "" "base" : ""
}, },
"unipush" : { "unipush" : {
"enable" : false "enable" : true
}, },
"sdkConfigs" : { "sdkConfigs" : {
"maps" : {} "maps" : {}

View File

@@ -118,7 +118,26 @@
{ {
"path": "pages/mine/setupMessage", "path": "pages/mine/setupMessage",
"style": { "style": {
"navigationBarTitleText": "个性化推荐" "navigationBarTitleText": "推送通知配置"
}
},
{
"path": "pages/index/comp/monitoringPoint",
"style": {
"navigationBarTitleText": "关键指标概览",
"enablePullDownRefresh": true,
"pullToRefresh": {
"support":true,
"style": "circle",
"color":"#007aff"
}
}
},
{
"path": "pages/index/comp/targetInfo",
"style": {
"navigationBarTitleText": "指标详情"
} }
}, },
{ {
@@ -215,13 +234,13 @@
{ {
"path": "pages/device/APF/about", "path": "pages/device/APF/about",
"style": { "style": {
"navigationBarTitleText": "关于" "navigationBarTitleText": "详情"
} }
}, },
{ {
"path": "pages/device/DVR/about", "path": "pages/device/DVR/about",
"style": { "style": {
"navigationBarTitleText": "关于" "navigationBarTitleText": "详情"
} }
}, },
{ {
@@ -420,18 +439,14 @@
"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": {

View File

@@ -1,91 +1,70 @@
<template> <template>
<view> <view>
<uni-load-more status="loading" v-if="IOData.length == 0"></uni-load-more> <uni-load-more status="loading" v-if="IOData.length == 0"></uni-load-more>
<view class="basic" v-else> <view class="basic mt10" v-else>
<view class="grid-card"> <view class="params-wrap">
<view class="grid-card-title">温度</view> <view class="section-title-row">
<view class="grid-card-content-4"> <view class="section-title">
<template v-for="item in renderData"> <view class="grid-card-title-with-icon"></view>
<view class="item item-title" <text>温度</text>
>{{ item[0].clDid }} </view>
<template v-if="item[0].clDid"> (°C)</template> </view>
<view class="params-section">
<view
v-for="(rowItems, rowIdx) in chunkedChildren(temperatureCards)"
:key="'temp-' + 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="param-value-wrap">
<text class="param-value">{{ child.value }}</text>
</view>
</view> </view>
<view class="item item-title" </view>
>{{ item[1].clDid }}
<template v-if="item[1].clDid"> (°C)</template>
</view>
<view class="item item-title"
>{{ item[2].clDid }}
<template v-if="item[2].clDid"> (°C)</template>
</view>
<view class="item item-title"
>{{ item[3].clDid }}
<template v-if="item[3].clDid"> (°C)</template>
</view>
<view class="item">{{ item[0].clDid ? Math.round(item[0].value) || '-' : '' }}</view>
<view class="item">{{ item[1].clDid ? Math.round(item[1].value) || '-' : '' }}</view>
<view class="item">{{ item[2].clDid ? Math.round(item[2].value) || '-' : '' }}</view>
<view class="item">{{ item[3].clDid ? Math.round(item[3].value) || '-' : '' }}</view>
</template>
</view> </view>
</view> </view>
<!-- 运维管理员工程用户 可看 -->
<view <view class="params-wrap" v-if="showModuleSection">
class="grid-card" <view class="section-title-row">
v-if="userInfo.authorities == 'operation_manager' || userInfo.authorities == 'engineering_user'" <view class="section-title">
> <view class="grid-card-title-with-icon"></view>
<view class="grid-card-title">状态</view> <text>状态</text>
<view class="grid-card-content-4"> </view>
<template v-for="(item, index) in moduleData"> </view>
<view class="item item-title" <view class="params-section">
>{{ item[0].moduleName }} <view
<template v-if="item[0].moduleName"></template> v-for="(rowItems, rowIdx) in chunkedChildren(moduleCards)"
:key="'module-' + 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="param-value-wrap">
<text
class="param-value"
:class="{ 'param-value--offline': child.value === '离线' }"
>{{ child.value }}</text>
</view>
</view> </view>
<view class="item item-title" </view>
>{{ item[1].moduleName }}
<template v-if="item[1].moduleName"></template>
</view>
<view class="item item-title"
>{{ item[2].moduleName }}
<template v-if="item[2].moduleName"></template>
</view>
<view class="item item-title"
>{{ item[3].moduleName }}
<template v-if="item[3].moduleName"></template>
</view>
<!-- <uni-tag :text="item[0].moduleState" :type=" item[0].moduleState=='离线'?'error' : 'success'" /> -->
<view class="item">{{ item[0].moduleState }}</view>
<view class="item">{{ item[1].moduleState }}</view>
<view class="item">{{ item[2].moduleState }}</view>
<view class="item">{{ item[3].moduleState }}</view>
</template>
</view> </view>
</view> </view>
<!-- <view class="grid-card">-->
<!-- <view class="grid-card-title">干接点</view>-->
<!-- <view class="grid-card-content-4">-->
<!-- <view class="item item-title">干接点1</view>-->
<!-- <view class="item item-title">干接点2</view>-->
<!-- <view class="item item-title"></view>-->
<!-- <view class="item item-title"></view>-->
<!-- <view class="item">正常</view>-->
<!-- <view class="item">正常</view>-->
<!-- <view class="item"></view>-->
<!-- <view class="item"></view>-->
<!-- </view>-->
<!-- </view>-->
</view> </view>
</view> </view>
</template> </template>
<script> <script>
import { getModuleState } from '@/common/api/harmonic.js' import { getModuleState } from '@/common/api/harmonic.js'
export default { export default {
props: { props: {
IOData: { IOData: {
type: Array, type: Array,
default: () => { default: () => [],
return []
},
}, },
ndid: { ndid: {
type: String, type: String,
@@ -95,70 +74,175 @@ export default {
return { return {
list: [], list: [],
userInfo: {}, userInfo: {},
flag: false,
} }
}, },
computed: { computed: {
renderData() { renderData() {
let arr = [] const arr = []
// 把IOData转换成每4个一组的二维数组 const data = this.IOData || []
for (let i = 0; i < this.IOData.length; i += 4) { for (let i = 0; i < data.length; i += 4) {
this.IOData.slice(i, i + 4).forEach((item) => { const group = data.slice(i, i + 4).map((item) => {
if (Number.isInteger(item.value) || item.value == '') { const next = { ...item }
} else { if (!Number.isInteger(next.value) && next.value !== '') {
item.value = (item.value - 0).toFixed(2) next.value = (next.value - 0).toFixed(2)
} }
return next
}) })
arr.push(this.IOData.slice(i, i + 4)) while (group.length < 4) {
} group.push({})
// 把每组的长度补齐到4
arr.forEach((item) => {
if (item.length < 4) {
let length = 4 - item.length
for (let i = 0; i < length; i++) {
item.push({})
}
} }
}) arr.push(group)
console.warn(arr) }
return arr return arr
}, },
moduleData() { moduleData() {
let arr = [] const arr = []
// 把IOData转换成每4个一组的二维数组
for (let i = 0; i < this.list.length; i += 4) { for (let i = 0; i < this.list.length; i += 4) {
arr.push(this.list.slice(i, i + 4)) const group = this.list.slice(i, i + 4)
} while (group.length < 4) {
// 把每组的长度补齐到4 group.push({})
arr.forEach((item) => {
if (item.length < 4) {
let length = 4 - item.length
for (let i = 0; i < length; i++) {
item.push({})
}
} }
}) arr.push(group)
console.warn(arr) }
return arr return arr
}, },
temperatureCards() {
const cards = []
this.renderData.forEach((row) => {
row.forEach((item) => {
if (!item.clDid) return
cards.push({
name: `${item.clDid} (°C)`,
value: Math.round(item.value) ,
})
})
})
return cards
},
moduleCards() {
const cards = []
this.moduleData.forEach((row) => {
row.forEach((item) => {
if (!item.moduleName) return
cards.push({
name: item.moduleName,
value: item.moduleState ,
})
})
})
return cards
},
showModuleSection() {
return (
(this.userInfo.authorities === 'operation_manager' ||
this.userInfo.authorities === 'engineering_user') &&
this.moduleCards.length > 0
)
},
},
mounted() {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
this.info()
}, },
methods: { methods: {
info() { info() {
getModuleState({ getModuleState({
id: this.ndid, id: this.ndid,
}).then((res) => { }).then((res) => {
this.list = res.data this.list = res.data || []
}) })
}, },
}, chunkedChildren(children) {
mounted() { const result = []
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo) for (let i = 0; i < children.length; i += 2) {
result.push(children.slice(i, i + 2))
this.info() }
return result
},
}, },
} }
</script> </script>
<style lang="scss"> <style lang="scss" scoped>
.basic { .basic {
.params-wrap {
margin-bottom: 20rpx;
background-color: #fff;
border-radius: 10rpx;
overflow: hidden;
}
.section-title-row {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12rpx;
padding: 20rpx 20rpx 0;
}
.section-title {
display: flex;
align-items: center;
font-size: 30rpx;
font-weight: 600;
color: #333;
}
.grid-card-title-with-icon {
display: inline-flex;
align-items: center;
position: relative;
width: 8rpx;
height: 28rpx;
margin-right: 12rpx;
background: $uni-theme-color;
border-radius: 3rpx;
}
.params-section {
padding: 16rpx 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: #f3f3f3;
border-radius: 16rpx;
padding: 16rpx 8rpx 12rpx;
}
.param-title {
font-size: 26rpx;
color: #666666;
margin-bottom: 8rpx;
padding-left: 4rpx;
}
.param-value-wrap {
display: flex;
justify-content: center;
align-items: center;
padding: 4rpx;
}
.param-value {
font-size: 28rpx;
font-weight: 700;
color: #333;
&--offline {
color: #ff3b30;
}
}
} }
</style> </style>

View File

@@ -1,98 +1,105 @@
<template> <template>
<view> <view>
<uni-load-more status="loading" v-if="basicData.length == 0"></uni-load-more> <uni-load-more status="loading" v-if="!isDataReady"></uni-load-more>
<view class="basic" v-else> <view class="basic mt10" v-else>
<view class="grid-card"> <view class="params-wrap" v-for="(section, ind) in sections" :key="section.title">
<view class="grid-card-title">电网电流</view> <view class="section-title-row">
<view class="grid-card-content-3"> <view class="section-title">
<view class="item item-title">名称</view> <view class="grid-card-title-with-icon"></view>
<view class="item item-title">有效值(A)</view> <text>{{ section.title }}</text>
<view class="item item-title">畸变率(%)</view> </view>
<template v-for="(item, index) in renderData.电网电流"> <view class="legend-row" v-if="ind == 0">
<view class="item">{{ item.phase }}</view> <view class="legend-item" v-for="phase in phaseColors" :key="phase.name">
<view class="item">{{ <view class="legend-dot" :style="{ background: phase.color }" />
item['Apf_RmsI_Sys(A)'] > 0 ? item['Apf_RmsI_Sys(A)'].toFixed(2) : item['Apf_RmsI_Sys(A)'] <text class="legend-text">{{ phase.name }}</text>
}}</view> </view>
<view class="item">{{ </view>
item['Apf_ThdA_Sys(%)'] > 0 ? item['Apf_ThdA_Sys(%)'].toFixed(2) : item['Apf_ThdA_Sys(%)']
}}</view>
</template>
</view> </view>
</view> <view class="params-section">
<view class="grid-card"> <view v-for="(rowItems, rowIdx) in chunkedChildren(getSectionCards(section))" :key="rowIdx"
<view class="grid-card-title">电网电压</view> class="double-row">
<view class="grid-card-content-4"> <view v-for="(child, childIdx) in rowItems" :key="childIdx" class="param-group">
<view class="item item-title">名称</view> <view class="param-title">
<view class="item item-title">电压(V)</view> <text>{{ child.name }}</text>
<view class="item item-title">频率(Hz)</view> </view>
<view class="item item-title">畸变率(%)</view> <view class="phase-vertical">
<template v-for="(item, index) in renderData.电网电压"> <view class="phase-item-vertical">
<view class="item">{{ item.phase }}</view> <text class="phase-value-vertical" :style="{ color: phaseColors[0].color }">{{
<view class="item">{{ child.A
item['Apf_PhV_Sys(V)'] > 0 ? item['Apf_PhV_Sys(V)'].toFixed(2) : item['Apf_PhV_Sys(V)'] }}</text>
}}</view> </view>
<view class="item">{{ <view class="phase-divider" />
item['Apf_Freq(Hz)'] > 0 ? item['Apf_Freq(Hz)'].toFixed(2) : item['Apf_Freq(Hz)'] <view class="phase-item-vertical">
}}</view> <text class="phase-value-vertical" :style="{ color: phaseColors[1].color }">{{
<view class="item">{{ child.B
item['Apf_ThdU_Sys(%)'] > 0 ? item['Apf_ThdU_Sys(%)'].toFixed(2) : item['Apf_ThdU_Sys(%)'] }}</text>
}}</view> </view>
</template> <view class="phase-divider" />
</view> <view class="phase-item-vertical">
</view> <text class="phase-value-vertical" :style="{ color: phaseColors[2].color }">{{
<view class="grid-card"> child.C
<view class="grid-card-title">负载电流</view> }}</text>
<view class="grid-card-content-3"> </view>
<view class="item item-title">名称</view> </view>
<view class="item item-title">有效值(A)</view> </view>
<view class="item item-title">畸变率(%)</view> </view>
<template v-for="(item, index) in renderData.负载电流">
<view class="item">{{ item.phase }}</view>
<view class="item">{{
item['Apf_RmsI_Load(A)'] > 0
? item['Apf_RmsI_Load(A)'].toFixed(2)
: item['Apf_RmsI_Load(A)']
}}</view>
<view class="item">{{
item['Apf_ThdA_Load(%)'] > 0
? item['Apf_ThdA_Load(%)'].toFixed(2)
: item['Apf_ThdA_Load(%)']
}}</view>
</template>
</view>
</view>
<view class="grid-card">
<view class="grid-card-title">补偿电流</view>
<view class="grid-card-content-3">
<view class="item item-title">名称</view>
<view class="item item-title">有效值(A)</view>
<view class="item item-title">负载率(%)</view>
<template v-for="(item, index) in renderData.补偿电流">
<view class="item">{{ item.phase }}</view>
<view class="item">{{
item['Apf_RmsI_TolOut(A)'] == 3.1415926
? '-'
: item['Apf_RmsI_TolOut(A)'] > 0
? item['Apf_RmsI_TolOut(A)'].toFixed(2)
: item['Apf_RmsI_TolOut(A)']
}}</view>
<view class="item">{{
item['load_Rate'] == 3.1415926
? '-'
: item['load_Rate'] > 0
? item['load_Rate'].toFixed(2)
: item['load_Rate']
}}</view>
</template>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
</template> </template>
<script> <script>
const SECTIONS = [
{
title: '电网电流',
dataKey: '电网电流',
metrics: [
{ label: '有效值(A)', field: 'Apf_RmsI_Sys(A)' },
{ label: '畸变率(%)', field: 'Apf_ThdA_Sys(%)' },
],
},
{
title: '电网电压',
dataKey: '电网电压',
metrics: [
{ label: '电压(V)', field: 'Apf_PhV_Sys(V)' },
{ label: '频率(Hz)', field: 'Apf_Freq(Hz)' },
{ label: '畸变率(%)', field: 'Apf_ThdU_Sys(%)' },
],
},
{
title: '负载电流',
dataKey: '负载电流',
metrics: [
{ label: '有效值(A)', field: 'Apf_RmsI_Load(A)' },
{ label: '畸变率(%)', field: 'Apf_ThdA_Load(%)' },
],
},
{
title: '补偿电流',
dataKey: '补偿电流',
metrics: [
{ label: '有效值(A)', field: 'Apf_RmsI_TolOut(A)' },
{ label: '负载率(%)', field: 'load_Rate' },
],
},
]
export default { export default {
props: {
basicData: {
type: Array,
default: () => [],
},
},
data() { data() {
return { return {
sections: SECTIONS,
phaseColors: [
{ name: 'A相', color: '#DAA520' },
{ name: 'B相', color: '#2E8B57' },
{ name: 'C相', color: '#D54941' },
],
renderData: { renderData: {
电网电流: [], 电网电流: [],
电网电压: [], 电网电压: [],
@@ -102,83 +109,209 @@ export default {
}, },
} }
}, },
props: { computed: {
basicData: { isDataReady() {
type: Array, return (
default: () => { this.renderData.电网电流.length > 0 &&
return [] this.renderData.电网电压.length > 0 &&
}, this.renderData.负载电流.length > 0 &&
this.renderData.补偿电流.length > 0
)
}, },
}, },
watch: { watch: {
basicData: { basicData: {
handler: function (newVal, oldVal) { handler(newVal) {
newVal.forEach((item) => { this.renderData = {
if (item.phase === 'avg') { 电网电流: [],
return 电网电压: [],
} 负载电流: [],
let key = '' 补偿电流: [],
switch (item.statisticalName) { 未知: [],
case 'Apf_RmsI_Sys(A)': }
key = '电网电流' ; (newVal || []).forEach((item) => {
break if (item.phase === 'avg') {
case 'Apf_ThdA_Sys(%)': return
key = '电网电流' }
break const key = this.getDataKey(item.statisticalName)
case 'Apf_PhV_Sys(V)': const index = this.renderData[key].findIndex((item2) => item2.phase === item.phase)
key = '电网电压' if (index > -1) {
break this.renderData[key][index][item.statisticalName] = item.statisticalData
case 'Apf_Freq(Hz)': } else {
key = '电网电压' this.renderData[key].push({
break phase: item.phase,
case 'Apf_ThdU_Sys(%)': [item.statisticalName]: item.statisticalData,
key = '电网电压' })
break }
case 'Apf_RmsI_Load(A)':
key = '负载电流'
break
case 'Apf_ThdA_Load(%)':
key = '负载电流'
break
case 'Apf_RmsI_TolOut(A)':
key = '补偿电流'
break
case 'Apf_PhV_Sys(V)':
key = '补偿电流'
break
case 'Apf_PhV_Sys(V)':
key = '补偿电流'
break
case 'load_Rate':
key = '补偿电流'
break
default:
key = '未知'
break
}
let index = this.renderData[key].findIndex((item2) => {
return item2.phase === item.phase
}) })
if (index > -1) {
this.renderData[key][index][item.statisticalName] = item.statisticalData //
} else {
this.renderData[key].push({
phase: item.phase,
[item.statisticalName]: item.statisticalData, //,
})
}
})
console.log(this.renderData)
}, },
deep: true, deep: true,
immediate: true, immediate: true,
}, },
}, },
methods: {}, methods: {
getDataKey(statisticalName) {
switch (statisticalName) {
case 'Apf_RmsI_Sys(A)':
case 'Apf_ThdA_Sys(%)':
return '电网电流'
case 'Apf_PhV_Sys(V)':
case 'Apf_Freq(Hz)':
case 'Apf_ThdU_Sys(%)':
return '电网电压'
case 'Apf_RmsI_Load(A)':
case 'Apf_ThdA_Load(%)':
return '负载电流'
case 'Apf_RmsI_TolOut(A)':
case 'load_Rate':
return '补偿电流'
default:
return '未知'
}
},
getSectionCards(section) {
const list = this.renderData[section.dataKey] || []
return section.metrics.map((metric) => ({
name: metric.label,
A: this.getPhaseValue(list, metric.field, 'A'),
B: this.getPhaseValue(list, metric.field, 'B'),
C: this.getPhaseValue(list, metric.field, 'C'),
}))
},
getPhaseValue(list, field, phase) {
const item = list.find(
(row) => String(row.phase || '').toUpperCase() === phase,
)
return this.formatValue(item[field])
},
formatValue(value) {
if (value == 3.1415926) return '-'
if (value === undefined || value === null || value === '') return '-'
const num = Number(value)
if (Number.isNaN(num)) return value
return num > 0 ? num.toFixed(2) : num
},
chunkedChildren(children) {
const result = []
for (let i = 0; i < children.length; i += 2) {
result.push(children.slice(i, i + 2))
}
return result
},
},
} }
</script> </script>
<style lang="scss"> <style lang="scss" scoped>
.basic { .basic {
.params-wrap {
margin-bottom: 20rpx;
background-color: #fff;
border-radius: 10rpx;
overflow: hidden;
}
.section-title-row {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12rpx;
padding: 20rpx 20rpx 0;
}
.section-title {
display: flex;
align-items: center;
font-size: 30rpx;
font-weight: 600;
color: #333;
}
.grid-card-title-with-icon {
display: inline-flex;
align-items: center;
position: relative;
width: 8rpx;
height: 28rpx;
margin-right: 12rpx;
background: $uni-theme-color;
border-radius: 3rpx;
}
.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;
}
.params-section {
padding: 16rpx 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: #f3f3f3;
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: 26rpx;
font-weight: 700;
}
.phase-divider {
width: 1px;
background: #d2d2d2;
margin: 8rpx 0;
}
} }
</style> </style>

View File

@@ -1,60 +1,92 @@
<template> <template>
<view> <view>
<uni-load-more status="loading" v-if="basicData.length == 0"></uni-load-more> <uni-load-more status="loading" v-if="!isDataReady"></uni-load-more>
<view class="basic" v-else> <view class="basic mt10" v-else>
<view class="grid-card"> <view class="params-wrap" v-for="(section, ind) in sections" :key="section.title">
<view class="grid-card-title">电网侧</view> <view class="section-title-row">
<view class="grid-card-content-5"> <view class="section-title">
<view class="item item-title">名称</view> <view class="grid-card-title-with-icon"></view>
<view class="item item-title">有功功率(kW)</view> <text>{{ section.title }}</text>
<view class="item item-title">无功功率(kVar)</view> </view>
<view class="item item-title">视在功率(kVA)</view> <view class="legend-row" v-if="ind == 0">
<view class="item item-title">功率因数</view> <view class="legend-item" v-for="phase in phaseColors" :key="phase.name">
<template v-for="(item, index) in renderData.电网侧"> <view class="legend-dot" :style="{ background: phase.color }" />
<view class="item">{{ item.phase }}</view> <text class="legend-text">{{ phase.name }}</text>
<view class="item"
>{{ item['Apf_P_Sys(W)'] == '-' ? '-' : (item['Apf_P_Sys(W)'] / 1000).toFixed(2) }}
</view> </view>
<view class="item" </view>
>{{ item['Apf_Q_Sys(Var)'] == '-' ? '-' : (item['Apf_Q_Sys(Var)'] / 1000).toFixed(2) }}
</view>
<view class="item"
>{{ item['Apf_S_Sys(VA)'] == '-' ? '-' : (item['Apf_S_Sys(VA)'] / 1000).toFixed(2) }}
</view>
<view class="item">{{ item['Apf_PF_Sys(null)'] || '-' }}</view>
</template>
</view> </view>
</view> <view class="params-section">
<view class="grid-card"> <view v-for="(rowItems, rowIdx) in chunkedChildren(getSectionCards(section))" :key="rowIdx"
<view class="grid-card-title">负载侧</view> class="double-row">
<view class="grid-card-content-5"> <view v-for="(child, childIdx) in rowItems" :key="childIdx" class="param-group">
<view class="item item-title">名称</view> <view class="param-title">
<view class="item item-title">有功功率(kW)</view> <text>{{ child.name }}</text>
<view class="item item-title">无功功率(kVar)</view> </view>
<view class="item item-title">视在功率(kVA)</view> <view class="phase-vertical">
<view class="item item-title">功率因数</view> <view class="phase-item-vertical">
<template v-for="(item, index) in renderData.负载侧"> <text class="phase-value-vertical" :style="{ color: phaseColors[0].color }">{{
<view class="item">{{ item.phase }}</view> child.A
<view class="item" }}</text>
>{{ item['Apf_P_Load(W)'] == '-' ? '-' : (item['Apf_P_Load(W)'] / 1000).toFixed(2) }} </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 class="item">{{ </view>
item['Apf_Q_Load(Var)'] == '-' ? '-' : (item['Apf_Q_Load(Var)'] / 1000).toFixed(2)
}}</view>
<view class="item"
>{{ item['Apf_S_Load(VA)'] == '-' ? '-' : (item['Apf_S_Load(VA)'] / 1000).toFixed(2) }}
</view>
<view class="item">{{ item['Apf_PF_Load(null)'] || '-' }}</view>
</template>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
</template> </template>
<script> <script>
const SECTIONS = [
{
title: '电网侧',
dataKey: '电网侧',
metrics: [
{ label: '有功功率(kW)', field: 'Apf_P_Sys(W)', divide: 1000 },
{ label: '无功功率(kVar)', field: 'Apf_Q_Sys(Var)', divide: 1000 },
{ label: '视在功率(kVA)', field: 'Apf_S_Sys(VA)', divide: 1000 },
{ label: '功率因数', field: 'Apf_PF_Sys(null)' },
],
},
{
title: '负载侧',
dataKey: '负载侧',
metrics: [
{ label: '有功功率(kW)', field: 'Apf_P_Load(W)', divide: 1000 },
{ label: '无功功率(kVar)', field: 'Apf_Q_Load(Var)', divide: 1000 },
{ label: '视在功率(kVA)', field: 'Apf_S_Load(VA)', divide: 1000 },
{ label: '功率因数', field: 'Apf_PF_Load(null)' },
],
},
]
export default { export default {
props: {
basicData: {
type: Array,
default: () => [],
},
},
data() { data() {
return { return {
sections: SECTIONS,
phaseColors: [
{ name: 'A相', color: '#DAA520' },
{ name: 'B相', color: '#2E8B57' },
{ name: 'C相', color: '#D54941' },
],
renderData: { renderData: {
电网侧: [], 电网侧: [],
负载侧: [], 负载侧: [],
@@ -62,74 +94,210 @@ export default {
}, },
} }
}, },
props: { computed: {
basicData: { isDataReady() {
type: Array, return this.renderData.电网侧.length > 0 && this.renderData.负载侧.length > 0
default: () => {
return []
},
}, },
}, },
watch: { watch: {
basicData: { basicData: {
handler: function (newVal, oldVal) { handler(newVal) {
newVal.forEach((item) => { this.renderData = {
if (item.phase === 'avg') { 电网侧: [],
return 负载侧: [],
} 未知: [],
let key = '' }
switch (item.statisticalName) { ; (newVal || []).forEach((item) => {
case 'Apf_P_Sys(W)': if (item.phase === 'avg') {
key = '电网侧' return
break }
case 'Apf_Q_Sys(Var)': const key = this.getDataKey(item.statisticalName)
key = '电网侧' const index = this.renderData[key].findIndex((item2) => item2.phase === item.phase)
break if (index > -1) {
case 'Apf_S_Sys(VA)': this.renderData[key][index][item.statisticalName] = this.normalizeStatisticalData(
key = '电网侧' item.statisticalData,
break )
case 'Apf_PF_Sys(null)': } else {
key = '电网侧' this.renderData[key].push({
break phase: item.phase,
case 'Apf_P_Load(W)': [item.statisticalName]: this.normalizeStatisticalData(item.statisticalData),
key = '负载侧' })
break }
case 'Apf_Q_Load(Var)':
key = '负载侧'
break
case 'Apf_S_Load(VA)':
key = '负载侧'
break
case 'Apf_PF_Load(null)':
key = '负载侧'
break
default:
key = '未知'
break
}
let index = this.renderData[key].findIndex((item2) => {
return item2.phase === item.phase
}) })
if (index > -1) {
this.renderData[key][index][item.statisticalName] = item.statisticalData || '-'
} else {
this.renderData[key].push({
phase: item.phase,
[item.statisticalName]: item.statisticalData || '-',
})
}
})
console.log(this.renderData)
}, },
deep: true, deep: true,
immediate: true, immediate: true,
}, },
}, },
methods: {}, methods: {
getDataKey(statisticalName) {
switch (statisticalName) {
case 'Apf_P_Sys(W)':
case 'Apf_Q_Sys(Var)':
case 'Apf_S_Sys(VA)':
case 'Apf_PF_Sys(null)':
return '电网侧'
case 'Apf_P_Load(W)':
case 'Apf_Q_Load(Var)':
case 'Apf_S_Load(VA)':
case 'Apf_PF_Load(null)':
return '负载侧'
default:
return '未知'
}
},
getSectionCards(section) {
const list = this.renderData[section.dataKey] || []
return section.metrics.map((metric) => ({
name: metric.label,
A: this.getPhaseValue(list, metric, 'A'),
B: this.getPhaseValue(list, metric, 'B'),
C: this.getPhaseValue(list, metric, 'C'),
}))
},
getPhaseValue(list, metric, phase = 'A') {
const item = list.find((row) => String(row.phase || '').toUpperCase() === phase)
return item ? this.formatValue(item[metric.field], metric.divide) : '-'
},
normalizeStatisticalData(value) {
if (value == 3.1415926 || value === null || value === '') {
return '-'
}
return value
},
formatValue(value, divide) {
if (value == 3.1415926 || value === null || value === '' || value === '-') {
return '-'
}
const num = Number(value)
if (Number.isNaN(num)) return value
if (divide) {
// return (num / divide).toFixed(2)
return num != 0 ? (num / divide).toFixed(2) : num.toFixed(2)
}
return num.toFixed(2)
},
chunkedChildren(children) {
const result = []
for (let i = 0; i < children.length; i += 2) {
result.push(children.slice(i, i + 2))
}
return result
},
},
} }
</script> </script>
<style lang="scss"> <style lang="scss" scoped>
.basic { .basic {
.params-wrap {
margin-bottom: 20rpx;
background-color: #fff;
border-radius: 10rpx;
overflow: hidden;
}
.section-title-row {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12rpx;
padding: 20rpx 20rpx 0;
}
.section-title {
display: flex;
align-items: center;
font-size: 30rpx;
font-weight: 600;
color: #333;
}
.grid-card-title-with-icon {
display: inline-flex;
align-items: center;
position: relative;
width: 8rpx;
height: 28rpx;
margin-right: 12rpx;
background: $uni-theme-color;
border-radius: 3rpx;
}
.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;
}
.params-section {
padding: 16rpx 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: #f3f3f3;
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: 26rpx;
font-weight: 700;
}
.phase-divider {
width: 1px;
background: #d2d2d2;
margin: 8rpx 0;
}
} }
</style> </style>

View File

@@ -1,24 +1,14 @@
<template> <template>
<view> <view >
<uni-load-more status="loading" v-if="basicData.length == 0"></uni-load-more> <uni-load-more status="loading" v-if="loading"></uni-load-more>
<view v-else> <view v-else class="xieBo">
<div class="header-form"> <div class="header-form">
<uni-data-select <uni-data-select v-model="parity" :localdata="parityOption" @change="initEcharts" style="flex: 1"
v-model="parity" :clear="false"></uni-data-select>
:localdata="parityOption"
@change="initEcharts"
style="flex: 1"
:clear="false"
></uni-data-select>
<!-- <uni-data-checkbox v-model="dataRadio" :localdata="dataOptions" @change="initEcharts"></uni-data-checkbox> --> <!-- <uni-data-checkbox v-model="dataRadio" :localdata="dataOptions" @change="initEcharts"></uni-data-checkbox> -->
<uni-data-select <uni-data-select v-model="dataRadio" :localdata="dataOptions" @change="initEcharts"
v-model="dataRadio" style="flex: 2; margin-left: 20rpx" :clear="false"></uni-data-select>
:localdata="dataOptions"
@change="initEcharts"
style="flex: 2; margin-left: 20rpx"
:clear="false"
></uni-data-select>
</div> </div>
<view class="charts-box"> <view class="charts-box">
<!-- <view class="data-time">{{ time }}</view> --> <!-- <view class="data-time">{{ time }}</view> -->
@@ -54,6 +44,7 @@ export default {
value: 1, value: 1,
}, },
], ],
loading: true,
parity: 2, parity: 2,
time: '', time: '',
dataOptions: [], dataOptions: [],
@@ -216,7 +207,6 @@ export default {
watch: { watch: {
basicData: { basicData: {
handler(newVal, oldVal) { handler(newVal, oldVal) {
console.log(this.basicData)
let basicData = JSON.parse(JSON.stringify(this.basicData)) let basicData = JSON.parse(JSON.stringify(this.basicData))
// this.dataRadio = 0 // this.dataRadio = 0
this.renderData = { this.renderData = {
@@ -284,9 +274,9 @@ export default {
}) })
}) })
this.dataOptions = dataOptions this.dataOptions = dataOptions
console.log(dataOptions)
this.initEcharts()
this.initEcharts()
this.loading = false
this.time = this.$util.parseTime(this.dataTime - 8 * 60 * 60) this.time = this.$util.parseTime(this.dataTime - 8 * 60 * 60)
}, },
deep: true, deep: true,
@@ -365,13 +355,29 @@ export default {
}, 100) }, 100)
}, },
}, },
mounted() {
this.loading = true
setTimeout(() => {
this.loading = false
}, 5000)
},
} }
</script> </script>
<style lang="scss"> <style lang="scss">
.xieBo {
margin-top: 10rpx;
background-color: #fff;
padding: 20rpx;
border-radius: 10rpx;
}
.charts-box { .charts-box {
margin-top: 20rpx; margin-top: 20rpx;
height: 100vh; height: 100vh;
.data-time { .data-time {
position: absolute; position: absolute;
right: 20rpx; right: 20rpx;
@@ -379,6 +385,7 @@ export default {
font-size: 24rpx; font-size: 24rpx;
} }
} }
.header-form { .header-form {
display: flex; display: flex;
} }

View File

@@ -5,18 +5,10 @@
<view class="detail-header"> <view class="detail-header">
<Cn-htmlToImg domId="header" @renderFinish="renderFinish"> <Cn-htmlToImg domId="header" @renderFinish="renderFinish">
<view class="header" id="header" ref="header" @click="previewImg"> <view class="header" id="header" ref="header" @click="previewImg">
<img <img :src="topoImg" style="width: 375px; display: block" mode="widthFix"
:src="topoImg" @load="domLoading = false" />
style="width: 375px; display: block" <view class="point" :style="{ left: item.lat + 'px', top: item.lng + 'px' }"
mode="widthFix" v-for="(item, index) in topolodyData" :key="index">
@load="domLoading = false"
/>
<view
class="point"
:style="{ left: item.lat + 'px', top: item.lng + 'px' }"
v-for="(item, index) in topolodyData"
:key="index"
>
<view class="grid-card mt10" style="width: fit-content"> <view class="grid-card mt10" style="width: fit-content">
<view class="grid-card-content-1"> <view class="grid-card-content-1">
<view class="item">{{ item.label }}</view> <view class="item">{{ item.label }}</view>
@@ -33,8 +25,8 @@
<template v-for="(item, index) in IOData"> <template v-for="(item, index) in IOData">
<view class="item">{{ item.clDid }}</view> <view class="item">{{ item.clDid }}</view>
<view class="item" style="font-weight: 700"> <view class="item" style="font-weight: 700">
{{ Math.floor(item.value) || '-' }} {{ Math.floor(item.value) }}
<view v-if="item.value"> °C</view> <view> °C</view>
</view> </view>
</template> </template>
<template v-for="(item, index) in 3 - (IOData.length % 3)"> <template v-for="(item, index) in 3 - (IOData.length % 3)">
@@ -51,13 +43,9 @@
<text class="ml10">设备状态</text> <text class="ml10">设备状态</text>
</view> --> </view> -->
<view class="nav" style="margin-top: -10rpx"> <view class="nav" style="margin-top: -10rpx">
<view <view class="nav-menu" :class="{ 'nav-menu-active': navMenuActive == index }"
class="nav-menu" v-for="(item, index) in navMenuList" :key="index" @click="navMenuClick(index)">{{ item.text
:class="{ 'nav-menu-active': navMenuActive == index }" }}
v-for="(item, index) in navMenuList"
:key="index"
@click="navMenuClick(index)"
>{{ item.text }}
</view> </view>
</view> </view>
</view> </view>
@@ -107,22 +95,10 @@
</uni-popup> --> </uni-popup> -->
<!-- 输入框示例 --> <!-- 输入框示例 -->
<uni-popup ref="inputDialog" type="dialog"> <uni-popup ref="inputDialog" type="dialog">
<uni-popup-dialog <uni-popup-dialog ref="inputClose" type="info" mode="input" :title="dialogType" value="对话框预置提示内容!"
ref="inputClose" placeholder="请输入内容" @confirm="dialogInputConfirm">
type="info" <uni-easyinput type="textarea" :maxlength="250" autoHeight v-model="remarkContent"
mode="input" placeholder="请输入备注"></uni-easyinput>
:title="dialogType"
value="对话框预置提示内容!"
placeholder="请输入内容"
@confirm="dialogInputConfirm"
>
<uni-easyinput
type="textarea"
:maxlength="250"
autoHeight
v-model="remarkContent"
placeholder="请输入备注"
></uni-easyinput>
</uni-popup-dialog> </uni-popup-dialog>
</uni-popup> </uni-popup>
</view> </view>
@@ -140,6 +116,7 @@ import { manualAccess } from '@/common/api/accessBoot'
import { MQTT_IP, MQTT_OPTIONS } from '@/common/js/mqtt.js' import { MQTT_IP, MQTT_OPTIONS } from '@/common/js/mqtt.js'
import mqtt from 'mqtt/dist/mqtt.js' import mqtt from 'mqtt/dist/mqtt.js'
import { base64ToPath, pathToBase64 } from 'image-tools' import { base64ToPath, pathToBase64 } from 'image-tools'
import { queryByCode, queryStatistical } from '@/common/api/dictionary'
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: {
@@ -164,6 +141,7 @@ export default {
navHeight: 0, navHeight: 0,
img: '', img: '',
topoImg: '', topoImg: '',
targetLists: [],
navMenuList: [ navMenuList: [
{ {
text: '基本', text: '基本',
@@ -177,9 +155,6 @@ export default {
text: '功率', text: '功率',
id: 'a16aceae7d1565bf9f94dd7410cf9bce', id: 'a16aceae7d1565bf9f94dd7410cf9bce',
}, },
// {
// text: '波形',
// },
{ {
text: '其他', text: '其他',
}, },
@@ -195,7 +170,7 @@ export default {
// }, // },
{ {
iconPath: '/static/about.png', iconPath: '/static/about.png',
text: '关于', text: '详情',
}, },
// { // {
// iconPath: '/static/access.png', // iconPath: '/static/access.png',
@@ -260,7 +235,7 @@ export default {
uni.switchTab({ uni.switchTab({
url: '/pages/index/message1', url: '/pages/index/message1',
}) })
} else if (e.text === '关于') { } else if (e.text === '详情') {
uni.navigateTo({ url: '/pages/device/APF/about?id=' + this.devId }) uni.navigateTo({ url: '/pages/device/APF/about?id=' + this.devId })
} else if (e.text === '移交') { } else if (e.text === '移交') {
uni.navigateTo({ url: '/pages/device/transfer?id=' + this.devId }) uni.navigateTo({ url: '/pages/device/transfer?id=' + this.devId })
@@ -358,11 +333,21 @@ export default {
}, },
}) })
}, },
init() {
getTarget() {
return queryByCode('app_harmonic_code').then((res) => {
return queryStatistical({ id: res.data.id }).then((resp) => {
this.targetLists = resp.data.selectedList
})
})
},
async init() {
console.log('init') console.log('init')
this.loading = true this.loading = true
this.domLoading = true this.domLoading = true
queryTopologyDiagram(this.devId).then((res) => {
await queryTopologyDiagram(this.devId).then((res) => {
res.data.filePath = this.$config.static + res.data.filePath res.data.filePath = this.$config.static + res.data.filePath
this.deviceInfo = res.data this.deviceInfo = res.data
this.downloadImg() this.downloadImg()
@@ -371,6 +356,7 @@ export default {
let index = this.deviceInfo.appsLineTopologyDiagramPO?.findIndex((element) => { let index = this.deviceInfo.appsLineTopologyDiagramPO?.findIndex((element) => {
element.label = element.name element.label = element.name
item.label = element.name item.label = element.name
item.target = element.target
return element.linePostion === item.linePostion return element.linePostion === item.linePostion
}) })
if (index > -1) { if (index > -1) {
@@ -384,10 +370,14 @@ export default {
}) })
console.log(this.topolodyData) console.log(this.topolodyData)
if (this.client) { if (this.client) {
this.client.publish(`/zl/askDevData/${this.devId}/${this.navMenuList[0].id}`)
this.loading = false this.loading = false
} else { } else {
this.initMqtt(this.navMenuList[0].id) this.initMqtt(this.navMenuList[0].id)
} }
console.log("🚀 ~ this.client:", this.client)
}) })
}, },
renderFinish(e) { renderFinish(e) {
@@ -460,22 +450,28 @@ export default {
console.log('连接断开') console.log('连接断开')
}) })
.on('message', (topic, message) => { .on('message', (topic, message) => {
console.log('接收推送信息:', JSON.parse(message.toString()), topic) // console.log('接收推送信息:', JSON.parse(message.toString()), topic)
console.log('🚀 ~ .on ~ topic:', topic) // console.log('🚀 ~ .on ~ topic:', topic)
if (topic === `/zl/devData/${this.devId}/${id}`) { if (topic === `/zl/devData/${this.devId}/${id}`) {
const data = JSON.parse(message.toString())
if (Array.isArray(data) && !data.length) return
if ((!message.toString() || message.toString().length < 10) && this.loading) { if ((!message.toString() || message.toString().length < 10) && this.loading) {
this.$util.toast('该设备暂无数据') this.$util.toast('该设备暂无数据')
} }
this.loading = false this.loading = false
this.handlerData(JSON.parse(message.toString())) this.handlerData(data)
} else if (topic === `/zl/TemperData/${this.devId}`) { } else if (topic === `/zl/TemperData/${this.devId}`) {
const data = JSON.parse(message.toString())
if (Array.isArray(data) && !data.length) return
// this.basicData.forEach((item) => { // this.basicData.forEach((item) => {
// if (item.statisticalName === '温度' && item.phase === 'avg') { // if (item.statisticalName === '温度' && item.phase === 'avg') {
// item.statisticalData = message.toString() // item.statisticalData = message.toString()
// } // }
// }) // })
this.IOData = JSON.parse(message.toString()) this.IOData = data
// this.IOData = this.IOData.filter((item) => item.value !== 0) // this.IOData = this.IOData.filter((item) => item.value !== 0)
this.IOData.forEach((item) => { this.IOData.forEach((item) => {
if (!item.value) { if (!item.value) {
@@ -490,37 +486,60 @@ export default {
}) })
}, },
handlerData(data) { async handlerData(data) {
this.basicData = data this.basicData = data
this.topolodyData.forEach((element) => { this.topolodyData.forEach((element) => {
let arr = [] let arr = []
let list = this.targetLists.filter(key => key.dataType == element.target)
element.showKey.forEach((key) => { if (list.length > 0) {
let id = list[0]?.eleEpdPqdVOS.filter(key => key.phase == 'A')[0]?.id || ''
data.forEach((item) => { data.forEach((item) => {
if (item.statisticalName === key && item.phase === 'avg') { if (item.statisticalIndex === id && item.phase === 'avg') {
if (key === 'Apf_RmsI_TolOut(A)') {
arr.push({ arr.push({
label: '总输出电流:', label: list[0].dataTypeName.split('-')[1] + ':',
value: Math.round(item.statisticalData) + 'A', value: (item.statisticalData) + `${item.unit || ''}`,
}) })
} else {
arr.push({
label: '电流畸变率:',
value: Math.round(item.statisticalData) + '%',
})
// arr.push('电流畸变率:' + item.statisticalData + '%')
}
} }
if (item.time) { if (item.time) {
this.dataTime = item.time.seconds this.dataTime = item.time.seconds
this.time = this.$util.parseTime(this.dataTime - 8 * 60 * 60) this.time = this.$util.parseTime(this.dataTime - 8 * 60 * 60)
// console.log(11111111,this.dataTime);
} }
}) })
}) }
else {
element.showKey.forEach((key) => {
data.forEach((item) => {
if (item.statisticalName === key && item.phase === 'avg') {
if (key === 'Apf_RmsI_TolOut(A)') {
arr.push({
label: '总输出电流:',
value: (item.statisticalData) + 'A',
})
} else {
arr.push({
label: '电流畸变率:',
value: (item.statisticalData) + '%',
})
}
}
if (item.time) {
this.dataTime = item.time.seconds
this.time = this.$util.parseTime(this.dataTime - 8 * 60 * 60)
}
})
})
}
element.value = arr element.value = arr
}) })
console.log("🚀 ~ this.topolodyData:", this.topolodyData)
console.log(this.topolodyData) console.log(this.topolodyData)
this.$forceUpdate() this.$forceUpdate()
}, },
@@ -539,13 +558,16 @@ export default {
}, 1000) }, 1000)
}, },
onLoad(options) { async onLoad(options) {
await this.getTarget()
this.pageOptions = options this.pageOptions = options
this.device = JSON.parse(options.device) this.device = JSON.parse(options.device)
console.log('🚀 ~ options:', options)
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo) this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
this.devId = options.id this.devId = options.id
this.isPrimaryUser = options.isPrimaryUser this.isPrimaryUser = options.isPrimaryUser
if (this.pageOptions.process == 2 || this.pageOptions.process == 3) { if (this.pageOptions.process == 2 || this.pageOptions.process == 3) {
this.content.splice( this.content.splice(
0, 0,
@@ -588,7 +610,7 @@ export default {
}) })
} }
} }
if (this.userInfo.authorities !== 'tourist') { if (this.userInfo.authorities !== 'tourist' && this.device.isPrimaryUser === '1') {
this.content.splice(0, 0, { this.content.splice(0, 0, {
iconPath: '/static/subordinate.png', iconPath: '/static/subordinate.png',
text: '用户', text: '用户',
@@ -626,9 +648,11 @@ export default {
lng: '', lng: '',
showKey: item.showKey, //要展示的指标key showKey: item.showKey, //要展示的指标key
value: [], value: [],
target: item.target
} }
}) })
}) })
this.init() this.init()
}, },
} }
@@ -636,6 +660,7 @@ export default {
<style lang="scss"> <style lang="scss">
.detail { .detail {
// background: $uni-theme-white; // background: $uni-theme-white;
.header-bg { .header-bg {
position: absolute; position: absolute;
@@ -648,8 +673,9 @@ export default {
.header { .header {
position: relative; position: relative;
width: 375px; width: 100vw;
margin: 0 auto; display: flex;
justify-content: center;
overflow: hidden; overflow: hidden;
image { image {
@@ -666,7 +692,7 @@ export default {
z-index: 2; z-index: 2;
text-align: center; text-align: center;
color: #111; color: #111;
width: 110rpx; width: 180rpx;
font-size: 16rpx; font-size: 16rpx;
opacity: 0.8; opacity: 0.8;

View File

@@ -19,8 +19,8 @@
<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 }}</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> </view>
<view class="ml10" v-if="type === '0' || item.status != '1'"> <view class="ml10" v-if="type === '0' || item.status != '1'">

View File

@@ -98,7 +98,7 @@ export default {
// }, // },
{ {
iconPath: '/static/about.png', iconPath: '/static/about.png',
text: '关于', text: '详情',
}, },
// { // {
// iconPath: '/static/access.png', // iconPath: '/static/access.png',
@@ -130,7 +130,7 @@ export default {
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' })

View File

@@ -5,7 +5,7 @@
<uni-forms> <uni-forms>
<uni-forms-item label="设备识别码"> <uni-forms-item label="设备识别码">
<view style="display: flex"> <view style="display: flex">
<uni-easyinput type="text" v-model="formData.nDid" placeholder="请输入设备识别码"/> <uni-easyinput type="text" v-model="formData.nDid" placeholder="请输入设备识别码" />
<!-- <uni-icons <!-- <uni-icons
type="camera" type="camera"
color="#007aff" color="#007aff"
@@ -25,13 +25,8 @@
<view class="content"> <view class="content">
<uni-forms> <uni-forms>
<uni-forms-item label="项目"> <uni-forms-item label="项目">
<uni-data-select <uni-data-select v-model="formData.projectId" :localdata="projectRange"
v-model="formData.projectId" @change="queryTopologyDiagramPage" disabled :clear="false"></uni-data-select>
:localdata="projectRange"
@change="queryTopologyDiagramPage"
disabled
:clear="false"
></uni-data-select>
</uni-forms-item> </uni-forms-item>
<!-- <uni-forms-item label="型号"> <!-- <uni-forms-item label="型号">
<uni-data-select v-model="formData.type" :localdata="typeRange" <uni-data-select v-model="formData.type" :localdata="typeRange"
@@ -41,26 +36,17 @@
<view style="display: flex"> <view style="display: flex">
<view style="flex: 1"> <view style="flex: 1">
<view v-if="formData.topologyDiagramUrl"> <view v-if="formData.topologyDiagramUrl">
<image :src="formData.topologyDiagramUrl" style="width: 100%" mode="widthFix"/> <image :src="formData.topologyDiagramUrl" style="width: 100%" mode="widthFix" />
</view> </view>
<view v-else class="gplot gplot-empty center" @click="chooseGplot"> 选择拓扑图</view> <view v-else class="gplot gplot-empty center" @click="chooseGplot"> 选择拓扑图</view>
</view> </view>
<uni-icons <uni-icons type="image" color="#007aff" size="26" class="ml20"
type="image" @click="chooseGplot"></uni-icons>
color="#007aff"
size="26"
class="ml20"
@click="chooseGplot"
></uni-icons>
</view> </view>
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="监测点" v-if="pointList.length && formData.topologyDiagramUrl"> <uni-forms-item label="监测点" v-if="pointList.length && formData.topologyDiagramUrl">
<view <view class="point-item" v-for="(item2, index2) in pointList" :key="index2"
class="point-item" @click="editPoint(item2, index2)">
v-for="(item2, index2) in pointList"
:key="index2"
@click="editPoint(item2, index2)"
>
<view style="flex: 1" v-if="item2.name">{{ item2.name }}</view> <view style="flex: 1" v-if="item2.name">{{ item2.name }}</view>
<view style="flex: 1; color: #999" v-else>请选择监测点</view> <view style="flex: 1; color: #999" v-else>请选择监测点</view>
<uni-icons type="compose" color="#007aff" size="26" class="ml20"></uni-icons> <uni-icons type="compose" color="#007aff" size="26" class="ml20"></uni-icons>
@@ -68,7 +54,7 @@
</uni-forms-item> </uni-forms-item>
</uni-forms> </uni-forms>
</view> </view>
<image class="gplot-image" ref="gplot-image" :src="formData.topologyDiagramUrl" mode="widthFix"/> <image class="gplot-image" ref="gplot-image" :src="formData.topologyDiagramUrl" mode="widthFix" />
<view class="btn-wrap"> <view class="btn-wrap">
<!-- <view class="btn-wrap-item" @click="add"> 添加监测点 </view> --> <!-- <view class="btn-wrap-item" @click="add"> 添加监测点 </view> -->
<view class="btn-wrap-item" @click="submit"> 提交</view> <view class="btn-wrap-item" @click="submit"> 提交</view>
@@ -76,15 +62,9 @@
<uni-drawer ref="gplot" mode="right" :mask-click="false"> <uni-drawer ref="gplot" mode="right" :mask-click="false">
<scroll-view style="height: 100%" scroll-y="true"> <scroll-view style="height: 100%" scroll-y="true">
<view class="content"> <view class="content">
<image <image class="gplot gplot-box" mode="aspectFill" :class="{ 'gplot-active': key == activeGplot }"
class="gplot gplot-box" :src="item.filePath" @click="activeGplot = key" v-for="(item, key) in imageList"
mode="aspectFill" :key="key" />
:class="{ 'gplot-active': key == activeGplot }"
:src="item.filePath"
@click="activeGplot = key"
v-for="(item, key) in imageList"
:key="key"
/>
<view class="btn-wrap"> <view class="btn-wrap">
<view class="btn-wrap-item" @click="closeDrawer"> 取消</view> <view class="btn-wrap-item" @click="closeDrawer"> 取消</view>
<view class="btn-wrap-item ml20" @click="confirmGplot"> 确定</view> <view class="btn-wrap-item ml20" @click="confirmGplot"> 确定</view>
@@ -96,7 +76,7 @@
<scroll-view style="height: 100%" scroll-y="true"> <scroll-view style="height: 100%" scroll-y="true">
<view style="background: #fff"> <view style="background: #fff">
<view class="map-pin-box"> <view class="map-pin-box">
<image class="gplot" mode="widthFix" :src="formData.topologyDiagramUrl"/> <image class="gplot" mode="widthFix" :src="formData.topologyDiagramUrl" />
<movable-area class="map-pin-box-area"> <movable-area class="map-pin-box-area">
<movable-view :x="point.lat" :y="point.lng" direction="all" @change="dragPoint"> <movable-view :x="point.lat" :y="point.lng" direction="all" @change="dragPoint">
@@ -109,22 +89,18 @@
</view> </view>
<view class="content"> <view class="content">
<view class="content-des">请拖动图中的文字选择监测点位置</view> <view class="content-des">请拖动图中的文字选择监测点位置</view>
<uni-forms> <uni-forms labelWidth="70px">
<uni-data-select <uni-forms-item label="位置">
v-model="point.linePostion" <uni-data-select v-model="point.linePostion" :localdata="positionList"
:localdata="positionList" @change="positionChange" :clear="false" disabled></uni-data-select>
@change="positionChange" </uni-forms-item>
:clear="false" <uni-forms-item label="别名">
disabled <uni-easyinput :clearable="false" maxlength="24" type="text" v-model="point.alias"
></uni-data-select> @change="aliasChange" placeholder="别名(非必填)" />
<uni-easyinput </uni-forms-item>
:clearable="false" <uni-forms-item label="绑定指标">
class="mt20" <uni-data-select v-model="point.target" :localdata="targetList"></uni-data-select>
type="text" </uni-forms-item>
v-model="point.alias"
@change="aliasChange"
placeholder="别名(非必填)"
/>
</uni-forms> </uni-forms>
<view class="btn-wrap"> <view class="btn-wrap">
<view class="btn-wrap-item" @click="closeDrawer"> 取消</view> <view class="btn-wrap-item" @click="closeDrawer"> 取消</view>
@@ -137,9 +113,9 @@
</view> </view>
</template> </template>
<script> <script>
import {registerDevice, getModel, addDevice, queryByTopoId, updateDevice} from '@/common/api/device.js' import { registerDevice, getModel, addDevice, queryByTopoId, updateDevice } from '@/common/api/device.js'
import {getProjectList, queryTopologyDiagramPage} from '@/common/api/project.js' import { getProjectList, queryTopologyDiagramPage } from '@/common/api/project.js'
import { queryByCode, queryStatistical } from '@/common/api/dictionary'
export default { export default {
data() { data() {
return { return {
@@ -159,6 +135,9 @@ export default {
imageList: [], imageList: [],
isAdaptive: false, // 是否适应当前项目 isAdaptive: false, // 是否适应当前项目
deviceInfo: {}, deviceInfo: {},
targetLists: [],//总数据
targetList: [],//根据位置切换数据
} }
}, },
onLoad(options) { onLoad(options) {
@@ -194,18 +173,27 @@ export default {
] ]
this.projectRange = arr this.projectRange = arr
}) })
let dictData = uni.getStorageSync(this.$cacheKey.dictData) queryByCode('app_harmonic_code').then((res) => {
dictData.forEach((item) => { queryStatistical({ id: res.data.id }).then((resp) => {
if (item.code == 'Line_Position') { this.targetLists = resp.data.selectedList.map((item) => {
this.positionList = item.children.map((item) => {
return { return {
...item, ...item,
text: item.name, text: item.dataTypeName,
value: item.id, value: item.dataType,
} }
}) })
} })
}) })
const dictData = uni.getStorageSync(this.$cacheKey.dictData) || []
const linePosition = dictData.find((d) => d.code === 'Line_Position')
this.positionList = (linePosition?.children || [])
.filter((child) => child.name !== 'PCC公共点')
.map((child) => ({
...child,
text: child.name,
value: child.id,
}))
}, },
methods: { methods: {
resize() { resize() {
@@ -238,13 +226,13 @@ export default {
queryTopologyDiagramPage({ queryTopologyDiagramPage({
projectId: this.formData.projectId, projectId: this.formData.projectId,
}).then((res) => { }).then((res) => {
this.imageList = res.data.records.map(item=>{ this.imageList = res.data.records.map((item) => {
return { return {
...item, ...item,
filePath: this.$config.static + item.filePath filePath: this.$config.static + item.filePath,
} }
}) })
this.activeGplot = this.imageList.findIndex(item => { this.activeGplot = this.imageList.findIndex((item) => {
return item.id === this.deviceInfo.id return item.id === this.deviceInfo.id
}) })
}) })
@@ -253,11 +241,12 @@ export default {
aliasChange(e) { aliasChange(e) {
this.$forceUpdate() this.$forceUpdate()
}, },
positionChange(e) { positionChange(e) {
point.target = ''
this.point.name = this.positionList.find((item) => item.id == e).name this.point.name = this.positionList.find((item) => item.id == e).name
}, },
projectChange(e) { projectChange(e) { },
},
scanCode() { scanCode() {
uni.scanCode({ uni.scanCode({
success: function (res) { success: function (res) {
@@ -331,9 +320,9 @@ export default {
this.pointList.splice(index, 1) this.pointList.splice(index, 1)
}, },
editPoint(item, index) { editPoint(item, index) {
console.log(item) // console.log(item)
this.point = item this.point = item
console.log(this.point) // console.log(this.point)
this.editIndex = index this.editIndex = index
if (!this.point.alias) { if (!this.point.alias) {
let every = this.positionList.every((item) => item.name != this.point.name) let every = this.positionList.every((item) => item.name != this.point.name)
@@ -344,9 +333,23 @@ export default {
this.point.alias = '' this.point.alias = ''
} }
} }
this.settarget()
this.$refs.point.open() this.$refs.point.open()
this.$forceUpdate() this.$forceUpdate()
}, },
// 设置绑定指标
settarget(e) {
let pointName = this.positionList.find((item) => item.id == this.point.linePostion).name
this.targetList = this.targetLists.filter(item => item.dataTypeName.includes(pointName)).map((item) => {
return {
...item,
text: item.dataTypeName.split('-')[1],
value: item.dataType,
}
})
},
dragPoint(e) { dragPoint(e) {
console.log(e) console.log(e)
this.point.coordinate = { this.point.coordinate = {
@@ -369,7 +372,7 @@ export default {
} }
updateDevice({ updateDevice({
pointList: this.pointList, pointList: this.pointList,
id: this.imageList[this.activeGplot].id id: this.imageList[this.activeGplot].id,
}).then((res) => { }).then((res) => {
console.log(res) console.log(res)
this.$util.toast('提交成功') this.$util.toast('提交成功')
@@ -377,7 +380,7 @@ export default {
console.log(prePage.$vm) console.log(prePage.$vm)
prePage.$vm.init() prePage.$vm.init()
setTimeout(() => { setTimeout(() => {
uni.navigateBack({delta: 1}) uni.navigateBack({ delta: 1 })
}, 1500) }, 1500)
}) })
}, },

View File

@@ -4,7 +4,7 @@
<view class="device"> <view class="device">
<view class="nav" :style="{ top: navTabHeight + 'px' }"> <view class="nav" :style="{ top: navTabHeight + 'px' }">
<view class="nav-menu" @click="selectEngineering" <view class="nav-menu" @click="selectEngineering"
>{{ >{{
select.engineeringName select.engineeringName
? select.engineeringName.length > 6 ? select.engineeringName.length > 6
? select.engineeringName.substring(0, 6) + '...' ? select.engineeringName.substring(0, 6) + '...'
@@ -40,7 +40,7 @@
:range="projectType" :range="projectType"
range-key="text" range-key="text"
> >
<view class="nav-menu" > <view class="nav-menu">
{{ {{
select.runStatusName select.runStatusName
? select.runStatusName.length > 12 ? select.runStatusName.length > 12
@@ -67,13 +67,13 @@
v-if=" v-if="
userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user' 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>
</view> </view>
@@ -89,7 +89,6 @@
<Cn-device-card :device="item" :key="index"> <Cn-device-card :device="item" :key="index">
<template v-slot:title> <template v-slot:title>
<!-- 卡片标题 --> <!-- 卡片标题 -->
<switch <switch
v-if="transfer || share" v-if="transfer || share"
:checked="checkList.indexOf(item.equipmentId) > -1" :checked="checkList.indexOf(item.equipmentId) > -1"
@@ -97,8 +96,7 @@
@change="switchChange(item)" @change="switchChange(item)"
/> />
<view class="star-icon" v-else> <view class="star-icon" v-else>
<!-- <uni-icons type="search" size="25" color="#376cf3"></uni-icons> --> <uni-icons type="search" size="25" color="#376cf3"></uni-icons>
🔍
</view> </view>
</template> </template>
</Cn-device-card> </Cn-device-card>
@@ -110,6 +108,9 @@
></uni-load-more> ></uni-load-more>
<Cn-empty v-else></Cn-empty> <Cn-empty v-else></Cn-empty>
</view> </view>
<view class="back-top boxClick" v-show="showBackTop" @click="backToTop">
<uni-icons type="arrow-up" size="22" color="#fff"></uni-icons>
</view>
</view> </view>
</template> </template>
</Cn-page> </Cn-page>
@@ -119,6 +120,7 @@ import { getProjectList } from '@/common/api/project'
import { queryDictData } from '@/common/api/dictionary' import { queryDictData } from '@/common/api/dictionary'
import list from '@/common/js/list' import list from '@/common/js/list'
import { engineeringPinToTop } from '@/common/api/device' import { engineeringPinToTop } from '@/common/api/device'
export default { export default {
mixins: [list], mixins: [list],
data() { data() {
@@ -157,6 +159,7 @@ export default {
}, },
], ],
pageOptions: {}, pageOptions: {},
showBackTop: false,
options1: [ options1: [
{ {
text: '置顶', text: '置顶',
@@ -459,19 +462,36 @@ export default {
this[type] = true this[type] = true
} }
}, },
switchChange(e) { backToTop() {
let index = this.checkList.indexOf(e.equipmentId) uni.pageScrollTo({
if (index > -1) { scrollTop: 0,
this.checkList.splice(index, 1) duration: 300,
} else { })
this.checkList.push(e.equipmentId) this.showBackTop = false
}
}, },
}, },
onPageScroll(e) {
this.showBackTop = e.scrollTop > 200
},
} }
</script> </script>
<style lang="scss"> <style lang="scss">
/deep/ .button-group--right { /deep/ .button-group--right {
padding: 0 0 20rpx; padding: 0 0 20rpx;
} }
.back-top {
position: fixed;
right: 30rpx;
bottom: 60rpx;
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: #376cf3;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 16rpx rgba(55, 108, 243, 0.35);
z-index: 1;
}
</style> </style>

View File

@@ -6,13 +6,8 @@
<uni-forms-item label="设备识别码"> <uni-forms-item label="设备识别码">
<view style="display: flex"> <view style="display: flex">
<uni-easyinput type="text" v-model="formData.nDid" placeholder="请输入设备识别码" /> <uni-easyinput type="text" v-model="formData.nDid" placeholder="请输入设备识别码" />
<uni-icons <uni-icons type="camera" color="#007aff" size="26" class="ml20"
type="camera" @click="scanCode"></uni-icons>
color="#007aff"
size="26"
class="ml20"
@click="scanCode"
></uni-icons>
</view> </view>
</uni-forms-item> </uni-forms-item>
</uni-forms> </uni-forms>
@@ -28,36 +23,18 @@
<uni-forms> <uni-forms>
<uni-forms-item label="工程"> <uni-forms-item label="工程">
<view style="display: flex; align-items: center"> <view style="display: flex; align-items: center">
<uni-data-select <uni-data-select v-model="formData.engineeringId" :localdata="engineeringList"
v-model="formData.engineeringId" @change="engineeringChang($event, true)" :clear="false"></uni-data-select>
:localdata="engineeringList" <uni-icons type="plusempty" color="#007aff" size="26" class="ml20"
@change="engineeringChang($event, true)" @click="createEngineering"></uni-icons>
:clear="false"
></uni-data-select>
<uni-icons
type="plusempty"
color="#007aff"
size="26"
class="ml20"
@click="createEngineering"
></uni-icons>
</view> </view>
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="项目"> <uni-forms-item label="项目">
<view style="display: flex; align-items: center"> <view style="display: flex; align-items: center">
<uni-data-select <uni-data-select v-model="formData.projectId" :localdata="projectRange"
v-model="formData.projectId" @change="queryTopologyDiagramPage" :clear="false"></uni-data-select>
:localdata="projectRange" <uni-icons type="plusempty" color="#007aff" size="26" class="ml20"
@change="queryTopologyDiagramPage" @click="createProject"></uni-icons>
:clear="false"
></uni-data-select>
<uni-icons
type="plusempty"
color="#007aff"
size="26"
class="ml20"
@click="createProject"
></uni-icons>
</view> </view>
</uni-forms-item> </uni-forms-item>
@@ -69,25 +46,14 @@
</view> </view>
<view v-else class="gplot gplot-empty center" @click="chooseGplot"> 选择拓扑图</view> <view v-else class="gplot gplot-empty center" @click="chooseGplot"> 选择拓扑图</view>
</view> </view>
<uni-icons <uni-icons type="image" color="#007aff" size="26" class="ml20"
type="image" @click="chooseGplot"></uni-icons>
color="#007aff"
size="26"
class="ml20"
@click="chooseGplot"
></uni-icons>
</view> </view>
</uni-forms-item> </uni-forms-item>
<uni-forms-item <uni-forms-item label="监测点"
label="监测点" v-if="pointList.length && formData.topologyDiagramUrl && formData.projectId">
v-if="pointList.length && formData.topologyDiagramUrl && formData.projectId" <view class="point-item" v-for="(item2, index2) in pointList" :key="index2"
> @click="editPoint(item2, index2)">
<view
class="point-item"
v-for="(item2, index2) in pointList"
:key="index2"
@click="editPoint(item2, index2)"
>
<view style="flex: 1" v-if="item2.name">{{ item2.name }}</view> <view style="flex: 1" v-if="item2.name">{{ item2.name }}</view>
<view style="flex: 1; color: #999" v-else>请选择监测点</view> <view style="flex: 1; color: #999" v-else>请选择监测点</view>
<uni-icons type="compose" color="#007aff" size="26" class="ml20"></uni-icons> <uni-icons type="compose" color="#007aff" size="26" class="ml20"></uni-icons>
@@ -106,17 +72,10 @@
<uni-drawer ref="gplot" mode="right" :mask-click="false"> <uni-drawer ref="gplot" mode="right" :mask-click="false">
<scroll-view style="height: 100%" scroll-y="true"> <scroll-view style="height: 100%" scroll-y="true">
<view class="content"> <view class="content">
<image <image class="gplot gplot-box" mode="aspectFill" :class="{ 'gplot-active': key == activeGplot }"
class="gplot gplot-box" :src="item.filePath" @click="activeGplot = key" v-for="(item, key) in imageList"
mode="aspectFill" :key="key" />
:class="{ 'gplot-active': key == activeGplot }" <view v-if="imageList.length === 0" style="text-align: center" class="mt50 mb50">暂无拓扑图
:src="item.filePath"
@click="activeGplot = key"
v-for="(item, key) in imageList"
:key="key"
/>
<view v-if="imageList.length === 0" style="text-align: center" class="mt50 mb50"
>暂无拓扑图
</view> </view>
<view class="btn-wrap"> <view class="btn-wrap">
<view class="btn-wrap-item" @click="closeDrawer"> 取消</view> <view class="btn-wrap-item" @click="closeDrawer"> 取消</view>
@@ -142,22 +101,18 @@
</view> </view>
<view class="content"> <view class="content">
<view class="content-des">请拖动图中的文字选择监测点位置</view> <view class="content-des">请拖动图中的文字选择监测点位置</view>
<uni-forms> <uni-forms labelWidth="70px">
<uni-data-select <uni-forms-item label="位置">
v-model="point.position" <uni-data-select v-model="point.position" :localdata="positionList"
:localdata="positionList" @change="positionChange" disabled :clear="false"></uni-data-select>
@change="positionChange" </uni-forms-item>
disabled <uni-forms-item label="别名">
:clear="false" <uni-easyinput :clearable="false" maxlength="24" type="text" v-model="point.alias"
></uni-data-select> @change="aliasChange" placeholder="别名(非必填)" />
<uni-easyinput </uni-forms-item>
:clearable="false" <uni-forms-item label="绑定指标">
class="mt20" <uni-data-select v-model="point.target" :localdata="targetList"></uni-data-select>
type="text" </uni-forms-item>
v-model="point.alias"
@change="aliasChange"
placeholder="别名(非必填)"
/>
</uni-forms> </uni-forms>
<view class="btn-wrap"> <view class="btn-wrap">
<view class="btn-wrap-item" @click="closeDrawer"> 取消</view> <view class="btn-wrap-item" @click="closeDrawer"> 取消</view>
@@ -181,6 +136,7 @@ import {
} from '@/common/api/device.js' } from '@/common/api/device.js'
import { getProjectList, queryTopologyDiagramPage } from '@/common/api/project.js' import { getProjectList, queryTopologyDiagramPage } from '@/common/api/project.js'
import ykAuthpup from '@/components/yk-authpup/yk-authpup' import ykAuthpup from '@/components/yk-authpup/yk-authpup'
import { queryByCode, queryStatistical } from '@/common/api/dictionary'
export default { export default {
components: { components: {
ykAuthpup, ykAuthpup,
@@ -204,6 +160,8 @@ export default {
activeGplot: 0, activeGplot: 0,
positionList: [], positionList: [],
imageList: [], imageList: [],
targetLists: [],//总数据
targetList: [],//根据位置切换数据
isAdaptive: false, // 是否适应当前项目 isAdaptive: false, // 是否适应当前项目
dialogOpen: false, dialogOpen: false,
options: {}, options: {},
@@ -226,9 +184,20 @@ export default {
onLoad(o) { onLoad(o) {
this.options = o this.options = o
let dictData = uni.getStorageSync(this.$cacheKey.dictData) let dictData = uni.getStorageSync(this.$cacheKey.dictData)
queryByCode('app_harmonic_code').then((res) => {
queryStatistical({ id: res.data.id }).then((resp) => {
this.targetLists = resp.data.selectedList.map((item) => {
return {
...item,
text: item.dataTypeName,
value: item.dataType,
}
})
})
})
dictData.forEach((item) => { dictData.forEach((item) => {
if (item.code == 'Line_Position') { if (item.code == 'Line_Position') {
this.positionList = item.children.map((item) => { this.positionList = item.children.filter((child) => child.name !== 'PCC公共点').map((item) => {
return { return {
...item, ...item,
text: item.name, text: item.name,
@@ -264,6 +233,19 @@ export default {
// }) // })
}, },
methods: { methods: {
// 设置绑定指标
settarget(e) {
let pointName = this.positionList.find((item) => item.id == this.point.position).name
this.targetList = this.targetLists.filter(item => item.dataTypeName.includes(pointName)).map((item) => {
return {
...item,
text: item.dataTypeName.split('-')[1],
value: item.dataType,
}
})
},
getEngineering() { getEngineering() {
queryEngineeringPage({ pageNum: 1, pageSize: 9999 }).then((res) => { queryEngineeringPage({ pageNum: 1, pageSize: 9999 }).then((res) => {
let arr = [ let arr = [
@@ -377,7 +359,7 @@ export default {
console.log(e) console.log(e)
}, },
projectChange(e) {}, projectChange(e) { },
scanCode() { scanCode() {
if (plus.os.name == 'Android') { if (plus.os.name == 'Android') {
this.$refs['authpup'].open() this.$refs['authpup'].open()
@@ -387,7 +369,7 @@ export default {
}, },
changeAuth() { changeAuth() {
uni.scanCode({ uni.scanCode({
onlyFromCamera: true, onlyFromCamera: false,
success: (res) => { success: (res) => {
console.log('条码类型:' + res.scanType) console.log('条码类型:' + res.scanType)
console.log('条码内容:' + res.result) console.log('条码内容:' + res.result)
@@ -509,6 +491,7 @@ export default {
this.point.alias = '' this.point.alias = ''
} }
} }
this.settarget()
this.dialogOpen = true this.dialogOpen = true
this.$refs.point.open() this.$refs.point.open()
this.$forceUpdate() this.$forceUpdate()
@@ -681,4 +664,19 @@ export default {
left: -9999px; left: -9999px;
width: 375px; width: 375px;
} }
/deep/ .uni-select__input-text {
width: 170px !important;
}
/deep/ .uni-select__selector-item {
uni-text {
white-space: nowrap !important;
/* 强制不换行 */
overflow: hidden !important;
/* 溢出内容隐藏 */
text-overflow: ellipsis !important;
/* 溢出部分显示省略号 */
}
}
</style> </style>

View File

@@ -6,33 +6,31 @@
<view class="info-card-wrap"> <view class="info-card-wrap">
<view class="info-card"> <view class="info-card">
<view class="info-item"> <view class="info-item">
监测点名称<view 监测点名称<view>
><picker <picker @change="lineChange" @cancel="selectProject = false" :value="lineKey"
@change="lineChange" :range="lineList" range-key="name">
@cancel="selectProject = false"
:value="lineKey"
:range="lineList"
range-key="name"
>
<view class="nav-menu" @click="selectProject = true"> <view class="nav-menu" @click="selectProject = true">
{{ lineList[lineKey].name }} {{ lineList[lineKey].name }}
<uni-icons type="bottom" size="18" color="#fff"></uni-icons> <uni-icons type="bottom" size="18" color="#fff"></uni-icons>
</view> </picker </view>
></view> </picker>
</view>
</view> </view>
<view class="info-item"> <view class="info-item">
所属工程<view>{{ device.engineeringName }}</view> 所属工程<view>{{ device.engineeringName }}</view>
</view> </view>
<view class="info-item"> <view class="info-item">
所属项目<view>{{ device.equipmentName }}</view> 所属项目<view>{{ device.projectName }}</view>
</view>
<view class="info-item">
所属设备<view>{{ device.equipmentName }}</view>
</view> </view>
<view class="info-item status"> <view class="info-item status">
通讯状态<view 通讯状态<view class="status-normal"
class="status-normal" :style="{ color: device.runStatus == 1 ? '#ff3b30' : '#00ff88' }">{{ device.runStatus ==
:style="{ color: device.runStatus == 1 ? '#ff3b30' : '#00ff88' }" 1 ? '离线' : '在线' }}
>{{ device.runStatus == 1 ? '离线' : '在线' }}
</view> </view>
</view> </view>
</view> </view>
@@ -47,80 +45,83 @@
{{ disabled ? `刷新(${countdown}s)` : '刷新' }} {{ disabled ? `刷新(${countdown}s)` : '刷新' }}
</button> </button>
</view> </view>
<!-- 仪表盘 --> <!-- 仪表盘 -->
<view> <view>
<view class="chartBox"> <view class="chartBox">
<view> <view>
<view class="chart"> <view class="chart">
<l-echart <l-echart ref="echartV1"
ref="echartV1" @finished="initChart('echartV1', 'echartsDataV1')"></l-echart>
@finished="initChart('echartV1', 'echartsDataV1')"
></l-echart>
</view> </view>
<view class="chart"> <view class="chart">
<l-echart <l-echart ref="echartV2"
ref="echartV2" @finished="initChart('echartV2', 'echartsDataV2')"></l-echart>
@finished="initChart('echartV2', 'echartsDataV2')"
></l-echart>
</view> </view>
<view class="chart"> <view class="chart">
<l-echart <l-echart ref="echartV3"
ref="echartV3" @finished="initChart('echartV3', 'echartsDataV3')"></l-echart>
@finished="initChart('echartV3', 'echartsDataV3')"
></l-echart>
</view> </view>
<view class="text" style="left: 20rpx"> 电压有效值(kV) </view> <view class="text" style="left: 20rpx"> 电压有效值(kV) </view>
</view> </view>
<view class="middle" style="width: 100%"> <view class="middle" style="width: 100%">
<l-echart <l-echart class="echart1" ref="echart0"
class="echart1" @finished="initChart('echart0', 'echartsData0')"></l-echart>
ref="echart0" <l-echart class="echart1" ref="echart1"
@finished="initChart('echart0', 'echartsData0')" @finished="initChart('echart1', 'echartsData1')"></l-echart>
></l-echart>
<l-echart
class="echart1"
ref="echart1"
@finished="initChart('echart1', 'echartsData1')"
></l-echart>
<view class="text text_center"> 基波电压/电流<br />幅值(相位) </view> <view class="text text_center"> 基波电压/电流<br />幅值(相位) </view>
</view> </view>
<view> <view>
<view class="chart"> <view class="chart">
<l-echart <l-echart ref="echartA1"
ref="echartA1" @finished="initChart('echartA1', 'echartsDataA1')"></l-echart>
@finished="initChart('echartA1', 'echartsDataA1')"
></l-echart>
</view> </view>
<view class="chart"> <view class="chart">
<l-echart <l-echart ref="echartA2"
ref="echartA2" @finished="initChart('echartA2', 'echartsDataA2')"></l-echart>
@finished="initChart('echartA2', 'echartsDataA2')"
></l-echart>
</view> </view>
<view class="chart"> <view class="chart">
<l-echart <l-echart ref="echartA3"
ref="echartA3" @finished="initChart('echartA3', 'echartsDataA3')"></l-echart>
@finished="initChart('echartA3', 'echartsDataA3')"
></l-echart>
</view> </view>
<view class="text" style="right: 20rpx"> 电流有效值(A) </view> <view class="text" style="right: 20rpx"> 电流有效值(A) </view>
</view> </view>
</view> </view>
</view> </view>
<!-- 底部数据表格 --> <!-- 底部指标数据 -->
<view class="data-table"> <view class="params-wrap ">
<view class="table-header"> <view class="legend-row mt10">
<text></text> <view class="legend-item" v-for="phase in phaseColors" :key="phase.name">
<text>A相</text> <view class="legend-dot" :style="{ background: phase.color }" />
<text>B相</text> <text class="legend-text">{{ phase.name }}</text>
<text>C相</text> </view>
</view> </view>
<view class="table-row" v-for="value in realTimeData"> <view class="params-section mb40">
<text>{{ value.name }}</text> <view v-for="(rowItems, rowIdx) in chunkedChildren(realTimeData)" :key="rowIdx"
<text>{{ value.A }}</text> class="double-row">
<text>{{ value.B }}</text> <view v-for="(child, childIdx) in rowItems" :key="childIdx" class="param-group">
<text>{{ value.C }}</text> <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>
</view> </view>
</view> </view>
@@ -142,7 +143,11 @@ export default {
data() { data() {
return { return {
loading: true, loading: true,
phaseColors: [
{ name: 'A相', color: '#DAA520' },
{ name: 'B相', color: '#2E8B57' },
{ name: 'C相', color: '#D54941' },
],
deviceInfo: {}, deviceInfo: {},
// 使用上面定义的图表配置项 // 使用上面定义的图表配置项
option: {}, option: {},
@@ -170,14 +175,19 @@ export default {
userInfo: {}, userInfo: {},
realTime: '', realTime: '',
realTimeData: [ realTimeData: [
{ name: '电压有效值(kV)', A: '/', B: '/', C: '/' }, { name: '电压有效值(kV)', A: '-', B: '-', C: '-' },
{ name: '电流有效值(A)', A: '/', B: '/', C: '/' }, { name: '电流有效值(A)', A: '-', B: '-', C: '-' },
{ name: '基波电压幅值(kV)', A: '/', B: '/', C: '/' }, { name: '基波电压幅值(kV)', A: '-', B: '-', C: '-' },
{ name: '基波电压相位(°)', A: '/', B: '/', C: '/' }, { name: '基波电流幅值(A)', A: '-', B: '-', C: '-' },
{ name: '基波电流幅值(A)', A: '/', B: '/', C: '/' }, { name: '基波电压相位(°)', A: '-', B: '-', C: '-' },
{ name: '基波电流相位(°)', A: '/', B: '/', C: '/' }, { name: '基波电流相位(°)', A: '-', B: '-', C: '-' },
{ name: '电压偏差(%)', A: '/', B: '/', C: '/' }, { name: '电压偏差(%)', A: '-', B: '-', C: '-' },
{ name: '电压总谐波畸变率(%)', A: '/', B: '/', C: '/' }, { name: '电压总谐波畸变率(%)', A: '-', B: '-', C: '-' },
],
phaseColors: [
{ name: 'A相', color: '#DAA520' },
{ name: 'B相', color: '#2E8B57' },
{ name: 'C相', color: '#D54941' },
], ],
disabled: false, disabled: false,
countdown: 30, countdown: 30,
@@ -192,7 +202,7 @@ export default {
}, },
{ {
iconPath: '/static/about.png', iconPath: '/static/about.png',
text: '关于', text: '详情',
}, },
], ],
device: {}, device: {},
@@ -238,7 +248,7 @@ export default {
}) })
} }
} }
if (this.userInfo.authorities !== 'tourist') { if (this.userInfo.authorities !== 'tourist' && this.device.isPrimaryUser === '1') {
this.content.splice(0, 0, { this.content.splice(0, 0, {
iconPath: '/static/subordinate.png', iconPath: '/static/subordinate.png',
text: '用户', text: '用户',
@@ -267,6 +277,14 @@ export default {
}, },
methods: { methods: {
// 将指标列表按每行两个分组
chunkedChildren(children) {
const result = []
for (let i = 0; i < children.length; i += 2) {
result.push(children.slice(i, i + 2))
}
return result
},
initEcharts0() { initEcharts0() {
return { return {
tooltip: { show: false }, tooltip: { show: false },
@@ -740,125 +758,128 @@ export default {
if (!this.connection) return if (!this.connection) return
// console.log('🚀 ~ .on ~ topic:', topic, this.userInfo.userIndex) // console.log('🚀 ~ .on ~ topic:', topic, this.userInfo.userIndex)
if (
if (topic == `/Web/RealData/${this.lineId}`) { topic == `/Web/RealData/${this.lineId}` ||
topic == `/Web/RealData/${this.userInfo.userIndex}`
) {
let list = JSON.parse(message.toString()) let list = JSON.parse(message.toString())
if (list.lineId != this.lineId) return
// if (list.userId == this.userInfo.userIndex) { // if (list.userId == this.userInfo.userIndex) {
// console.log(list) // console.log(list)
this.realTime = list.dataTime this.realTime = list.dataTime
let pt = list.pt || 0 let pt = list.pt || 0
let ct = list.ct || 0 let ct = list.ct || 0
let data = { let data = {
vRmsA: ((list.vRmsA * pt) / 1000).toFixed(2), vRmsA: ((list.vRmsA * pt) / 1000).toFixed(2),
vRmsB: ((list.vRmsB * pt) / 1000).toFixed(2), vRmsB: ((list.vRmsB * pt) / 1000).toFixed(2),
vRmsC: ((list.vRmsC * pt) / 1000).toFixed(2), vRmsC: ((list.vRmsC * pt) / 1000).toFixed(2),
iRmsA: (list.iRmsA * ct).toFixed(2), iRmsA: (list.iRmsA * ct).toFixed(2),
iRmsB: (list.iRmsB * ct).toFixed(2), iRmsB: (list.iRmsB * ct).toFixed(2),
iRmsC: (list.iRmsC * ct).toFixed(2), iRmsC: (list.iRmsC * ct).toFixed(2),
v1A: ((list.v1A * pt) / 1000).toFixed(2), v1A: ((list.v1A * pt) / 1000).toFixed(2),
v1B: ((list.v1B * pt) / 1000).toFixed(2), v1B: ((list.v1B * pt) / 1000).toFixed(2),
v1C: ((list.v1C * pt) / 1000).toFixed(2), v1C: ((list.v1C * pt) / 1000).toFixed(2),
v1AngA: list.v1AngA.toFixed(2), v1AngA: list.v1AngA.toFixed(2),
v1AngB: list.v1AngB.toFixed(2), v1AngB: list.v1AngB.toFixed(2),
v1AngC: list.v1AngC.toFixed(2), v1AngC: list.v1AngC.toFixed(2),
i1A: (list.i1A * ct).toFixed(2), i1A: (list.i1A * ct).toFixed(2),
i1B: (list.i1B * ct).toFixed(2), i1B: (list.i1B * ct).toFixed(2),
i1C: (list.i1C * ct).toFixed(2), i1C: (list.i1C * ct).toFixed(2),
i1AngA: list.i1AngA.toFixed(2), i1AngA: list.i1AngA.toFixed(2),
i1AngB: list.i1AngB.toFixed(2), i1AngB: list.i1AngB.toFixed(2),
i1AngC: list.i1AngC.toFixed(2), i1AngC: list.i1AngC.toFixed(2),
vDevA: list.vDevA.toFixed(2), vDevA: list.vDevA.toFixed(2),
vDevB: list.vDevB.toFixed(2), vDevB: list.vDevB.toFixed(2),
vDevC: list.vDevC.toFixed(2), vDevC: list.vDevC.toFixed(2),
vThdA: list.vThdA.toFixed(2), vThdA: list.vThdA.toFixed(2),
vThdB: list.vThdB.toFixed(2), vThdB: list.vThdB.toFixed(2),
vThdC: list.vThdC.toFixed(2), vThdC: list.vThdC.toFixed(2),
}
this.realTimeData = [
{ name: '电压有效值(kV)', A: data.vRmsA, B: data.vRmsB, C: data.vRmsC },
{ name: '电流有效值(A)', A: data.iRmsA, B: data.iRmsB, C: data.iRmsC },
{ name: '基波电压幅值(kV)', A: data.v1A, B: data.v1B, C: data.v1C },
{ name: '基波电流幅值(A)', A: data.i1A, B: data.i1B, C: data.i1C },
{ name: '基波电压相位(°)', A: data.v1AngA, B: data.v1AngB, C: data.v1AngC },
{ name: '基波电流相位(°)', A: data.i1AngA, B: data.i1AngB, C: data.i1AngC },
{ name: '电压偏差(%)', A: data.vDevA, B: data.vDevB, C: data.vDevC },
{ name: '电压总谐波畸变率(%)', A: data.vThdA, B: data.vThdB, C: data.vThdC },
]
// 电压
let vMax =
Math.ceil(
(Math.max(
...[
Math.floor(data.vRmsA * 100) / 100 || 1,
Math.floor(data.vRmsB * 100) / 100 || 1,
Math.floor(data.vRmsC * 100) / 100 || 1,
],
) *
1.2) /
10,
) * 10
this.echartsDataV1.series[0].max = vMax
this.echartsDataV2.series[0].max = vMax
this.echartsDataV3.series[0].max = vMax
this.echartsDataV1.series[0].data[0].value = data.vRmsA
this.echartsDataV2.series[0].data[0].value = data.vRmsB
this.echartsDataV3.series[0].data[0].value = data.vRmsC
// 电流
let aMax =
Math.ceil(
(Math.max(
...[
Math.floor(data.iRmsA * 100) / 100 || 1,
Math.floor(data.iRmsB * 100) / 100 || 1,
Math.floor(data.iRmsC * 100) / 100 || 1,
],
) *
1.2) /
10,
) * 10
this.echartsDataA1.series[0].max = aMax
this.echartsDataA2.series[0].max = aMax
this.echartsDataA3.series[0].max = aMax
this.echartsDataA1.series[0].data[0].value = data.iRmsA
this.echartsDataA2.series[0].data[0].value = data.iRmsB
this.echartsDataA3.series[0].data[0].value = data.iRmsC
this.echartsData0.series[0].data[0].value = data.i1AngA
this.echartsData0.series[0].data[1].value = data.i1AngB
this.echartsData0.series[0].data[2].value = data.i1AngC
this.echartsData1.series[0].data[0].value = data.v1AngA
this.echartsData1.series[0].data[1].value = data.v1AngB
this.echartsData1.series[0].data[2].value = data.v1AngC
const charts = [
{ instance: this.echart0, data: this.echartsData0 },
{ instance: this.echart1, data: this.echartsData1 },
{ instance: this.echartV1, data: this.echartsDataV1 },
{ instance: this.echartV2, data: this.echartsDataV2 },
{ instance: this.echartV3, data: this.echartsDataV3 },
{ instance: this.echartA1, data: this.echartsDataA1 },
{ instance: this.echartA2, data: this.echartsDataA2 },
{ instance: this.echartA3, data: this.echartsDataA3 },
]
charts.forEach(({ instance, data }) => {
if (instance && instance.setOption) {
instance.setOption(data, true)
} }
this.realTimeData = [ })
{ name: '电压有效值(kV)', A: data.vRmsA, B: data.vRmsB, C: data.vRmsC },
{ name: '电流有效值(A)', A: data.iRmsA, B: data.iRmsB, C: data.iRmsC },
{ name: '基波电压幅值(kV)', A: data.v1A, B: data.v1B, C: data.v1C },
{ name: '基波电压相位(°)', A: data.v1AngA, B: data.v1AngB, C: data.v1AngC },
{ name: '基波电流幅值(A)', A: data.i1A, B: data.i1B, C: data.i1C },
{ name: '基波电流相位(°)', A: data.i1AngA, B: data.i1AngB, C: data.i1AngC },
{ name: '电压偏差(%)', A: data.vDevA, B: data.vDevB, C: data.vDevC },
{ name: '电压总谐波畸变率(%)', A: data.vThdA, B: data.vThdB, C: data.vThdC },
]
// 电压
let vMax =
Math.ceil(
(Math.max(
...[
Math.floor(data.vRmsA * 100) / 100 || 1,
Math.floor(data.vRmsB * 100) / 100 || 1,
Math.floor(data.vRmsC * 100) / 100 || 1,
],
) *
1.2) /
10,
) * 10
this.echartsDataV1.series[0].max = vMax
this.echartsDataV2.series[0].max = vMax
this.echartsDataV3.series[0].max = vMax
this.echartsDataV1.series[0].data[0].value = data.vRmsA
this.echartsDataV2.series[0].data[0].value = data.vRmsB
this.echartsDataV3.series[0].data[0].value = data.vRmsC
// 电流 // this.echart0.setOption(this.echartsData0, true)
let aMax = // this.echart1.setOption(this.echartsData1, true)
Math.ceil( // this.echartV1.setOption(this.echartsDataV1, true)
(Math.max( // this.echartV2.setOption(this.echartsDataV2, true)
...[ // this.echartV3.setOption(this.echartsDataV3, true)
Math.floor(data.iRmsA * 100) / 100 || 1, // this.echartA1.setOption(this.echartsDataA1, true)
Math.floor(data.iRmsB * 100) / 100 || 1, // this.echartA2.setOption(this.echartsDataA2, true)
Math.floor(data.iRmsC * 100) / 100 || 1, // this.echartA3.setOption(this.echartsDataA3, true)
],
) *
1.2) /
10,
) * 10
this.echartsDataA1.series[0].max = aMax
this.echartsDataA2.series[0].max = aMax
this.echartsDataA3.series[0].max = aMax
this.echartsDataA1.series[0].data[0].value = data.iRmsA
this.echartsDataA2.series[0].data[0].value = data.iRmsB
this.echartsDataA3.series[0].data[0].value = data.iRmsC
this.echartsData0.series[0].data[0].value = data.i1AngA
this.echartsData0.series[0].data[1].value = data.i1AngB
this.echartsData0.series[0].data[2].value = data.i1AngC
this.echartsData1.series[0].data[0].value = data.v1AngA
this.echartsData1.series[0].data[1].value = data.v1AngB
this.echartsData1.series[0].data[2].value = data.v1AngC
const charts = [
{ instance: this.echart0, data: this.echartsData0 },
{ instance: this.echart1, data: this.echartsData1 },
{ instance: this.echartV1, data: this.echartsDataV1 },
{ instance: this.echartV2, data: this.echartsDataV2 },
{ instance: this.echartV3, data: this.echartsDataV3 },
{ instance: this.echartA1, data: this.echartsDataA1 },
{ instance: this.echartA2, data: this.echartsDataA2 },
{ instance: this.echartA3, data: this.echartsDataA3 },
]
charts.forEach(({ instance, data }) => {
if (instance && instance.setOption) {
instance.setOption(data, true)
}
})
// this.echart0.setOption(this.echartsData0, true)
// this.echart1.setOption(this.echartsData1, true)
// this.echartV1.setOption(this.echartsDataV1, true)
// this.echartV2.setOption(this.echartsDataV2, true)
// this.echartV3.setOption(this.echartsDataV3, true)
// this.echartA1.setOption(this.echartsDataA1, true)
// this.echartA2.setOption(this.echartsDataA2, true)
// this.echartA3.setOption(this.echartsDataA3, true)
// } // }
} }
}) })
@@ -867,14 +888,14 @@ export default {
clear() { clear() {
this.realTime = '' this.realTime = ''
this.realTimeData = [ this.realTimeData = [
{ name: '电压有效值(kV)', A: '/', B: '/', C: '/' }, { name: '电压有效值(kV)', A: '-', B: '-', C: '-' },
{ name: '电流有效值(A)', A: '/', B: '/', C: '/' }, { name: '电流有效值(A)', A: '-', B: '-', C: '-' },
{ name: '基波电压幅值(kV)', A: '/', B: '/', C: '/' }, { name: '基波电压幅值(kV)', A: '-', B: '-', C: '-' },
{ name: '基波电压相位(°)', A: '/', B: '/', C: '/' }, { name: '基波电流幅值(A)', A: '-', B: '-', C: '-' },
{ name: '基波电流幅值(A)', A: '/', B: '/', C: '/' }, { name: '基波电压相位(°)', A: '-', B: '-', C: '-' },
{ name: '基波电流相位(°)', A: '/', B: '/', C: '/' }, { name: '基波电流相位(°)', A: '-', B: '-', C: '-' },
{ name: '电压偏差(%)', A: '/', B: '/', C: '/' }, { name: '电压偏差(%)', A: '-', B: '-', C: '-' },
{ name: '电压总谐波畸变率(%)', A: '/', B: '/', C: '/' }, { name: '电压总谐波畸变率(%)', A: '-', B: '-', C: '-' },
] ]
this.echartsDataV1.series[0].data[0].value = 0 this.echartsDataV1.series[0].data[0].value = 0
this.echartsDataV2.series[0].data[0].value = 0 this.echartsDataV2.series[0].data[0].value = 0
@@ -960,7 +981,7 @@ export default {
url: '/pages/index/message1', url: '/pages/index/message1',
}) })
// uni.navigateTo({ url: '/pages/device/APF/report?id=' + this.device.equipmentId }) // uni.navigateTo({ url: '/pages/device/APF/report?id=' + this.device.equipmentId })
} else if (e.text === '关于') { } else if (e.text === '详情') {
uni.navigateTo({ url: '/pages/device/APF/about?id=' + this.device.equipmentId }) uni.navigateTo({ url: '/pages/device/APF/about?id=' + this.device.equipmentId })
} else if (e.text === '移交') { } else if (e.text === '移交') {
uni.navigateTo({ url: '/pages/device/transfer?id=' + this.device.equipmentId }) uni.navigateTo({ url: '/pages/device/transfer?id=' + this.device.equipmentId })
@@ -990,30 +1011,38 @@ export default {
padding: 20rpx; padding: 20rpx;
background-color: #fff; background-color: #fff;
} }
// padding: 20rpx; // padding: 20rpx;
.info-card { .info-card {
background-image: url('/static/background.png'); background-image: url('/static/background.png');
background-position: center center; /* 水平+垂直居中 */ background-position: center center;
background-repeat: no-repeat; /* 不平铺 */ /* 水平+垂直居中 */
background-size: 100% 100%; /* 覆盖整个容器(可选,根据需求调整) */ background-repeat: no-repeat;
/* 不平铺 */
background-size: 100% 100%;
/* 覆盖整个容器(可选,根据需求调整) */
color: #fff; color: #fff;
padding: 20rpx 40rpx; padding: 20rpx 40rpx;
border-radius: 20rpx; border-radius: 20rpx;
.info-item { .info-item {
display: flex; display: flex;
align-items: center; align-items: center;
font-size: 28rpx; font-size: 28rpx;
margin-bottom: 10rpx; margin-bottom: 10rpx;
view { view {
// font-size: 28rpx; // font-size: 28rpx;
// .nav-menu { // .nav-menu {
// font-size: 32rpx; // font-size: 32rpx;
// } // }
} }
&:last-child { &:last-child {
margin-bottom: 0rpx; margin-bottom: 0rpx;
} }
} }
.status { .status {
.status-normal { .status-normal {
// font-weight: bold; // font-weight: bold;
@@ -1021,32 +1050,92 @@ export default {
} }
} }
.data-table { .params-wrap {
margin-top: 20rpx; margin-top: 20rpx;
background-color: #fff; background-color: #fff;
border-radius: 10rpx;
overflow: hidden; overflow: hidden;
.table-header, }
.table-row {
display: flex; .legend-row {
justify-content: space-between; display: flex;
padding: 20rpx 30rpx; gap: 20rpx;
border-bottom: 1rpx solid #eee; align-items: center;
text { justify-content: flex-end;
flex: 1; padding: 0rpx 20rpx 0;
text-align: center; background-color: #fff;
font-size: 28rpx; }
// color: #333;
&:first-child { .legend-item {
text-align: left; display: flex;
flex: 2; align-items: center;
} gap: 8rpx;
} }
}
.table-header { .legend-dot {
// background-color: #fafafa; width: 16rpx;
font-weight: bold; height: 16rpx;
border-radius: 50%;
}
.legend-text {
font-size: 24rpx;
color: #666666;
}
.params-section {
padding: 16rpx 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: #f3f3f3;
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: 26rpx;
font-weight: 700;
}
.phase-divider {
width: 1px;
background: #d2d2d2;
margin: 8rpx 0;
}
.time-bar { .time-bar {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@@ -1055,54 +1144,88 @@ export default {
background-color: #fff; background-color: #fff;
margin: 20rpx 0 0; margin: 20rpx 0 0;
border-radius: 10rpx; border-radius: 10rpx;
.time { .time {
display: flex; display: flex;
align-items: center; align-items: center;
flex: 1; flex: 1;
font-size: 28rpx; font-size: 28rpx;
text { text {
margin-left: 20rpx; margin-left: 20rpx;
} }
} }
} }
} }
.chartBox { .chartBox {
background-color: #fff; background-color: #fff;
padding: 0 0rpx 20rpx; padding: 0 0rpx 20rpx;
display: flex; display: flex;
padding-bottom: 55rpx; padding-bottom: 55rpx;
.middle { .middle {
display: flex; display: flex;
position: relative; position: relative;
height: 600rpx; height: 600rpx;
margin: 0 10rpx; margin: 0 10rpx;
flex: 1; flex: 1;
.echart1 { .echart1 {
position: absolute; position: absolute;
height: 500rpx; height: 500rpx;
top: 0; top: 0;
} }
} }
.chart { .chart {
width: 170rpx; width: 170rpx;
height: 200rpx; height: 200rpx;
margin-bottom: 5rpx; margin-bottom: 5rpx;
} }
.text { .text {
text-align: center; text-align: center;
font-size: 28rpx; font-size: 28rpx;
position: absolute; position: absolute;
} }
.text_center { .text_center {
bottom: -5px; bottom: -5px;
left: 50%; left: 50%;
transform: translateX(-50%) translateY(50%); transform: translateX(-50%) translateY(50%);
} }
} }
.mini-btn { .mini-btn {
font-size: 24rpx; font-size: 24rpx;
border-radius: 45rpx; border-radius: 45rpx;
height: 45rpx; height: 45rpx;
line-height: 45rpx; line-height: 45rpx;
} }
.legend-row {
display: flex;
gap: 20rpx;
align-items: center;
justify-content: end;
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;
}
</style> </style>

View File

@@ -5,14 +5,8 @@
<view class="transfer"> <view class="transfer">
<!-- <div class="transfer-img" ref="qrCodeUrl" /> --> <!-- <div class="transfer-img" ref="qrCodeUrl" /> -->
<!-- <uqrcode ref="uqrcode" canvas-id="qrcode" :value="content" :options="{ margin: 10 }"></uqrcode> --> <!-- <uqrcode ref="uqrcode" canvas-id="qrcode" :value="content" :options="{ margin: 10 }"></uqrcode> -->
<uqrcode <uqrcode ref="uqrcode" canvas-id="qrcode" :value="content" size="200" @complete="complete"
ref="uqrcode" :loading="false"></uqrcode>
canvas-id="qrcode"
:value="content"
size="200"
@complete="complete"
:loading="false"
></uqrcode>
<view style="height: 200rpx"></view> <view style="height: 200rpx"></view>
<view class="transfer-text">请让接收人员扫码接收</view> <view class="transfer-text">请让接收人员扫码接收</view>
<view class="transfer-btn"> <view class="transfer-btn">
@@ -24,24 +18,16 @@
</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%" type="info" cancelText="禁止" confirmText="允许" title="权限说明"
style="width: 90%; margin: 5%" content='是否允许"灿能物联"使用相机?' @confirm="handleScon('camera')" @close="dialogClose"></uni-popup-dialog>
type="info" </uni-popup>
cancelText="禁止" <uni-popup ref="message" type="message">
confirmText="允许" <uni-popup-message type="info" :duration="0" style="width: 90%; margin: 5%">
title="权限说明" <view style="color: #909399; font-style: 16px">相机权限使用说明:</view>
content='是否允许"灿能物联"使用相机?' <view style="color: #6c6c6c; margin-top: 3rpx; "> 用于相机扫描二维码!</view>
@confirm="handleScon('camera')" </uni-popup-message>
@close="dialogClose" </uni-popup>
></uni-popup-dialog>
</uni-popup>
<uni-popup ref="message" type="message">
<uni-popup-message type="info" :duration="0" style="width: 90%; margin: 5%">
<view style="color: #909399; font-style: 16px">相机权限使用说明:</view>
<view style="color: #6c6c6c; margin-top: 3rpx; "> 用于相机扫描二维码!</view>
</uni-popup-message>
</uni-popup>
</view> </view>
</template> </template>
<script> <script>
@@ -82,17 +68,17 @@ export default {
plus.os.name == 'Android' && plus.os.name == 'Android' &&
plus.navigator.checkPermission('android.permission.CAMERA') === 'undetermined' plus.navigator.checkPermission('android.permission.CAMERA') === 'undetermined'
) { ) {
//未授权 //未授权
this.$refs.message.open() this.$refs.message.open()
this.$refs.alertDialog.open('bottom') this.$refs.alertDialog.open('bottom')
} else { } else {
this.handleScon() this.handleScon()
} }
}, },
handleScon() { handleScon() {
this.$refs.message.close() this.$refs.message.close()
uni.scanCode({ uni.scanCode({
onlyFromCamera:true, // onlyFromCamera:false,
success: (res) => { success: (res) => {
console.log(res) console.log(res)
let data = JSON.parse(res.result) let data = JSON.parse(res.result)
@@ -107,7 +93,7 @@ export default {
}, },
}) })
}, },
dialogClose() {this.$refs.message.close()}, dialogClose() { this.$refs.message.close() },
}, },
onLoad(options) { onLoad(options) {
this.options = options this.options = options
@@ -125,8 +111,7 @@ export default {
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
.transfer-img { .transfer-img {}
}
.transfer-text { .transfer-text {
font-size: 28rpx; font-size: 28rpx;

View File

@@ -24,9 +24,10 @@
</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">
<!-- extra="🔍" -->
<uni-card <uni-card
:title="item.name" :title="item.name"
extra="🔍"
@click="jumpProject(item)" @click="jumpProject(item)"
v-for="(item, index) in store.data" v-for="(item, index) in store.data"
:key="index" :key="index"
@@ -258,7 +259,7 @@ export default {
.term-list-bottom { .term-list-bottom {
.term-list-bottom-item { .term-list-bottom-item {
font-size: 28rpx; font-size: 28rpx;
margin-bottom: 20rpx; // margin-bottom: 20rpx;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
// view:first-of-type{ // view:first-of-type{
@@ -270,4 +271,10 @@ export default {
margin-bottom: 0; margin-bottom: 0;
} }
} }
/deep/ .uni-card__content {
padding: 5px 10px 10px !important;
}
/deep/ .uni-card__header-content-title {
font-weight: 700;
}
</style> </style>

View File

@@ -10,34 +10,32 @@
<view class="message"> <view class="message">
<uni-swipe-action>
<uni-swipe-action-item v-for="(item, index) in store.data" <view v-for="(item, index) in store.data" :key="index" style="margin: 0px 7px 7px;">
:style="{ marginTop: index === 0 ? '0' : '' }" :key="index" :threshold="0" <!-- extra="🔍" -->
:right-options="item.isTop == 0 ? options1 : options12" @click="bindClick($event, item)"> <uni-card class="boxClick" :title="item.name" @click="jump(item)">
<uni-card class="boxClick" :title="item.name" extra="🔍" @click="jump(item)"> <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 class="term-list-bottom-item">
<view>创建时间</view>
<view>{{ item.createTime }}</view>
</view>
</view> </view>
<view class="pinToTop" v-if="item.isTop == 1"> 置顶 </view> <view class="term-list-bottom-item">
</uni-card> <view>创建时间</view>
</uni-swipe-action-item> <view>{{ item.createTime }}</view>
</uni-swipe-action> </view>
</view>
</uni-card>
</view>
<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 v-if="store.status == 'loading' || (store.data && store.data.length > 0)" <uni-load-more v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"></uni-load-more> :status="store.status"></uni-load-more>
</view>
</view> </view>
</view>
</template> </template>
<script> <script>

View File

@@ -6,7 +6,7 @@
<page-meta :page-style="'overflow:'+(show?'hidden':'visible')"></page-meta> <page-meta :page-style="'overflow:'+(show?'hidden':'visible')"></page-meta>
<uni-forms :label-width="80"> <uni-forms :label-width="80">
<uni-forms-item label="工程名称"> <uni-forms-item label="工程名称">
<uni-easyinput type="text" v-model="formData.name" placeholder="请输入工程名称"/> <uni-easyinput type="text" v-model="formData.name" maxlength="50" placeholder="请输入工程名称"/>
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="位置"> <uni-forms-item label="位置">
<!-- <view style="display:flex;"> <!-- <view style="display:flex;">

View File

@@ -25,11 +25,8 @@
<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" style="transform: scale(0.8)"
:checked="selectList.indexOf(item.engineerId) > -1" @change="switchChange(item)" />
style="transform: scale(0.8)"
@change="switchChange(item)"
/>
</view> </view>
</template> </template>
</uni-list-item> </uni-list-item>
@@ -74,8 +71,9 @@ export default {
init() { init() {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo) this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
queryAllEnginner().then((res) => { queryAllEnginner().then((res) => {
this.list = res.data this.list = (res.data || []).slice().sort((a, b) =>
console.log(this.list) (a.engineerName || '').localeCompare(b.engineerName || '', 'zh', { sensitivity: 'accent' }),
)
this.selectList = res.data.filter((item) => item.isSelect === '1').map((item) => item.engineerId) this.selectList = res.data.filter((item) => item.isSelect === '1').map((item) => item.engineerId)
console.log(this.selectList) console.log(this.selectList)
this.loading = false this.loading = false
@@ -117,7 +115,7 @@ export default {
uni.removeStorage({ uni.removeStorage({
key: this.$cacheKey.engineering, key: this.$cacheKey.engineering,
}) })
} else if (engineering && !res.data.some((item) => (item.id = engineering.id))) { } else if (engineering && !res.data.some((item) => (item.id == engineering.id))) {
uni.removeStorage({ uni.removeStorage({
key: this.$cacheKey.engineering, key: this.$cacheKey.engineering,
}) })

View File

@@ -24,7 +24,7 @@
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="位置"> <uni-forms-item label="位置">
<view style="display:flex;"> <view style="display:flex;">
<uni-easyinput :clearable="false" type="textarea" autoHeight v-model="formData.address" <uni-easyinput :clearable="false" maxlength="250" type="textarea" autoHeight v-model="formData.address"
placeholder="请输入位置信息" /> placeholder="请输入位置信息" />
<!-- <uni-icons type="location" color="#007aff" size="26" class="ml20" <!-- <uni-icons type="location" color="#007aff" size="26" class="ml20"
@click="chooseLocation"></uni-icons> --> @click="chooseLocation"></uni-icons> -->

View File

@@ -65,7 +65,7 @@
<view class="content"> <view class="content">
<view class="content-des">请拖动图中的蓝色定位图标选择监测点位置(左上角)</view> <view class="content-des">请拖动图中的蓝色定位图标选择监测点位置(左上角)</view>
<uni-forms> <uni-forms>
<uni-easyinput type="text" v-model="pointName" placeholder="请输入设监测点名称" /> <uni-easyinput type="text" v-model="pointName" maxlength="24" placeholder="请输入设监测点名称" />
</uni-forms> </uni-forms>
<view class="btn-wrap"> <view class="btn-wrap">
<view class="btn-wrap-item" @click="closeDrawer"> 取消 </view> <view class="btn-wrap-item" @click="closeDrawer"> 取消 </view>

View File

@@ -8,10 +8,10 @@
<uni-data-select v-model="item.type" :localdata="range"></uni-data-select> <uni-data-select v-model="item.type" :localdata="range"></uni-data-select>
</uni-forms-item> --> </uni-forms-item> -->
<uni-forms-item label="标题"> <uni-forms-item label="标题">
<uni-easyinput type="text" v-model="formData.title" placeholder="请输入问题简要"/> <uni-easyinput type="text" v-model="formData.title" maxlength="32" placeholder="请输入问题简要"/>
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="描述"> <uni-forms-item label="描述">
<uni-easyinput type="textarea" v-model="formData.description" placeholder="请输入详细描述"/> <uni-easyinput type="textarea" v-model="formData.description" maxlength="999" placeholder="请输入详细描述"/>
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="图片"> <uni-forms-item label="图片">
<uni-file-picker :auto-upload="false" @select="fileChange" @delete="delImg"> <uni-file-picker :auto-upload="false" @select="fileChange" @delete="delImg">
@@ -23,9 +23,9 @@
<view class="btn-wrap"> <view class="btn-wrap">
<view class="btn-wrap-item " @click="submit"> 提交</view> <view class="btn-wrap-item " @click="submit"> 提交</view>
</view> </view>
<navigator url="/pages/home/service" hover-class="none" class="fixed-btn"> <!-- <navigator url="/pages/home/service" hover-class="none" class="fixed-btn">
<image src="/static/service.png" style="height:66rpx;width:66rpx"/> <image src="/static/service.png" style="height:66rpx;width:66rpx"/>
</navigator> </navigator> -->
</view> </view>
</view> </view>
</Cn-page> </Cn-page>
@@ -83,6 +83,7 @@ export default {
}) })
return return
} }
console.log("🚀 ~ this.formData:", this.formData)
addFeedBack(this.formData).then(res => { addFeedBack(this.formData).then(res => {
console.log(res) console.log(res)
console.log(this.formData.files.length) console.log(this.formData.files.length)

View File

@@ -9,11 +9,11 @@
</view> </view>
<view class="smallLabel mt20"> <view class="smallLabel mt20">
<view class="boxCenter"> <view class="boxCenter">
<view> <!-- <view>
<checkbox-group @change="changeBox" class="boxCenter" <checkbox-group @change="changeBox" class="boxCenter"
><checkbox value="true" :checked="checkedAll" />全选  ><checkbox value="true" :checked="checkedAll" />全选 
</checkbox-group></view </checkbox-group></view
> > -->
已选择 {{ checkedTotal }} 条事件 已选择 {{ checkedTotal }} 条事件
</view> </view>
<view class="nav-menu nav-menu-btn" @click="selectDevice">申请报告 </view> <view class="nav-menu nav-menu-btn" @click="selectDevice">申请报告 </view>
@@ -61,9 +61,9 @@
}}</text> }}</text>
</view> </view>
<view class="event-desc"> <view class="event-desc">
<text>工程名称{{ item.engineeringName }}</text> <text>工程{{ item.engineeringName }}</text>
<text>项目名称{{ item.projectName }}</text> <text>项目{{ item.projectName }}</text>
<text>设备名称{{ item.equipmentName }}</text> <text>设备{{ item.equipmentName }}</text>
</view> </view>
</view> </view>
<view class="event-action" @click="handleWrapperClick(item, !item.wavePath)"> <view class="event-action" @click="handleWrapperClick(item, !item.wavePath)">
@@ -92,6 +92,11 @@
? ',相别:' + item.evtParamPhase ? ',相别:' + item.evtParamPhase
: '' : ''
}} }}
{{
item.landPoint != null && item.landPoint !== ''
? ',落点区域:' + item.landPoint
: ',落点区域:未知'
}}
</text> </text>
</view> </view>
</uni-card> </uni-card>
@@ -122,7 +127,7 @@ export default {
checkedAll: false, checkedAll: false,
checkedTotal: 0, checkedTotal: 0,
sort: 0, sort: 0,
array: ['发生时间', '暂降深度', '持续时间'], array: ['发生时间', '暂降幅值', '持续时间'],
} }
}, },
mounted() {}, mounted() {},
@@ -217,21 +222,21 @@ export default {
}, },
judgment(val, key) { judgment(val, key) {
switch (val) { switch (val) {
case '电压暂降': case '暂降':
return { return {
type: 'sag', type: 'sag',
icon: 'icon-a-svg4', icon: 'icon-a-svg4',
color: '#2563eb', color: '#2563eb',
size: '25', size: '25',
} }
case '电压暂升': case '暂升':
return { return {
type: 'swell', type: 'swell',
icon: 'icon-a-svg5', icon: 'icon-a-svg5',
color: '#e6a23c', color: '#e6a23c',
size: '25', size: '25',
} }
case '电压中断': case '中断':
return { return {
type: 'interrupt', type: 'interrupt',
icon: 'icon-zhongduan2', icon: 'icon-zhongduan2',

View File

@@ -4,14 +4,8 @@
<!-- <view class="nav-menu" :class="{ 'nav-menu-active': select.engineeringName }" @click="openDrawer" <!-- <view class="nav-menu" :class="{ 'nav-menu-active': select.engineeringName }" @click="openDrawer"
>{{ select.engineeringName || '工程' }} >{{ select.engineeringName || '工程' }}
</view> --> </view> -->
<picker <picker @change="projectNameChange" @cancel="selectProject = false" :value="select.projectNameIndex"
@change="projectNameChange" :range="projectList" range-key="text" v-if="store.params.engineerId">
@cancel="selectProject = false"
:value="select.projectNameIndex"
:range="projectList"
range-key="text"
v-if="store.params.engineerId"
>
<view class="nav-menu" :class="{ 'nav-menu-active': select.projectName }" @click="selectProject = true"> <view class="nav-menu" :class="{ 'nav-menu-active': select.projectName }" @click="selectProject = true">
{{ {{
select.projectName select.projectName
@@ -20,18 +14,10 @@
: select.projectName : select.projectName
: '全部项目' : '全部项目'
}} }}
<uni-icons <uni-icons type="top" size="14" :color="select.projectName ? '#376cf3' : '#666'"
type="top" v-if="selectProject"></uni-icons>
size="14" <uni-icons type="bottom" size="14" :color="select.projectName ? '#376cf3' : '#666'"
:color="select.projectName ? '#376cf3' : '#666'" v-else></uni-icons>
v-if="selectProject"
></uni-icons>
<uni-icons
type="bottom"
size="14"
:color="select.projectName ? '#376cf3' : '#666'"
v-else
></uni-icons>
</view> </view>
</picker> </picker>
<view style="flex: 1"></view> <view style="flex: 1"></view>
@@ -40,17 +26,11 @@
<view class="nav-menu nav-menu-btn" @click="submit">确定</view> <view class="nav-menu nav-menu-btn" @click="submit">确定</view>
</template> </template>
<template v-else-if="deviceListFilter.length"> <template v-else-if="deviceListFilter.length">
<view <view class="nav-menu nav-menu-btn" @click="selectDevice('transfer')"
class="nav-menu nav-menu-btn" v-if="userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'">移交
@click="selectDevice('transfer')"
v-if="userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'"
>移交
</view> </view>
<view <view class="nav-menu nav-menu-btn" @click="selectDevice('share')"
class="nav-menu nav-menu-btn" v-if="userInfo.authorities === 'app_vip_user'">分享
@click="selectDevice('share')"
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">
@@ -59,36 +39,25 @@
</view> </view>
</picker> --> </picker> -->
</view> </view>
<view class="content device" :style="{ minHeight: minHeight }"> <view class="content device">
<uni-swipe-action> <uni-swipe-action>
<uni-swipe-action-item <uni-swipe-action-item v-for="(item, index) in deviceListFilter" :threshold="0"
v-for="(item, index) in deviceListFilter" :right-options="item.isTop == 0 ? options1 : options12" @click="bindClick($event, item)">
:threshold="0"
:right-options="item.isTop == 0 ? options1 : options12"
@click="bindClick($event, item)"
>
<Cn-device-card :device="item" :key="index"> <Cn-device-card :device="item" :key="index">
<template v-slot:title> <template v-slot:title>
<!-- 卡片标题 --> <!-- 卡片标题 -->
<switch v-if="transfer || share" :checked="checkList.indexOf(item.equipmentId) > -1"
<switch
v-if="transfer || share"
: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 class="star-icon" v-else> <view class="star-icon" v-else>
<!-- <uni-icons type="search" size="25" color="#376cf3"></uni-icons> --> <uni-icons type="search" size="25" color="#376cf3"></uni-icons>
🔍
</view> </view>
</template> </template>
</Cn-device-card> </Cn-device-card>
</uni-swipe-action-item> </uni-swipe-action-item>
</uni-swipe-action> </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"></uni-load-more>
:status="store.status"
></uni-load-more>
<Cn-empty v-else></Cn-empty> <Cn-empty v-else></Cn-empty>
</view> </view>
</view> </view>
@@ -97,6 +66,7 @@
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' import { engineeringPinToTop } from '@/common/api/device'
export default { export default {
props: { props: {
store: { store: {
@@ -141,8 +111,10 @@ export default {
], ],
} }
}, },
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
@@ -167,7 +139,8 @@ 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) { bindClick(e, item) {
engineeringPinToTop({ engineeringPinToTop({
@@ -272,6 +245,8 @@ export default {
engineeringId: this.store.params.engineerId, engineeringId: this.store.params.engineerId,
}).then((res) => { }).then((res) => {
console.log(res) console.log(res)
this.select.projectName = ''
this.select.projectNameIndex = 0
let arr = [ let arr = [
{ {
text: '全部项目', text: '全部项目',
@@ -286,6 +261,7 @@ export default {
}), }),
] ]
this.projectList = arr this.projectList = arr
uni.setStorageSync('projectList', arr) uni.setStorageSync('projectList', arr)
}) })
}, },
@@ -369,13 +345,12 @@ export default {
} }
</script> </script>
<style lang="scss"> <style lang="scss">
.index-device { .index-device {}
.nav-menu {
}
}
/deep/ .button-group--right { /deep/ .button-group--right {
padding: 0 0 20rpx; padding: 0 0 20rpx;
} }
.star-icon { .star-icon {
font-size: 40rpx; font-size: 40rpx;
} }

View File

@@ -1,7 +1,8 @@
<template> <template>
<view class="index-device"> <view class="index-device">
<view class="nav" :style="{ top: navTabHeight + 'px' }"> </view> <view class="nav" :style="{ top: navTabHeight + 'px' }"> </view>
<view class="content device project-list" :style="{ minHeight: minHeight }"> <!-- :style="{ minHeight: minHeight }" -->
<view class="content device project-list" >
<uni-swipe-action> <uni-swipe-action>
<uni-swipe-action-item <uni-swipe-action-item
v-for="(item, index) in store.data" v-for="(item, index) in store.data"
@@ -151,8 +152,8 @@ export default {
// 存储参数 // 存储参数
uni.setStorageSync('messageParams', { uni.setStorageSync('messageParams', {
engineeringName: this.device.engineeringName, engineeringName: item.engineeringName,
engineeringId: this.device.engineeringId, //工程ID engineeringId: item.engineeringId, //工程ID
projectName: '', projectName: '',
projectId: '', //項目ID projectId: '', //項目ID
deviceName: '', deviceName: '',
@@ -208,7 +209,7 @@ export default {
} }
.project-name { .project-name {
font-size: 28rpx; font-size: 30rpx;
font-weight: 700; font-weight: 700;
color: #333333; color: #333333;
margin-bottom: 20rpx; margin-bottom: 20rpx;
@@ -231,14 +232,14 @@ export default {
} }
.stat-value { .stat-value {
font-size: 36rpx; font-size: 32rpx;
font-weight: 700; font-weight: 700;
} }
.stat-label { .stat-label {
font-size: 26rpx; font-size: 24rpx;
margin-top: 5rpx; margin-top: 5rpx;
// color: #666666; color: #666666;
} }
.blue { .blue {

View File

@@ -1,7 +1,10 @@
<template> <template>
<view class="index-zhuyonghu"> <view class="index-zhuyonghu">
<template v-if="devCount.engineeringListLength > 0"> <template v-if="devCount.engineeringListLength > 0">
<view class="canneng-index-title mb20">所有工程设备统计</view> <view class="canneng-index-title mb20 ml20 canneng-index-title-with-icon">
<uni-icons custom-prefix="iconfont" type="icon-gongcheng" size="18" color="#376cf3" />
<text>所有工程设备统计</text>
</view>
<view class="header"> <view class="header">
<view class="header-item boxClick" @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>
@@ -30,7 +33,7 @@
</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 ml20">当前工程设备统计</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"
@@ -47,7 +50,10 @@
<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 ml20 canneng-index-title-with-icon">
<uni-icons type="settings" size="18" color="#376cf3" />
<text>常用功能</text>
</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 <Cn-grid-item
@@ -205,4 +211,13 @@ export default {
}, },
} }
</script> </script>
<style lang="scss"></style> <style lang="scss">
.index-zhuyonghu {
.canneng-index-title-with-icon {
display: inline-flex;
align-items: center;
gap: 8rpx;
font-size: 30rpx;
}
}
</style>

View File

@@ -1,7 +1,10 @@
<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 ml20 canneng-index-title-with-icon">
<uni-icons custom-prefix="iconfont" type="icon-gongcheng" size="18" color="#376cf3" />
<text>所有工程设备统计</text>
</view>
<view class="header"> <view class="header">
<view class="header-item boxClick" @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>
@@ -18,7 +21,10 @@
</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 ml20 canneng-index-title-with-icon">
<uni-icons custom-prefix="iconfont" type="icon-zaixianjianceshebei" size="18" color="#376cf3" />
<text>当前工程设备统计</text>
</view>
<view class="header"> <view class="header">
<view class="header-item boxClick" @click="jump('nowEngineering')"> <view class="header-item boxClick" @click="jump('nowEngineering')">
<view class="header-item-value">{{ <view class="header-item-value">{{
@@ -68,4 +74,13 @@ export default {
}, },
} }
</script> </script>
<style lang="scss"></style> <style lang="scss">
.index-zhuyonghu {
.canneng-index-title-with-icon {
display: inline-flex;
align-items: center;
gap: 8rpx;
font-size: 30rpx;
}
}
</style>

View File

@@ -1,7 +1,10 @@
<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 ml20 canneng-index-title-with-icon">
<uni-icons custom-prefix="iconfont" type="icon-gongcheng" size="18" color="#376cf3" />
<text>所有工程设备统计</text>
</view>
<view class="header"> <view class="header">
<view class="header-item boxClick" @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>
@@ -32,7 +35,10 @@
</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 ml20 canneng-index-title-with-icon">
<uni-icons custom-prefix="iconfont" type="icon-zaixianjianceshebei" size="18" color="#376cf3" />
<text>当前工程设备统计</text>
</view>
<view class="header"> <view class="header">
<view class="header-item boxClick" @click="jump('nowEngineering')"> <view class="header-item boxClick" @click="jump('nowEngineering')">
<view class="header-item-value">{{ <view class="header-item-value">{{
@@ -131,5 +137,11 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
.index-zhuanzhi { .index-zhuanzhi {
.canneng-index-title-with-icon {
display: inline-flex;
align-items: center;
gap: 8rpx;
font-size: 30rpx;
}
} }
</style> </style>

View File

@@ -1,7 +1,10 @@
<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 ml20 canneng-index-title-with-icon">
<uni-icons custom-prefix="iconfont" type="icon-gongcheng" size="18" color="#376cf3" />
<text>所有工程设备统计</text>
</view>
<view class="header"> <view class="header">
<view class="header-item boxClick" @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>
@@ -18,7 +21,10 @@
</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 ml20 canneng-index-title-with-icon">
<uni-icons custom-prefix="iconfont" type="icon-zaixianjianceshebei" size="18" color="#376cf3" />
<text>当前工程设备统计</text>
</view>
<view class="header"> <view class="header">
<view class="header-item boxClick" @click="jump('nowEngineering')"> <view class="header-item boxClick" @click="jump('nowEngineering')">
<view class="header-item-value" <view class="header-item-value"
@@ -43,7 +49,10 @@
<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 ml20 canneng-index-title-with-icon">
<uni-icons type="settings" size="18" color="#376cf3" />
<text>常用功能</text>
</view>
<view style="padding: 20rpx 20rpx 0"> <view style="padding: 20rpx 20rpx 0">
<Cn-grid title=""> <Cn-grid title="">
<Cn-grid-item <Cn-grid-item
@@ -171,4 +180,13 @@ export default {
}, },
} }
</script> </script>
<style lang="scss"></style> <style lang="scss">
.index-zhuyonghu {
.canneng-index-title-with-icon {
display: inline-flex;
align-items: center;
gap: 8rpx;
font-size: 30rpx;
}
}
</style>

View File

@@ -1,7 +1,10 @@
<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 ml20 canneng-index-title-with-icon">
<uni-icons custom-prefix="iconfont" type="icon-gongcheng" size="18" color="#376cf3" />
<text>所有工程设备统计</text>
</view>
<view class="header"> <view class="header">
<view class="header-item boxClick" @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>
@@ -30,7 +33,10 @@
</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 ml20 canneng-index-title-with-icon">
<uni-icons custom-prefix="iconfont" type="icon-zaixianjianceshebei" size="18" color="#376cf3" />
<text>当前工程设备统计</text>
</view>
<view class="header"> <view class="header">
<view class="header-item boxClick" @click="jump('nowEngineering')"> <view class="header-item boxClick" @click="jump('nowEngineering')">
<view class="header-item-value" <view class="header-item-value"
@@ -127,5 +133,11 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
.index-zhuanzhi { .index-zhuanzhi {
.canneng-index-title-with-icon {
display: inline-flex;
align-items: center;
gap: 8rpx;
font-size: 30rpx;
}
} }
</style> </style>

View File

@@ -0,0 +1,928 @@
<template>
<page-meta :page-style="'overflow:' + (indicatorPopupShow ? 'hidden' : 'visible')"></page-meta>
<view class="itic2-page">
<view class="itic2-content">
<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 mb16">
<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-search">
<uni-search-bar v-model="filterKeyword" bgColor="#fff" placeholder="搜索项目、设备、监测点"
cancelButton="none" />
</view>
<view class="monitor-list">
<view class="monitor-card card" v-for="(point, idx) in filteredMonitoringPoints" :key="idx">
<view class="card-header">
<view class="event-icon">
<Cn-icon-transient name="监测点" />
</view>
<view class="card-header-info">
<view class="point-name-row">
<text class="point-name ellipsis">{{ point.pointName }}</text>
<text class="event-tag" :class="point.runStatus == 0 ? 'zx-tag' : 'lx-tag'">
{{ point.runStatus == 0 ? '在线' : '离线' }}
</text>
</view>
<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 }} {{ child.unit ? `(${child.unit})` : '' }}</text>
</view>
<view v-if="hasTPhaseData(child)" class="phase-single">
<text class="phase-value-vertical phase-value-vertical--neutral">{{ child.T
}}</text>
</view>
<view v-else 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" v-if="shouldShowMoreBtn(point)" @click="onMoreIndicators(point)">
<uni-icons type="list" size="16" color="#376cf3" />
<text>更多指标</text>
</view>
</view>
<uni-load-more v-if="listStatus == 'loading' || filteredMonitoringPoints.length > 0"
:status="listStatus"></uni-load-more>
<Cn-empty v-else-if="listStatus !== 'loading'" style="top: 45%"></Cn-empty>
</view>
</view>
</view>
<view class="back-top boxClick" v-show="showBackTop" @click="backToTop">
<uni-icons type="arrow-up" size="22" color="#fff"></uni-icons>
</view>
<uni-popup ref="indicatorPopup" type="bottom" :safe-area="false" @change="onIndicatorPopupChange">
<view class="indicator-popup">
<view class="indicator-popup-header" @touchmove.stop.prevent>
<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 :show-scrollbar="false" @touchmove.stop>
<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'
import { getLineDataByEngineer } from '@/common/api/harmonic'
import { getDevCount } from '@/common/api/device.js'
/** 无本地缓存时的默认展示指标:电压、电流 */
const DEFAULT_INDICATOR_CODES = ['Key_Power_Quality_V', 'Key_Power_Quality_I']
/** 治理测点(lineType=0)卡片默认展示的指标 */
const GOVERNANCE_DEFAULT_INDICATORS = [
'电网电流',
'电网电压',
'负载电流',
'总输出电流',
]
export default {
data() {
return {
targetLists: [],
popupSelectedIndicators: [],
engineeringName: '',
engineeringId: '',
summaryStats: [
{ label: '项目总数', value: 0 },
{ label: '设备总数', value: 0 },
{ label: '监测点总数', value: 0 },
],
selectedIndicators: [],
phaseColors: [
{ name: 'A相', color: '#DAA520' },
{ name: 'B相', color: '#2E8B57' },
{ name: 'C相', color: '#D54941' },
],
monitoringPoints: [],
filterKeyword: '',
listStatus: 'noMore',
lineDataRequestId: 0,
showBackTop: false,
indicatorPopupShow: false,
skipRefreshOnShow: false,
}
},
computed: {
filteredMonitoringPoints() {
const keyword = (this.filterKeyword || '').trim().toLowerCase()
if (!keyword) return this.monitoringPoints
return this.monitoringPoints.filter((point) => {
const projectName = String(point.projectName || '').toLowerCase()
const deviceName = String(point.deviceName || '').toLowerCase()
const pointName = String(point.pointName || '').toLowerCase()
return (
projectName.indexOf(keyword) !== -1 ||
deviceName.indexOf(keyword) !== -1 ||
pointName.indexOf(keyword) !== -1
)
})
},
},
onPageScroll(e) {
this.showBackTop = e.scrollTop > 200
},
// 页面显示时同步工程名称;从指标详情返回时不刷新
onShow() {
const engineering = uni.getStorageSync('engineering')
const skipRefresh = this.skipRefreshOnShow
this.skipRefreshOnShow = false
if (engineering?.id) {
this.engineeringName = engineering.name || ''
this.engineeringId = engineering.id
if (!skipRefresh) {
this.info()
}
}
if (this.targetLists.length && !skipRefresh) {
this.loadSelectedIndicators()
}
},
// 加载电能质量指标字典
created() {
queryByCode('Key_Power_Quality').then((res) => {
queryCsDictTree(res.data.id).then((resp) => {
this.targetLists = (resp.data || []).slice().reverse()
this.loadSelectedIndicators()
})
})
},
// 下拉刷新
onPullDownRefresh() {
this.info()
},
methods: {
// 查询接口
info() {
if (!this.engineeringId) {
uni.stopPullDownRefresh()
return
}
this.loadDevCount()
this.loadLineData()
},
loadDevCount() {
getDevCount(this.engineeringId).then((res) => {
if (res.code == 'A0000') {
this.updateSummaryStats(res.data)
}
})
},
loadLineData() {
this.listStatus = 'loading'
this.monitoringPoints = []
this.filterKeyword = ''
const requestId = ++this.lineDataRequestId
const engineerId = this.engineeringId
getLineDataByEngineer({ id: engineerId })
.then((res) => {
if (requestId !== this.lineDataRequestId) return
if (res.code == 'A0000') {
this.monitoringPoints = this.parseMonitoringPoints(res.data)
} else if (res.message) {
this.$util.toast(res.message)
}
})
.catch(() => {
if (requestId !== this.lineDataRequestId) return
this.$util.toast('加载失败,请稍后重试')
})
.finally(() => {
if (requestId !== this.lineDataRequestId) return
this.listStatus = 'noMore'
uni.stopPullDownRefresh()
})
},
// 接口 data 转为页面 monitoringPoints
parseMonitoringPoints(data = []) {
const list = Array.isArray(data) ? data : []
return list.map((point) => ({
projectName: point.projectName || '',
deviceName: point.deviceName || '',
pointName: point.pointName || '',
dataTime: point.dataTime || '',
lineType: point.lineType,
runStatus: point.runStatus,
children: this.groupChildren(point.children || []),
}))
},
// 将按相别拆分的指标合并为 A/B/C 结构
groupChildren(children = []) {
const map = {}
const order = []
children.forEach((item) => {
const key = item.targetId || item.name
if (!map[key]) {
map[key] = {
targetId: item.targetId,
name: item.name,
unit: item.unit,
A: '-',
B: '-',
C: '-',
T: '-',
}
order.push(key)
}
const phase = item.phase
if (phase === 'A' || phase === 'B' || phase === 'C' || phase === 'T') {
map[key][phase] = this.formatPhaseValue(item.data)
}
})
return order.map((key) => map[key])
},
formatPhaseValue(value) {
if (value === null || value === undefined || value === '') return '-'
const num = Number(value)
if (Number.isNaN(num)) return String(value)
return num.toFixed(2)
},
hasTPhaseData(child) {
return child.T !== undefined && child.T !== null && child.T !== '-'
},
updateSummaryStats(devCount = {}) {
const deviceTotal =
(devCount.currentOnLineDevCount || 0) + (devCount.currentOffLineDevCount || 0)
this.summaryStats = [
{ label: '项目总数', value: devCount.currentProjectCount || 0 },
{ label: '设备总数', value: deviceTotal },
{ label: '监测点总数', value: devCount.lineCount || 0 },
]
},
// 指标名称超过6个字截断显示
formatIndicatorTag(name) {
if (!name || name.length <= 6) return name
return `${name.slice(0, 5)}...`
},
// 判断指标名称是否匹配(兼容括号后缀)
matchIndicator(name, selected) {
if (!name || !selected) return false
const base = (name || '').replace(/\(.*\)/, '').trim()
const selectedBase = (selected || '').replace(/\(.*\)/, '').trim()
return base === selectedBase
},
// 从缓存读取已选指标,无缓存时使用默认电压/电流指标
loadSelectedIndicators() {
const cached = uni.getStorageSync(this.$cacheKey.monitorSelectedIndicators)
if (Array.isArray(cached) && cached.length) {
const valid = cached.filter((name) =>
this.targetLists.some((item) => this.matchIndicator(item.name, name)),
)
if (valid.length) {
this.selectedIndicators = valid
return
}
}
this.selectedIndicators = this.getDefaultIndicatorsByCode()
this.saveSelectedIndicators()
},
getDefaultIndicatorsByCode() {
return this.targetLists
.filter((item) => DEFAULT_INDICATOR_CODES.includes(item.code) && item.name)
.map((item) => item.name)
},
saveSelectedIndicators() {
uni.setStorageSync(this.$cacheKey.monitorSelectedIndicators, this.selectedIndicators)
},
// 跳转切换工程
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)
this.saveSelectedIndicators()
},
// 打开指标选择弹窗
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 = []
},
onIndicatorPopupChange(e) {
this.indicatorPopupShow = !!e.show
},
// 切换弹窗内指标勾选状态
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.saveSelectedIndicators()
this.closeIndicatorPopup()
},
// 跳转指标详情页,展示该监测点全部指标
onMoreIndicators(point) {
this.skipRefreshOnShow = true
uni.setStorageSync('monitorPointDetail', {
...point,
engineeringName: this.engineeringName,
showAllIndicators: true,
})
uni.navigateTo({
url: '/pages/index/comp/targetInfo',
})
},
// 治理测点默认 4 项;普通测点按顶部已选指标过滤
getDisplayChildren(point) {
const children = point.children || []
if (point.lineType === 0) {
return GOVERNANCE_DEFAULT_INDICATORS.map((name) =>
children.find((child) => this.matchIndicator(child.name, name)),
).filter(Boolean)
}
return children.filter((child) =>
this.selectedIndicators.some((name) => this.matchIndicator(child.name, name)),
)
},
// 有指标数据时显示「更多指标」
shouldShowMoreBtn(point) {
return (point.children || []).length > 0
},
// 将指标列表按每行两个分组
chunkedChildren(children) {
const result = []
for (let i = 0; i < children.length; i += 2) {
result.push(children.slice(i, i + 2))
}
return result
},
backToTop() {
uni.pageScrollTo({
scrollTop: 0,
duration: 300,
})
this.showBackTop = false
},
},
}
</script>
<style lang="scss" scoped>
.itic2-page {
min-height: 100vh;
background: #f7f8fa;
position: relative;
}
.itic2-content {
padding: 20rpx 0 0rpx;
box-sizing: border-box;
}
.back-top {
position: fixed;
right: 30rpx;
bottom: 60rpx;
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: #376cf3;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 16rpx rgba(55, 108, 243, 0.35);
z-index: 1;
}
.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: 6rpx;
padding: 6rpx 14rpx;
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 0rpx;
}
.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-search {
position: sticky;
top: 0;
z-index: 10;
padding: 16rpx 10px 16rpx;
background: #f7f8fa;
/deep/ .uni-searchbar {
padding: 0;
}
}
.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-row {
display: flex;
align-items: center;
gap: 12rpx;
margin-bottom: 8rpx;
min-width: 0;
}
.point-name {
// flex: 1;
min-width: 0;
font-size: 30rpx;
font-weight: 700;
color: #333333;
}
.point-type-tag {
flex-shrink: 0;
padding: 4rpx 12rpx;
font-size: 22rpx;
color: #2E8B57;
background: #2E8B5715;
border-radius: 8rpx;
line-height: 1.2;
}
.meta-row {
display: grid;
grid-template-columns: 1fr;
gap: 6rpx 12rpx;
}
.meta-item {
font-size: 24rpx;
color: #666666;
line-height: 1.2;
}
.meta-time {
display: block;
margin-top: 8rpx;
font-size: 24rpx;
color: #666666;
line-height: 1.2;
}
.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-single {
display: flex;
justify-content: center;
align-items: center;
padding: 4rpx;
}
.phase-item-vertical {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding: 4rpx;
}
.phase-value-vertical {
font-size: 26rpx;
font-weight: 700;
&--neutral {
color: #333333;
}
}
.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 {
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;
}
}
.event-tag {
font-size: 22rpx;
padding: 2rpx 10rpx;
border-radius: 8rpx;
margin-top: 5rpx;
margin-left: 10rpx;
// height: 38rpx;
}
// 在线
.zx-tag {
background-color: #10b98120;
color: #10b981;
}
.lx-tag {
background-color: #ff3b3020;
color: #ff3b30;
}
/deep/ .uni-searchbar__box {
justify-content: left;
}
</style>

View File

@@ -3,13 +3,8 @@
<!-- {{ height }} --> <!-- {{ height }} -->
<view class="pd20"> <view class="pd20">
<uni-segmented-control <uni-segmented-control :current="curSub" class="subsection" active-color="#376cf3" :values="subsectionList"
:current="curSub" @clickItem="sectionChange" />
class="subsection"
active-color="#376cf3"
:values="subsectionList"
@clickItem="sectionChange"
/>
</view> </view>
<view class="filterCriteria"> <view class="filterCriteria">
<!-- 筛选条件 --> <!-- 筛选条件 -->
@@ -17,14 +12,10 @@
</view> </view>
<!-- 卡片 --> <!-- 卡片 -->
<scroll-view <scroll-view scroll-y="true" @scroll="onScroll" :scroll-top="scrollTop" scroll-with-animation
scroll-y="true" @refresherrefresh="refresherrefresh" :refresher-triggered="triggered" refresher-enabled="true"
@refresherrefresh="refresherrefresh"
:refresher-triggered="triggered"
refresher-enabled="true"
class="event-list mt20" class="event-list mt20"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }" :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"> <uni-card class="event-item" :class="item.type" v-for="(item, index) in store.data" :key="index">
<!-- 头部图标 + 信息 + 操作 --> <!-- 头部图标 + 信息 + 操作 -->
@@ -37,7 +28,7 @@
size="40" size="40"
color="#E6A23C" color="#E6A23C"
></uni-icons> --> ></uni-icons> -->
<Cn-icon-transient :name="`报告`" /> <Cn-icon-transient :name="`报告1`" />
<view class="badge1" v-if="item.isRead == 0"> </view> <view class="badge1" v-if="item.isRead == 0"> </view>
</view> </view>
<view class="event-info"> <view class="event-info">
@@ -48,22 +39,20 @@
</view> --> </view> -->
</view> </view>
<view class="event-desc"> <view class="event-desc">
<text <text>统计时间{{
>统计时间{{ curSub == 0 ? item.startTime : item.startTime + ' 至 ' + item.endTime
curSub == 0 ? item.startTime : item.startTime + ' 至 ' + item.endTime }}</text>
}}</text
>
</view> </view>
</view> </view>
<view class="event-action" v-if="curSub == 0 ? monthFlag : item.endTime != thisMonth01"> <view class="event-action" v-if="!showNotGenerated(item)">
<view class="iconText boxClick" @click="download(item)" <view class="iconText boxClick" @click="download(item)"><uni-icons type="arrow-down"
><uni-icons type="arrow-down" color="#fff" size="16"></uni-icons> color="#fff" size="16"></uni-icons>
</view> </view>
</view> </view>
</view> </view>
<!-- 详情区域 --> <!-- 详情区域 -->
<view class="event-detail textBox" @touchmove.stop> <view class="event-detail textBox" @touchmove.stop>
<text v-if="curSub == 0 ? monthFlag : item.endTime != thisMonth01">{{ <text v-if="!showNotGenerated(item)">{{
item.overLimitDesc == '' ? '该监测点暂无指标越限' : item.overLimitDesc item.overLimitDesc == '' ? '该监测点暂无指标越限' : item.overLimitDesc
}}</text> }}</text>
<text v-else>数据未生成暂不支持下载</text> <text v-else>数据未生成暂不支持下载</text>
@@ -72,12 +61,13 @@
<uni-icons type="download" size="16" color="#376cf3"></uni-icons>下载报告 <uni-icons type="download" size="16" color="#376cf3"></uni-icons>下载报告
</view> --> </view> -->
</uni-card> </uni-card>
<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)" :status="store.status"></uni-load-more>
:status="store.status"
></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty> <Cn-empty v-else style="top: 20%"></Cn-empty>
</scroll-view> </scroll-view>
<!-- <view class="back-top boxClick" v-show="showBackTop" @click="backToTop">
<uni-icons type="arrow-up" size="22" color="#fff"></uni-icons>
</view> -->
</view> </view>
</template> </template>
<script> <script>
@@ -105,18 +95,19 @@ export default {
return { return {
status: 'noMore', status: 'noMore',
curSub: 0, curSub: 0,
subsectionList: ['报', '月报'], subsectionList: ['报', '月报'],
thisSelectValue: {}, thisSelectValue: {},
triggered: true, triggered: true,
height: 0, height: 0,
thisMonth01: '', thisMonth01: '',
monthFlag: true, scrollTop: 0,
oldScrollTop: 0,
showBackTop: false,
} }
}, },
created() {}, created() { },
mounted() { mounted() {
this.thisMonth01 = this.$util.getToday().slice(0, -3) + '-01' this.thisMonth01 = this.$util.getToday().slice(0, -3) + '-01'
this.monthFlag = this.$util.getToday() != this.$util.getToday().slice(0, -3) + '-01'
// this.setHeight() // this.setHeight()
}, },
@@ -137,6 +128,8 @@ export default {
}, },
sectionChange(index) { sectionChange(index) {
this.curSub = index.currentIndex this.curSub = index.currentIndex
this.showBackTop = false
this.scrollTop = 0
this.init() this.init()
}, },
init() { init() {
@@ -156,7 +149,9 @@ export default {
} }
// this.store.params.startTime = this.selectValue.range[0] // this.store.params.startTime = this.selectValue.range[0]
// this.store.params.endTime = this.selectValue.range[1] // this.store.params.endTime = this.selectValue.range[1]
this.store.loadedCallback = () => {} this.store.loadedCallback = () => {
this.store.status = 'noMore'
}
this.store.reload() this.store.reload()
}, },
@@ -185,46 +180,14 @@ export default {
timeType: this.selectValue.report, timeType: this.selectValue.report,
}) })
.then((res) => { .then((res) => {
// 下载文件资源到本地 const match = this.$config.static + res.data.match(/excelreport([^?]*)/)[1]
uni.downloadFile({ uni.downloadFile({
url: res.data, // 后端返回的线上文件路径 url: match,
success: function (res) { success: (downloadRes) => {
if (res.statusCode === 200) { if (downloadRes.statusCode === 200) {
// 文件到本地 this.openReportFile(downloadRes.tempFilePath)
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 { } else {
uni.hideLoading()
uni.showToast({ uni.showToast({
icon: 'none', icon: 'none',
mask: true, mask: true,
@@ -233,10 +196,19 @@ export default {
}) })
} }
}, },
fail: function (res) {}, fail: () => {
uni.hideLoading()
uni.showToast({
icon: 'none',
mask: true,
title: '下载失败!',
duration: 1000,
})
},
}) })
}) })
.catch((err) => { .catch((err) => {
uni.hideLoading()
uni.showToast({ uni.showToast({
icon: 'none', icon: 'none',
mask: true, mask: true,
@@ -245,6 +217,72 @@ export default {
}) })
}) })
}, },
openReportFile(tempFilePath) {
const previewFile = (filePath) => {
uni.hideLoading()
uni.openDocument({
filePath,
fileType: 'xlsx',
showMenu: true,
success: () => {
console.log('成功打开文件')
},
fail: (err) => {
console.log('打开文件失败', err)
uni.showToast({
icon: 'none',
title: '预览失败',
})
},
})
}
// #ifdef APP-PLUS
// iOS 需保留 xlsx 后缀saveFile 随机路径会导致 openDocument 失败
if (plus.os.name === 'iOS') {
const fileName = `harmonic_report_${Date.now()}.xlsx`
plus.io.resolveLocalFileSystemURL(
tempFilePath,
(entry) => {
plus.io.resolveLocalFileSystemURL(
'_doc/',
(docEntry) => {
entry.copyTo(
docEntry,
fileName,
(newEntry) => previewFile(newEntry.fullPath),
() => previewFile(tempFilePath)
)
},
() => previewFile(tempFilePath)
)
},
() => previewFile(tempFilePath)
)
return
}
// #endif
uni.saveFile({
tempFilePath,
success: (data) => {
uni.showToast({
icon: 'success',
mask: true,
title: '下载成功!',
duration: 1000,
})
setTimeout(() => previewFile(data.savedFilePath), 500)
},
fail: () => {
uni.hideLoading()
uni.showToast({
icon: 'none',
title: '保存失败!',
})
},
})
},
// 下拉 // 下拉
refresherrefresh() { refresherrefresh() {
this.triggered = true this.triggered = true
@@ -253,6 +291,24 @@ export default {
this.triggered = false this.triggered = false
}, 500) }, 500)
}, },
onScroll(e) {
this.oldScrollTop = e.detail.scrollTop
this.showBackTop = e.detail.scrollTop > 200
},
backToTop() {
this.scrollTop = this.oldScrollTop
this.$nextTick(() => {
this.scrollTop = 0
})
this.showBackTop = false
},
/** 日报统计时间与今天相同月报开始、结束时间均为当月1号 */
showNotGenerated(item) {
if (this.curSub === 0) {
return item.startTime === this.$util.getToday()
}
return item.startTime === this.thisMonth01 && item.endTime === this.thisMonth01
},
}, },
computed: {}, computed: {},
@@ -262,12 +318,14 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import '@/pages/message1/index.scss'; @import '@/pages/message1/index.scss';
.event-title { .event-title {
justify-content: space-between; justify-content: space-between;
} }
.event-tags { .event-tags {
display: flex; display: flex;
font-size: 27rpx !important ; font-size: 27rpx !important;
line-height: 50rpx; line-height: 50rpx;
} }
@@ -276,6 +334,7 @@ export default {
// display: grid; // display: grid;
// grid-template-columns: 1fr 1fr; // grid-template-columns: 1fr 1fr;
} }
.downloadReport { .downloadReport {
width: 100%; width: 100%;
background: #376cf320; background: #376cf320;
@@ -288,25 +347,31 @@ export default {
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
.filterCriteria { .filterCriteria {
.nav { .nav {
background-color: #fff; background-color: #fff;
} }
.choose1 { .choose1 {
background-color: #fff; background-color: #fff;
padding: 0 20rpx; padding: 0 20rpx;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
/deep/ .uni-checkbox-input { /deep/ .uni-checkbox-input {
width: 30rpx; width: 30rpx;
height: 30rpx; height: 30rpx;
} }
font-size: 26rpx; font-size: 26rpx;
} }
} }
/deep/ .uni-scroll-view-refresher { /deep/ .uni-scroll-view-refresher {
display: none; display: none;
} }
.iconText { .iconText {
width: 45rpx; width: 45rpx;
height: 45rpx; height: 45rpx;
@@ -315,13 +380,16 @@ export default {
text-align: center; text-align: center;
line-height: 40rpx; line-height: 40rpx;
} }
.segmented-control { .segmented-control {
flex: 1; flex: 1;
margin-right: 24rpx; margin-right: 24rpx;
height: 60rpx; height: 60rpx;
} }
/* 列表容器 */ /* 列表容器 */
.event-list { .event-list {
/* 头部:图标 + 信息 + 操作 */ /* 头部:图标 + 信息 + 操作 */
.event-header { .event-header {
display: flex; display: flex;
@@ -332,15 +400,37 @@ export default {
/* 图标区域(按类型区分背景色) */ /* 图标区域(按类型区分背景色) */
.event-icon { .event-icon {
background-color: #376cf320; background-color: #376cf320;
width: 80rpx;
height: 80rpx;
} }
.event-tags { .event-tags {
font-size: 24rpx; font-size: 24rpx;
} }
} }
.textBox { .textBox {
// @touchmove.stop // @touchmove.stop
max-height: 110rpx; max-height: 110rpx;
overflow-y: auto; overflow-y: auto;
} }
.back-top {
position: fixed;
right: 30rpx;
bottom: 60rpx;
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: #376cf3;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 16rpx rgba(55, 108, 243, 0.35);
z-index: 1;
}
/deep/ .segmented-control__text {
line-height: 60rpx !important;
}
</style> </style>

View File

@@ -0,0 +1,315 @@
<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">
<view class="point-name-row">
<text class="point-name ellipsis">{{ pointInfo.pointName || '-' }}</text>
<text class="event-tag ml10" :class="pointInfo.runStatus == 0 ? 'zx-tag' : 'lx-tag'">
{{ pointInfo.runStatus == 0 ? '在线' : '离线' }}
</text>
</view>
<view class="meta-row">
<text v-if="pointInfo.engineeringName" class="meta-item ellipsis">
工程{{ pointInfo.engineeringName }}
</text>
<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 v-if="moreChildren.length" class="params-section">
<view v-for="(rowItems, rowIdx) in chunkedChildren(moreChildren)" :key="rowIdx" class="double-row">
<view v-for="(child, childIdx) in rowItems" :key="child.targetId || childIdx"
class="param-group">
<view class="param-title">
<text>{{ child.name }}{{ child.unit ? ` (${child.unit})` : '' }}</text>
</view>
<view v-if="hasTPhaseData(child)" class="phase-single">
<text class="phase-value-vertical phase-value-vertical--neutral">{{ child.T }}</text>
</view>
<view v-else 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 v-else class="empty-wrap">
<Cn-empty msg="暂无指标数据" :paddingTop="120"></Cn-empty>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
export default {
data() {
return {
pointInfo: {},
phaseColors: [
{ name: 'A相', color: '#DAA520' },
{ name: 'B相', color: '#2E8B57' },
{ name: 'C相', color: '#D54941' },
],
}
},
computed: {
moreChildren() {
return this.pointInfo.children || []
},
},
onLoad() {
const point = uni.getStorageSync('monitorPointDetail')
if (point) {
this.pointInfo = { ...point }
if (point.pointName) {
uni.setNavigationBarTitle({ title: point.pointName })
}
}
},
onUnload() {
uni.removeStorageSync('monitorPointDetail')
},
methods: {
hasTPhaseData(child) {
return child.T !== undefined && child.T !== null && child.T !== '-'
},
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-row {
display: flex;
align-items: center;
gap: 12rpx;
margin-bottom: 8rpx;
min-width: 0;
}
.point-name {
// flex: 1;
min-width: 0;
font-size: 30rpx;
font-weight: 700;
color: #333333;
}
.meta-row {
display: grid;
grid-template-columns: 1fr ;
gap: 6rpx 12rpx;
}
.meta-item {
font-size: 24rpx;
color: #666666;
line-height: 1.2;
}
.meta-time {
display: block;
margin-top: 8rpx;
font-size: 24rpx;
color: #666666;
line-height: 1.2;
}
.legend-row {
display: flex;
gap: 20rpx;
align-items: center;
justify-content: end;
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;
}
.empty-wrap {
position: relative;
min-height: 320rpx;
}
.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-single {
display: flex;
justify-content: center;
align-items: center;
padding: 4rpx;
}
.phase-item-vertical {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding: 4rpx;
}
.phase-value-vertical {
font-size: 26rpx;
font-weight: 700;
&--neutral {
color: #333333;
}
}
.phase-divider {
width: 1px;
background: #d2d2d2;
margin: 8rpx 0;
}
.ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.event-tag {
flex-shrink: 0;
font-size: 22rpx;
padding: 2rpx 10rpx;
border-radius: 8rpx;
}
.zx-tag {
background-color: #10b98120;
color: #10b981;
}
.lx-tag {
background-color: #ff3b3020;
color: #ff3b30;
}
</style>

View File

@@ -12,13 +12,14 @@
</view> </view>
<!-- 申请记录 --> <!-- 申请记录 -->
<view v-if="curSub == 1"> <view v-if="curSub == 1" style="position: relative">
<view class="filterCriteria"> <view class="filterCriteria">
<!-- 筛选条件 --> <!-- 筛选条件 -->
<Cn-filterCriteria @select="select" :showQianTree="false"> </Cn-filterCriteria> <Cn-filterCriteria @select="select" :showQianTree="false"> </Cn-filterCriteria>
</view> </view>
<scroll-view scroll-y="true" @refresherrefresh="refresherrefresh" @scrolltolower="scrolltolower" <scroll-view scroll-y="true" @scroll="onScroll" :scroll-top="scrollTop" scroll-with-animation
:refresher-triggered="triggered" refresher-enabled="true" class="record event-list mt20" @refresherrefresh="refresherrefresh" @scrolltolower="scrolltolower" :refresher-triggered="triggered"
refresher-enabled="true" class="record event-list mt20"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }"> :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"> <uni-card class="event-item" :class="item.type" v-for="(item, index) in store.data" :key="index">
<!-- 头部图标 + 信息 + 操作 --> <!-- 头部图标 + 信息 + 操作 -->
@@ -39,9 +40,9 @@
<text class="event-id">{{ item.lineName }}</text> <text class="event-id">{{ item.lineName }}</text>
</view> </view>
<view class="event-desc"> <view class="event-desc">
<text>工程名称{{ item.engineeringName }}</text> <text>工程{{ item.engineeringName }}</text>
<text>项目名称{{ item.projectName }}</text> <text>项目{{ item.projectName }}</text>
<text>设备名称{{ item.deviceName }}</text> <text>设备{{ item.deviceName }}</text>
<!-- <text>申请时间{{ item.time }}</text> <!-- <text>申请时间{{ item.time }}</text>
<text>事件数{{ item.eventNums }}</text> --> <text>事件数{{ item.eventNums }}</text> -->
</view> </view>
@@ -66,7 +67,7 @@
<text>报告状态</text> <text>报告状态</text>
<text :style="{ color: item.isComplete == 1 ? '#10b981' : '#FF0000' }">{{ <text :style="{ color: item.isComplete == 1 ? '#10b981' : '#FF0000' }">{{
item.isComplete == 1 ? '已完成' : '未完成' item.isComplete == 1 ? '已完成' : '未完成'
}}</text> }}</text>
</view> </view>
<view class="device-body-item"> <view class="device-body-item">
<text>申请时间</text> <text>申请时间</text>
@@ -90,6 +91,9 @@
:status="store.status"></uni-load-more> :status="store.status"></uni-load-more>
<Cn-empty v-else style="top: 30%"></Cn-empty> <Cn-empty v-else style="top: 30%"></Cn-empty>
</scroll-view> </scroll-view>
<view class="back-top boxClick" v-show="showBackTop" @click="backToTop">
<uni-icons type="arrow-up" size="22" color="#fff"></uni-icons>
</view>
</view> </view>
</view> </view>
</template> </template>
@@ -132,6 +136,9 @@ export default {
userInfo: {}, userInfo: {},
height: 0, height: 0,
selectValue: {}, selectValue: {},
scrollTop: 0,
oldScrollTop: 0,
showBackTop: false,
} }
}, },
created() { }, created() { },
@@ -170,6 +177,8 @@ export default {
sectionChange(index) { sectionChange(index) {
this.curSub = index.currentIndex this.curSub = index.currentIndex
this.showBackTop = false
this.scrollTop = 0
}, },
// 生成报告 // 生成报告
generate(item) { generate(item) {
@@ -183,10 +192,17 @@ export default {
uni.showToast({ uni.showToast({
icon: 'success', icon: 'success',
mask: true, mask: true,
title: '生成事件报告成功!', title: '生成报告成功!',
duration: 1000, duration: 1000,
}) })
this.store.reload() this.store.reload()
}).catch((err) => {
uni.showToast({
icon: 'none',
mask: true,
title: err.message,
duration: 1000,
})
}) })
}, },
// 下载报告 // 下载报告
@@ -199,46 +215,26 @@ export default {
id: item.eventId, id: item.eventId,
}) })
.then((res) => { .then((res) => {
// 下载文件资源到本地 const pathMatch = res.data.match(/excelreport([^?]*)/)
if (!pathMatch) {
uni.hideLoading()
uni.showToast({
icon: 'none',
mask: true,
title: '文件地址无效',
duration: 1000,
})
return
}
const fileMeta = this.getReportFileMeta(pathMatch[1])
const match = this.$config.static + pathMatch[1]
uni.downloadFile({ uni.downloadFile({
url: res.data, // 后端返回的线上文件路径 url: match,
success: function (res) { success: (downloadRes) => {
if (res.statusCode === 200) { if (downloadRes.statusCode === 200) {
// 文件到本地 this.openReportFile(downloadRes.tempFilePath, fileMeta)
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 { } else {
uni.hideLoading()
uni.showToast({ uni.showToast({
icon: 'none', icon: 'none',
mask: true, mask: true,
@@ -247,10 +243,19 @@ export default {
}) })
} }
}, },
fail: function (res) { }, fail: () => {
uni.hideLoading()
uni.showToast({
icon: 'none',
mask: true,
title: '下载失败!',
duration: 1000,
})
},
}) })
}) })
.catch((err) => { .catch((err) => {
uni.hideLoading()
uni.showToast({ uni.showToast({
icon: 'none', icon: 'none',
mask: true, mask: true,
@@ -259,6 +264,79 @@ export default {
}) })
}) })
}, },
getReportFileMeta(filePath) {
const lower = (filePath || '').toLowerCase()
if (lower.endsWith('.doc')) {
return { fileType: 'doc', ext: 'doc' }
}
return { fileType: 'docx', ext: 'docx' }
},
openReportFile(tempFilePath, fileMeta) {
const previewFile = (filePath) => {
uni.hideLoading()
uni.openDocument({
filePath,
fileType: fileMeta.fileType,
showMenu: true,
success: () => {
console.log('成功打开文件')
},
fail: (err) => {
console.log('打开文件失败', err)
uni.showToast({
icon: 'none',
title: '预览失败',
})
},
})
}
// #ifdef APP-PLUS
// iOS 需保留 doc/docx 后缀saveFile 随机路径会导致 openDocument 失败
if (plus.os.name === 'iOS') {
const fileName = `event_report_${Date.now()}.${fileMeta.ext}`
plus.io.resolveLocalFileSystemURL(
tempFilePath,
(entry) => {
plus.io.resolveLocalFileSystemURL(
'_doc/',
(docEntry) => {
entry.copyTo(
docEntry,
fileName,
(newEntry) => previewFile(newEntry.fullPath),
() => previewFile(tempFilePath)
)
},
() => previewFile(tempFilePath)
)
},
() => previewFile(tempFilePath)
)
return
}
// #endif
uni.saveFile({
tempFilePath,
success: (data) => {
uni.showToast({
icon: 'success',
mask: true,
title: '下载成功!',
duration: 1000,
})
setTimeout(() => previewFile(data.savedFilePath), 500)
},
fail: () => {
uni.hideLoading()
uni.showToast({
icon: 'none',
title: '保存失败!',
})
},
})
},
// 刷新 // 刷新
reload() { reload() {
switch (this.curSub) { switch (this.curSub) {
@@ -284,6 +362,17 @@ export default {
this.store.next && this.store.next() this.store.next && this.store.next()
} }
}, },
onScroll(e) {
this.oldScrollTop = e.detail.scrollTop
this.showBackTop = e.detail.scrollTop > 200
},
backToTop() {
this.scrollTop = this.oldScrollTop
this.$nextTick(() => {
this.scrollTop = 0
})
this.showBackTop = false
},
}, },
watch: {}, watch: {},
} }
@@ -327,11 +416,12 @@ export default {
.device-body-item { .device-body-item {
display: flex; display: flex;
// justify-content: space-between; // justify-content: space-between;
font-size: 28rpx; font-size: 26rpx;
color: #666666; color: #666666;
line-height: 1.5; line-height: 1.5;
} }
// } // }
@@ -382,4 +472,23 @@ export default {
/deep/ .uni-scroll-view-refresher { /deep/ .uni-scroll-view-refresher {
display: none; display: none;
} }
.back-top {
position: fixed;
right: 30rpx;
bottom: 60rpx;
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: #376cf3;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 16rpx rgba(55, 108, 243, 0.35);
z-index: 1;
}
/deep/ .segmented-control__text {
line-height: 60rpx !important;
}
</style> </style>

View File

@@ -1,33 +1,20 @@
<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">{{
>{{ userInfo.authorities === 'engineering_user'
userInfo.authorities === 'engineering_user' ? '创建工程'
? '创建工程' : select.engineeringName || emptyEngineeringName
: select.engineeringName || emptyEngineeringName }}
}}
</text> </text>
<uni-icons <uni-icons type="bottom" size="16" color="#111"
type="bottom" v-if="select.engineeringName && userInfo.authorities != 'engineering_user'"></uni-icons>
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">
@@ -43,15 +30,34 @@
<YouKe :devCount="devCount" v-if="userInfo.authorities === 'tourist'"></YouKe> <YouKe :devCount="devCount" v-if="userInfo.authorities === 'tourist'"></YouKe>
<!-- 工程列表 --> <!-- 工程列表 -->
<template v-show="engineeringList.length" v-if="userInfo.authorities === 'engineering_user'"> <template v-show="engineeringList.length" v-if="userInfo.authorities === 'engineering_user'">
<view class="canneng-index-title mt20">工程列表</view> <!-- <view class="canneng-index-title mt20 canneng-index-title-with-icon">
<uni-icons type="list" size="18" color="#376cf3" />
<text>工程列表</text>
</view> -->
<view class="canneng-index-title mt20">
<view class="canneng-index-title-with-icon">
<uni-icons type="list" size="18" color="#376cf3" />
<text>工程列表</text>
</view>
<view class="nav-menu nav-menu-btn boxClick" @click="jump">关键指标概览 </view>
</view>
<Engineering ref="engineering" :store="store" @refresh="store.search()" /> <Engineering ref="engineering" :store="store" @refresh="store.search()" />
</template> </template>
<!-- 设备列表 --> <!-- 设备列表 -->
<template v-else v-show="engineeringList.length"> <template v-else v-show="engineeringList.length">
<view class="canneng-index-title mt20">设备列表</view> <view class="canneng-index-title mt20">
<view class="canneng-index-title-with-icon">
<uni-icons custom-prefix="iconfont" type="icon-shebei4" size="18" color="#376cf3" />
<text>设备列表</text>
</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>
<view class="back-top boxClick" v-show="showBackTop" @click="backToTop">
<uni-icons type="arrow-up" size="22" color="#fff"></uni-icons>
</view>
</view> </view>
</Cn-page> </Cn-page>
</template> </template>
@@ -66,6 +72,7 @@ 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'
import { checkAppUpdate } from '@/common/js/update.js'
export default { export default {
mixins: [list], mixins: [list],
@@ -90,6 +97,7 @@ export default {
engineeringList: [], engineeringList: [],
navTabHeight: 0, navTabHeight: 0,
timer: null, timer: null,
showBackTop: false,
} }
}, },
computed: { computed: {
@@ -103,6 +111,7 @@ export default {
} }
}, },
}, },
methods: { methods: {
selectEngineering() { selectEngineering() {
if (this.userInfo.authorities === 'engineering_user') { if (this.userInfo.authorities === 'engineering_user') {
@@ -227,8 +236,28 @@ export default {
}) })
}, },
// 动态配置导航栏按钮 // 动态配置导航栏按钮
jump() {
uni.navigateTo({
url: `/pages/index/comp/monitoringPoint`,
})
},
backToTop() {
uni.pageScrollTo({
scrollTop: 0,
duration: 300,
})
this.showBackTop = false
},
},
onPageScroll(e) {
this.showBackTop = e.scrollTop > 200
}, },
onLoad() { onLoad() {
// #ifdef APP-PLUS
checkAppUpdate()
// #endif
// 页面加载时,动态配置导航栏按钮 // 页面加载时,动态配置导航栏按钮
if (!uni.getStorageSync(this.$cacheKey.access_token)) { if (!uni.getStorageSync(this.$cacheKey.access_token)) {
uni.reLaunch({ uni.reLaunch({
@@ -266,6 +295,8 @@ export default {
// #endif // #endif
}, },
onShow() { onShow() {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo) this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
let access_token = uni.getStorageSync(this.$cacheKey.access_token) let access_token = uni.getStorageSync(this.$cacheKey.access_token)
@@ -296,7 +327,7 @@ export default {
}, },
} }
</script> </script>
<style lang="scss"> <style lang="scss" scoped>
.popup-content { .popup-content {
background: #fff; background: #fff;
} }
@@ -307,7 +338,16 @@ export default {
.canneng-index-title { .canneng-index-title {
padding: 0 20rpx; padding: 0 20rpx;
font-weight: 500; /* font-weight: 500; */
display: flex;
align-items: center;
}
.canneng-index-title-with-icon {
display: inline-flex;
align-items: center;
gap: 8rpx;
font-size: 30rpx;
} }
/deep/ .uni-card { /deep/ .uni-card {
@@ -317,4 +357,43 @@ 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: 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;
}
margin-left: auto;
}
.back-top {
position: fixed;
right: 30rpx;
bottom: 60rpx;
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: #376cf3;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 16rpx rgba(55, 108, 243, 0.35);
z-index: 1;
}
</style> </style>

View File

@@ -2,13 +2,8 @@
<Cn-page :loading="loading" class="messageBox" style="padding-top: 10px"> <Cn-page :loading="loading" class="messageBox" style="padding-top: 10px">
<view slot="body" class="message"> <view slot="body" class="message">
<view class="tabsBox"> <view class="tabsBox">
<uni-segmented-control <uni-segmented-control :current="current" :values="items" style-type="text" active-color="#376cf3"
:current="current" @clickItem="onClickItem" />
:values="items"
style-type="text"
active-color="#376cf3"
@clickItem="onClickItem"
/>
<!-- 角标 --> <!-- 角标 -->
<view class="badge-container"> <view class="badge-container">
<span v-for="(item, index) in items" :key="index" class="badge"> <span v-for="(item, index) in items" :key="index" class="badge">
@@ -17,42 +12,28 @@
</span> </span>
</view> </view>
<!-- 筛选条件 --> <!-- 筛选条件 -->
<Cn-filterCriteria <Cn-filterCriteria ref="cnFilterCriteria" :level="current === 0 ? 3 : current === 1 ? 3 : 2"
ref="cnFilterCriteria" @select="select">
:level="current === 0 ? 3 : current === 1 ? 3 : 2" <picker v-if="current === 0" @change="bindPickerChange" :value="sortIndex" :range="sortOptions">
@select="select" <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> </Cn-filterCriteria>
</view> </view>
<view class="content"> <view class="content">
<Transient <Transient ref="TransientRef" v-if="current === 0" :navHeight="navHeight" :selectValue="selectValue"
ref="TransientRef" :sortIndex="sortIndex" @getDevCount="getDevCount" />
v-if="current === 0" <SteadyState ref="SteadyStateRef" v-if="current === 1" :navHeight="navHeight" :selectValue="selectValue"
:navHeight="navHeight" @getDevCount="getDevCount" />
:selectValue="selectValue" <Alarm ref="AlarmRef" v-if="current === 2" :navHeight="navHeight" :selectValue="selectValue"
@getDevCount="getDevCount" @getDevCount="getDevCount" />
/> <Run ref="RunRef" v-if="current === 3" :navHeight="navHeight" :selectValue="selectValue"
<SteadyState @getDevCount="getDevCount" />
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>
</view> </view>
</Cn-page> </Cn-page>
@@ -79,10 +60,11 @@ export default {
navHeight: 0, navHeight: 0,
selectValue: {}, selectValue: {},
devCount: [], devCount: [],
// 筛选数据 sortIndex: 0,
sortOptions: ['发生时间', '暂降幅值', '持续时间'],
} }
}, },
onLoad() {}, onLoad() { },
mounted() { mounted() {
this.setHeight() this.setHeight()
}, },
@@ -119,13 +101,11 @@ export default {
this.getDevCount() this.getDevCount()
this.$nextTick(() => { this.$nextTick(() => {
if (params.type !== '') { if (params.type !== '') {
this.current = params.type - 0 this.current = (params.type - 0)||0
} }
if (params.engineeringName != '') { if (params.engineeringName != '') {
this.$refs.cnFilterCriteria && this.$refs.cnFilterCriteria.external(params) this.$refs.cnFilterCriteria && this.$refs.cnFilterCriteria.external(params)
} }
// this.refresh()
this.$refs.TransientRef && this.$refs.TransientRef.getConfig()
}) })
}, },
// 页面销毁 // 页面销毁
@@ -186,6 +166,14 @@ export default {
this.setHeight() this.setHeight()
}, 100) }, 100)
}, },
bindPickerChange(e) {
this.sortIndex = e.detail.value
setTimeout(() => {
if (this.$refs.TransientRef) {
this.$refs.TransientRef.init()
}
}, 0)
},
// 设置角标 // 设置角标
getDevCount() { getDevCount() {
if (uni.getStorageSync('projectList')[1] != undefined) { if (uni.getStorageSync('projectList')[1] != undefined) {
@@ -253,13 +241,16 @@ export default {
<style lang="scss"> <style lang="scss">
.messageBox { .messageBox {
overflow: hidden; overflow: hidden;
/deep/.tabsBox { /deep/.tabsBox {
position: relative; position: relative;
background-color: #fff; background-color: #fff;
.segmented-control { .segmented-control {
// height: 40px; // height: 40px;
background-color: #fff; background-color: #fff;
border-bottom: 1px solid #cccccc70; border-bottom: 1px solid #cccccc70;
.segmented-control__item { .segmented-control__item {
align-items: baseline; align-items: baseline;
margin-top: 5px; margin-top: 5px;
@@ -270,10 +261,12 @@ export default {
font-size: 30rpx !important; font-size: 30rpx !important;
color: rgb(96, 98, 102); color: rgb(96, 98, 102);
} }
.segmented-control__item--text { .segmented-control__item--text {
font-weight: bold; font-weight: bold;
padding: 0 0 5rpx; padding: 0 0 5rpx;
} }
.choose { .choose {
// padding: 20rpx; // padding: 20rpx;
// display: flex; // display: flex;
@@ -287,38 +280,68 @@ export default {
width: 90%; width: 90%;
margin: 20rpx auto; margin: 20rpx auto;
} }
.badge-container { .badge-container {
position: absolute; position: absolute;
top: -10rpx; /* 徽章向上偏移,与控件重叠 */ top: -10rpx;
/* 徽章向上偏移,与控件重叠 */
display: flex; display: flex;
justify-content: space-around; justify-content: space-around;
right: 0; right: 0;
width: 100%; width: 100%;
height: 0; height: 0;
pointer-events: none; /* 确保徽章不干扰点击事件 */ pointer-events: none;
/* 确保徽章不干扰点击事件 */
} }
/deep/ .uni-badge--error { /deep/ .uni-badge--error {
background-color: #ff3b30; background-color: #ff3b30;
} }
.badge { .badge {
flex: 1; flex: 1;
// position: absolute;
// min-width: 18px;
// height: 16px;
// padding: 0 4px;
// background-color: #ff3b30; /* 红色徽章 */
// color: white;
// font-size: 22rpx;
// line-height: 16px;
// text-align: center;
// border-radius: 9px;
//
text-align: center; text-align: center;
// transform: translateX(-110%); /* 使徽章中心对齐右上角 */
.uni-badge--x { .uni-badge--x {
left: 70rpx; 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> </style>

View File

@@ -52,6 +52,7 @@
<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')" v-if="userInfo.authorities !== 'tourist'"> <view class="mine-nav" @click="jump('feedback')" v-if="userInfo.authorities !== 'tourist'">
<image mode="aspectFill" class="mine-nav-icon" src="/static/feedback.png" /> <image mode="aspectFill" class="mine-nav-icon" src="/static/feedback.png" />
<view class="mine-nav-label">反馈列表</view> <view class="mine-nav-label">反馈列表</view>
@@ -75,18 +76,13 @@
<view <view
class="mine-nav" class="mine-nav"
@click="jump('engineering/setting')" @click="jump('engineering/setting')"
v-if="userInfo.authorities === 'engineering_user' || userInfo.authorities !== 'tourist'" v-if="userInfo.authorities === 'engineering_user' || userInfo.authorities == 'operation_manager'"
> >
<image mode="aspectFill" class="mine-nav-icon" src="/static/like.png" /> <image mode="aspectFill" class="mine-nav-icon" src="/static/like.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('transientSetting')" v-if="userInfo.authorities !== 'tourist'">
<!-- 调试内容配置 serverSetting-->
<image mode="aspectFill" class="mine-nav-icon" src="/static/tongji.png" />
<view class="mine-nav-label">暂态统计配置</view>
<uni-icons type="forward" color="#aaa" size="20"></uni-icons>
</view>
<view class="mine-nav" @click="jump('setup')" style="border-bottom: none"> <view class="mine-nav" @click="jump('setup')" style="border-bottom: none">
<image mode="aspectFill" class="mine-nav-icon" src="/static/setup.png" /> <image mode="aspectFill" class="mine-nav-icon" src="/static/setup.png" />
<view class="mine-nav-label">设置</view> <view class="mine-nav-label">设置</view>
@@ -259,7 +255,7 @@ export default {
handleScon() { handleScon() {
this.$refs.message.close() this.$refs.message.close()
uni.scanCode({ uni.scanCode({
onlyFromCamera: true, // onlyFromCamera: false,
success: (res) => { success: (res) => {
console.log('条码类型:' + res.scanType) console.log('条码类型:' + res.scanType)
console.log('条码内容:' + res.result) console.log('条码内容:' + res.result)

View File

@@ -6,34 +6,33 @@
<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')" v-if="userInfo.authorities === 'app_vip_user'">关闭</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')" v-if="userInfo.authorities === 'app_vip_user'">关闭</view>
<!-- </template>--> </template>
<!-- <view class="title-btn" @click="open">回复</view>--> <view class="title-btn" @click="open" v-if="pageData.status != '0'">回复</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" clearable
<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>
@@ -41,7 +40,7 @@
</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() {
@@ -55,11 +54,13 @@ export default {
"url": "/static/logo.png", "url": "/static/logo.png",
} }
], ],
userInfo: {},
pageData: {}, pageData: {},
pageOption: {} pageOption: {}
} }
}, },
onLoad(o) { onLoad(o) {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
this.pageOption = o this.pageOption = o
this.init() this.init()
updateChatStatus({ updateChatStatus({
@@ -93,7 +94,7 @@ export default {
}) })
}, },
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()
@@ -101,7 +102,9 @@ export default {
}) })
}, },
open() { open() {
this.chatContent = ''
this.$refs.inputDialog.open() this.$refs.inputDialog.open()
}, },
over() { over() {
}, },

View File

@@ -18,20 +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 class="ml10" v-if="type === '0' || item.status != '1'">
<!-- <uni-icons type="search" size="25" color="#376cf3"></uni-icons> --> <uni-icons type="search" size="25" color="#376cf3"></uni-icons>
🔍 </view>
</view>
</view> </view>
<view class="content-item-footer">{{ item.subTitle }}</view> <view class="content-item-footer">{{ item.subTitle }}</view>
</view> </view>

View File

@@ -7,10 +7,10 @@
</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>
@@ -82,9 +82,25 @@ export default {
font-size: 26rpx; font-size: 26rpx;
.detail-content-title { .detail-content-title {
font-size: 28rpx; display: inline-flex;
align-items: center;
position: relative;
padding-left: 20rpx;
font-size: 30rpx;
color: #111; color: #111;
font-weight: 700; font-weight: 700;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 8rpx;
height: 28rpx;
background: $uni-theme-color;
border-radius: 3rpx;
}
} }
} }
} }

View File

@@ -3,23 +3,13 @@
<!-- 运行告警 --> <!-- 运行告警 -->
<!-- 卡片 --> <!-- 卡片 -->
<scroll-view <scroll-view scroll-y="true" @scroll="onScroll" :scroll-top="scrollTop" scroll-with-animation
scroll-y="true" @refresherrefresh="refresherrefresh" @scrolltolower="scrolltolower"
@refresherrefresh="refresherrefresh" :refresher-triggered="triggered" refresher-enabled="true" class="event-list"
@scrolltolower="scrolltolower" :style="{ height: 'calc(100vh - ' + (navHeight + 10) + 'px)', overflow: 'auto' }">
:refresher-triggered="triggered"
refresher-enabled="true"
class="event-list"
:style="{ height: 'calc(100vh - ' + (navHeight + 10) + 'px)', overflow: 'auto' }"
>
<!-- 循环渲染事件项 --> <!-- 循环渲染事件项 -->
<uni-card <uni-card class="event-item boxClick" :class="item.type" v-for="(item, index) in this.store.data"
class="event-item boxClick" :key="index" @click="jump(item)">
:class="item.type"
v-for="(item, index) in this.store.data"
:key="index"
@click="jump(item)"
>
<!-- 头部图标 + 信息 + 操作 --> <!-- 头部图标 + 信息 + 操作 -->
<view class="event-header"> <view class="event-header">
<view class="event-icon"> <view class="event-icon">
@@ -31,38 +21,40 @@
color="#376cf3" color="#376cf3"
></uni-icons> --> ></uni-icons> -->
<Cn-icon-transient :name="`运行告警`" /> <Cn-icon-transient :name="`运行告警`" />
<view class="badge1" v-if="item.isRead == 0"> </view> <view class="badge1" v-if="item.isRead == 0"></view>
</view> </view>
<view class="event-info"> <view class="event-info">
<view class="event-title"> <view class="event-title">
<text class="event-id">{{ item.date }}</text> <text class="event-id">{{ item.date }}</text>
</view> </view>
<view class="event-desc"> <view class="event-desc">
<text>告警终端{{ item.warnNums }}</text> <text>告警终端总数{{ item.warnNums }}</text>
<text>通讯中断{{ item.interruptCounts }}</text> <text v-if="item.onlineRateIsWarn">在线率偏低</text>
<text>终端告警{{ item.warnCounts}}</text> <text v-if="item.integrityIsWarn">完整性偏低</text>
<text v-if="item.warnCounts > 0">事件触发终端告警{{ item.warnCounts }}</text>
</view> </view>
</view> </view>
<view class="event-action"> <view class="event-action">
<!-- <uni-icons type="search" size="25" color="#376cf3"></uni-icons> --> <uni-icons type="search" size="25" color="#376cf3"></uni-icons>
🔍
</view> </view>
</view> </view>
<!-- <view class="event-detail"> <!-- <view class="event-detail">
<text> 告警终端{{ item.warnNums }} </text> <text> 告警终端总数{{ item.warnNums }} </text>
</view> --> </view> -->
</uni-card> </uni-card>
<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)" :status="store.status"></uni-load-more>
:status="store.status"
></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty> <Cn-empty v-else style="top: 20%"></Cn-empty>
</scroll-view> </scroll-view>
<view class="back-top boxClick" v-show="showBackTop" @click="backToTop">
<uni-icons type="arrow-up" size="22" color="#fff"></uni-icons>
</view>
</view> </view>
</template> </template>
<script> <script>
import list from '@/common/js/list' import list from '@/common/js/list'
export default { export default {
components: {}, components: {},
props: { props: {
@@ -80,9 +72,13 @@ export default {
return { return {
triggered: true, triggered: true,
status: 'noMore', //more加载前 loading加载中 noMore加载后 status: 'noMore', //more加载前 loading加载中 noMore加载后
scrollTop: 0,
oldScrollTop: 0,
showBackTop: false,
} }
}, },
mounted() {}, mounted() {
},
methods: { methods: {
init() { init() {
@@ -101,8 +97,9 @@ export default {
}, },
jump(item) { jump(item) {
let str = JSON.stringify(item).replace(/%/g, '百分比') let str = JSON.stringify(item).replace(/%/g, '百分比')
item.status = '1'
uni.navigateTo({ url: '/pages/message1/comp/alarmDetails?detail=' + encodeURIComponent(str) }) uni.navigateTo({ url: '/pages/message1/comp/alarmDetails?detail=' + encodeURIComponent(str) })
item.isRead = 1
}, },
// 下拉 // 下拉
refresherrefresh() { refresherrefresh() {
@@ -118,6 +115,17 @@ export default {
this.store.next && this.store.next() this.store.next && this.store.next()
} }
}, },
onScroll(e) {
this.oldScrollTop = e.detail.scrollTop
this.showBackTop = e.detail.scrollTop > 200
},
backToTop() {
this.scrollTop = this.oldScrollTop
this.$nextTick(() => {
this.scrollTop = 0
})
this.showBackTop = false
},
}, },
computed: {}, computed: {},
@@ -137,6 +145,7 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
@import './index.scss'; @import './index.scss';
/* 列表容器 */ /* 列表容器 */
.event-list { .event-list {
margin-top: 20rpx; margin-top: 20rpx;
@@ -160,7 +169,27 @@ export default {
flex: 1; flex: 1;
} }
} }
/deep/ .uni-scroll-view-refresher { /deep/ .uni-scroll-view-refresher {
display: none; display: none;
} }
.event-header {
margin-bottom: 0rpx !important;
}
.back-top {
position: fixed;
right: 30rpx;
bottom: 60rpx;
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: #376cf3;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 16rpx rgba(55, 108, 243, 0.35);
z-index: 1;
}
</style> </style>

View File

@@ -225,7 +225,7 @@ export default {
// 点击查看详情 // 点击查看详情
let item = params.value[3] let item = params.value[3]
let str = JSON.stringify(item).replace(/%/g, '百分比') let str = JSON.stringify(item).replace(/%/g, '百分比')
uni.navigateTo({ url: '/pages/message1/comp/transientDetails?detail=' + encodeURIComponent(str) }) // uni.navigateTo({ url: '/pages/message1/comp/transientDetails?detail=' + encodeURIComponent(str) })
}) })
}, },
}, },

View File

@@ -217,7 +217,7 @@ export default {
// 点击查看详情 // 点击查看详情
let item = params.value[3] let item = params.value[3]
let str = JSON.stringify(item).replace(/%/g, '百分比') let str = JSON.stringify(item).replace(/%/g, '百分比')
uni.navigateTo({ url: '/pages/message1/comp/transientDetails?detail=' + encodeURIComponent(str) }) // uni.navigateTo({ url: '/pages/message1/comp/transientDetails?detail=' + encodeURIComponent(str) })
}) })
}, },
}, },

View File

@@ -5,7 +5,7 @@
<!-- <view class="detail-content-title mb20">发生时间</view> --> <!-- <view class="detail-content-title mb20">发生时间</view> -->
<view>{{ detail.date }}</view> <view>{{ detail.date }}</view>
</view> </view>
<view class="detail-content" style="padding: 0px"> <view class="detail-content" style="padding-top: 0px;padding-bottom: 0px">
<view class="detail-content-title pb20 pt20 pl20">终端告警列表</view> <view class="detail-content-title pb20 pt20 pl20">终端告警列表</view>
</view> </view>
@@ -13,58 +13,65 @@
<uni-card class="event-item" :class="item.type" v-for="(item, index) in list" :key="index"> <uni-card class="event-item" :class="item.type" v-for="(item, index) in list" :key="index">
<!-- 头部图标 + 信息 + 操作 --> <!-- 头部图标 + 信息 + 操作 -->
<view class="event-header"> <view class="event-header">
<view <view class="event-icon"
class="event-icon" :class="item.devType == 'Direct_Connected_Device' ? 'zl-bgc' : 'jc-bgc'">
:class="item.devType == 'Direct_Connected_Device' ? 'zl-bgc' : 'jc-bgc'"
> <Cn-icon-transient :name="item.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备'" />
<!-- 动态图标根据类型切换 -->
<!-- <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 class="badge1" v-if="item.status == 0"> </view>
</view> </view>
<view class="event-info"> <view class="event-info">
<view class="event-title"> <view class="event-title">
<text class="event-id">{{ item.devName }}</text> <text class="event-id">{{ item.devName }}</text>
<text <text class="event-tag"
class="event-tag" :class="item.devType == 'Direct_Connected_Device' ? 'zl-tag' : 'jc-tag'">{{
:class="item.devType == 'Direct_Connected_Device' ? 'zl-tag' : 'jc-tag'" item.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备' }}</text>
>{{ item.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备' }}</text
>
</view> </view>
<view class="event-desc"> <view class="event-desc">
<text>工程名称{{ item.engineeringName }}</text> <text>工程{{ item.engineeringName }}</text>
<text>项目名称{{ item.projectName }}</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> --> <!-- <text>事件时间{{ item.startTime }}</text> -->
</view> </view>
</view> </view>
</view> </view>
<!-- 详情区域 --> <!-- 详情区域 -->
<view class="event-detail"> <view class="event-detail">
<view v-if="item.interruptCounts"> <view v-if="item.dataDetails.onlineRate.isAbnormal">
通讯中断 {{ item.interruptCounts }} 详情如下 <text>在线率
<view class="textBox"> <text class="integrity-value">{{ item.dataDetails.onlineRate.value }}%</text> 
<view </text>
v-for="date in String(item.interruptDetails || '').split('')"
class="textBox mb5"
>{{ date }}</view
></view
>
</view> </view>
<view v-if="item.warnCounts"> <view v-if="hasIntegrityAbnormal(item)" class="mt10">
数据完整性
<view class="integrity-grid">
<view
v-for="(rowItems, rowIdx) in chunkedPoints(getAbnormalPoints(item))"
:key="rowIdx"
class="grid-row">
<view
v-for="(point, pIdx) in rowItems"
:key="pIdx"
class="param-group">
<view class="param-title">
<text>{{ point.monitorName }}</text>
</view>
<view class="integrity-value-row">
<text class="integrity-value">{{ point.value }}%</text>
</view>
</view>
</view>
</view>
</view>
<view v-if="item.warnCounts" class="mt10 ">
终端告警 {{ item.warnCounts }} 详情如下 终端告警 {{ item.warnCounts }} 详情如下
<view class="textBox"> <view class="textBox mt10">
<view v-for="val in item.warnDetails" class="textBox mb5"> <view v-for="val in item.warnDetails" class="textBox mb5" style=" font-size: 26rpx;">
{{ val.warnEventTime + '发生' + val.warnEventDesc }} {{ val.warnEventTime + '发生' + val.warnEventDesc }}
</view></view </view>
> </view>
</view> </view>
</view> </view>
</uni-card> </uni-card>
@@ -97,6 +104,21 @@ export default {
} }
}, },
methods: { methods: {
hasIntegrityAbnormal(item) {
const points = item?.dataDetails?.integrity?.monitorPoints
if (!Array.isArray(points) || !points.length) return false
return points.some((p) => p.isAbnormal === true)
},
getAbnormalPoints(item) {
return item?.dataDetails?.integrity?.monitorPoints?.filter((p) => p.isAbnormal === true) || []
},
chunkedPoints(points) {
const result = []
for (let i = 0; i < points.length; i += 3) {
result.push(points.slice(i, i + 3))
}
return result
},
init() { init() {
queryAlarmDetail({ queryAlarmDetail({
devList: this.detail.devIds, devList: this.detail.devIds,
@@ -115,75 +137,150 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import '../index.scss'; @import '../index.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: 28rpx; font-size: 28rpx;
.detail-content-title { .detail-content-title {
display: inline-flex;
align-items: center;
position: relative;
padding-left: 20rpx;
font-size: 30rpx; font-size: 30rpx;
color: #111; color: #111;
font-weight: 700; font-weight: 700;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 8rpx;
height: 28rpx;
background: $uni-theme-color;
border-radius: 3rpx;
}
} }
} }
.collapseTop { .collapseTop {
padding: 10rpx 0; padding: 10rpx 0;
margin-left: 15px; margin-left: 15px;
.name { .name {
font-size: 28rpx; font-size: 28rpx;
font-weight: 700; font-weight: 700;
color: #333333; color: #333333;
} }
} }
.frequency { .frequency {
display: flex; display: flex;
font-size: 28rpx; font-size: 28rpx;
// color: #666666; // color: #666666;
} }
} }
.textBox { .textBox {
// border-bottom: 1px solid #eee; // border-bottom: 1px solid #eee;
font-size: 28rpx; font-size: 28rpx;
color: #666666; color: #666666;
text-indent: 2em; text-indent: 2em;
} }
.event-list { .event-list {
// background: #fff; // background: #fff;
padding-bottom: 10rpx; padding-bottom: 10rpx;
// .event-icon { // .event-icon {
// background-color: #376cf320; // background-color: #376cf320;
// } // }
.zl-bgc { .zl-bgc {
background-color: #376cf320; background-color: #376cf320;
} }
.jc-bgc { .jc-bgc {
background-color: #376cf320; background-color: #376cf320;
} }
.zl-tag { .zl-tag {
background-color: #007aff20; background-color: #007aff20;
color: #007aff; color: #007aff;
} }
.jc-tag { .jc-tag {
background-color: #007aff20; background-color: #007aff20;
color: #007aff; color: #007aff;
} }
} }
/deep/ .uni-collapse-item__title-box { /deep/ .uni-collapse-item__title-box {
padding: 0 15px 0 0; padding: 0 15px 0 0;
height: 56rpx; height: 56rpx;
line-height: 56rpx; line-height: 56rpx;
font-size: 26rpx !important; font-size: 26rpx !important;
color: #666666; color: #666666;
span { span {
font-size: 26rpx !important; font-size: 26rpx !important;
} }
} }
.textBox { .textBox {
max-height: 120rpx; max-height: 150rpx;
overflow-y: auto; overflow-y: auto;
} }
.integrity-grid {
margin-top: 16rpx;
}
.grid-row {
display: grid;
grid-template-columns: repeat(3, 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;
text-align: center;
}
.param-title {
font-size: 24rpx;
color: #666666;
// margin-bottom: 8rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.integrity-value-row {
display: flex;
justify-content: center;
align-items: center;
padding: 2rpx;
}
.integrity-value {
font-size: 26rpx;
font-weight: 700;
color: #333333;
}
</style> </style>

View File

@@ -7,19 +7,17 @@
</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.engineeringName }} </view> <view class="mb5"> 工程{{ detail.engineeringName }} </view>
<view class="mb5"> 项目名称{{ detail.projectName }} </view> <view class="mb5"> 项目{{ detail.projectName }} </view>
<view class="mb5"> 设备名称{{ detail.devName }} </view> <view class="mb5"> 设备{{ detail.devName }} </view>
<view class="mb5"> 监测点名称{{ detail.lineName }}</view> <view class="mb5"> 监测点{{ detail.lineName }}</view>
<view class="mb5" style="display: flex"> <view class="mb5" style="display: flex">
越限详情 越限详情
<view style="flex: 1" class="details">{{ detail.overLimitDesc }}</view></view <view style="flex: 1" class="details">{{ detail.overLimitDesc }}</view>
> </view>
</view> </view>
<view class="detail-content"> <view class="detail-content">
<view class="detail-content-title mb20" <view class="detail-content-title mb20">指标越限详情<text class="prompt">仅显示最严重的10组数据</text></view>
>指标越限详情<text class="prompt">仅显示最严重的10组数据</text></view
>
<uni-collapse accordion v-model="collapseValue"> <uni-collapse accordion v-model="collapseValue">
<uni-collapse-item :title="item.targetName" v-for="item in list"> <uni-collapse-item :title="item.targetName" v-for="item in list">
@@ -30,12 +28,12 @@
<text v-if="!item.harmDetailList[0].hasT">A相</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">B相</text>
<text v-if="!item.harmDetailList[0].hasT">C相</text> <text v-if="!item.harmDetailList[0].hasT">C相</text>
<text v-if="item.harmDetailList[0].hasT"></text> <text v-if="item.harmDetailList[0].hasT"></text>
<text>限值</text> <text>限值</text>
</view> </view>
<view class="table-row" v-for="value in item.harmDetailList"> <view class="table-row" v-for="value in item.harmDetailList">
<text>{{ value.statisticsTime }}</text> <text>{{ value.statisticsTime }}</text>
<text>{{ value.valueType }}</text> <text>{{ value.valueType || '/' }}</text>
<text v-if="!value.hasT">{{ value.dataA }}</text> <text v-if="!value.hasT">{{ value.dataA }}</text>
<text v-if="!value.hasT">{{ value.dataB }}</text> <text v-if="!value.hasT">{{ value.dataB }}</text>
<text v-if="!value.hasT">{{ value.dataC }}</text> <text v-if="!value.hasT">{{ value.dataC }}</text>
@@ -100,11 +98,28 @@ export default {
font-size: 28rpx; font-size: 28rpx;
.detail-content-title { .detail-content-title {
display: inline-flex;
align-items: center;
position: relative;
padding-left: 20rpx;
font-size: 30rpx; font-size: 30rpx;
color: #111; color: #111;
font-weight: 700; font-weight: 700;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 8rpx;
height: 28rpx;
background: $uni-theme-color;
border-radius: 3rpx;
}
} }
} }
.limit { .limit {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -112,46 +127,58 @@ export default {
width: 450rpx; width: 450rpx;
margin-left: auto; margin-left: auto;
} }
.prompt { .prompt {
font-size: 24rpx; font-size: 24rpx;
color: #111; color: #111;
font-weight: 500; font-weight: 500;
} }
} }
.data-table { .data-table {
margin-top: 20rpx; margin-top: 20rpx;
background-color: #fff; background-color: #fff;
overflow: hidden; overflow: hidden;
color: #666;
.table-header, .table-header,
.table-row { .table-row {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
padding: 20rpx 0rpx; padding: 15rpx 0rpx;
height: 20px;
border-bottom: 1rpx solid #eee; border-bottom: 1rpx solid #eee;
text { text {
width: 100rpx; width: 100rpx;
text-align: center; text-align: center;
font-size: 28rpx; font-size: 28rpx;
// color: #333; // color: #333;
&:nth-child(1) { &:nth-child(1) {
flex: 1; flex: 1;
} }
&:nth-child(2) { &:nth-child(2) {
flex: 1; flex: 1;
} }
} }
} }
.table-header { .table-header {
padding: 0rpx; padding: 0rpx;
padding-bottom: 10rpx; padding-bottom: 10rpx;
} }
} }
/deep/ .uni-collapse-item__title-text { /deep/ .uni-collapse-item__title-text {
font-weight: 700; font-weight: 700;
span { span {
font-size: 28rpx; font-size: 28rpx;
} }
} }
.details { .details {
max-height: 70px; max-height: 70px;
overflow-y: auto; overflow-y: auto;

View File

@@ -2,60 +2,102 @@
<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>{{ 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.engineeringName }} </view>
<view class="mb5"> 项目名称{{ detail.projectName }} </view> <view class="mb5"> 工程{{ detail.engineeringName }} </view>
<view class="mb5"> 设备名称{{ detail.equipmentName }}</view> <view class="mb5"> 项目{{ detail.projectName }} </view>
<view class="mb5"> 监测点名称{{ detail.lineName }}</view> <view class="mb5"> 设备{{ detail.equipmentName }}</view>
<view class="mb5"> 监测点{{ detail.lineName }}</view>
<view class="mb5"> 暂态类型{{ detail.showName }}</view> <view class="mb5"> 暂态类型{{ detail.showName }}</view>
<view class="mb5" v-if="detail.evtParamPhase"> 相别{{ detail.evtParamPhase }}</view>
<view class="mb5" v-if="detail.evtParamTm"> 持续时间{{ detail.evtParamTm }}s</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.evtParamVVaDepth"> 幅值{{ detail.evtParamVVaDepth }}%</view>
<view class="mb5" v-if="detail.evtParamPhase"> 相别{{ detail.evtParamPhase }}</view> <view class="mb5"> 落点区域{{ detail.landPoint != null && detail.landPoint !== '' ? detail.landPoint :
<!-- <view class="mb5" v-for="(item, textIndex) in detail.dataSet" :key="textIndex"> '未知'
{{ item.showName + '' + (item.value == 3.1415926 ? '-' : item.value) + (item.unit || '') }} }}</view>
</view> -->
</view> </view>
<view class="detail-content"> <view class="detail-tabs">
<view class="detail-content-title mb20">瞬时波形图</view> <uni-segmented-control :current="detailTab" active-color="#376cf3" :values="['波形图', 'ITIC', 'F47']"
<image @clickItem="onDetailTabChange" />
style="width: 100%"
:src="detail.instantPics"
mode="widthFix"
v-if="detail.instantPics"
@click="previewImage(detail.instantPics)"
/>
<text v-else>暂无</text>
</view> </view>
<view class="detail-content"> <view v-if="detailTab == 0">
<view class="detail-content-title mb20">RMS波形图</view> <view class="detail-content">
<image <view class="detail-content-title mb20">瞬时波形图</view>
style="width: 100%" <image style="width: 100%" :src="detail.instantPics" mode="widthFix" v-if="detail.instantPics"
:src="detail.rmsPics" @click="previewImage(detail.instantPics)" />
mode="widthFix" <text v-else>暂无</text>
v-if="detail.rmsPics" <!-- <view v-if="listWaveData.length > 0">
@click="previewImage(detail.rmsPics)" <waveform v-for="(value, ind) in listWaveData" :index="ind" :unit="unit" :data="value"
/> style="height: 150px;" />
<text v-else>暂无</text> </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>
</view> </view>
</Cn-page> </Cn-page>
</template> </template>
<script> <script>
import { updateStatus } from '@/common/api/message' 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 { export default {
components: { ITIC, F47, waveform },
data() { data() {
return { return {
loading: true, loading: true,
detail: {}, 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) { onLoad(options) {
// console.log(options.detail) console.log("🚀 ~ options:", options)
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)
@@ -66,16 +108,79 @@ export default {
eventIds: [this.detail.id], 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: { methods: {
onDetailTabChange(e) {
this.detailTab = e.currentIndex
},
previewImage(url) { previewImage(url) {
// uni.previewImage({
// urls: [url],
// })
uni.navigateTo({ uni.navigateTo({
url: `/pages/message1/comp/preview?url=${encodeURIComponent(url)}`, 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> </script>
@@ -95,5 +200,45 @@ export default {
font-weight: 700; 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;
}
/deep/ .segmented-control__text {
line-height: 60rpx !important;
}
.detail-content-info {
display: grid;
grid-template-columns: 1fr 1fr;
}
// .detail-content-info {
// display: grid;
// grid-template-columns: 1fr 1fr;
// }
.detail-content-info {
display: grid;
grid-template-columns: 1fr 1fr;
} }
</style> </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>

View File

@@ -76,11 +76,11 @@
border-radius: 20rpx; border-radius: 20rpx;
} }
/* 电压暂降 - 蓝色系 */ /* 暂降 - 蓝色系 */
.sag .event-icon { .sag .event-icon {
background-color: #2563eb20; background-color: #2563eb20;
} }
/* 电压暂升 - 橙色系 */ /* 暂升 - 橙色系 */
.swell .event-icon { .swell .event-icon {
background-color: #e6a23c20; background-color: #e6a23c20;
} }
@@ -150,7 +150,7 @@
gap: 8rpx; gap: 8rpx;
} }
.event-desc text { .event-desc text {
font-size: 28rpx; font-size: 24rpx;
color: #666666; color: #666666;
line-height: 1.2; line-height: 1.2;
} }
@@ -172,7 +172,7 @@
/* 详情文本 */ /* 详情文本 */
.event-detail { .event-detail {
font-size: 28rpx; font-size: 26rpx;
color: #666666; color: #666666;
line-height: 1.5; line-height: 1.5;
padding-top: 10rpx; padding-top: 10rpx;

View File

@@ -3,7 +3,8 @@
<!-- 运行事件 --> <!-- 运行事件 -->
<!-- 卡片 --> <!-- 卡片 -->
<scroll-view scroll-y="true" @refresherrefresh="refresherrefresh" @scrolltolower="scrolltolower" <scroll-view scroll-y="true" @scroll="onScroll" :scroll-top="scrollTop" scroll-with-animation
@refresherrefresh="refresherrefresh" @scrolltolower="scrolltolower"
:refresher-triggered="triggered" refresher-enabled="true" class="event-list" :refresher-triggered="triggered" refresher-enabled="true" class="event-list"
:style="{ height: 'calc(100vh - ' + (navHeight + 10) + 'px)', overflow: 'auto' }"> :style="{ height: 'calc(100vh - ' + (navHeight + 10) + 'px)', overflow: 'auto' }">
<!-- 循环渲染事件项 --> <!-- 循环渲染事件项 -->
@@ -25,9 +26,9 @@
== 'Direct_Connected_Device' ? '治理设备' : '监测设备' }}</text> == 'Direct_Connected_Device' ? '治理设备' : '监测设备' }}</text>
</view> </view>
<view class="event-desc"> <view class="event-desc">
<text>工程名称{{ item.engineeringName }}</text> <text>工程{{ item.engineeringName }}</text>
<text>项目名称{{ item.projectName }}</text> <text>项目{{ item.projectName }}</text>
<text>事件时间{{ item.startTime }}</text> <text>事件时间{{ item.startTime2 }}</text>
</view> </view>
</view> </view>
</view> </view>
@@ -40,6 +41,9 @@
:status="store.status"></uni-load-more> :status="store.status"></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty> <Cn-empty v-else style="top: 20%"></Cn-empty>
</scroll-view> </scroll-view>
<view class="back-top boxClick" v-show="showBackTop" @click="backToTop">
<uni-icons type="arrow-up" size="22" color="#fff"></uni-icons>
</view>
</view> </view>
</template> </template>
<script> <script>
@@ -61,6 +65,9 @@ export default {
data() { data() {
return { return {
triggered: true, triggered: true,
scrollTop: 0,
oldScrollTop: 0,
showBackTop: false,
} }
}, },
mounted() { }, mounted() { },
@@ -106,6 +113,17 @@ export default {
this.store.next && this.store.next() this.store.next && this.store.next()
} }
}, },
onScroll(e) {
this.oldScrollTop = e.detail.scrollTop
this.showBackTop = e.detail.scrollTop > 200
},
backToTop() {
this.scrollTop = this.oldScrollTop
this.$nextTick(() => {
this.scrollTop = 0
})
this.showBackTop = false
},
}, },
computed: {}, computed: {},
@@ -155,4 +173,20 @@ export default {
/deep/ .uni-scroll-view-refresher { /deep/ .uni-scroll-view-refresher {
display: none; display: none;
} }
.back-top {
position: fixed;
right: 30rpx;
bottom: 60rpx;
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: #376cf3;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 16rpx rgba(55, 108, 243, 0.35);
z-index: 1;
}
</style> </style>

View File

@@ -4,8 +4,8 @@
<view class="transientBox"> <view class="transientBox">
<view class="statistics pd20"> <view class="statistics pd20">
<view <view
class="box" class="box boxClick"
:class="{ boxClick: item.label == filterValue }" :class="{ boxClick1: item.label == filterValue }"
v-for="item in list" v-for="item in list"
@click=" @click="
filterValue = item.label filterValue = item.label
@@ -17,10 +17,13 @@
</view> </view>
</view> </view>
</view> </view>
<!-- 稳态数量 --> <!-- 越限数量 -->
<scroll-view <scroll-view
v-if="filterValue == '稳态数量'" v-if="filterValue == '越限数量'"
scroll-y="true" scroll-y="true"
@scroll="onScroll"
:scroll-top="scrollTop"
scroll-with-animation
@refresherrefresh="refresherrefresh" @refresherrefresh="refresherrefresh"
@scrolltolower="scrolltolower" @scrolltolower="scrolltolower"
:refresher-triggered="triggered" :refresher-triggered="triggered"
@@ -47,27 +50,26 @@
color="#E6A23C" color="#E6A23C"
></uni-icons> --> ></uni-icons> -->
<Cn-icon-transient :name="`稳态越限`" /> <Cn-icon-transient :name="`稳态越限`" />
<view class="badge1" v-if="item.isRead == 0"> </view> <view class="badge1" v-if="item.isRead == 0"></view>
</view> </view>
<view class="event-info"> <view class="event-info">
<view class="event-title"> <view class="event-title">
<text class="event-id">{{ item.lineName }}</text> <text class="event-id">{{ item.lineName }}</text>
</view> </view>
<view class="event-desc"> <view class="event-desc">
<text>工程名称{{ item.engineeringName }}</text> <text>工程{{ item.engineeringName }}</text>
<text>项目名称{{ item.projectName }}</text> <text>项目{{ item.projectName }}</text>
<text>设备名称{{ item.devName }}</text> <text>设备{{ item.devName }}</text>
<!-- <text>统计日期{{ item.statisticsDate }}</text> --> <!-- <text>统计日期{{ item.statisticsDate }}</text> -->
</view> </view>
</view> </view>
<view class="event-action"> <view class="event-action">
<!-- <uni-icons type="search" size="25" color="#376cf3"></uni-icons> --> <uni-icons type="search" size="25" color="#376cf3"></uni-icons>
🔍
</view> </view>
</view> </view>
<!-- 详情区域 --> <!-- 详情区域 -->
<view class="event-detail textBox" @touchmove.stop> <view class="event-detail textBox" @touchmove.stop>
<text>{{ item.statisticsDate }}发生 {{ item.overLimitDesc }} </text> <text>{{ item.statisticsDate }}发生 {{ item.overLimitDesc }}</text>
</view> </view>
</uni-card> </uni-card>
@@ -92,6 +94,9 @@
<scroll-view <scroll-view
v-if="filterValue == '越限测点数'" v-if="filterValue == '越限测点数'"
scroll-y="true" scroll-y="true"
@scroll="onScroll"
:scroll-top="scrollTop"
scroll-with-animation
@refresherrefresh="refresherrefresh" @refresherrefresh="refresherrefresh"
@scrolltolower="scrolltolower" @scrolltolower="scrolltolower"
:refresher-triggered="triggered" :refresher-triggered="triggered"
@@ -118,9 +123,9 @@
<text class="event-id">{{ item.lineName }}</text> <text class="event-id">{{ item.lineName }}</text>
</view> </view>
<view class="event-desc"> <view class="event-desc">
<text>工程名称{{ item.engineeringName }}</text> <text>工程{{ item.engineeringName }}</text>
<text>项目名称{{ item.projectName }}</text> <text>项目{{ item.projectName }}</text>
<text>设备名称{{ item.devName }}</text> <text>设备{{ item.devName }}</text>
<!-- <text>统计日期{{ item.statisticsDate }}</text> --> <!-- <text>统计日期{{ item.statisticsDate }}</text> -->
</view> </view>
</view> </view>
@@ -144,11 +149,15 @@
></uni-load-more> ></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty> <Cn-empty v-else style="top: 20%"></Cn-empty>
</scroll-view> </scroll-view>
<view class="back-top boxClick" v-show="showBackTop" @click="backToTop">
<uni-icons type="arrow-up" size="22" color="#fff"></uni-icons>
</view>
</view> </view>
</template> </template>
<script> <script>
import list from '@/common/js/list' import list from '@/common/js/list'
import { queryAppHarmonicCounts, queryAppHarmonicLine } from '../../common/api/harmonic.js' import { queryAppHarmonicCounts, queryAppHarmonicLine } from '../../common/api/harmonic.js'
export default { export default {
components: {}, components: {},
props: { props: {
@@ -165,9 +174,9 @@ export default {
data() { data() {
return { return {
height: 0, height: 0,
filterValue: '稳态数量', filterValue: '越限数量',
list: [ list: [
{ value: 0, label: '稳态数量' }, { value: 0, label: '越限数量' },
{ value: 0, label: '越限天数' }, { value: 0, label: '越限天数' },
{ value: 0, label: '越限测点数' }, { value: 0, label: '越限测点数' },
], ],
@@ -181,6 +190,9 @@ export default {
triggered: true, triggered: true,
status: 'noMore', //more加载前 loading加载中 noMore加载后 status: 'noMore', //more加载前 loading加载中 noMore加载后
scrollTop: 0,
oldScrollTop: 0,
showBackTop: false,
} }
}, },
mounted() { mounted() {
@@ -206,6 +218,8 @@ export default {
// "time": "" // "time": ""
// 查詢 // 查詢
init() { init() {
this.showBackTop = false
this.scrollTop = 0
if (this.filterValue == '越限测点数') { if (this.filterValue == '越限测点数') {
this.store = this.DataSource('/cs-harmonic-boot/csHarmonic/queryAppHarmonicLine') this.store = this.DataSource('/cs-harmonic-boot/csHarmonic/queryAppHarmonicLine')
} else { } else {
@@ -235,7 +249,7 @@ export default {
jump(item) { jump(item) {
let str = JSON.stringify(item).replace(/%/g, '百分比') let str = JSON.stringify(item).replace(/%/g, '百分比')
item.status = '1' item.isRead = '1'
uni.navigateTo({ url: '/pages/message1/comp/steadyStateDetails?detail=' + encodeURIComponent(str) }) uni.navigateTo({ url: '/pages/message1/comp/steadyStateDetails?detail=' + encodeURIComponent(str) })
}, },
@@ -253,6 +267,17 @@ export default {
this.store.next && this.store.next() this.store.next && this.store.next()
} }
}, },
onScroll(e) {
this.oldScrollTop = e.detail.scrollTop
this.showBackTop = e.detail.scrollTop > 200
},
backToTop() {
this.scrollTop = this.oldScrollTop
this.$nextTick(() => {
this.scrollTop = 0
})
this.showBackTop = false
},
}, },
computed: {}, computed: {},
@@ -276,6 +301,7 @@ export default {
.box:first-child { .box:first-child {
flex: 1.3 !important; flex: 1.3 !important;
} }
/* 列表容器 */ /* 列表容器 */
.event-list { .event-list {
/* 头部:图标 + 信息 + 操作 */ /* 头部:图标 + 信息 + 操作 */
@@ -294,9 +320,26 @@ export default {
font-size: 24rpx; font-size: 24rpx;
} }
} }
/deep/ .uni-scroll-view-refresher { /deep/ .uni-scroll-view-refresher {
display: none; display: none;
} }
.back-top {
position: fixed;
right: 30rpx;
bottom: 60rpx;
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: #376cf3;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 16rpx rgba(55, 108, 243, 0.35);
z-index: 1;
}
.textBox { .textBox {
max-height: 110rpx; max-height: 110rpx;
overflow-y: auto; overflow-y: auto;
@@ -308,15 +351,18 @@ export default {
// text-overflow: ellipsis; // text-overflow: ellipsis;
// word-break: break-all; // word-break: break-all;
} }
/deep/ .uni-calendar-item--checked { /deep/ .uni-calendar-item--checked {
background-color: #ffffff00; background-color: #ffffff00;
color: #000000e6; color: #000000e6;
opacity: 1; opacity: 1;
} }
/deep/ .uni-calendar-item--isDay { /deep/ .uni-calendar-item--isDay {
background-color: #ffffff00; background-color: #ffffff00;
color: #000000e6; color: #000000e6;
opacity: 1; opacity: 1;
.uni-calendar-item__weeks-lunar-text { .uni-calendar-item__weeks-lunar-text {
background-color: #ffffff00; background-color: #ffffff00;
color: #000000e6; color: #000000e6;
@@ -325,49 +371,69 @@ export default {
} }
/deep/ .uni-calendar-item__weeks-box-text { /deep/ .uni-calendar-item__weeks-box-text {
position: relative;
z-index: 1; z-index: 1;
line-height: 1;
} }
/deep/ .uni-calendar-item--isDay-text {
color: #333 !important; /* 改成你想要的颜色 */ /deep/ .uni-calendar-item__weeks-box-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
} }
/deep/ .uni-calendar-item__weeks-box-circle { /deep/ .uni-calendar-item__weeks-box-circle {
position: absolute; position: absolute;
top: 7px; top: 50%;
right: 6px; left: 50%;
transform: translate(-50%, -50%);
width: 39px; width: 39px;
height: 39px; height: 39px;
border-radius: 50%; border-radius: 50%;
z-index: 0; z-index: 0;
background-color: #e6a23c; background-color: #e6a23c;
} }
/* 核心:选中圆圈下的 子元素(日期数字) */
/* 选中圆圈下的日期数字 */
/deep/ .uni-calendar-item__weeks-box-circle + .uni-calendar-item__weeks-box-text { /deep/ .uni-calendar-item__weeks-box-circle + .uni-calendar-item__weeks-box-text {
color: #fff !important; /* 改成你想要的颜色 */ color: #fff !important;
} }
/deep/ .uni-calendar-item--isDay-text {
color: #333 !important;
}
/deep/ .uni-calendar__backtoday, /deep/ .uni-calendar__backtoday,
/deep/ .uni-calendar__header-btn-box { /deep/ .uni-calendar__header-btn-box {
display: none; display: none;
} }
/deep/ .uni-calendar-item__weeks-lunar-text { /deep/ .uni-calendar-item__weeks-lunar-text {
display: none; display: none;
} }
/deep/ .uni-calendar__header { /deep/ .uni-calendar__header {
pointer-events: none !important; pointer-events: none !important;
} }
.event-detail { .event-detail {
/deep/ .uni-calendar__header { /deep/ .uni-calendar__header {
display: none !important; display: none !important;
} }
/deep/ .uni-calendar__weeks-day { /deep/ .uni-calendar__weeks-day {
height: 35px; height: 35px;
} }
/deep/ .uni-calendar-item__weeks-box-item { /deep/ .uni-calendar-item__weeks-box-item {
height: 40px; height: 40px;
} }
/deep/ .uni-calendar-item__weeks-box-circle { /deep/ .uni-calendar-item__weeks-box-circle {
position: absolute; top: 50%;
top: 3px; left: 50%;
right: 8px; transform: translate(-50%, -50%);
width: 35px; width: 35px;
height: 35px; height: 35px;
} }

View File

@@ -3,62 +3,26 @@
<!-- 暂态 --> <!-- 暂态 -->
<view class="transientBox"> <view class="transientBox">
<view class="statistics pd20"> <view class="statistics pd20">
<view <view class="box boxClick" :class="{ boxClick1: filterValue == index }"
class="box boxClick" v-for="(item, index) in dataList" @click="
:class="{ boxClick1: filterValue == index }"
v-for="(item, index) in dataList"
@click="
filterValue = index filterValue = index
init() init()
" ">
>
<!-- <text class="num">{{ item.value }}</text> --> <!-- <text class="num">{{ item.value }}</text> -->
<text class="num">{{ item.value }}</text> <text class="num">{{ item.value }}</text>
<text class="label">{{ item.label }}</text> <text class="label">{{ item.label }}</text>
</view> </view>
</view> </view>
<view class="smallLabel"> <!-- <view class="smallLabel"> </view> -->
<uni-segmented-control
:current="curSub"
active-color="#376cf3"
:values="subsectionList"
@clickItem="sectionChange"
v-if="subsectionList.length > 1"
/>
<view style="width: 180rpx">
<picker @change="bindPickerChange" :value="sort" :range="array" v-if="curSub == 0">
<view class="uni-input"
>{{ array[sort] }}排序
<uni-icons
custom-prefix="iconfont"
type="icon-paixu1"
size="10"
color="#2563EB"
></uni-icons>
</view>
</picker>
</view>
</view>
</view> </view>
<!-- 卡片 --> <!-- 卡片 -->
<scroll-view <scroll-view scroll-y="true" @scroll="onScroll" :scroll-top="scrollTop" scroll-with-animation
scroll-y="true" @refresherrefresh="refresherrefresh" @scrolltolower="scrolltolower"
@refresherrefresh="refresherrefresh" :refresher-triggered="triggered" refresher-enabled="true" class="event-list"
@scrolltolower="scrolltolower" :style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }">
:refresher-triggered="triggered"
refresher-enabled="true"
class="event-list"
v-if="curSub == 0"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }"
>
<!-- 循环渲染事件项 --> <!-- 循环渲染事件项 -->
<uni-card <uni-card class="event-item boxClick" :class="judgment(item.showName).type"
class="event-item boxClick" v-for="(item, index) in store.data || []" :key="index" @click="jump(item)">
:class="judgment(item.showName).type"
v-for="(item, index) in store.data || []"
:key="index"
@click="jump(item)"
>
<!-- 头部图标 + 信息 + 操作 --> <!-- 头部图标 + 信息 + 操作 -->
<view class="event-header"> <view class="event-header">
<view class="event-icon"> <view class="event-icon">
@@ -78,17 +42,16 @@
<text class="event-id">{{ item.lineName }}</text> <text class="event-id">{{ item.lineName }}</text>
<text class="event-tag" :class="`${judgment(item.showName).type}-tag`">{{ <text class="event-tag" :class="`${judgment(item.showName).type}-tag`">{{
item.showName item.showName
}}</text> }}</text>
</view> </view>
<view class="event-desc"> <view class="event-desc">
<text>工程名称{{ item.engineeringName }}</text> <text>工程{{ item.engineeringName }}</text>
<text>项目名称{{ item.projectName }}</text> <text>项目{{ item.projectName }}</text>
<text>设备名称{{ item.equipmentName }}</text> <text>设备{{ item.equipmentName }}</text>
</view> </view>
</view> </view>
<view class="event-action"> <view class="event-action">
<!-- <uni-icons type="search" size="25" color="#376cf3"></uni-icons> --> <uni-icons type="search" size="25" color="#376cf3"></uni-icons>
🔍
</view> </view>
</view> </view>
<!-- 详情区域 --> <!-- 详情区域 -->
@@ -96,8 +59,8 @@
<text> <text>
{{ item.startTime ? '发生时间:' + item.startTime : '' }} {{ item.startTime ? '发生时间:' + item.startTime : '' }}
{{ {{
item.evtParamVVaDepth != null && item.evtParamVVaDepth !== '' item.evtParamPhase != null && item.evtParamPhase !== ''
? '幅值' + item.evtParamVVaDepth + '%' ? '相别' + item.evtParamPhase
: '' : ''
}} }}
{{ {{
@@ -106,42 +69,33 @@
: '' : ''
}} }}
{{ {{
item.evtParamPhase != null && item.evtParamPhase !== '' item.evtParamVVaDepth != null && item.evtParamVVaDepth !== ''
? '相别' + item.evtParamPhase ? '幅值' + item.evtParamVVaDepth + '%'
: '' : ''
}} }}
{{
item.landPoint != null && item.landPoint !== ''
? ',落点区域:' + item.landPoint
: ',落点区域:未知'
}}
</text> </text>
</view> </view>
</uni-card> </uni-card>
<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)" :status="store.status"></uni-load-more>
:status="store.status"
></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty> <Cn-empty v-else style="top: 20%"></Cn-empty>
</scroll-view> </scroll-view>
<!-- ITIC 列表 --> <view class="back-top boxClick" v-show="showBackTop" @click="backToTop">
<ITIC <uni-icons type="arrow-up" size="22" color="#fff"></uni-icons>
v-if="subsectionList[curSub] == 'ITIC'" </view>
:store="store"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }"
></ITIC>
<!-- F47 列表 -->
<F47
v-if="subsectionList[curSub] == 'F47'"
:store="store"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }"
></F47>
</view> </view>
</template> </template>
<script> <script>
import list from '@/common/js/list' import list from '@/common/js/list'
import { queryUserPushConfig } from '@/common/api/mine'
import ITIC from './comp/ITIC.vue'
import F47 from './comp/F47.vue'
import { queryAppEventCounts } from '../../common/api/harmonic.js' import { queryAppEventCounts } from '../../common/api/harmonic.js'
export default { export default {
components: { ITIC, F47 },
props: { props: {
navHeight: { navHeight: {
type: Number, type: Number,
@@ -151,6 +105,10 @@ export default {
type: Object, type: Object,
// default: () => {}, // default: () => {},
}, },
sortIndex: {
type: [Number, String],
// default: () => {},
},
}, },
mixins: [list], mixins: [list],
data() { data() {
@@ -159,24 +117,19 @@ export default {
filterValue: 0, filterValue: 0,
dataList: [ dataList: [
{ value: 0, label: '暂态数量', key: '' }, { value: 0, label: '暂态数量', key: '' },
{ value: 0, label: '暂降', key: '电压暂降' }, { value: 0, label: '暂降', key: '暂降' },
{ value: 0, label: '中断', key: '电压中断' }, { value: 0, label: '中断', key: '中断' },
{ value: 0, label: '暂升', key: '电压暂升' }, { value: 0, label: '暂升', key: '暂升' },
], ],
curSub: 0,
subsectionList: [], //'列表', 'ITIC', 'F47'
status: 'noMore', //more加载前 loading加载中 noMore加载后 status: 'noMore', //more加载前 loading加载中 noMore加载后
sort: 0, sort: 0,
triggered: true, triggered: true,
// config: {}, scrollTop: 0,
array: ['发生时间', '暂降深度', '持续时间'], oldScrollTop: 0,
showBackTop: false,
} }
}, },
mounted() {
this.getConfig()
},
methods: { methods: {
getHeight() { getHeight() {
uni.createSelectorQuery() uni.createSelectorQuery()
@@ -197,7 +150,7 @@ export default {
this.store = this.DataSource('/cs-harmonic-boot/eventUser/queryEventpage') this.store = this.DataSource('/cs-harmonic-boot/eventUser/queryEventpage')
this.store.params.type = 0 this.store.params.type = 0
// this.store.params.pageSize = 10000 // this.store.params.pageSize = 10000
this.store.params.sortField = this.sort this.store.params.sortField = this.sortIndex
this.store.params.engineeringid = this.selectValue.engineeringId this.store.params.engineeringid = this.selectValue.engineeringId
this.store.params.projectId = this.selectValue.projectId this.store.params.projectId = this.selectValue.projectId
this.store.params.deviceId = this.selectValue.deviceId this.store.params.deviceId = this.selectValue.deviceId
@@ -206,54 +159,41 @@ export default {
this.filterValue == 0 this.filterValue == 0
? [] ? []
: this.filterValue == 1 : this.filterValue == 1
? ['Evt_Sys_DipStr'] ? ['Evt_Sys_DipStr']
: this.filterValue == 2 : this.filterValue == 2
? ['Evt_Sys_IntrStr'] ? ['Evt_Sys_IntrStr']
: ['Evt_Sys_SwlStr'] : ['Evt_Sys_SwlStr']
this.store.params.startTime = this.$util.getMonthFirstAndLastDay(this.selectValue.date).firstDay 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.endTime = this.$util.getMonthFirstAndLastDay(this.selectValue.date).lastDay
this.store.loadedCallback = () => { this.store.loadedCallback = () => {
this.getHeight() this.getHeight()
this.loading = false this.loading = false
queryAppEventCounts(this.store.params).then((res) => { queryAppEventCounts(this.store.params).then((res) => {
this.dataList[0].value = res.data.allNum this.dataList[0].value = res.data?.allNum || 0
this.dataList[1].value = res.data.eventDown this.dataList[1].value = res.data?.eventDown || 0
this.dataList[2].value = res.data.eventOff this.dataList[2].value = res.data?.eventOff || 0
this.dataList[3].value = res.data.eventUp this.dataList[3].value = res.data?.eventUp || 0
}) })
} }
this.store.reload() this.store.reload()
}, },
getConfig() {
queryUserPushConfig().then((res) => {
// this.config = res.data
let list = [
'列表',
res.data.iticFunction == 1 ? 'ITIC' : '',
res.data.f47Function == 1 ? 'F47' : '',
].filter((item) => item)
this.curSub = !list[this.curSub] ? 0 : this.curSub
this.subsectionList = JSON.parse(JSON.stringify(list))
})
},
judgment(val, key) { judgment(val, key) {
switch (val) { switch (val) {
case '电压暂降': case '暂降':
return { return {
type: 'sag', type: 'sag',
icon: 'icon-a-svg4', icon: 'icon-a-svg4',
color: '#2563eb', color: '#2563eb',
size: '25', size: '25',
} }
case '电压暂升': case '暂升':
return { return {
type: 'swell', type: 'swell',
icon: 'icon-a-svg5', icon: 'icon-a-svg5',
color: '#e6a23c', color: '#e6a23c',
size: '25', size: '25',
} }
case '电压中断': case '中断':
return { return {
type: 'interrupt', type: 'interrupt',
icon: 'icon-zhongduan2', icon: 'icon-zhongduan2',
@@ -283,14 +223,12 @@ export default {
item.status = '1' item.status = '1'
uni.navigateTo({ url: '/pages/message1/comp/transientDetails?detail=' + encodeURIComponent(str) }) uni.navigateTo({ url: '/pages/message1/comp/transientDetails?detail=' + encodeURIComponent(str) })
}, },
// 切换排序 setSort(index) {
bindPickerChange(e) { console.log(123, this.sortIndex);
this.sort = e.detail.value
// this.sort = index
this.init() this.init()
}, },
sectionChange(e) {
this.curSub = e.currentIndex
},
// 下拉 // 下拉
refresherrefresh() { refresherrefresh() {
this.triggered = true this.triggered = true
@@ -305,9 +243,17 @@ export default {
this.store.next && this.store.next() this.store.next && this.store.next()
} }
}, },
}, onScroll(e) {
onShow() { this.oldScrollTop = e.detail.scrollTop
this.curSub = 0 this.showBackTop = e.detail.scrollTop > 200
},
backToTop() {
this.scrollTop = this.oldScrollTop
this.$nextTick(() => {
this.scrollTop = 0
})
this.showBackTop = false
},
}, },
computed: {}, computed: {},
@@ -330,4 +276,19 @@ export default {
/deep/ .uni-scroll-view-refresher { /deep/ .uni-scroll-view-refresher {
display: none; display: none;
} }
.back-top {
position: fixed;
right: 30rpx;
bottom: 60rpx;
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: #376cf3;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 16rpx rgba(55, 108, 243, 0.35);
z-index: 1;
}
</style> </style>

View File

@@ -8,7 +8,7 @@
<uni-data-select v-model="item.type" :localdata="range"></uni-data-select> <uni-data-select v-model="item.type" :localdata="range"></uni-data-select>
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="区域"> <uni-forms-item label="区域">
<uni-easyinput type="textarea" v-model="item.title" placeholder="请输入问题简要" /> <uni-easyinput type="textarea" v-model="item.title" placeholder="请输入区域" />
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="描述"> <uni-forms-item label="描述">
<uni-easyinput type="textarea" v-model="item.des" placeholder="请输入详细描述" /> <uni-easyinput type="textarea" v-model="item.des" placeholder="请输入详细描述" />

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{{ version }}</view> <view style="color: #828282; font-size: 24rpx">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">

View File

@@ -1,41 +1,25 @@
<template> <template>
<Cn-page :loading="loading"> <Cn-page>
<view class="mine" slot="body"> <view class="mine" slot="body">
<view class="mine-nav mt20" style="border-bottom: none"> <view class="mine-nav mt20" style="border-bottom: none">
<view class="mine-nav-label">暂态事件</view> <view class="mine-nav-label">暂态事件</view>
<switch <switch style="transform: scale(0.8)" color="#376cf3" @change="change('eventInfo')"
style="transform: scale(0.8)" :checked="config.eventInfo === 1" />
color="#376cf3"
@change="change('eventInfo')"
:checked="config.eventInfo === 1"
/>
</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)" color="#376cf3" @change="change('harmonicInfo')"
style="transform: scale(0.8)" :checked="config.harmonicInfo === 1" />
color="#376cf3"
@change="change('harmonicInfo')"
:checked="config.harmonicInfo === 1"
/>
</view> </view>
<view class="mine-nav" style="border-bottom: none"> <view class="mine-nav" style="border-bottom: none" v-if="flag">
<view class="mine-nav-label">运行告警</view> <view class="mine-nav-label">运行告警</view>
<switch <switch style="transform: scale(0.8)" color="#376cf3" @change="change('alarmInfo')"
style="transform: scale(0.8)" :checked="config.alarmInfo === 1" />
color="#376cf3"
@change="change('alarmInfo')"
:checked="config.alarmInfo === 1"
/>
</view> </view>
<view class="mine-nav" > <view class="mine-nav" v-if="flag">
<view class="mine-nav-label">运行事件</view> <view class="mine-nav-label">运行事件</view>
<switch <switch style="transform: scale(0.8)" color="#376cf3" @change="change('runInfo')"
style="transform: scale(0.8)" :checked="config.runInfo === 1" />
color="#376cf3"
@change="change('runInfo')"
:checked="config.runInfo === 1"
/>
</view> </view>
</view> </view>
</Cn-page> </Cn-page>
@@ -49,6 +33,7 @@ export default {
return { return {
loading: true, loading: true,
config: {}, config: {},
flag: false,
} }
}, },
methods: { methods: {
@@ -100,12 +85,18 @@ export default {
} }
}, },
onUnload() { onUnload() {
updatePushConfig(this.config).then((res) => { if (this.config.eventInfo != undefined) {
// this.$util.toast(`配置修改成功!`) updatePushConfig(this.config).then((res) => {
}) // this.$util.toast(`配置修改成功!`)
})
}
}, },
}, },
onLoad() { onLoad() {
if (uni.getStorageSync(this.$cacheKey.userInfo).authorities === 'operation_manager') {
this.flag = true
}
this.init() this.init()
}, },
} }

View File

@@ -1,129 +0,0 @@
<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

@@ -42,7 +42,7 @@ export default {
}, },
newDevice() { newDevice() {
uni.scanCode({ uni.scanCode({
onlyFromCamera: true, onlyFromCamera: false,
success: function (res) { success: function (res) {
console.log('条码类型:' + res.scanType) console.log('条码类型:' + res.scanType)
console.log('条码内容:' + res.result) console.log('条码内容:' + res.result)

View File

@@ -33,6 +33,12 @@
> >
</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">
<template v-slot:title>
<view class="star-icon">
<uni-icons type="search" size="25" color="#376cf3"></uni-icons>
</view>
</template>
</Cn-device-card> </Cn-device-card>
<Cn-empty v-if="store.empty"></Cn-empty> <Cn-empty v-if="store.empty"></Cn-empty>
<uni-load-more <uni-load-more
@@ -40,24 +46,7 @@
:status="store.status" :status="store.status"
></uni-load-more> ></uni-load-more>
</view> </view>
<!-- <view style="padding: 0 20rpx" v-show="navMenuActive == 1">-->
<!-- <uni-list>-->
<!-- <uni-list-item-->
<!-- title="张三"-->
<!-- note="2023-02-10 14:55"-->
<!-- thumb="/static/head.png"-->
<!-- thumb-size="lg"-->
<!-- >-->
<!-- </uni-list-item>-->
<!-- <uni-list-item-->
<!-- title="李四"-->
<!-- note="2023-02-10 14:55"-->
<!-- thumb="/static/head.png"-->
<!-- thumb-size="lg"-->
<!-- >-->
<!-- </uni-list-item>-->
<!-- </uni-list>-->
<!-- </view>-->
<view style="padding: 0 20rpx" v-show="navMenuActive == 1"> <view style="padding: 0 20rpx" v-show="navMenuActive == 1">
<!-- <image <!-- <image
class="gplot gplot-box" class="gplot gplot-box"

View File

@@ -8,7 +8,8 @@
<uni-search-bar v-model="store.params.searchValue" clearButton="none" bgColor="#fff" placeholder="请输入关键词" <uni-search-bar v-model="store.params.searchValue" clearButton="none" bgColor="#fff" placeholder="请输入关键词"
@input="store.search()"></uni-search-bar> @input="store.search()"></uni-search-bar>
<view class="message"> <view class="message">
<uni-card class="boxClick" :title="item.name" @click="jump(item)" extra="🔍" <!-- 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' : '' }"> v-for="(item, index) in store.data" :key="index" :style="{ marginTop: index === 0 ? '0' : '' }">
<view class="term-list-bottom"> <view class="term-list-bottom">
<view class="term-list-bottom-item"> <view class="term-list-bottom-item">

View File

@@ -1,29 +1,27 @@
<template> <template>
<Cn-page :loading="loading"> <Cn-page :loading="loading">
<view slot="body"> <view slot="body">
<view class="new" :class="{'project-new':!this.options.project}"> <view class="new" :class="{ 'project-new': !this.options.project }">
<view class="content"> <view class="content">
<uni-forms :label-width="80"> <uni-forms :label-width="80">
<uni-forms-item label="工程名称" @click.native.stop.prevent="selectEngineering"> <uni-forms-item label="工程名称">
<uni-easyinput <view class="engineering-select" @click="selectEngineering">
v-model="formData.engineeringName" <uni-easyinput
placeholder="请选择工程" v-model="formData.engineeringName"
:clearable="false" disabled
:disabled="true" maxlength="50"
/> placeholder="请选择工程"
:clearable="false"
/>
</view>
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="项目名称"> <uni-forms-item label="项目名称">
<uni-easyinput v-model="formData.name" placeholder="请输入项目名称"/> <uni-easyinput v-model="formData.name" maxlength="50" placeholder="请输入项目名称" />
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="区域"> <uni-forms-item label="区域">
<view style="display: flex"> <view style="display: flex">
<uni-easyinput <uni-easyinput :clearable="false" type="textarea" maxlength="250" autoHeight
:clearable="false" v-model="formData.area" placeholder="请输入区域信息" />
type="textarea"
autoHeight
v-model="formData.area"
placeholder="请输入区域信息"
/>
<!-- <uni-icons <!-- <uni-icons
type="location" type="location"
color="#007aff" color="#007aff"
@@ -34,25 +32,17 @@
</view> </view>
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="描述"> <uni-forms-item label="描述">
<uni-easyinput <uni-easyinput type="textarea" autoHeight maxlength="999" v-model="formData.description"
type="textarea" placeholder="请输入项目描述" />
autoHeight
maxlength="999"
v-model="formData.description"
placeholder="请输入项目描述"
/>
</uni-forms-item> </uni-forms-item>
<view class="temp-choose"> <view class="temp-choose">
<view class="temp-choose-title">从模版库选择拓扑图</view> <view class="temp-choose-title">从模版库选择拓扑图</view>
<view class="temp-choose-content"> <view class="temp-choose-content">
<view class="temp-choose-content-item" v-for="(item, index) in formData.tempFiles"> <view class="temp-choose-content-item" v-for="(item, index) in formData.tempFiles">
<image <image class="temp-choose-content-item-img" :src="item.filePath"
class="temp-choose-content-item-img" mode="aspectFill" />
:src="item.filePath"
mode="aspectFill"
/>
<view class="temp-choose-content-item-close" @click="deleteImg(index)"> <view class="temp-choose-content-item-close" @click="deleteImg(index)">
<uni-icons style="font-size: 18px" type="closeempty" color="#fff" size="20"/> <uni-icons style="font-size: 18px" type="closeempty" color="#fff" size="20" />
</view> </view>
</view> </view>
<view class="temp-choose-content-item" @click="openTemp"> <view class="temp-choose-content-item" @click="openTemp">
@@ -60,13 +50,8 @@
</view> </view>
</view> </view>
</view> </view>
<uni-file-picker <uni-file-picker v-model="formData.files" title="从本地上传拓扑图" :sourceType="['album']"
v-model="formData.files" :before-remove="beforeRemove" @select="select"></uni-file-picker>
title="从本地上传拓扑图"
:sourceType="['album']"
:before-remove="beforeRemove"
@select="select"
></uni-file-picker>
</uni-forms> </uni-forms>
</view> </view>
<view class="btn-wrap"> <view class="btn-wrap">
@@ -76,21 +61,16 @@
<view class="popup-header"> <view class="popup-header">
<view class="popup-header-title">模版库</view> <view class="popup-header-title">模版库</view>
<view class="popup-header-close" @click="closeTemp"> <view class="popup-header-close" @click="closeTemp">
<uni-icons type="closeempty" color="#111" size="20"/> <uni-icons type="closeempty" color="#111" size="20" />
</view> </view>
</view> </view>
<view class="temp-list"> <view class="temp-list">
<view <view class="temp-list-item" :class="{
class="temp-list-item" 'temp-list-item-active': formData.tempFiles.some(
:class="{ (item2) => item2.id === item.id || item2.topoId === item.id,
'temp-list-item-active': formData.tempFiles.some( ),
(item2) => item2.id === item.id || item2.topoId === item.id, }" v-for="(item, index) in tempList" @click="chooseTempItem(item)">
), <image class="temp-list-item-img" :src="item.filePath" mode="aspectFill" />
}"
v-for="(item, index) in tempList"
@click="chooseTempItem(item)"
>
<image class="temp-list-item-img" :src="item.filePath" mode="aspectFill"/>
<view class="temp-list-item-name">{{ item.name }}</view> <view class="temp-list-item-name">{{ item.name }}</view>
</view> </view>
</view> </view>
@@ -100,10 +80,10 @@
</Cn-page> </Cn-page>
</template> </template>
<script> <script>
import {pinyin} from 'pinyin-pro' import { pinyin } from 'pinyin-pro'
import {addAppProject, updateAppProject, checkCanDelete} from '../../common/api/project' import { addAppProject, updateAppProject, checkCanDelete } from '../../common/api/project'
import {getTopoTemplate} from '../../common/api/device' import { getTopoTemplate } from '../../common/api/device'
import {queryEngineering} from '@/common/api/engineering.js' import { queryEngineering } from '@/common/api/engineering.js'
export default { export default {
data() { data() {
@@ -154,21 +134,14 @@ export default {
this.formData.engineeringId = engineering.id this.formData.engineeringId = engineering.id
this.formData.engineeringName = engineering.name this.formData.engineeringName = engineering.name
} }
uni.getLocation({
type: 'wgs84',
success: function (res) {
console.log(res)
console.log('当前位置的经度:' + res.longitude)
console.log('当前位置的纬度:' + res.latitude)
},
})
getTopoTemplate().then((res) => { getTopoTemplate().then((res) => {
console.log(res) console.log(res)
this.tempList = res.data.map((item) => { this.tempList = res.data.map((item) => {
return { return {
...item, ...item,
filePath:this.$config.static + item.filePath filePath: this.$config.static + item.filePath
} }
}) })
if (this.project) { if (this.project) {
this.project.topologyDiagramPaths.forEach((item) => { this.project.topologyDiagramPaths.forEach((item) => {
@@ -176,7 +149,7 @@ export default {
this.formData.tempFiles.push(item) this.formData.tempFiles.push(item)
} else { } else {
this.formData.files.push({ this.formData.files.push({
url: item.filePath, url: item.filePath,
extname: item.name.split('.')[1], extname: item.name.split('.')[1],
name: item.name, name: item.name,
...item, ...item,
@@ -337,12 +310,19 @@ export default {
color: #111; color: #111;
} }
.engineering-select {
width: 100%;
/deep/ .uni-easyinput,
/deep/ .uni-easyinput__content {
pointer-events: none;
}
}
.new { .new {
padding: 34rpx; padding: 34rpx;
.project-new { .project-new {}
}
.content { .content {
.content-des { .content-des {

View File

@@ -3,7 +3,7 @@
<view slot="body"> <view slot="body">
<view class="change-name"> <view class="change-name">
<view class="content"> <view class="content">
<uni-easyinput type="text" v-model="name" placeholder="请输入昵称" /> <uni-easyinput type="text" maxlength="24" v-model="name" placeholder="请输入昵称" />
</view> </view>
<view class="btn-wrap"> <view class="btn-wrap">
<view class="btn-wrap-item" @click="submit"> 提交 </view> <view class="btn-wrap-item" @click="submit"> 提交 </view>

View File

@@ -4,33 +4,18 @@
<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 type="number" maxlength="11" v-model="formData.phone" placeholder="请输入手机号" />
type="number"
maxlength="11"
v-model="formData.phone"
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 <uni-easyinput type="text" v-model="formData.code" placeholder="请输入验证码" maxlength="6" />
type="text" <view class="ml40" style="
v-model="formData.code"
placeholder="请输入验证码"
maxlength="6"
/>
<view
class="ml40"
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">{{ waitTime + 's后重新获取' }}</view>
v-if="waitTime > 0"
>{{ 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>
@@ -41,7 +26,8 @@
<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" :loading="loadingButton" :disabled="loadingButton"
@click="submit">提交</button>
<view class="login-box-tips"> <view class="login-box-tips">
<view style="color: #999">说明密码长度为6-18</view> <view style="color: #999">说明密码长度为6-18</view>
</view> </view>
@@ -71,6 +57,7 @@ export default {
password: '', password: '',
password2: '', password2: '',
}, },
loadingButton: false,
rules: { rules: {
phone: { phone: {
rules: [ rules: [
@@ -107,7 +94,7 @@ export default {
}, },
} }
}, },
onLoad() {}, onLoad() { },
methods: { methods: {
getCode() { getCode() {
if (!this.formData.phone) { if (!this.formData.phone) {
@@ -151,6 +138,7 @@ export default {
}) })
return return
} }
this.loadingButton = true
let loginName = encrypt(this.formData.phone) let loginName = encrypt(this.formData.phone)
gongkey({ loginName }).then((response) => { gongkey({ loginName }).then((response) => {
let publicKey = response.data let publicKey = response.data
@@ -169,9 +157,13 @@ export default {
}, 1000) }, 1000)
}) })
.catch((err) => { .catch((err) => {
uni.hideLoading()
console.log(err) console.log(err)
}) })
.finally(() => {
this.loadingButton = false
})
}).finally(() => {
this.loadingButton = false
}) })
}) })
}, },

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: '',

View File

@@ -5,32 +5,18 @@
<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 type="number" v-model="formData.phone" maxlength="11" placeholder="请输入手机号" />
type="number"
v-model="formData.phone"
maxlength="11"
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 <uni-easyinput type="text" v-model="formData.code" placeholder="请输入验证码" maxlength="6" />
type="text" <view class="ml40" style="
v-model="formData.code"
placeholder="请输入验证码"
maxlength="6"
/>
<view
class="ml40"
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">{{ waitTime + 's后重新获取' }}
v-if="waitTime > 0"
>{{ waitTime + 's后重新获取' }}
</view> </view>
<button class="login-box-input-btn" v-else @click="getCode" size="mini"> <button class="login-box-input-btn" v-else @click="getCode" size="mini">
获取验证码 获取验证码
@@ -38,16 +24,13 @@
</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" :loading="loadingButton" :disabled="loadingButton"
@click="firstSubmit">注册</button>
<view class="login-box-tips"> <view class="login-box-tips">
<view style="color: #999" <view style="color: #999">
><checkbox <checkbox style="transform: scale(0.7)" :checked="checkbox" @click="checkbox = !checkbox" />
style="transform: scale(0.7)" 我已阅读并同意
:checked="checkbox" </view>
@click="checkbox = !checkbox"
/>
我已阅读并同意</view
>
<navigator url="/pages/mine/agreement" hover-class="none">用户协议</navigator> <navigator url="/pages/mine/agreement" hover-class="none">用户协议</navigator>
<navigator url="/pages/mine/policy" hover-class="none">隐私政策</navigator> <navigator url="/pages/mine/policy" hover-class="none">隐私政策</navigator>
</view> </view>
@@ -61,7 +44,8 @@
<uni-easyinput type="text" v-model="formData.password2" placeholder="请再次确认密码" /> <uni-easyinput type="text" v-model="formData.password2" placeholder="请再次确认密码" />
</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" :loading="loadingButton" :disabled="loadingButton"
@click="secondSubmit">提交</button>
<view class="login-box-tips"> <view class="login-box-tips">
<view style="color: #999">说明密码长度为6-18</view> <view style="color: #999">说明密码长度为6-18</view>
</view> </view>
@@ -77,11 +61,12 @@ 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,
inter: null, inter: null,
loadingButton: false,
// 表单数据 // 表单数据
formData: { formData: {
phone: '', phone: '',
@@ -125,7 +110,7 @@ export default {
}, },
} }
}, },
onLoad() {}, onLoad() { },
methods: { methods: {
getCode() { getCode() {
if (!this.checkbox) { if (!this.checkbox) {
@@ -163,7 +148,9 @@ export default {
if (!this.checkbox) { if (!this.checkbox) {
return this.$util.toast('请先阅读并同意用户协议和隐私政策!') return this.$util.toast('请先阅读并同意用户协议和隐私政策!')
} }
this.$refs.form.validate().then((valid, errors) => { this.$refs.form.validate().then((valid, errors) => {
this.loadingButton = true
apiRegister({ apiRegister({
phone: this.formData.phone, phone: this.formData.phone,
code: this.formData.code, code: this.formData.code,
@@ -176,11 +163,14 @@ export default {
autoLogin(this.formData.phone).then((res) => { autoLogin(this.formData.phone).then((res) => {
this.$util.loginSuccess(res.data) this.$util.loginSuccess(res.data)
}) })
}).finally(() => {
this.loadingButton = false
}) })
}) })
}, },
secondSubmit() { secondSubmit() {
this.$refs.form.validate().then((valid, errors) => { this.$refs.form.validate().then((valid, errors) => {
this.loadingButton = true
console.log(this.formData.password.length) console.log(this.formData.password.length)
if (this.formData.password.length < 6 || this.formData.password.length > 18) { if (this.formData.password.length < 6 || this.formData.password.length > 18) {
return this.$util.toast('密码长度为6-18位') return this.$util.toast('密码长度为6-18位')
@@ -197,6 +187,8 @@ export default {
uni.reLaunch({ uni.reLaunch({
url: '/pages/user/login', url: '/pages/user/login',
}) })
}).finally(() => {
this.loadingButton = false
}) })
}) })
}, },

826
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

Binary file not shown.

BIN
static/user_manual1.docx Normal file

Binary file not shown.

View File

@@ -72,7 +72,7 @@
}, },
margin: { margin: {
type: String, type: String,
default: '10px' default: '15rpx'
}, },
spacing: { spacing: {
type: String, type: String,
@@ -136,9 +136,9 @@
.uni-card { .uni-card {
margin: $uni-card-spacing; margin: $uni-card-spacing;
padding: 0 $uni-spacing-sm; padding: 0 $uni-spacing-sm;
border-radius: 4px; border-radius: 20rpx;
overflow: hidden; overflow: hidden;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif; // font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif;
background-color: #fff; background-color: #fff;
flex: 1; flex: 1;

View File

@@ -381,11 +381,12 @@ export default {
}, },
}) })
.then((result) => { .then((result) => {
console.log('选择失败', result) if (this.autoUpload && !this.noSpace) {
this.setSuccessAndError(result.tempFiles) this.setSuccessAndError(result.tempFiles)
}
}) })
.catch((err) => { .catch((err) => {
console.log('选择失败', err) console.log('选择文件失败', err)
}) })
}, },