6 Commits

Author SHA1 Message Date
guanj
7bcc68a9df 绘制电脑治理信息页面 2026-05-27 10:10:19 +08:00
dk
17e47c1f07 fix(APP功能调整): 文档中的第7、8、10没有做;第4点需要再核查下ITIC、F47曲线中的可容忍事件、不可容忍事件的显示是否正确。 2026-05-15 11:16:00 +08:00
guanj
eb72146e0d 提交代码 2026-04-25 15:22:50 +08:00
guanj
ce78b65875 提交代码 2026-04-24 09:13:17 +08:00
guanj
747d3139cf 调整app页面图标样式 2026-04-17 08:50:07 +08:00
guanj
bac0f83f64 提交app 2026-04-13 10:12:04 +08:00
83 changed files with 10508 additions and 6355 deletions

View File

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

View File

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

14
App.vue
View File

@@ -1,9 +1,11 @@
<script>
import { queryDictDataCache } from './common/api/dictionary.js'
import { getImageUrl } from '@/common/api/basic'
import { checkAppUpdate } from './common/js/update.js'
export default {
onLaunch: function () {
checkAppUpdate()
// uni.onPushMessage((res) => {
// console.log("收到推送消息:",res) //监听推送消息
// })
@@ -23,8 +25,14 @@ export default {
console.log('收到推送消息:', res.data.payload.path) //监听推送消息
if (res.data.payload && res.data.payload.path) {
uni.setStorageSync('messageParams', {
name: '',
id: '',
engineeringName: '',
engineeringId: '', //工程ID
projectName: '',
projectId: '', //項目ID
deviceName: '',
deviceId: '', //设备ID
lineName: '',
lineId: '', //测点ID
type: res.data.payload.path.split('type=')[1],
})
uni.switchTab({
@@ -39,6 +47,8 @@ export default {
onHide: function () {
console.log('App Hide')
},
methods: {},
}
</script>

10
changelog.md Normal file
View File

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

View File

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

View File

@@ -13,4 +13,37 @@ export function getBaseRealData(id) {
url: '/cs-harmonic-boot/realData/getBaseRealData?lineId='+id,
method: 'post',
})
}
// 查询App暂态事件总数
export function queryAppEventCounts(params) {
return request({
url: '/cs-harmonic-boot/eventUser/queryAppEventCounts',
method: 'post',
data: params,
header: {
'Content-Type': 'application/json',
},
})
}
// 查询App稳态事件总数
export function queryAppHarmonicCounts(params) {
return request({
url: '/cs-harmonic-boot/csHarmonic/queryAppHarmonicCounts',
method: 'post',
data: params,
header: {
'Content-Type': 'application/json',
},
})
}
// 查询App稳态越限监测点
export function queryAppHarmonicLine(params) {
return request({
url: '/cs-harmonic-boot/csHarmonic/queryAppHarmonicLine',
method: 'post',
data: params,
header: {
'Content-Type': 'application/json',
},
})
}

View File

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

View File

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

View File

@@ -152,7 +152,7 @@ page {
margin: 0 20rpx;
display: grid;
grid-gap: 20rpx;
grid-template-columns: 1fr 1fr 1fr ;
grid-template-columns: 1fr 1fr 1fr;
.header-item {
display: flex;
flex-direction: column;
@@ -167,7 +167,7 @@ page {
font-size: 44rpx;
}
.header-item-label {
font-size: 24rpx;
font-size: 26rpx;
}
}
}
@@ -277,14 +277,35 @@ page {
}
}
image {
will-change: transform;//解决加载时瞬间拉伸问题
width: auto;//解决加载时瞬间拉伸问题
height: auto;//解决加载时瞬间拉伸问题
image-rendering:-moz-crisp-edges;
image-rendering:-o-crisp-edges;
image-rendering:-webkit-optimize-contrast;
will-change: transform; //解决加载时瞬间拉伸问题
width: auto; //解决加载时瞬间拉伸问题
height: auto; //解决加载时瞬间拉伸问题
image-rendering: -moz-crisp-edges;
image-rendering: -o-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
-ms-interpolation-mode:nearest-neighbor;
-ms-interpolation-mode: nearest-neighbor;
}
.canneng-index-title {
font-size: 30rpx;
}
.boxClick:active {
// transform: scale(0.94);
// opacity: 0.8;
animation: elastic-bounce 0.5s;
}
@keyframes elastic-bounce {
0% {
transform: scale(1);
}
50% {
transform: scale(0.96);
}
100% {
transform: scale(1);
}
}

View File

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

View File

@@ -1,5 +1,5 @@
// 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
const MQTT_USERNAME = 't_user'//mqtt用户名
const MQTT_PASSWORD = 'njcnpqs'//密码

View File

@@ -27,7 +27,7 @@ export default (options = {}) => {
}
uni.request({
url,
timeout: 1000 *30,
timeout: 1000 * 60,
data: {
...options.data,
},

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

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

View File

@@ -0,0 +1,533 @@
<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;
}
</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,23 +1,14 @@
<template>
<uni-card
:title="device.equipmentName"
:sub-title="device.mac"
:extra="device.isPrimaryUser == 1 ? '主设备' : '分享设备'"
padding="0"
@click="jump(device)"
:thumbnail="deviceIcon(device.runStatus)"
>
<uni-card :title="device.equipmentName" :sub-title="device.mac" :extra="device.isPrimaryUser == 1 ? '主设备' : '分享设备'"
padding="0" @click="jump(device)" class="boxClick" :thumbnail="deviceIcon(device.runStatus)">
<template v-slot:title>
<!-- 卡片标题 -->
<view class="uni-card__header" @click="jump(device)">
<view class="uni-card__header-box">
<view class="uni-card__header-avatar">
<view
class="event-icon"
:style="{ backgroundColor: getColor(device.runStatus, device.devType) }"
>
<view class="event-icon">
<!-- 动态图标根据类型切换 -->
<uni-icons
<!-- <uni-icons
custom-prefix="iconfont"
:type="
device.devType == 'Direct_Connected_Device'
@@ -26,30 +17,39 @@
"
:color="device.runStatus == 1 ? '#ff3b30' : '#10B981'"
:size="device.devType == 'Direct_Connected_Device' ? '35' : '40'"
></uni-icons>
></uni-icons> -->
<Cn-icon-device :devType="device.devType" :runStatus="device.runStatus"
:alarmStatus="device.isAlarm ? 1 : 0"></Cn-icon-device>
</view>
</view>
<view class="uni-card__header-content">
<text class="uni-card__header-content-title uni-ellipsis">
{{ device.equipmentName }}
</text>
<text class="uni-card__header-content-subtitle uni-ellipsis">
{{ device.mac }}
</text>
<!-- <text class="uni-card__header-content-subtitle uni-ellipsis">
{{ device.mac }}
</text> -->
<view class="event-desc mt10 mb8">
<text>
工程名称{{ device.engineeringName }}
</text>
<text>
项目名称{{ device.projectName }}
</text>
</view>
<view class="tagBox">
<text class="event-tag" :class="device.runStatus == 1 ? 'lx-tag' : 'zx-tag'">{{
device.runStatus == 1 ? '离线' : '在线'
}}</text>
<text
class="event-tag"
:class="device.devType == 'Direct_Connected_Device' ? 'zl-tag' : 'jc-tag'"
>
<text class="event-tag" :class="device.runStatus == 1 ? 'lx-tag' : 'zx-tag'">
{{ device.runStatus == 1 ? '离线' : '在线' }}
</text>
<text class="event-tag"
:class="device.devType == 'Direct_Connected_Device' ? 'zl-tag' : 'jc-tag'">
{{ device.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备' }}
</text>
<text class="event-tag" :class="device.isPrimaryUser == 1 ? 'z-tag' : 'fx-tag'">{{
device.isPrimaryUser == 1 ? '设备' : '分享设备'
}}</text></view
>
<text class="event-tag" :class="device.isPrimaryUser == 1 ? 'z-tag' : 'fx-tag'">
{{ device.isPrimaryUser == 1 ? '我的设备' : '他人设备' }}
</text>
</view>
</view>
</view>
<view class="uni-card__header-extra" style="position: relative" @click.stop>
@@ -59,8 +59,8 @@
</view>
<!-- <slot name="title"></slot> -->
</template>
<view class="device-body">
<view class="device-body-item">
<!-- <view class="device-body">
<view class="device-body-item">
<text>工程名称</text>
<text>{{ device.engineeringName }}</text>
</view>
@@ -71,9 +71,9 @@
<view class="device-body-item mt6" v-if="device.process == 2 || device.process == 3">
<text>调试阶段</text>
<text>{{ device.process == 2 ? '功能调试' : '出厂调试' }}</text>
</view>
</view>
<view class="pinToTop" v-if="device.isTop == 1"> 置顶 </view>
</view>
</view> -->
<view class="pinToTop" v-if="device.isTop == 1"> 置顶</view>
</uni-card>
</template>
<script>
@@ -84,7 +84,8 @@ export default {
props: {
device: {
type: Object,
default: () => {},
default: () => {
},
},
},
methods: {
@@ -114,30 +115,16 @@ export default {
'&process=' +
this.device.process +
'&ndid=' +
this.device.ndid,
this.device.ndid +
'&device=' +
JSON.stringify(this.device),
})
} else {
if (this.device.lineList.length == 0) {
return this.$util.toast('暂无监测点!')
}
uni.navigateTo({
url:
'/pages/device/realTime/index?id=' +
this.device.equipmentId +
'&isPrimaryUser=' +
this.device.isPrimaryUser +
'&process=' +
this.device.process +
'&ndid=' +
this.device.ndid +
'&lineList=' +
JSON.stringify(this.device.lineList) +
'&engineeringName=' +
this.device.engineeringName +
'&equipmentName=' +
this.device.equipmentName +
'&runStatus=' +
this.device.runStatus,
url: '/pages/device/realTime/index?device=' + JSON.stringify(this.device),
})
}
},
@@ -158,11 +145,12 @@ export default {
.device-body-item {
display: flex;
justify-content: space-between;
font-size: 26rpx;
font-size: 28rpx;
color: #666666;
line-height: 1.2;
}
}
.uni-card {
/deep/ .uni-card__header-box {
display: flex;
@@ -171,25 +159,30 @@ export default {
align-items: center;
overflow: hidden;
}
/deep/ .uni-card__header {
display: flex;
border-bottom: 2rpx #ebeef5 solid;
// border-bottom: 2rpx #ebeef5 solid;
flex-direction: row;
align-items: center;
padding: 20rpx 20rpx 10rpx 0;
padding: 20rpx 0;
overflow: hidden;
}
}
.uni-card .uni-card__header .uni-card__header-content .uni-card__header-content-title {
font-size: 28rpx;
font-size: 30rpx;
color: #3a3a3a;
font-weight: 700;
}
.uni-card .uni-card__header .uni-card__header-content .uni-card__header-content-subtitle {
font-size: 12px;
margin-top: 15rpx;
font-size: 24rpx;
// margin-top: 5px;
color: #666666;
}
.uni-card .uni-card__header .uni-card__header-avatar .uni-card__header-avatar-image {
width: 40px;
height: 40px;
@@ -197,6 +190,7 @@ export default {
border-radius: 5px;
margin-right: 10px;
}
.uni-card .uni-card__header .uni-card__header-content {
display: flex;
flex-direction: column;
@@ -204,10 +198,12 @@ export default {
flex: 1;
overflow: hidden;
}
.tagBox {
display: flex;
gap: 15rpx;
}
.event-icon {
position: relative;
width: 100rpx;
@@ -218,8 +214,9 @@ export default {
align-items: center;
margin-right: 20rpx;
}
.event-tag {
font-size: 20rpx;
font-size: 22rpx;
padding: 2rpx 10rpx;
border-radius: 8rpx;
margin-top: 5rpx;
@@ -228,29 +225,37 @@ export default {
// 在线
.zx-tag {
background-color: #67c23a20;
color: #67c23a;
background-color: #10b98120;
color: #10b981;
}
.lx-tag {
background-color: #ff3b3020;
color: #ff3b30;
}
.z-tag {
background-color: #2563eb20;
color: #2563eb;
}
.fx-tag {
background-color: #90939920;
color: #909399;
}
.zl-tag {
// background-color: #007aff20;
// color: #007aff;
background-color: #007aff20;
color: #007aff;
}
.jc-tag {
background-color: #36cfc920;
color: #36cfc9;
background-color: #007aff20;
color: #007aff;
}
.pinToTop {
background-color: $uni-theme-color;
width: 100rpx;
@@ -270,4 +275,16 @@ export default {
transform: rotate(45deg) translate(50rpx, -10rpx);
transform-origin: top right;
}
.event-desc {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.event-desc text {
font-size: 28rpx;
color: #666666;
line-height: 1.2;
}
</style>

View File

@@ -1,13 +1,16 @@
<template>
<view class="nav choose">
<view class="nav-menu" @click="selectEngineering" v-if="showQianTree"
>{{
select.engineeringName || select.projectName || select.deviceName || select.lineName
? [select.engineeringName, select.projectName, select.deviceName, select.lineName]
.filter((item) => item && item !== '')
.join('>')
: '全部工程'
}}
<view class="nav-menu nav-menu1" @click="selectEngineering" v-if="showQianTree">
<view class="nav-text">
{{
select.engineeringName || select.projectName || select.deviceName || select.lineName
? [select.engineeringName, select.projectName, select.deviceName, select.lineName]
.filter((item) => item && item !== '')
.join('>')
: '全部工程'
}}
</view>
<uni-icons type="bottom" size="14"></uni-icons>
</view>
<!-- 弹框组件 -->
@@ -30,23 +33,35 @@
@change="bindDateChange"
v-if="showDatetime"
>
<view class="nav-menu"
>{{ select.date }}
<view class="nav-menu nav-menu1"
><view class="nav-text">
{{ select.date }}
</view>
<uni-icons type="bottom" size="14"></uni-icons>
</view>
</picker>
<uni-datetime-picker v-if="!showDatetime" v-model="select.range" type="daterange" :end="endDate">
<!-- <uni-datetime-picker v-if="!showDatetime" v-model="select.range" type="daterange" :end="endDate">
<view class="nav-menu"
>{{ select.range[0] + '至' + select.range[1] }}
<uni-icons type="bottom" size="14"></uni-icons>
</view>
</uni-datetime-picker>
<picker @change="bindReport" v-if="report" :value="select.report" :range="reportList">
<view class="nav-menu"
>{{ reportList[select.report] }}
</uni-datetime-picker> -->
<picker
mode="date"
:value="select.range"
fields="year"
:end="endDate.slice(0, -6)"
@change="yearChange"
v-if="!showDatetime"
>
<view class="nav-menu nav-menu1"
><view class="nav-text">
{{ select.range }}
</view>
<uni-icons type="bottom" size="14"></uni-icons>
</view>
</picker>
<slot />
</view>
</template>
@@ -57,7 +72,6 @@ export default {
props: {
level: { type: Number, default: 3 },
showDatetime: { type: Boolean, default: true },
report: { type: Boolean, default: false },
singleChoice: { type: Boolean, default: false },
showQianTree: { type: Boolean, default: true },
},
@@ -65,6 +79,10 @@ export default {
const currentDate = this.getDate({
format: true,
})
const rangeDate = this.getDate({
format: true,
}).slice(0, -3)
console.log('🚀 ~ rangeDate:', rangeDate)
return {
select: {
engineeringName: '',
@@ -76,18 +94,12 @@ export default {
lineName: '',
lineId: '', //测点ID
date: currentDate,
range: ['', ''],
report: 0,
range: rangeDate,
},
list: [],
reportList: ['日报', '月报'],
}
},
created() {
if (!this.showDatetime) {
this.select.range = [this.endDate.slice(0, -3) + '-01', this.endDate]
}
},
created() {},
onShow() {},
mounted() {},
@@ -172,9 +184,10 @@ export default {
bindDateChange(e) {
this.select.date = e.detail.value
},
bindReport(e) {
this.select.report = e.detail.value
yearChange(e) {
this.select.range = e.detail.value
},
selectEngineering() {
this.$refs.qiantree._show()
},
@@ -219,10 +232,18 @@ export default {
break
}
},
external(name, id) {
external(params) {
this.getTree()
this.select.engineeringId = id
this.select.engineeringName = name
// this.select.engineeringId = id
// this.select.engineeringName = name
this.select.engineeringName = params.engineeringName
this.select.engineeringId = params.engineeringId //工程ID
this.select.projectName = params.projectName
this.select.projectId = params.projectId //項目ID
this.select.deviceName = params.deviceName
this.select.deviceId = params.deviceId //设备ID
this.select.lineName = params.lineName
this.select.lineId = params.lineId //测点ID
},
// 取消回调事件
treeCancel(e) {
@@ -273,6 +294,15 @@ export default {
deep: true,
immediate: true,
},
// showDatetime: {
// handler(val, oldVal) {
// if (val == false) {
// console.log("🚀 ~ this.select.range:", this.select.range)
// }
// },
// deep: true,
// },
},
}
</script>
@@ -280,4 +310,37 @@ export default {
/deep/ .uni-date-editor {
width: 360rpx;
}
.nav-menu {
display: flex;
align-items: center;
}
// .nav-menu1 {
// max-width: calc(100vw - 150px);
// overflow: hidden !important;
// -webkit-line-clamp: 1;
// display: -webkit-box;
// -webkit-box-orient: vertical;
// text-overflow: ellipsis;
// word-break: break-all;
// white-space: nowrap;
// }
.nav-menu1 {
display: flex;
align-items: center;
max-width: calc(100vw - 150px);
}
/* 文字容器:单行溢出省略 */
.nav-text {
flex: 1;
overflow: hidden;
white-space: nowrap; /* 强制不换行 */
text-overflow: ellipsis;
// -webkit-line-clamp: 1;
// display: -webkit-box;
// -webkit-box-orient: vertical;
// text-overflow: ellipsis;
// word-break: break-all;
// white-space: nowrap;
line-height: 1;
}
</style>

View File

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

View File

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

View File

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

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

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

View File

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

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -20,7 +20,7 @@
class="uni-input"
radius="5"
placeholder="请输入关键字搜索"
clearButton="none"
clearButton="none"
@input="input"
/>
@@ -212,6 +212,12 @@ export default {
}
})
this._hide()
console.log('🚀 ~ rt:', rt)
if (rt.length == 0) return
if (this.singleChoice) {
if (rt[0].rank != 3) return
}
this.$emit('confirm', rt)
},
//扁平化树结构

File diff suppressed because one or more lines are too long

View File

@@ -139,7 +139,8 @@
"/api" : {
"https" : true,
// "target" : "https://pqmcn.com:8092/api",
"target" : "http://192.168.2.126:10215",
// "target" : "http://192.168.1.103:10215",
"target" : "http://192.168.1.103:10215",
"changOrigin" : true,
"pathRewrite" : {
"/api" : ""

557
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -25,7 +25,7 @@
"image-tools": "^1.4.0",
"jsrsasign": "^11.1.0",
"mqtt": "^3.0.0",
"pinyin-pro": "^3.26.0",
"pinyin-pro": "^3.28.1",
"uview-ui": "^2.0.38"
}
}

View File

@@ -46,7 +46,13 @@
{
"path": "pages/index/report",
"style": {
"navigationBarTitleText": "报表"
"navigationBarTitleText": "报表",
"enablePullDownRefresh": true, // 开启下拉刷新
"pullToRefresh": {
"support":true,
"style": "circle",
"color":"#007aff"
}
}
},
{
@@ -115,6 +121,13 @@
"navigationBarTitleText": "个性化推荐"
}
},
{
"path": "pages/index/comp/monitoringPoint",
"style": {
"navigationBarTitleText": "监测点电能质量信息"
}
},
{
"path": "pages/mine/system",
"style": {
@@ -161,7 +174,12 @@
"path": "pages/device/APF/detail",
"style": {
"navigationBarTitleText": "APF 设备名称 + 型号",
"enablePullDownRefresh": true
"enablePullDownRefresh": true,
"pullToRefresh": {
"support":true,
"style": "circle",
"color":"#007aff"
}
}
},
{
@@ -409,6 +427,7 @@
"navigationBarTitleText": "关注工程配置"
}
},
{
"path": "pages/mine/serverSetting",
"style": {

View File

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

View File

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

View File

@@ -1,172 +1,184 @@
<template>
<view class="basic">
<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_Sys(A)'] > 0 ? item['Apf_RmsI_Sys(A)'].toFixed(2) : item['Apf_RmsI_Sys(A)']
}}</view>
<view class="item">{{
item['Apf_ThdA_Sys(%)'] > 0 ? item['Apf_ThdA_Sys(%)'].toFixed(2) : item['Apf_ThdA_Sys(%)']
}}</view>
</template>
</view>
</view>
<view class="grid-card">
<view class="grid-card-title">电网电压</view>
<view class="grid-card-content-4">
<view class="item item-title">名称</view>
<view class="item item-title">电压(V)</view>
<view class="item item-title">频率(Hz)</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_PhV_Sys(V)'] > 0 ? item['Apf_PhV_Sys(V)'].toFixed(2) : item['Apf_PhV_Sys(V)']
}}</view>
<view class="item">{{
item['Apf_Freq(Hz)'] > 0 ? item['Apf_Freq(Hz)'].toFixed(2) : item['Apf_Freq(Hz)']
}}</view>
<view class="item">{{
item['Apf_ThdU_Sys(%)'] > 0 ? item['Apf_ThdU_Sys(%)'].toFixed(2) : item['Apf_ThdU_Sys(%)']
}}</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_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>
</template>
<script>
export default {
data() {
return {
renderData: {
电网电流: [],
电网电压: [],
负载电流: [],
补偿电流: [],
未知: [],
},
}
},
props: {
basicData: {
type: Array,
default: () => {
return []
},
},
},
watch: {
basicData: {
handler: function (newVal, oldVal) {
newVal.forEach((item) => {
if (item.phase === 'avg') {
return
}
let key = ''
switch (item.statisticalName) {
case 'Apf_RmsI_Sys(A)':
key = '电网电流'
break
case 'Apf_ThdA_Sys(%)':
key = '电网电流'
break
case 'Apf_PhV_Sys(V)':
key = '电网电压'
break
case 'Apf_Freq(Hz)':
key = '电网电压'
break
case 'Apf_ThdU_Sys(%)':
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,
immediate: true,
},
},
methods: {},
}
</script>
<style lang="scss">
.basic {}
</style>
<template>
<view>
<uni-load-more status="loading"
v-if="renderData.电网电流.length == 0 || renderData.电网电压.length == 0 || renderData.负载电流.length == 0 || renderData.补偿电流.length == 0 "></uni-load-more>
<view class="basic" v-else>
<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_Sys(A)'] > 0 ? item['Apf_RmsI_Sys(A)'].toFixed(2) : item['Apf_RmsI_Sys(A)']
}}</view>
<view class="item">{{
item['Apf_ThdA_Sys(%)'] > 0 ? item['Apf_ThdA_Sys(%)'].toFixed(2) : item['Apf_ThdA_Sys(%)']
}}</view>
</template>
</view>
</view>
<view class="grid-card">
<view class="grid-card-title">网电</view>
<view class="grid-card-content-4">
<view class="item item-title">名称</view>
<view class="item item-title">电压(V)</view>
<view class="item item-title">频率(Hz)</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_PhV_Sys(V)'] > 0 ? item['Apf_PhV_Sys(V)'].toFixed(2) : item['Apf_PhV_Sys(V)']
}}</view>
<view class="item">{{
item['Apf_Freq(Hz)'] > 0 ? item['Apf_Freq(Hz)'].toFixed(2) : item['Apf_Freq(Hz)']
}}</view>
<view class="item">{{
item['Apf_ThdU_Sys(%)'] > 0 ? item['Apf_ThdU_Sys(%)'].toFixed(2) : item['Apf_ThdU_Sys(%)']
}}</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_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>
</template>
<script>
export default {
data() {
return {
renderData: {
电网电流: [],
电网电压: [],
负载电流: [],
补偿电流: [],
未知: [],
},
}
},
props: {
basicData: {
type: Array,
default: () => {
return []
},
},
},
watch: {
basicData: {
handler: function (newVal, oldVal) {
newVal.forEach((item) => {
if (item.phase === 'avg') {
return
}
let key = ''
switch (item.statisticalName) {
case 'Apf_RmsI_Sys(A)':
key = '电网电'
break
case 'Apf_ThdA_Sys(%)':
key = '电网电流'
break
case 'Apf_PhV_Sys(V)':
key = '电网电压'
break
case 'Apf_Freq(Hz)':
key = '电网电压'
break
case 'Apf_ThdU_Sys(%)':
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,
immediate: true,
},
},
methods: {},
}
</script>
<style lang="scss">
.basic {}
</style>

View File

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

View File

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

View File

@@ -5,18 +5,10 @@
<view class="detail-header">
<Cn-htmlToImg domId="header" @renderFinish="renderFinish">
<view class="header" id="header" ref="header" @click="previewImg">
<img
:src="topoImg"
style="width: 375px; display: block"
mode="widthFix"
@load="domLoading = false"
/>
<view
class="point"
:style="{ left: item.lat + 'px', top: item.lng + 'px' }"
v-for="(item, index) in topolodyData"
:key="index"
>
<img :src="topoImg" style="width: 375px; display: block" mode="widthFix"
@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-content-1">
<view class="item">{{ item.label }}</view>
@@ -51,13 +43,9 @@
<text class="ml10">设备状态</text>
</view> -->
<view class="nav" style="margin-top: -10rpx">
<view
class="nav-menu"
:class="{ 'nav-menu-active': navMenuActive == index }"
v-for="(item, index) in navMenuList"
:key="index"
@click="navMenuClick(index)"
>{{ item.text }}
<view class="nav-menu" :class="{ 'nav-menu-active': navMenuActive == index }"
v-for="(item, index) in navMenuList" :key="index" @click="navMenuClick(index)">{{ item.text
}}
</view>
</view>
</view>
@@ -107,22 +95,10 @@
</uni-popup> -->
<!-- 输入框示例 -->
<uni-popup ref="inputDialog" type="dialog">
<uni-popup-dialog
ref="inputClose"
type="info"
mode="input"
:title="dialogType"
value="对话框预置提示内容!"
placeholder="请输入内容"
@confirm="dialogInputConfirm"
>
<uni-easyinput
type="textarea"
:maxlength="250"
autoHeight
v-model="remarkContent"
placeholder="请输入备注"
></uni-easyinput>
<uni-popup-dialog ref="inputClose" type="info" mode="input" :title="dialogType" value="对话框预置提示内容!"
placeholder="请输入内容" @confirm="dialogInputConfirm">
<uni-easyinput type="textarea" :maxlength="250" autoHeight v-model="remarkContent"
placeholder="请输入备注"></uni-easyinput>
</uni-popup-dialog>
</uni-popup>
</view>
@@ -140,6 +116,7 @@ import { manualAccess } from '@/common/api/accessBoot'
import { MQTT_IP, MQTT_OPTIONS } from '@/common/js/mqtt.js'
import mqtt from 'mqtt/dist/mqtt.js'
import { base64ToPath, pathToBase64 } from 'image-tools'
import { queryByCode, queryStatistical } from '@/common/api/dictionary'
import hoverMenu from '@/hover-menu/components/hover-menu/hover-menu.vue'
export default {
components: {
@@ -159,10 +136,12 @@ export default {
domLoading: true,
loading: true,
deviceInfo: {},
device: {},
navMenuActive: 0,
navHeight: 0,
img: '',
topoImg: '',
targetLists: [],
navMenuList: [
{
text: '基本',
@@ -176,17 +155,14 @@ export default {
text: '功率',
id: 'a16aceae7d1565bf9f94dd7410cf9bce',
},
// {
// text: '波形',
// },
{
text: '其他',
},
],
content: [
{
iconPath: '/static/report.png',
text: '告警',
iconPath: '/static/tongji.png',
text: '事件',
},
// {
// iconPath: '/static/record.png',
@@ -196,10 +172,10 @@ export default {
iconPath: '/static/about.png',
text: '关于',
},
{
iconPath: '/static/access.png',
text: '接入',
},
// {
// iconPath: '/static/access.png',
// text: '接入',
// },
],
client: null,
timer: null,
@@ -243,8 +219,22 @@ export default {
this.$util.toast('下载成功')
} else if (e.text === '记录') {
uni.navigateTo({ url: '/pages/device/APF/record' })
} else if (e.text === '告警') {
uni.navigateTo({ url: '/pages/device/APF/report?id=' + this.devId })
} else if (e.text === '事件') {
// uni.navigateTo({ url: '/pages/device/APF/report?id=' + this.devId })
uni.setStorageSync('messageParams', {
engineeringName: this.device.engineeringName,
engineeringId: this.device.engineeringId, //工程ID
projectName: this.device.projectName,
projectId: this.device.projectId, //項目ID
deviceName: this.device.equipmentName,
deviceId: this.device.equipmentId, //设备ID
lineName: '',
lineId: '', //测点ID
type: 0,
})
uni.switchTab({
url: '/pages/index/message1',
})
} else if (e.text === '关于') {
uni.navigateTo({ url: '/pages/device/APF/about?id=' + this.devId })
} else if (e.text === '移交') {
@@ -343,19 +333,30 @@ 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')
this.loading = true
this.domLoading = true
queryTopologyDiagram(this.devId).then((res) => {
await queryTopologyDiagram(this.devId).then((res) => {
res.data.filePath = this.$config.static + res.data.filePath
this.deviceInfo = res.data
this.downloadImg()
uni.setNavigationBarTitle({ title: this.deviceInfo.devName || '设备详情' })
this.topolodyData = this.topolodyData.filter((item) => {
let index = this.deviceInfo.appsLineTopologyDiagramPO.findIndex((element) => {
let index = this.deviceInfo.appsLineTopologyDiagramPO?.findIndex((element) => {
element.label = element.name
item.label = element.name
item.target = element.target
return element.linePostion === item.linePostion
})
if (index > -1) {
@@ -369,10 +370,14 @@ export default {
})
console.log(this.topolodyData)
if (this.client) {
this.client.publish(`/zl/askDevData/${this.devId}/${this.navMenuList[0].id}`)
this.loading = false
} else {
this.initMqtt(this.navMenuList[0].id)
}
console.log("🚀 ~ this.client:", this.client)
})
},
renderFinish(e) {
@@ -445,22 +450,28 @@ export default {
console.log('连接断开')
})
.on('message', (topic, message) => {
console.log('接收推送信息:', JSON.parse(message.toString()), topic)
console.log('🚀 ~ .on ~ topic:', topic)
// console.log('接收推送信息:', JSON.parse(message.toString()), topic)
// console.log('🚀 ~ .on ~ topic:', topic)
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) {
this.$util.toast('该设备暂无数据')
}
this.loading = false
this.handlerData(JSON.parse(message.toString()))
this.handlerData(data)
} else if (topic === `/zl/TemperData/${this.devId}`) {
const data = JSON.parse(message.toString())
if (Array.isArray(data) && !data.length) return
// this.basicData.forEach((item) => {
// if (item.statisticalName === '温度' && item.phase === 'avg') {
// item.statisticalData = message.toString()
// }
// })
this.IOData = JSON.parse(message.toString())
this.IOData = data
// this.IOData = this.IOData.filter((item) => item.value !== 0)
this.IOData.forEach((item) => {
if (!item.value) {
@@ -475,37 +486,60 @@ export default {
})
},
handlerData(data) {
async handlerData(data) {
this.basicData = data
this.topolodyData.forEach((element) => {
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) => {
if (item.statisticalName === key && item.phase === 'avg') {
if (key === 'Apf_RmsI_TolOut(A)') {
arr.push({
label: '总输出电流:',
value: Math.round(item.statisticalData) + 'A',
})
} else {
arr.push({
label: '电流畸变率:',
value: Math.round(item.statisticalData) + '%',
})
// arr.push('电流畸变率:' + item.statisticalData + '%')
}
if (item.statisticalIndex === id && item.phase === 'avg') {
arr.push({
label: list[0].dataTypeName.split('-')[1] + ':',
value: (item.statisticalData) + `${item.unit || ''}`,
})
}
if (item.time) {
this.dataTime = item.time.seconds
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
})
console.log("🚀 ~ this.topolodyData:", this.topolodyData)
console.log(this.topolodyData)
this.$forceUpdate()
},
@@ -524,11 +558,16 @@ export default {
}, 1000)
},
onLoad(options) {
async onLoad(options) {
await this.getTarget()
this.pageOptions = options
this.device = JSON.parse(options.device)
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
this.devId = options.id
this.isPrimaryUser = options.isPrimaryUser
if (this.pageOptions.process == 2 || this.pageOptions.process == 3) {
this.content.splice(
0,
@@ -571,12 +610,18 @@ export default {
})
}
}
if (this.userInfo.authorities !== 'tourist') {
if (this.userInfo.authorities !== 'tourist' && this.device.isPrimaryUser === '1') {
this.content.splice(0, 0, {
iconPath: '/static/subordinate.png',
text: '用户',
})
}
if (this.userInfo.authorities === 'operation_manager') {
this.content.push({
iconPath: '/static/access.png',
text: '接入',
})
}
}
this.$util.getDictData('Line_Position').then((res) => {
this.topolodyData = res.map((item) => {
@@ -603,9 +648,11 @@ export default {
lng: '',
showKey: item.showKey, //要展示的指标key
value: [],
target: item.target
}
})
})
this.init()
},
}
@@ -613,6 +660,7 @@ export default {
<style lang="scss">
.detail {
// background: $uni-theme-white;
.header-bg {
position: absolute;
@@ -643,7 +691,7 @@ export default {
z-index: 2;
text-align: center;
color: #111;
width: 110rpx;
width: 150rpx;
font-size: 16rpx;
opacity: 0.8;

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,13 @@
<view class="device">
<view class="nav" :style="{ top: navTabHeight + 'px' }">
<view class="nav-menu" @click="selectEngineering"
>{{ select.engineeringName || '全部工程' }}
>{{
select.engineeringName
? select.engineeringName.length > 6
? select.engineeringName.substring(0, 6) + '...'
: select.engineeringName
: '全部工程'
}}
<uni-icons type="bottom" size="14"></uni-icons>
</view>
<picker
@@ -19,7 +25,7 @@
{{
select.projectName
? select.projectName.length > 6
? select.projectName.substring(0, 12) + '...'
? select.projectName.substring(0, 6) + '...'
: select.projectName
: '全部项目'
}}
@@ -29,12 +35,12 @@
</picker>
<picker
@change="runStatusChange"
@cancel="select.runStatusSelect = false"
:value="select.runStatusIndex"
:range="projectType"
range-key="text"
>
<view class="nav-menu" @click="select.runStatusSelect = true">
<view class="nav-menu">
{{
select.runStatusName
? select.runStatusName.length > 12
@@ -61,13 +67,13 @@
v-if="
userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'
"
>移交
>移交
</view>
<view
class="nav-menu nav-menu-btn"
@click="selectDevice('share')"
v-if="userInfo.authorities === 'app_vip_user'"
>分享
>分享
</view>
</template>
</view>
@@ -83,7 +89,6 @@
<Cn-device-card :device="item" :key="index">
<template v-slot:title>
<!-- 卡片标题 -->
<switch
v-if="transfer || share"
:checked="checkList.indexOf(item.equipmentId) > -1"
@@ -91,8 +96,7 @@
@change="switchChange(item)"
/>
<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>
</template>
</Cn-device-card>
@@ -113,6 +117,7 @@ import { getProjectList } from '@/common/api/project'
import { queryDictData } from '@/common/api/dictionary'
import list from '@/common/js/list'
import { engineeringPinToTop } from '@/common/api/device'
export default {
mixins: [list],
data() {
@@ -452,15 +457,7 @@ export default {
} else {
this[type] = true
}
},
switchChange(e) {
let index = this.checkList.indexOf(e.equipmentId)
if (index > -1) {
this.checkList.splice(index, 1)
} else {
this.checkList.push(e.equipmentId)
}
},
}
},
}
</script>

View File

@@ -6,13 +6,8 @@
<uni-forms-item label="设备识别码">
<view style="display: flex">
<uni-easyinput type="text" v-model="formData.nDid" placeholder="请输入设备识别码" />
<uni-icons
type="camera"
color="#007aff"
size="26"
class="ml20"
@click="scanCode"
></uni-icons>
<uni-icons type="camera" color="#007aff" size="26" class="ml20"
@click="scanCode"></uni-icons>
</view>
</uni-forms-item>
</uni-forms>
@@ -28,36 +23,18 @@
<uni-forms>
<uni-forms-item label="工程">
<view style="display: flex; align-items: center">
<uni-data-select
v-model="formData.engineeringId"
:localdata="engineeringList"
@change="engineeringChang($event, true)"
:clear="false"
></uni-data-select>
<uni-icons
type="plusempty"
color="#007aff"
size="26"
class="ml20"
@click="createEngineering"
></uni-icons>
<uni-data-select v-model="formData.engineeringId" :localdata="engineeringList"
@change="engineeringChang($event, true)" :clear="false"></uni-data-select>
<uni-icons type="plusempty" color="#007aff" size="26" class="ml20"
@click="createEngineering"></uni-icons>
</view>
</uni-forms-item>
<uni-forms-item label="项目">
<view style="display: flex; align-items: center">
<uni-data-select
v-model="formData.projectId"
:localdata="projectRange"
@change="queryTopologyDiagramPage"
:clear="false"
></uni-data-select>
<uni-icons
type="plusempty"
color="#007aff"
size="26"
class="ml20"
@click="createProject"
></uni-icons>
<uni-data-select v-model="formData.projectId" :localdata="projectRange"
@change="queryTopologyDiagramPage" :clear="false"></uni-data-select>
<uni-icons type="plusempty" color="#007aff" size="26" class="ml20"
@click="createProject"></uni-icons>
</view>
</uni-forms-item>
@@ -69,25 +46,14 @@
</view>
<view v-else class="gplot gplot-empty center" @click="chooseGplot"> 选择拓扑图</view>
</view>
<uni-icons
type="image"
color="#007aff"
size="26"
class="ml20"
@click="chooseGplot"
></uni-icons>
<uni-icons type="image" color="#007aff" size="26" class="ml20"
@click="chooseGplot"></uni-icons>
</view>
</uni-forms-item>
<uni-forms-item
label="监测点"
v-if="pointList.length && formData.topologyDiagramUrl && formData.projectId"
>
<view
class="point-item"
v-for="(item2, index2) in pointList"
:key="index2"
@click="editPoint(item2, index2)"
>
<uni-forms-item label="监测点"
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 style="flex: 1" v-if="item2.name">{{ item2.name }}</view>
<view style="flex: 1; color: #999" v-else>请选择监测点</view>
<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">
<scroll-view style="height: 100%" scroll-y="true">
<view class="content">
<image
class="gplot gplot-box"
mode="aspectFill"
:class="{ 'gplot-active': key == activeGplot }"
: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"
>暂无拓扑图
<image class="gplot gplot-box" mode="aspectFill" :class="{ 'gplot-active': key == activeGplot }"
: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 class="btn-wrap">
<view class="btn-wrap-item" @click="closeDrawer"> 取消</view>
@@ -142,22 +101,18 @@
</view>
<view class="content">
<view class="content-des">请拖动图中的文字选择监测点位置</view>
<uni-forms>
<uni-data-select
v-model="point.position"
:localdata="positionList"
@change="positionChange"
disabled
:clear="false"
></uni-data-select>
<uni-easyinput
:clearable="false"
class="mt20"
type="text"
v-model="point.alias"
@change="aliasChange"
placeholder="别名(非必填)"
/>
<uni-forms labelWidth="70px">
<uni-forms-item label="位置">
<uni-data-select v-model="point.position" :localdata="positionList"
@change="positionChange" disabled :clear="false"></uni-data-select>
</uni-forms-item>
<uni-forms-item label="别名">
<uni-easyinput :clearable="false" type="text" v-model="point.alias"
@change="aliasChange" placeholder="别名(非必填)" />
</uni-forms-item>
<uni-forms-item label="绑定指标">
<uni-data-select v-model="point.target" :localdata="targetList"></uni-data-select>
</uni-forms-item>
</uni-forms>
<view class="btn-wrap">
<view class="btn-wrap-item" @click="closeDrawer"> 取消</view>
@@ -181,6 +136,7 @@ import {
} from '@/common/api/device.js'
import { getProjectList, queryTopologyDiagramPage } from '@/common/api/project.js'
import ykAuthpup from '@/components/yk-authpup/yk-authpup'
import { queryByCode, queryStatistical } from '@/common/api/dictionary'
export default {
components: {
ykAuthpup,
@@ -204,6 +160,8 @@ export default {
activeGplot: 0,
positionList: [],
imageList: [],
targetLists: [],//总数据
targetList: [],//根据位置切换数据
isAdaptive: false, // 是否适应当前项目
dialogOpen: false,
options: {},
@@ -226,9 +184,20 @@ export default {
onLoad(o) {
this.options = o
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) => {
if (item.code == 'Line_Position') {
this.positionList = item.children.map((item) => {
this.positionList = item.children.filter((child) => child.name !== 'PCC公共点').map((item) => {
return {
...item,
text: item.name,
@@ -264,6 +233,19 @@ export default {
// })
},
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() {
queryEngineeringPage({ pageNum: 1, pageSize: 9999 }).then((res) => {
let arr = [
@@ -377,7 +359,7 @@ export default {
console.log(e)
},
projectChange(e) {},
projectChange(e) { },
scanCode() {
if (plus.os.name == 'Android') {
this.$refs['authpup'].open()
@@ -509,6 +491,7 @@ export default {
this.point.alias = ''
}
}
this.settarget()
this.dialogOpen = true
this.$refs.point.open()
this.$forceUpdate()

View File

@@ -22,17 +22,17 @@
></view>
</view>
<view class="info-item">
所属工程<view>{{ engineeringName }}</view>
所属工程<view>{{ device.engineeringName }}</view>
</view>
<view class="info-item">
所属项目<view>{{ equipmentName }}</view>
所属项目<view>{{ device.equipmentName }}</view>
</view>
<view class="info-item status">
通讯状态<view
class="status-normal"
:style="{ color: runStatus == 1 ? '#ff3b30' : '#00ff88' }"
>{{ runStatus == 1 ? '离线' : '在线' }}
:style="{ color: device.runStatus == 1 ? '#ff3b30' : '#00ff88' }"
>{{ device.runStatus == 1 ? '离线' : '在线' }}
</view>
</view>
</view>
@@ -69,7 +69,7 @@
@finished="initChart('echartV3', 'echartsDataV3')"
></l-echart>
</view>
<view class="text"> 电压有效值 </view>
<view class="text" style="left: 20rpx"> 电压有效值(kV) </view>
</view>
<view class="middle" style="width: 100%">
<l-echart
@@ -103,7 +103,7 @@
@finished="initChart('echartA3', 'echartsDataA3')"
></l-echart>
</view>
<view class="text"> 有效值 </view>
<view class="text" style="right: 20rpx"> 有效值(A) </view>
</view>
</view>
</view>
@@ -125,6 +125,7 @@
</view>
</view>
</view>
<hover-menu :btnList="content" @trigger="trigger"></hover-menu>
</view>
</Cn-page>
</template>
@@ -133,12 +134,16 @@ const echarts = require('../../../uni_modules/lime-echart/static/echarts.min')
import { MQTT_IP, MQTT_OPTIONS } from '@/common/js/mqtt.js'
import mqtt from 'mqtt/dist/mqtt.js'
import { getBaseRealData } from '@/common/api/harmonic.js'
import hoverMenu from '@/hover-menu/components/hover-menu/hover-menu.vue'
import { queryTopologyDiagram, deleteDevice, cancelDebug, finishDebug } from '@/common/api/device'
export default {
components: {},
components: { hoverMenu },
props: {},
data() {
return {
loading: true,
deviceInfo: {},
// 使用上面定义的图表配置项
option: {},
echartsData0: {},
@@ -179,34 +184,66 @@ export default {
lineId: '00B78D00A87A1',
lineKey: 0,
lineList: [],
engineeringName: '',
equipmentName: '',
runStatus: 1,
connection: false,
content: [
{
iconPath: '/static/tongji.png',
text: '事件',
},
{
iconPath: '/static/about.png',
text: '关于',
},
],
device: {},
}
},
onLoad(options) {
console.log('🚀 ~ options:', options)
this.device = JSON.parse(options.device)
this.lineKey = 0
this.lineList = JSON.parse(options.lineList)
this.lineList = this.device.lineList
this.lineId = this.lineList[0].lineId
this.engineeringName = options.engineeringName
this.equipmentName = options.equipmentName
this.runStatus = options.runStatus
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
this.echartsData0 = this.initEcharts0()
this.echartsData1 = this.initEcharts1()
this.echartsDataV1 = this.initEcharts('#DAA520', 0, 'A相(kV)')
this.echartsDataV2 = this.initEcharts('#2E8B57', 0, 'B相(kV)')
this.echartsDataV3 = this.initEcharts('#A52a2a', 0, 'C相(kV)')
this.echartsDataA1 = this.initEcharts('#DAA520', 1, 'A相(A)')
this.echartsDataA2 = this.initEcharts('#2E8B57', 1, 'B相(A)')
this.echartsDataA3 = this.initEcharts('#A52a2a', 1, 'C相(A)')
this.echartsDataV1 = this.initEcharts('#DAA520', 0, 'A相')
this.echartsDataV2 = this.initEcharts('#2E8B57', 0, 'B相')
this.echartsDataV3 = this.initEcharts('#A52a2a', 0, 'C相')
this.echartsDataA1 = this.initEcharts('#DAA520', 1, 'A相')
this.echartsDataA2 = this.initEcharts('#2E8B57', 1, 'B相')
this.echartsDataA3 = this.initEcharts('#A52a2a', 1, 'C相')
this.loading = false
this.$nextTick(() => {
this.setMqtt(0)
this.initMqtt()
})
if (this.device.isPrimaryUser == 1) {
this.content.splice(
0,
0,
{
iconPath: '/static/transfer.png',
text: '移交',
},
{
iconPath: '/static/delate.png',
text: '删除',
},
)
if (this.userInfo.authorities === 'app_vip_user') {
this.content.splice(3, 0, {
iconPath: '/static/share.png',
text: '分享',
})
}
}
if (this.userInfo.authorities !== 'tourist' && this.device.isPrimaryUser === '1') {
this.content.splice(0, 0, {
iconPath: '/static/subordinate.png',
text: '用户',
})
}
},
onUnload() {
const charts = [
@@ -623,6 +660,7 @@ export default {
.then((res) => {
if (res.code == 'A0000') {
this.connection = true
this.$util.toast(e == 0 ? '连接成功!' : '刷新成功!')
if (this.timer) {
clearInterval(this.timer)
@@ -668,21 +706,21 @@ export default {
}
})
// this.client.subscribe(`/zl/devData/${this.devId}/${id}`, (err) => {
// this.client.subscribe(`/zl/devData/${this.device.equipmentId}/${id}`, (err) => {
// if (!err) {
// console.log(`订阅成功:/zl/devData/${this.devId}/${id}`)
// console.log(`订阅成功:/zl/devData/${this.device.equipmentId}/${id}`)
// // 默认推送
// this.client.publish(`/zl/askDevData/${this.devId}/${id}`)
// this.client.publish(`/zl/askTemperData/${this.devId}`)
// this.client.publish(`/zl/askDevData/${this.device.equipmentId}/${id}`)
// this.client.publish(`/zl/askTemperData/${this.device.equipmentId}`)
// if (this.timer) {
// clearInterval(this.timer)
// this.timer = null
// }
// this.timer = setInterval(() => {
// console.log('askDevData')
// this.client.publish(`/zl/askDevData/${this.devId}/${id}`)
// this.client.publish(`/zl/askTemperData/${this.devId}`)
// this.client.publish(`/zl/askDevData/${this.device.equipmentId}/${id}`)
// this.client.publish(`/zl/askTemperData/${this.device.equipmentId}`)
// }, 1000 * 60)
// }
// })
@@ -699,128 +737,132 @@ export default {
})
.on('message', (topic, message) => {
// console.log('接收推送信息:', JSON.parse(message.toString()), topic)
// console.log('🚀 ~ .on ~ topic:', topic)
if (!this.connection) return
// console.log('🚀 ~ .on ~ topic:', topic, this.userInfo.userIndex)
if (topic === `/Web/RealData/${this.userInfo.userIndex}`) {
if (
topic == `/Web/RealData/${this.lineId}` ||
topic == `/Web/RealData/${this.userInfo.userIndex}`
) {
let list = JSON.parse(message.toString())
if (list.lineId == this.lineId) {
// console.log(list)
this.realTime = list.dataTime
let pt = list.pt || 0
let ct = list.ct || 0
if (list.lineId != this.lineId) return
// if (list.userId == this.userInfo.userIndex) {
// console.log(list)
this.realTime = list.dataTime
let pt = list.pt || 0
let ct = list.ct || 0
let data = {
vRmsA: ((list.vRmsA * pt) / 1000).toFixed(2),
vRmsB: ((list.vRmsB * pt) / 1000).toFixed(2),
vRmsC: ((list.vRmsC * pt) / 1000).toFixed(2),
iRmsA: (list.iRmsA * ct).toFixed(2),
iRmsB: (list.iRmsB * ct).toFixed(2),
iRmsC: (list.iRmsC * ct).toFixed(2),
v1A: ((list.v1A * pt) / 1000).toFixed(2),
v1B: ((list.v1B * pt) / 1000).toFixed(2),
v1C: ((list.v1C * pt) / 1000).toFixed(2),
v1AngA: list.v1AngA.toFixed(2),
v1AngB: list.v1AngB.toFixed(2),
v1AngC: list.v1AngC.toFixed(2),
let data = {
vRmsA: ((list.vRmsA * pt) / 1000).toFixed(2),
vRmsB: ((list.vRmsB * pt) / 1000).toFixed(2),
vRmsC: ((list.vRmsC * pt) / 1000).toFixed(2),
iRmsA: (list.iRmsA * ct).toFixed(2),
iRmsB: (list.iRmsB * ct).toFixed(2),
iRmsC: (list.iRmsC * ct).toFixed(2),
v1A: ((list.v1A * pt) / 1000).toFixed(2),
v1B: ((list.v1B * pt) / 1000).toFixed(2),
v1C: ((list.v1C * pt) / 1000).toFixed(2),
v1AngA: list.v1AngA.toFixed(2),
v1AngB: list.v1AngB.toFixed(2),
v1AngC: list.v1AngC.toFixed(2),
i1A: (list.i1A * ct).toFixed(2),
i1B: (list.i1B * ct).toFixed(2),
i1C: (list.i1C * ct).toFixed(2),
i1AngA: list.i1AngA.toFixed(2),
i1AngB: list.i1AngB.toFixed(2),
i1AngC: list.i1AngC.toFixed(2),
vDevA: list.vDevA.toFixed(2),
vDevB: list.vDevB.toFixed(2),
vDevC: list.vDevC.toFixed(2),
vThdA: list.vThdA.toFixed(2),
vThdB: list.vThdB.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: 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
// 电流
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.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)
i1A: (list.i1A * ct).toFixed(2),
i1B: (list.i1B * ct).toFixed(2),
i1C: (list.i1C * ct).toFixed(2),
i1AngA: list.i1AngA.toFixed(2),
i1AngB: list.i1AngB.toFixed(2),
i1AngC: list.i1AngC.toFixed(2),
vDevA: list.vDevA.toFixed(2),
vDevB: list.vDevB.toFixed(2),
vDevC: list.vDevC.toFixed(2),
vThdA: list.vThdA.toFixed(2),
vThdB: list.vThdB.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: 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
// 电流
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.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)
// }
}
})
},
@@ -878,6 +920,66 @@ export default {
await this.setMqtt(0)
await this.initMqtt()
},
trigger(e) {
console.log(e)
if (e.text === '分享') {
uni.navigateTo({ url: '/pages/device/share?id=' + this.lineId })
} else if (e.text === '删除') {
uni.showModal({
title: '提示',
content: '确定删除该设备吗?',
success: (res) => {
if (res.confirm) {
console.log('用户点击确定')
deleteDevice(this.device.equipmentId).then((res) => {
uni.showToast({
title: '删除成功',
icon: 'none',
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
})
} else if (res.cancel) {
console.log('用户点击取消')
}
},
})
} else if (e.text === '记录') {
uni.navigateTo({ url: '/pages/device/APF/record' })
} else if (e.text === '事件') {
uni.setStorageSync('messageParams', {
engineeringName: this.device.engineeringName,
engineeringId: this.device.engineeringId, //工程ID
projectName: this.device.projectName,
projectId: this.device.projectId, //項目ID
deviceName: this.device.equipmentName,
deviceId: this.device.equipmentId, //设备ID
lineName: '',
lineId: '', //测点ID
type: 0,
})
uni.switchTab({
url: '/pages/index/message1',
})
// uni.navigateTo({ url: '/pages/device/APF/report?id=' + this.device.equipmentId })
} else if (e.text === '关于') {
uni.navigateTo({ url: '/pages/device/APF/about?id=' + this.device.equipmentId })
} else if (e.text === '移交') {
uni.navigateTo({ url: '/pages/device/transfer?id=' + this.device.equipmentId })
} else if (e.text === '反馈') {
uni.navigateTo({ url: '/pages/device/feedback' })
} else if (e.text === '用户') {
uni.navigateTo({
url:
'/pages/device/user?id=' +
this.device.equipmentId +
'&isPrimaryUser=' +
this.device.isPrimaryUser,
})
}
// this.$refs.fab.close()
},
},
computed: {},
@@ -907,9 +1009,9 @@ export default {
margin-bottom: 10rpx;
view {
// font-size: 28rpx;
.nav-menu {
font-size: 32rpx;
}
// .nav-menu {
// font-size: 32rpx;
// }
}
&:last-child {
margin-bottom: 0rpx;
@@ -930,7 +1032,8 @@ export default {
.table-row {
display: flex;
justify-content: space-between;
padding: 20rpx 30rpx;
padding: 15rpx 30rpx;
height: 20px;
border-bottom: 1rpx solid #eee;
text {
flex: 1;
@@ -971,6 +1074,7 @@ export default {
background-color: #fff;
padding: 0 0rpx 20rpx;
display: flex;
padding-bottom: 55rpx;
.middle {
display: flex;
position: relative;
@@ -990,11 +1094,11 @@ export default {
}
.text {
text-align: center;
font-size: 30rpx;
font-size: 28rpx;
position: absolute;
}
.text_center {
position: absolute;
bottom: 0;
bottom: -5px;
left: 50%;
transform: translateX(-50%) translateY(50%);
}

View File

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

View File

@@ -1,60 +1,49 @@
<template>
<view :loading="loading">
<!-- <uni-nav-bar left-icon="left" right-icon="cart" title="标题" /> -->
<uni-nav-bar
dark
:fixed="true"
status-bar
left-icon="left"
:rightIcon="
userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'
? 'plusempty'
: ''
"
background-color="#fff"
color="#111"
title="工程管理"
@clickLeft="back"
@clickRight="add"
/>
<uni-search-bar
v-model="store.params.name"
clearButton="none"
bgColor="#fff"
placeholder="请输入关键词"
@input="store.search()"
></uni-search-bar>
<uni-nav-bar dark :fixed="true" status-bar left-icon="left" :rightIcon="userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'
? 'plusempty'
: ''
" background-color="#fff" color="#111" title="工程管理" @clickLeft="back" @clickRight="add" />
<uni-search-bar v-model="store.params.name" clearButton="none" bgColor="#fff" placeholder="请输入关键词"
@input="store.search()"></uni-search-bar>
<view class="message">
<uni-card
:title="item.name"
extra="🔍"
@click="jump(item)"
v-for="(item, index) in store.data"
:style="{ marginTop: index === 0 ? '0' : '' }"
:key="index"
>
<view class="term-list-bottom">
<view class="term-list-bottom-item">
<view>区域</view>
<view>{{ item.provinceName + item.cityName }}</view>
</view>
<view class="term-list-bottom-item">
<view>创建时间</view>
<view>{{ item.createTime }}</view>
</view>
</view>
</uni-card>
<uni-swipe-action>
<uni-swipe-action-item v-for="(item, index) in store.data"
:style="{ marginTop: index === 0 ? '0' : '' }" :key="index" :threshold="0"
:right-options="item.isTop == 0 ? options1 : options12" @click="bindClick($event, item)">
<!-- extra="🔍" -->
<uni-card class="boxClick" :title="item.name" @click="jump(item)">
<view class="term-list-bottom">
<view class="term-list-bottom-item">
<view>区域</view>
<view>{{ item.provinceName + item.cityName }}</view>
</view>
<view class="term-list-bottom-item">
<view>创建时间</view>
<view>{{ item.createTime }}</view>
</view>
</view>
<view class="pinToTop" v-if="item.isTop == 1"> 置顶 </view>
</uni-card>
</uni-swipe-action-item>
</uni-swipe-action>
<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)"
:status="store.status"
></uni-load-more>
<uni-load-more v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"></uni-load-more>
</view>
</view>
</template>
<script>
import list from '../../common/js/list'
import { engineeringPinToTop } from '@/common/api/device'
export default {
mixins: [list],
@@ -62,9 +51,39 @@ export default {
return {
loading: true,
userInfo: {},
options1: [
{
text: '置顶',
style: {
backgroundColor: '#376cf3',
},
},
],
options12: [
{
text: '取消',
style: {
backgroundColor: '#ccc',
},
},
],
}
},
methods: {
bindClick(e, item) {
engineeringPinToTop({
targetId: item.id,
targetType: 2,
userId: uni.getStorageSync(this.$cacheKey.userInfo).userIndex,
}).then((res) => {
if (res.code == 'A0000') {
this.$util.toast('操作成功!')
this.store.search()
} else {
this.$util.toast(res.message)
}
})
},
init() {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
this.store = this.DataSource('/cs-device-boot/engineering/queryEngineeringPage')
@@ -173,7 +192,7 @@ export default {
.term-list-bottom {
.term-list-bottom-item {
font-size: 28rpx;
margin-bottom: 20rpx;
// margin-bottom: 20rpx;
display: flex;
justify-content: space-between;
// view:first-of-type{
@@ -185,4 +204,42 @@ export default {
margin-bottom: 0;
}
}
/deep/ .uni-card--border {
margin: 0 10px !important;
padding-bottom: 10px;
}
/deep/ .uni-swipe {
margin-bottom: 10px;
}
.pinToTop {
background-color: $uni-theme-color;
width: 100rpx;
height: 60rpx;
line-height: 90rpx;
text-align: center;
color: #fff;
font-size: 20rpx;
position: absolute;
top: 0rpx;
right: 0rpx;
position: absolute;
top: 0;
right: 0;
/* 核心:旋转成斜三角效果 */
transform: rotate(45deg) translate(50rpx, -10rpx);
transform-origin: top right;
}
/deep/ .uni-card__content {
padding: 5px 10px 10px !important;
}
/deep/ .uni-card__header-content-title {
font-weight: 700;
}
</style>

View File

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

View File

@@ -66,18 +66,7 @@ export default {
},
onShow() {
queryEngineering().then((res) => {
this.engineeringList = res.data.sort((a, b) => {
const nameA = a.name
const nameB = b.name
const isANumber = /^\d/.test(nameA)
const isBNumber = /^\d/.test(nameB)
if (isANumber !== isBNumber) {
return isANumber ? 1 : -1
}
return nameA.localeCompare(nameB, 'zh', { sensitivity: 'accent' })
})
this.engineeringList = this.sortByFirstLetter(res.data)
})
},
onNavigationBarButtonTap(e) {
@@ -93,6 +82,33 @@ export default {
}
},
methods: {
// 处理函数
sortByFirstLetter(data) {
// 1. 添加首字母字段
const withLetter = data.map((item) => {
let letter = '#'
const firstChar = item.name?.charAt(0) || ''
if (/[A-Za-z]/.test(firstChar)) {
letter = firstChar.toUpperCase()
} else if (/[0-9]/.test(firstChar)) {
letter = '#'
} else {
const py = pinyin(firstChar, { pattern: 'first', toneType: 'none' })
letter = py ? py.toUpperCase() : '#'
}
return { ...item, letter }
})
// 2. 排序
return withLetter.sort((a, b) => {
if (a.letter === '#') return 1
if (b.letter === '#') return -1
return a.letter.localeCompare(b.letter)
})
},
all() {
uni.setStorageSync('onceSelectEngineering', {
createBy: '',

View File

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

View File

@@ -3,29 +3,33 @@
<view class="filterCriteria">
<!-- 筛选条件 -->
<Cn-filterCriteria @select="select" :singleChoice="true" :showDatetime="true"> </Cn-filterCriteria>
<view class="choose1">
<view>
<checkbox-group @change="changeBox"
><checkbox value="true" :checked="checkedAll" />全选
</checkbox-group></view
>
<!-- <view class="choose1">
<view class="nav-menu nav-menu-btn" @click="selectDevice">申请报告 </view>
</view>
</view> -->
</view>
<view class="smallLabel mt20">
<view> {{ store.total }} 条事件 | 已选择 {{ checkedTotal }} 条事件 </view>
<view style="width: 180rpx">
<view class="boxCenter">
<view>
<checkbox-group @change="changeBox" class="boxCenter"
><checkbox value="true" :checked="checkedAll" />全选 
</checkbox-group></view
>
已选择 {{ checkedTotal }} 条事件
</view>
<view class="nav-menu nav-menu-btn" @click="selectDevice">申请报告 </view>
<!-- <view style="width: 180rpx">
<picker @change="bindPickerChange" :value="sort" :range="array">
<view class="uni-input"
>{{ array[sort] }}排序
<uni-icons custom-prefix="iconfont" type="icon-paixu1" size="10" color="#2563EB"></uni-icons>
</view>
</picker>
</view>
</view> -->
</view>
<!-- 卡片 -->
<scroll-view
scroll-y="true"
@scrolltolower="scrolltolower"
class="event-list"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }"
>
@@ -41,16 +45,17 @@
<view class="event-header">
<view class="event-icon">
<!-- 动态图标根据类型切换 -->
<uni-icons
<!-- <uni-icons
:custom-prefix="judgment(item.showName) == 'interrupt' ? 'custom-icon' : 'iconfont'"
:type="judgment(item.showName).icon"
:color="judgment(item.showName).color"
:size="judgment(item.showName).size"
></uni-icons>
></uni-icons> -->
<Cn-icon-transient :name="item.showName" />
</view>
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.equipmentName }}</text>
<text class="event-id">{{ item.lineName }}</text>
<text class="event-tag" :class="`${judgment(item.showName).type}-tag`">{{
item.showName
}}</text>
@@ -58,22 +63,35 @@
<view class="event-desc">
<text>工程名称{{ item.engineeringName }}</text>
<text>项目名称{{ item.projectName }}</text>
<text>监测点名称{{ item.lineName }}</text>
<text>设备名称{{ item.equipmentName }}</text>
</view>
</view>
<view class="event-action">
<view class="event-action" @click="handleWrapperClick(item, !item.wavePath)">
<!-- 选择 -->
<checkbox-group @change="changeChild($event, item)"
><checkbox value="true" :checked="item.checked" />
><checkbox value="true" :disabled="!item.wavePath" :checked="item.checked" />
</checkbox-group>
</view>
</view>
<!-- 详情区域 -->
<view class="event-detail">
<text>
发生时间{{ item.startTime }}幅值{{ item.evtParamVVaDepth }}持续时间{{
item.evtParamTm
}}相别{{ item.evtParamPhase }}
{{ item.startTime ? '发生时间:' + item.startTime : '' }}
{{
item.evtParamVVaDepth != null && item.evtParamVVaDepth !== ''
? ',幅值:' + item.evtParamVVaDepth + '%'
: ''
}}
{{
item.evtParamTm != null && item.evtParamTm !== ''
? ',持续时间:' + item.evtParamTm + 's'
: ''
}}
{{
item.evtParamPhase != null && item.evtParamPhase !== ''
? ',相别:' + item.evtParamPhase
: ''
}}
</text>
</view>
</uni-card>
@@ -107,9 +125,7 @@ export default {
array: ['发生时间', '暂降深度', '持续时间'],
}
},
mounted() {
this.setHeight()
},
mounted() {},
methods: {
setHeight() {
@@ -118,10 +134,10 @@ export default {
.boundingClientRect((rect) => {
//
// #ifdef H5
this.height = rect?.height + 100 || 0
this.height = rect?.height + 170 || 0
// #endif
// #ifdef APP-PLUS
this.height = rect?.height + 90 || 0
this.height = rect?.height + 110 || 0
// #endif
})
.exec()
@@ -129,12 +145,14 @@ export default {
async select(val) {
this.selectValue = val
await this.init()
this.setHeight()
setTimeout(() => {
this.setHeight()
}, 200)
},
init() {
this.store = this.DataSource('/cs-harmonic-boot/eventUser/queryEventpage')
this.store.params.type = 0
this.store.params.pageSize = 10000
// this.store.params.pageSize = 10000
this.store.params.sortField = this.sort
this.store.params.engineeringid = this.selectValue.engineeringId
this.store.params.projectId = this.selectValue.projectId
@@ -158,11 +176,17 @@ export default {
changeBox(e) {
this.checkedAll = !this.checkedAll
if (e.target.value.length > 0) {
let total = 0
this.store.data = this.store.data.map((item) => {
item.checked = true
if (item.wavePath != null) {
item.checked = true
total += 1
} else {
item.checked = false
}
return item
})
this.checkedTotal = this.store.total
this.checkedTotal = total
} else {
this.store.data = this.store.data.map((item) => {
item.checked = false
@@ -176,6 +200,14 @@ export default {
this.checkedAll = this.store.data.every((item) => item.checked === true)
this.checkedTotal = this.store.data.filter((item) => item.checked === true).length
},
handleWrapperClick(e, flag) {
if (flag) {
return uni.showToast({
title: '当前事件没有波形,不支持生成报告!',
icon: 'none',
})
}
},
// 点击卡片
clackCard() {},
// 切换排序
@@ -242,12 +274,12 @@ export default {
startTime: this.$util.getMonthFirstAndLastDay(this.selectValue.date).firstDay,
endTime: this.$util.getMonthFirstAndLastDay(this.selectValue.date).lastDay,
}).then((res) => {
this.checkedAll = false
this.store.reload()
uni.showToast({
icon: 'success',
mask: true,
title: '申请暂态报告,成功!',
duration: 1000,
title: '申请报告,成功!',
})
})
}
@@ -266,6 +298,20 @@ export default {
return true
},
// 下拉
refresherrefresh() {
this.triggered = true
uni.startPullDownRefresh()
setTimeout(() => {
this.triggered = false
}, 500)
},
// 上拉
scrolltolower() {
if (this.store.status != 'noMore') {
this.store.next && this.store.next()
}
},
},
computed: {},
@@ -283,7 +329,7 @@ export default {
background-color: #fff;
padding: 0 20rpx;
display: flex;
justify-content: space-between;
justify-content: flex-end;
/deep/ .uni-checkbox-input {
width: 30rpx;
height: 30rpx;
@@ -294,8 +340,8 @@ export default {
.nav-menu {
height: 40rpx;
padding: 6rpx 20rpx;
margin-left: 20rpx;
margin-bottom: 20rpx;
// margin-left: 20rpx;
// margin-bottom: 20rpx;
line-height: 40rpx;
font-size: 24rpx;
border-radius: 8rpx;
@@ -315,6 +361,10 @@ export default {
}
.smallLabel {
justify-content: space-between;
font-size: 24rpx !important;
font-size: 26rpx !important;
}
.boxCenter {
display: flex !important;
align-items: center !important;
}
</style>

View File

@@ -44,13 +44,13 @@
class="nav-menu nav-menu-btn"
@click="selectDevice('transfer')"
v-if="userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'"
>移交
>移交
</view>
<view
class="nav-menu nav-menu-btn"
@click="selectDevice('share')"
v-if="userInfo.authorities === 'app_vip_user'"
>分享
>分享
</view>
</template>
<!-- <picker @change="projectTypeChange" :value="select.projectTypeIndex" :range="projectType" range-key="text">
@@ -70,7 +70,6 @@
<Cn-device-card :device="item" :key="index">
<template v-slot:title>
<!-- 卡片标题 -->
<switch
v-if="transfer || share"
:checked="checkList.indexOf(item.equipmentId) > -1"
@@ -78,8 +77,7 @@
@change="switchChange(item)"
/>
<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>
</template>
</Cn-device-card>
@@ -97,6 +95,7 @@
import { getProjectList } from '@/common/api/project'
import { queryDictData } from '@/common/api/dictionary'
import { engineeringPinToTop } from '@/common/api/device'
export default {
props: {
store: {
@@ -143,6 +142,7 @@ export default {
},
computed: {
deviceListFilter() {
let arr = this.store.data.filter((item) => {
if (this.select.projectName && this.select.projectType) {
return item.project === this.select.projectName && item.type === this.select.projectType
@@ -167,7 +167,8 @@ export default {
created() {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
},
mounted() {},
mounted() {
},
methods: {
bindClick(e, item) {
engineeringPinToTop({
@@ -373,9 +374,11 @@ export default {
.nav-menu {
}
}
/deep/ .button-group--right {
padding: 0 0 20rpx;
}
.star-icon {
font-size: 40rpx;
}

View File

@@ -22,21 +22,21 @@
<view class="project-info">
<view class="project-name">{{ item.engineeringName }}</view>
<view class="project-stats">
<view class="stat-item" @click="jump('nowEngineering', item)">
<view class="stat-item boxClick" @click="jump('nowEngineering', item)">
<text class="stat-value blue">{{ item.devTotal }}</text>
<text class="stat-label">设备总数</text>
</view>
<view class="stat-item" @click="jump('currentOnLineDevs', item)">
<view class="stat-item boxClick" @click="jump('currentOnLineDevs', item)">
<text class="stat-value green">{{ item.onlineDevTotal }}</text>
<text class="stat-label">在线设备</text>
</view>
<view class="stat-item" @click="jump('currentOffLineDevs', item)">
<view class="stat-item boxClick" @click="jump('currentOffLineDevs', item)">
<text class="stat-value red">{{ item.offlineDevTotal }}</text>
<text class="stat-label">离线设备</text>
</view>
<view class="stat-item" @click="jump('event', item)">
<view class="stat-item boxClick" @click="jump('event', item)">
<text class="stat-value red">{{ item.alarmTotal }}</text>
<text class="stat-label">告警数量</text>
<text class="stat-label">事件数量</text>
</view>
</view>
</view>
@@ -150,8 +150,15 @@ export default {
if (type == 'event') {
// 存储参数
uni.setStorageSync('messageParams', {
name: item.engineeringName,
id: item.engineeringId,
engineeringName: item.engineeringName,
engineeringId: item.engineeringId, //工程ID
projectName: '',
projectId: '', //項目ID
deviceName: '',
deviceId: '', //设备ID
lineName: '',
lineId: '', //测点ID
type: '',
})
uni.switchTab({
@@ -204,7 +211,7 @@ export default {
font-size: 28rpx;
font-weight: 700;
color: #333333;
margin-bottom: 10rpx;
margin-bottom: 20rpx;
}
.project-stats {
@@ -224,13 +231,14 @@ export default {
}
.stat-value {
font-size: 32rpx;
font-size: 36rpx;
font-weight: 700;
}
.stat-label {
font-size: 26rpx;
color: #666666;
margin-top: 5rpx;
// color: #666666;
}
.blue {

View File

@@ -3,27 +3,27 @@
<template v-if="devCount.engineeringListLength > 0">
<view class="canneng-index-title mb20">所有工程设备统计</view>
<view class="header">
<view class="header-item" @click="jump('allEngineering')">
<view class="header-item boxClick" @click="jump('allEngineering')">
<view class="header-item-value">{{ devCount.onLineDevCount + devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">设备总数</view>
</view>
<view class="header-item" @click="jump('onLineDevs')">
<view class="header-item boxClick" @click="jump('onLineDevs')">
<view class="header-item-value">{{ devCount.onLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view>
</view>
<view class="header-item" @click="jump('offLineDevs')">
<view class="header-item boxClick" @click="jump('offLineDevs')">
<view class="header-item-value">{{ devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view>
</view>
<view class="header-item" @click="jumpMessage(0)">
<view class="header-item boxClick" @click="jumpMessage(0)">
<view class="header-item-value">{{ devCount.eventCount || 0 }}</view>
<view class="header-item-label">暂态事件数</view>
</view>
<view class="header-item" @click="jumpMessage(1)">
<view class="header-item boxClick" @click="jumpMessage(1)">
<view class="header-item-value">{{ devCount.harmonicCount || 0 }}</view>
<view class="header-item-label">稳态事件数</view>
</view>
<view class="header-item" @click="eningerNum">
<view class="header-item boxClick" @click="eningerNum">
<view class="header-item-value">{{ devCount.eningerCount || 0 }}</view>
<view class="header-item-label">工程个数</view>
</view>
@@ -50,7 +50,12 @@
<view class="canneng-index-title mt20">常用功能</view>
<view style="padding: 20rpx 20rpx 0">
<Cn-grid title="" :auto-fill="false">
<Cn-grid-item src="/static/device2.png" text="设备注册" @click="registerDevice(4)"></Cn-grid-item>
<Cn-grid-item
class="boxClick"
src="/static/device2.png"
text="设备注册"
@click="registerDevice(4)"
></Cn-grid-item>
<!-- <Cn-grid-item
src="/static/device2.png"
text="功能调试"
@@ -178,8 +183,14 @@ export default {
},
jumpMessage(type) {
uni.setStorageSync('messageParams', {
name: '',
id: '',
engineeringName: '',
engineeringId: '', //工程ID
projectName: '',
projectId: '', //項目ID
deviceName: '',
deviceId: '', //设备ID
lineName: '',
lineId: '', //测点ID
type: type,
})
uni.switchTab({

View File

@@ -3,15 +3,15 @@
<template v-if="devCount.engineeringListLength > 1">
<view class="canneng-index-title mb20">所有工程设备统计</view>
<view class="header">
<view class="header-item" @click="jump('allEngineering')">
<view class="header-item boxClick" @click="jump('allEngineering')">
<view class="header-item-value">{{ devCount.onLineDevCount + devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">设备总数</view>
</view>
<view class="header-item" @click="jump('onLineDevs')">
<view class="header-item boxClick" @click="jump('onLineDevs')">
<view class="header-item-value">{{ devCount.onLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view>
</view>
<view class="header-item" @click="jump('offLineDevs')">
<view class="header-item boxClick" @click="jump('offLineDevs')">
<view class="header-item-value">{{ devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view>
</view>
@@ -20,28 +20,27 @@
</template>
<view class="canneng-index-title mb20">当前工程设备统计</view>
<view class="header">
<view class="header-item" @click="jump('nowEngineering')">
<view class="header-item boxClick" @click="jump('nowEngineering')">
<view class="header-item-value">{{
devCount.currentOnLineDevCount + devCount.currentOffLineDevCount || 0
}}</view>
<view class="header-item-label">设备总数</view>
</view>
<view class="header-item" @click="jump('currentOnLineDevs')">
<view class="header-item boxClick" @click="jump('currentOnLineDevs')">
<view class="header-item-value">{{ devCount.currentOnLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view>
</view>
<view class="header-item" @click="jump('currentOffLineDevs')">
<view class="header-item boxClick" @click="jump('currentOffLineDevs')">
<view class="header-item-value">{{ devCount.currentOffLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view>
</view>
</view>
<view style="padding: 20rpx 20rpx 0">
<!-- <view style="padding: 20rpx 20rpx 0">
<Cn-grid title="">
<Cn-grid-item src="/static/device2.png" text="设备注册" @click="registerDevice"></Cn-grid-item>
<!-- <Cn-grid-item src="/static/gateway2.png" text="网关注册" @click="registerGateway"></Cn-grid-item> -->
<Cn-grid-item src="/static/feedback2.png" text="问题反馈" @click="submitFeedBack"></Cn-grid-item>
</Cn-grid>
</view>
</view> -->
</view>
</template>

View File

@@ -3,29 +3,29 @@
<template v-if="devCount.engineeringListLength > 1">
<view class="canneng-index-title mb20">所有工程设备统计</view>
<view class="header">
<view class="header-item" @click="jump('allEngineering')">
<view class="header-item boxClick" @click="jump('allEngineering')">
<view class="header-item-value">{{ devCount.onLineDevCount + devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">设备总数</view>
</view>
<view class="header-item" @click="jump('onLineDevs')">
<view class="header-item boxClick" @click="jump('onLineDevs')">
<view class="header-item-value">{{ devCount.onLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view>
</view>
<view class="header-item" @click="jump('offLineDevs')">
<view class="header-item boxClick" @click="jump('offLineDevs')">
<view class="header-item-value">{{ devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view>
</view>
<view class="header-item" @click="jumpMessage(2, false)">
<view class="header-item boxClick" @click="jumpMessage(2, false)">
<view class="header-item-value">{{ devCount.alarmCount || 0 }}</view>
<view class="header-item-label">告警数量</view>
</view>
<view class="header-item" @click="jumpMessage(0, false)">
<view class="header-item boxClick" @click="jumpMessage(0, false)">
<view class="header-item-value">{{
devCount.eventCount + devCount.runCount + devCount.harmonicCount || 0
}}</view>
<view class="header-item-label">事件数量</view>
</view>
<view class="header-item" @click="eningerNum">
<view class="header-item boxClick" @click="eningerNum">
<view class="header-item-value">{{ devCount.eningerCount || 0 }}</view>
<view class="header-item-label">工程个数</view>
</view>
@@ -34,31 +34,31 @@
</template>
<view class="canneng-index-title mb20">当前工程设备统计</view>
<view class="header">
<view class="header-item" @click="jump('nowEngineering')">
<view class="header-item boxClick" @click="jump('nowEngineering')">
<view class="header-item-value">{{
devCount.currentOnLineDevCount + devCount.currentOffLineDevCount || 0
}}</view>
<view class="header-item-label">设备总数</view>
</view>
<view class="header-item" @click="jump('currentOnLineDevs')">
<view class="header-item boxClick" @click="jump('currentOnLineDevs')">
<view class="header-item-value">{{ devCount.currentOnLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view>
</view>
<view class="header-item" @click="jump('currentOffLineDevs')">
<view class="header-item boxClick" @click="jump('currentOffLineDevs')">
<view class="header-item-value">{{ devCount.currentOffLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view>
</view>
<view class="header-item" @click="jumpMessage(2, true)">
<view class="header-item boxClick" @click="jumpMessage(2, true)">
<view class="header-item-value">{{ devCount.currentAlarmCount || 0 }}</view>
<view class="header-item-label">告警数量</view>
</view>
<view class="header-item" @click="jumpMessage(0, true)">
<view class="header-item boxClick" @click="jumpMessage(0, true)">
<view class="header-item-value">{{
devCount.currentEventCount + devCount.currentRunCount + devCount.currentHarmonicCount || 0
}}</view>
<view class="header-item-label">事件数量</view>
</view>
<view class="header-item" @click="projectNum(true)">
<view class="header-item boxClick" @click="projectNum(true)">
<view class="header-item-value">{{ devCount.currentProjectCount || 0 }}</view>
<view class="header-item-label">项目个数</view>
</view>
@@ -81,8 +81,16 @@ export default {
methods: {
jumpMessage(type, flag) {
uni.setStorageSync('messageParams', {
name: flag ? uni.getStorageSync('engineering').name : '',
id: flag ? uni.getStorageSync('engineering').id : '',
// name: flag ? uni.getStorageSync('engineering').name : '',
// id: flag ? uni.getStorageSync('engineering').id : '',
engineeringName: flag ? uni.getStorageSync('engineering').name : '',
engineeringId: flag ? uni.getStorageSync('engineering').id : '', //工程ID
projectName: '',
projectId: '', //項目ID
deviceName: '',
deviceId: '', //设备ID
lineName: '',
lineId: '', //测点ID
type: type,
})
uni.switchTab({

View File

@@ -3,15 +3,15 @@
<template v-if="devCount.engineeringListLength > 1">
<view class="canneng-index-title mb20">所有工程设备统计</view>
<view class="header">
<view class="header-item" @click="jump('allEngineering')">
<view class="header-item boxClick" @click="jump('allEngineering')">
<view class="header-item-value">{{ devCount.onLineDevCount + devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">设备总数</view>
</view>
<view class="header-item" @click="jump('onLineDevs')">
<view class="header-item boxClick" @click="jump('onLineDevs')">
<view class="header-item-value">{{ devCount.onLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view>
</view>
<view class="header-item" @click="jump('offLineDevs')">
<view class="header-item boxClick" @click="jump('offLineDevs')">
<view class="header-item-value">{{ devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view>
</view>
@@ -20,35 +20,45 @@
</template>
<view class="canneng-index-title mb20">当前工程设备统计</view>
<view class="header">
<view class="header-item" @click="jump('nowEngineering')">
<view class="header-item boxClick" @click="jump('nowEngineering')">
<view class="header-item-value"
>{{ devCount.currentOnLineDevCount + devCount.currentOffLineDevCount || 0 }}
</view>
<view class="header-item-label">设备总数</view>
</view>
<view class="header-item" @click="jump('currentOnLineDevs')">
<view class="header-item boxClick" @click="jump('currentOnLineDevs')">
<view class="header-item-value">{{ devCount.currentOnLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view>
</view>
<view class="header-item" @click="jump('currentOffLineDevs')">
<view class="header-item boxClick" @click="jump('currentOffLineDevs')">
<view class="header-item-value">{{ devCount.currentOffLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view>
</view>
<view class="header-item" @click="jumpMessage('0')">
<view class="header-item-value">{{ devCount.eventCount || 0 }}</view>
<view class="header-item boxClick" @click="jumpMessage('0')">
<view class="header-item-value">{{ devCount.currentEventCount || 0 }}</view>
<view class="header-item-label">暂态事件数</view>
</view>
<view class="header-item" @click="jumpMessage('1')">
<view class="header-item-value">{{ devCount.harmonicCount || 0 }}</view>
<view class="header-item boxClick" @click="jumpMessage('1')">
<view class="header-item-value">{{ devCount.currentHarmonicCount || 0 }}</view>
<view class="header-item-label">稳态事件数</view>
</view>
</view>
<view class="canneng-index-title mt20">常用功能</view>
<view style="padding: 20rpx 20rpx 0">
<Cn-grid title="">
<Cn-grid-item src="/static/device2.png" text="设备注册" @click="registerDevice"></Cn-grid-item>
<Cn-grid-item
src="/static/device2.png"
class="boxClick"
text="设备注册"
@click="registerDevice"
></Cn-grid-item>
<!-- <Cn-grid-item src="/static/gateway2.png" text="网关注册" @click="registerGateway"></Cn-grid-item> -->
<Cn-grid-item src="/static/feedback2.png" text="问题反馈" @click="submitFeedBack"></Cn-grid-item>
<Cn-grid-item
src="/static/feedback2.png"
class="boxClick"
text="问题反馈"
@click="submitFeedBack"
></Cn-grid-item>
</Cn-grid>
</view>
<uni-popup ref="popup" type="dialog" @maskClick="maskClick">
@@ -144,8 +154,14 @@ export default {
},
jumpMessage(type) {
uni.setStorageSync('messageParams', {
name:'',
id: '',
engineeringName: '',
engineeringId: '', //工程ID
projectName: '',
projectId: '', //項目ID
deviceName: '',
deviceId: '', //设备ID
lineName: '',
lineId: '', //测点ID
type: type,
})
uni.switchTab({

View File

@@ -3,27 +3,27 @@
<template v-if="devCount.engineeringListLength > 1">
<view class="canneng-index-title mb20">所有工程设备统计</view>
<view class="header">
<view class="header-item" @click="jump('allEngineering')">
<view class="header-item boxClick" @click="jump('allEngineering')">
<view class="header-item-value">{{ devCount.onLineDevCount + devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">设备总数</view>
</view>
<view class="header-item" @click="jump('onLineDevs')">
<view class="header-item boxClick" @click="jump('onLineDevs')">
<view class="header-item-value">{{ devCount.onLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view>
</view>
<view class="header-item" @click="jump('offLineDevs')">
<view class="header-item boxClick" @click="jump('offLineDevs')">
<view class="header-item-value">{{ devCount.offLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view>
</view>
<view class="header-item" @click="jumpMessage(0, false)">
<view class="header-item boxClick" @click="jumpMessage(0, false)">
<view class="header-item-value">{{ devCount.eventCount || 0 }}</view>
<view class="header-item-label">暂态事件数</view>
</view>
<view class="header-item" @click="jumpMessage(1, false)">
<view class="header-item boxClick" @click="jumpMessage(1, false)">
<view class="header-item-value">{{ devCount.harmonicCount || 0 }}</view>
<view class="header-item-label">稳态事件数</view>
</view>
<view class="header-item" @click="eningerNum">
<view class="header-item boxClick" @click="eningerNum">
<view class="header-item-value">{{ devCount.eningerCount || 0 }}</view>
<view class="header-item-label">工程个数</view>
</view>
@@ -32,29 +32,29 @@
</template>
<view class="canneng-index-title mb20">当前工程设备统计</view>
<view class="header">
<view class="header-item" @click="jump('nowEngineering')">
<view class="header-item boxClick" @click="jump('nowEngineering')">
<view class="header-item-value"
>{{ devCount.currentOnLineDevCount + devCount.currentOffLineDevCount || 0 }}
</view>
<view class="header-item-label">设备总数</view>
</view>
<view class="header-item" @click="jump('currentOnLineDevs')">
<view class="header-item boxClick" @click="jump('currentOnLineDevs')">
<view class="header-item-value">{{ devCount.currentOnLineDevCount || 0 }}</view>
<view class="header-item-label">在线设备</view>
</view>
<view class="header-item" @click="jump('currentOffLineDevs')">
<view class="header-item boxClick" @click="jump('currentOffLineDevs')">
<view class="header-item-value">{{ devCount.currentOffLineDevCount || 0 }}</view>
<view class="header-item-label">离线设备</view>
</view>
<view class="header-item" @click="jumpMessage(0, true)">
<view class="header-item boxClick" @click="jumpMessage(0, true)">
<view class="header-item-value">{{ devCount.currentEventCount || 0 }}</view>
<view class="header-item-label">暂态事件数</view>
</view>
<view class="header-item" @click="jumpMessage(1, true)">
<view class="header-item boxClick" @click="jumpMessage(1, true)">
<view class="header-item-value">{{ devCount.currentHarmonicCount || 0 }}</view>
<view class="header-item-label">稳态事件数</view>
</view>
<view class="header-item" @click="projectNum(true)">
<view class="header-item boxClick" @click="projectNum(true)">
<view class="header-item-value">{{ devCount.currentProjectCount || 0 }}</view>
<view class="header-item-label">项目个数</view>
</view>
@@ -87,8 +87,16 @@ export default {
},
jumpMessage(type, flag) {
uni.setStorageSync('messageParams', {
name: flag ? uni.getStorageSync('engineering').name : '',
id: flag ? uni.getStorageSync('engineering').id : '',
// name: flag ? uni.getStorageSync('engineering').name : '',
// id: flag ? uni.getStorageSync('engineering').id : '',
engineeringName: flag ? uni.getStorageSync('engineering').name : '',
engineeringId: flag ? uni.getStorageSync('engineering').id : '', //工程ID
projectName: '',
projectId: '', //項目ID
deviceName: '',
deviceId: '', //设备ID
lineName: '',
lineId: '', //测点ID
type: type,
})
uni.switchTab({

View File

@@ -0,0 +1,349 @@
<template>
<view class="dashboard-container">
<!-- 页面头部 -->
<view class="page-header">
<Cn-filterInformation @select="select" />
<view class="legend-row">
<view class="legend-item">
<view class="legend-color" style="background:#DAA520"></view>
<text class="legend-text">A相</text>
</view>
<view class="legend-item">
<view class="legend-color" style="background:#2E8B57"></view>
<text class="legend-text">B相</text>
</view>
<view class="legend-item">
<view class="legend-color" style="background:#A52A2A"></view>
<text class="legend-text">C相</text>
</view>
</view>
</view>
<!-- 监测点列表 - 竖向滚动 -->
<scroll-view class="monitors-scroll" scroll-y :show-scrollbar="true">
<view class="monitors-list">
<view v-for="(point, idx) in monitoringPoints" :key="idx" class="monitor-card">
<!-- 卡片头部 -->
<view class="card-header">
<view class="event-icon">
<Cn-icon-transient :name="`监测点`" />
</view>
<view class="card-header-info">
<view class="point-name">
<text class="point-text ellipsis">{{ point.pointName }}</text>
</view>
<view class="meta-row">
<text class="meta-item ellipsis">工程: {{ point.projectName }}</text>
<text class="meta-item ellipsis">项目: {{ point.siteName }}</text>
<text class="meta-item ellipsis meta-item-full">设备: {{ point.deviceName }}</text>
</view>
</view>
</view>
<!-- 参数区域使用 children 数据循环每两个指标放一行 -->
<view class="params-section">
<view v-for="(rowItems, rowIdx) in chunkedChildren(point.children)" :key="rowIdx"
class="double-row">
<view v-for="(child, childIdx) in rowItems" :key="childIdx" class="param-group">
<view class="param-title">
<text>{{ child.name }}</text>
</view>
<!-- 三相数据颜色区分无文字 -->
<view class="phase-vertical">
<view class="phase-item-vertical">
<text class="phase-value-vertical" style="color:#DAA520">{{ child.A }}</text>
</view>
<view class="phase-divider"></view>
<view class="phase-item-vertical">
<text class="phase-value-vertical" style="color:#2E8B57">{{ child.B }}</text>
</view>
<view class="phase-divider"></view>
<view class="phase-item-vertical">
<text class="phase-value-vertical" style="color:#A52A2A">{{ child.C }}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
export default {
data() {
return {
// 监测点基础信息 + children 指标数据
monitoringPoints: [
{
pointName: "升压站#1主变测点",
projectName: "华光100MW工程11111",
siteName: "绿色智慧能源11111",
deviceName: "PMC-800终端",
children: [
{ name: '电压有效值(kV)', A: '10.52', B: '10.45', C: '10.39' },
{ name: '电流有效值(A)', A: '408.0', B: '395.0', C: '403.0' },
{ name: '基波电压幅值(kV)', A: '10.48', B: '10.42', C: '10.35' },
{ name: '基波电流幅值(A)', A: '405.5', B: '392.8', C: '400.2' }
]
},
{
pointName: "光伏区#3汇流箱",
projectName: "华光100MW工程",
siteName: "绿色智慧能源示范",
deviceName: "汇流监测单元",
children: [
{ name: '电压有效值(kV)', A: '10.72', B: '10.65', C: '10.59' },
{ name: '电流有效值(A)', A: '426.0', B: '413.0', C: '421.0' },
{ name: '基波电压幅值(kV)', A: '10.68', B: '10.62', C: '10.55' },
{ name: '基波电流幅值(A)', A: '423.5', B: '410.8', C: '418.2' }
]
},
],
// 三相颜色配置
phaseColors: [
{ name: 'A相', color: '#DAA520' },
{ name: 'B相', color: '#2E8B57' },
{ name: 'C相', color: '#A52A2A' }
]
}
},
methods: {
// 将 children 数组每两个一组进行分组,用于一行显示两个指标
chunkedChildren(children) {
const result = []
for (let i = 0; i < children.length; i += 2) {
result.push(children.slice(i, i + 2))
}
return result
},
select(value) {
console.log("🚀 ~ value:", value)
},
}
}
</script>
<style>
* {
box-sizing: border-box;
}
.dashboard-container {
min-height: 100vh;
background: #f5f7fb;
padding: 20rpx 20rpx 0rpx 20rpx;
display: flex;
flex-direction: column;
}
/* 头部样式 */
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
flex-shrink: 0;
}
.title-section {
display: flex;
align-items: baseline;
gap: 12rpx;
}
.title-icon {
font-size: 40rpx;
}
.title {
font-size: 34rpx;
font-weight: 700;
color: #2c3e50;
}
/* 图例 */
.legend-row {
display: flex;
gap: 20rpx;
align-items: center;
}
.legend-item {
display: flex;
align-items: center;
gap: 6rpx;
}
.legend-color {
width: 24rpx;
height: 24rpx;
border-radius: 50%;
}
.legend-text {
font-size: 24rpx;
color: #333;
font-weight: 500;
}
/* 竖向滚动区域 */
.monitors-scroll {
flex: 1;
max-height: calc(100vh - 100rpx);
}
.monitors-list {
display: flex;
flex-direction: column;
gap: 20rpx;
padding-bottom: 20rpx;
}
/* 卡片样式 */
.monitor-card {
background: #ffffff;
border-radius: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
overflow: hidden;
display: flex;
flex-direction: column;
border: 1rpx solid #e8ecf0;
}
.card-header {
padding: 20rpx 20rpx 10rpx 20rpx;
border-bottom: 1rpx solid #eef2f6;
display: flex;
align-items: center;
}
.card-header-info {
flex: 1;
min-width: 0;
overflow: hidden;
}
.point-name {
margin-bottom: 4rpx;
}
.point-text {
display: block;
font-size: 30rpx;
font-weight: 700;
color: #333333;
}
/* 工程、项目、设备:两列布局,超出显示省略号 */
.meta-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 6rpx 8rpx;
width: 100%;
}
.meta-item {
display: block;
min-width: 0;
font-size: 24rpx;
color: #666666;
line-height: 1.3;
}
.meta-item-full {
grid-column: 1 / -1;
}
/* 参数区域 */
.params-section {
padding: 20rpx 16rpx 24rpx 16rpx;
flex: 1;
}
.double-row {
display: flex;
gap: 16rpx;
margin-bottom: 16rpx;
flex-wrap: wrap;
}
.double-row:last-child {
margin-bottom: 0;
}
.param-group {
flex: 1;
min-width: 200rpx;
background: transparent;
border-radius: 20rpx;
padding: 12rpx 8rpx 8rpx;
border: 1rpx solid #e8ecf0;
}
.param-title {
font-size: 24rpx;
color: #666666;
font-weight: 650;
margin-bottom: 4rpx;
display: flex;
align-items: center;
gap: 8rpx;
padding-left: 4rpx;
}
/* 三相数据垂直布局 */
.phase-vertical {
display: flex;
align-items: stretch;
justify-content: space-between;
gap: 0;
}
.phase-item-vertical {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 4rpx 4rpx;
}
.phase-value-vertical {
font-size: 28rpx;
font-weight: 700;
display: block;
letter-spacing: -0.5rpx;
}
/* 竖线分割 */
.phase-divider {
width: 1rpx;
background-color: #e0e4e8;
margin: 8rpx 0;
}
/* 文字溢出显示省略号 */
.ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 100%;
}
.event-icon {
position: relative;
width: 110rpx;
height: 110rpx;
border-radius: 12rpx;
display: flex;
justify-content: center;
align-items: center;
margin-right: 20rpx;
background-color: #376cf320;
}
</style>

View File

@@ -1,6 +1,8 @@
<template>
<view class="dateReport">
<!-- <view class="pd20">
<!-- {{ height }} -->
<view class="pd20">
<uni-segmented-control
:current="curSub"
class="subsection"
@@ -8,10 +10,10 @@
:values="subsectionList"
@clickItem="sectionChange"
/>
</view> -->
</view>
<view class="filterCriteria">
<!-- 筛选条件 -->
<Cn-filterCriteria @select="select" :singleChoice="true" :report="true"> </Cn-filterCriteria>
<Cn-filterCriteria @select="select" :singleChoice="true" :showDatetime="curSub == 0"> </Cn-filterCriteria>
</view>
<!-- 卡片 -->
@@ -21,28 +23,50 @@
:refresher-triggered="triggered"
refresher-enabled="true"
class="event-list mt20"
v-if="eventList.length != 0"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }"
>
<!-- 循环渲染事件项 -->
<uni-card class="event-item" :class="item.type" v-for="(item, index) in store.data" :key="index">
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view class="event-icon">
<!-- 动态图标根据类型切换 -->
<!-- <uni-icons
custom-prefix="iconfont"
type="icon-kouanjiancedian"
size="40"
color="#E6A23C"
></uni-icons> -->
<Cn-icon-transient :name="`报告`" />
<view class="badge1" v-if="item.isRead == 0"> </view>
</view>
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.lineName }}</text>
<view class="event-tags"
<!-- <view class="event-tags"
>{{ selectValue.report == 0 ? item.startTime : item.startTime + '至' + item.endTime }}
<view class="iconText ml10" @click="download(item)"
><uni-icons type="arrow-down" color="#fff" size="16"></uni-icons>
</view>
</view>
</view> -->
</view>
<view class="event-desc">
<text
>统计时间{{
curSub == 0 ? item.startTime : item.startTime + ' 至 ' + item.endTime
}}</text
>
</view>
</view>
<view class="event-action" v-if="curSub == 0 ? monthFlag : item.endTime != thisMonth01">
<view class="iconText boxClick" @click="download(item)"
><uni-icons type="arrow-down" color="#fff" size="16"></uni-icons>
</view>
</view>
</view>
<!-- 详情区域 -->
<view class="event-detail">
<text>{{ item.overLimitDesc == '' ? '该监测点暂无指标越限' : item.overLimitDesc }}</text>
<view class="event-detail textBox" @touchmove.stop>
<text v-if="curSub == 0 ? monthFlag : item.endTime != thisMonth01">{{
item.overLimitDesc == '' ? '该监测点暂无指标越限' : item.overLimitDesc
}}</text>
<text v-else>数据未生成暂不支持下载</text>
</view>
<!-- <view class="downloadReport" @click="download">
<uni-icons type="download" size="16" color="#376cf3"></uni-icons>下载报告
@@ -82,22 +106,19 @@ export default {
status: 'noMore',
curSub: 0,
subsectionList: ['周报', '月报'],
eventList: [
{
id: '测试监测点',
tag: '2026-01-23至2026-01-23',
status: '1',
},
],
thisSelectValue: {},
triggered: true,
height: 0,
thisMonth01: '',
monthFlag: true,
}
},
created() {},
mounted() {
this.setHeight()
this.thisMonth01 = this.$util.getToday().slice(0, -3) + '-01'
this.monthFlag = this.$util.getToday() != this.$util.getToday().slice(0, -3) + '-01'
// this.setHeight()
},
methods: {
setHeight() {
@@ -106,28 +127,33 @@ export default {
.boundingClientRect((rect) => {
//
// #ifdef H5
this.height = rect?.height + 20 || 0
this.height = rect?.height + 140 || 0
// #endif
// #ifdef APP-PLUS
this.height = rect?.height + 30 || 0
this.height = rect?.height + 75 || 0
// #endif
})
.exec()
},
sectionChange(index) {
this.curSub = index.currentIndex
this.init()
},
init() {
if (this.selectValue.lineId == '') return
this.store = this.DataSource('/cs-report-boot/csAppReport/reportList')
this.store.params.pageSize = 10000
this.store.params.timeType = this.selectValue.report
// this.store.params.pageSize = 10000
this.store.params.timeType = this.curSub //this.selectValue.report
this.store.params.engineerId = this.selectValue.engineeringId
this.store.params.projectId = this.selectValue.projectId
this.store.params.devId = this.selectValue.deviceId
this.store.params.lineId = this.selectValue.lineId
this.store.params.time = this.selectValue.date
if (this.curSub == 0) {
this.store.params.time = this.selectValue.date
} else {
this.store.params.time = this.selectValue.range + '-01'
}
// this.store.params.startTime = this.selectValue.range[0]
// this.store.params.endTime = this.selectValue.range[1]
this.store.loadedCallback = () => {}
@@ -136,10 +162,10 @@ export default {
select(value) {
this.selectValue = value
this.init()
setTimeout(() => {
this.setHeight()
}, 100)
}, 200)
this.init()
},
// 下载
download(item) {
@@ -246,7 +272,7 @@ export default {
}
.event-detail {
font-size: 25rpx !important;
// font-size: 25rpx !important;
// display: grid;
// grid-template-columns: 1fr 1fr;
}
@@ -287,6 +313,34 @@ export default {
border-radius: 50%;
background-color: $uni-theme-color;
text-align: center;
line-height: 45rpx;
line-height: 40rpx;
}
.segmented-control {
flex: 1;
margin-right: 24rpx;
height: 60rpx;
}
/* 列表容器 */
.event-list {
/* 头部:图标 + 信息 + 操作 */
.event-header {
display: flex;
align-items: center;
margin-bottom: 10rpx;
}
/* 图标区域(按类型区分背景色) */
.event-icon {
background-color: #376cf320;
}
.event-tags {
font-size: 24rpx;
}
}
.textBox {
// @touchmove.stop
max-height: 110rpx;
overflow-y: auto;
}
</style>

View File

@@ -1,19 +1,14 @@
<template>
<view class="dateReport">
<view class="pd20">
<uni-segmented-control
:current="curSub"
class="subsection"
active-color="#376cf3"
:values="subsectionList"
@clickItem="sectionChange"
/>
<uni-segmented-control :current="curSub" class="subsection" active-color="#376cf3" :values="subsectionList"
@clickItem="sectionChange" />
</view>
<!-- 申请报告 -->
<view v-show="curSub == 0">
<!-- apply -->
<Apply :navHeight="navHeight" />
<Apply ref="applyRef" :navHeight="navHeight" />
</view>
<!-- 申请记录 -->
@@ -22,24 +17,22 @@
<!-- 筛选条件 -->
<Cn-filterCriteria @select="select" :showQianTree="false"> </Cn-filterCriteria>
</view>
<view
class="record event-list mt20"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }"
>
<scroll-view scroll-y="true" @refresherrefresh="refresherrefresh" @scrolltolower="scrolltolower"
:refresher-triggered="triggered" refresher-enabled="true" class="record event-list mt20"
:style="{ height: 'calc(100vh - ' + (navHeight + height) + 'px)', overflow: 'auto' }">
<uni-card class="event-item" :class="item.type" v-for="(item, index) in store.data" :key="index">
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view
class="event-icon"
:style="{ backgroundColor: item.isComplete == 1 ? '#10b98120' : '#FF000020' }"
>
<view class="event-icon">
<!-- :style="{ backgroundColor: item.isComplete == 1 ? '#10b98120' : '#FF000020' }" -->
<!-- 动态图标根据类型切换 -->
<uni-icons
<!-- <uni-icons
custom-prefix="iconfont"
type="icon-baogaoguanli"
size="40"
:color="item.isComplete == 1 ? '#10b981' : '#FF0000'"
></uni-icons>
></uni-icons> -->
<Cn-icon-transient :name="`报告`" />
</view>
<view class="event-info">
<view class="event-title">
@@ -54,14 +47,11 @@
</view>
</view>
<view class="event-action">
<view class="iconText" v-if="item.isComplete == 1" @click="download(item)"
><uni-icons type="arrow-down" color="#fff" size="16"></uni-icons>
<view class="iconText boxClick" v-if="item.isComplete == 1" @click="download(item)">
<uni-icons type="arrow-down" color="#fff" size="16"></uni-icons>
</view>
<view
class="nav-menu nav-menu-btn"
v-else-if="userInfo.authorities === 'operation_manager'"
@click="generate(item)"
>生成报告
<view class="nav-menu nav-menu-btn boxClick"
v-else-if="userInfo.authorities === 'operation_manager'" @click="generate(item)">生成报告
</view>
</view>
</view>
@@ -72,6 +62,12 @@
<text>申请人</text>
<text>{{ item.applyUser }}</text>
</view>
<view class="device-body-item">
<text>报告状态</text>
<text :style="{ color: item.isComplete == 1 ? '#10b981' : '#FF0000' }">{{
item.isComplete == 1 ? '已完成' : '未完成'
}}</text>
</view>
<view class="device-body-item">
<text>申请时间</text>
<text>{{ item.time }}</text>
@@ -80,14 +76,7 @@
<text>暂降事件</text>
<text>{{ item.eventNums }}</text>
</view>
<view class="device-body-item">
<text>申请状态</text>
<text
:style="{ color: item.isComplete == 1 ? '#10b981' : '#FF0000' }"
style="font-weight: 700"
>{{ item.isComplete == 1 ? '已完成' : '未完成' }}</text
>
</view>
<!-- <view class="device-body-item">
<text>申请时间</text>
@@ -97,12 +86,10 @@
<!-- </view> -->
</uni-card>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
></uni-load-more>
<uni-load-more v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"></uni-load-more>
<Cn-empty v-else style="top: 30%"></Cn-empty>
</view>
</scroll-view>
</view>
</view>
</template>
@@ -141,12 +128,13 @@ export default {
type: 0,
lindId: '',
},
triggered: true,
userInfo: {},
height: 0,
selectValue: {},
}
},
created() {},
created() { },
mounted() {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
},
@@ -158,10 +146,10 @@ export default {
.boundingClientRect((rect) => {
//
// #ifdef H5
this.height = rect?.height + 115 || 0
this.height = rect?.height + 180 || 0
// #endif
// #ifdef APP-PLUS
this.height = rect?.height + 10 || 0
this.height = rect?.height + 110 || 0
// #endif
})
.exec()
@@ -170,13 +158,14 @@ export default {
this.store = this.DataSource('/cs-report-boot/csAppReport/getApplicationReport')
this.store.params.startTime = this.$util.getMonthFirstAndLastDay(this.selectValue.date).firstDay
this.store.params.endTime = this.$util.getMonthFirstAndLastDay(this.selectValue.date).lastDay
this.store.loadedCallback = () => {}
this.store.loadedCallback = () => {
this.setHeight()
}
this.store.reload()
},
async select(val) {
this.selectValue = val
await this.init()
this.setHeight()
},
sectionChange(index) {
@@ -258,7 +247,7 @@ export default {
})
}
},
fail: function (res) {},
fail: function (res) { },
})
})
.catch((err) => {
@@ -270,6 +259,31 @@ export default {
})
})
},
// 刷新
reload() {
switch (this.curSub) {
case 0:
this.$refs.applyRef.store.reload()
break
case 1:
this.store && this.store.reload()
break
}
},
// 下拉
refresherrefresh() {
this.triggered = true
uni.startPullDownRefresh()
setTimeout(() => {
this.triggered = false
}, 500)
},
// 上拉
scrolltolower() {
if (this.store.status != 'noMore') {
this.store.next && this.store.next()
}
},
},
watch: {},
}
@@ -279,7 +293,7 @@ export default {
.event-detail {
display: grid;
grid-template-columns: 1fr 1.2fr;
grid-template-columns: 1.6fr 1fr;
}
// /deep/ .record {
@@ -291,28 +305,35 @@ export default {
.nav {
background-color: #fff;
}
.choose1 {
background-color: #fff;
padding: 0 20rpx;
display: flex;
justify-content: space-between;
/deep/ .uni-checkbox-input {
width: 30rpx;
height: 30rpx;
}
font-size: 26rpx;
}
}
// .device-body {
// padding: 10rpx 20rpx 20rpx;
.device-body-item {
display: flex;
// justify-content: space-between;
font-size: 26rpx;
font-size: 28rpx;
color: #666666;
line-height: 1.5;
}
// }
.iconText {
display: flex;
@@ -323,6 +344,7 @@ export default {
justify-content: center;
align-items: center;
}
.nav-menu {
height: 40rpx;
padding: 6rpx 20rpx;
@@ -331,13 +353,33 @@ export default {
line-height: 40rpx;
background: #ebeaec;
color: #666;
&-active {
background: #dfe5f7;
color: $uni-theme-color;
}
&-btn {
background: $uni-theme-color;
color: #fff;
}
}
.event-list {
/* 图标区域(按类型区分背景色) */
.event-icon {
background-color: #376cf320;
}
}
.segmented-control {
flex: 1;
margin-right: 24rpx;
height: 60rpx;
}
/deep/ .uni-scroll-view-refresher {
display: none;
}
</style>

View File

@@ -1,33 +1,20 @@
<template>
<Cn-page :loading="loading" noPadding>
<view slot="body" class="canneng-index">
<uni-nav-bar
rightWidth="300rpx"
leftWidth="300rpx"
dark
:fixed="true"
status-bar
background-color="#fff"
color="#111"
@clickRight="selectEngineering"
>
<uni-nav-bar rightWidth="300rpx" leftWidth="300rpx" dark :fixed="true" status-bar background-color="#fff"
color="#111" @clickRight="selectEngineering">
<template slot="left">
<text style="font-size: 32rpx; font-weight: 500">灿能物联</text>
</template>
<template slot="right">
<text class="hide-txt mr5" style="font-size: 28rpx"
>{{
userInfo.authorities === 'engineering_user'
? '创建工程'
: select.engineeringName || emptyEngineeringName
}}
<text class="hide-txt mr5" style="font-size: 28rpx">{{
userInfo.authorities === 'engineering_user'
? '创建工程'
: select.engineeringName || emptyEngineeringName
}}
</text>
<uni-icons
type="bottom"
size="16"
color="#111"
v-if="select.engineeringName && userInfo.authorities != 'engineering_user'"
></uni-icons>
<uni-icons type="bottom" size="16" color="#111"
v-if="select.engineeringName && userInfo.authorities != 'engineering_user'"></uni-icons>
</template>
</uni-nav-bar>
<view class="index">
@@ -48,7 +35,10 @@
</template>
<!-- 设备列表 -->
<template v-else v-show="engineeringList.length">
<view class="canneng-index-title mt20">设备列表</view>
<view class="canneng-index-title mt20">
<view>设备列表</view>
<view class="nav-menu nav-menu-btn boxClick" @click="jump">电能质量信息 </view>
</view>
<Device ref="device" :store="store" />
</template>
</view>
@@ -187,11 +177,18 @@ export default {
key: this.$cacheKey.messageCount,
data: this.devCount,
})
// let messagePage =
// this.devCount.runCount +
// this.devCount.eventCount +
// this.devCount.alarmCount +
// this.devCount.harmonicCount
let messagePage =
this.devCount.runCount +
this.devCount.eventCount +
this.devCount.alarmCount +
this.devCount.harmonicCount
this.devCount.harmonicCount +
(uni.getStorageSync(this.$cacheKey.userInfo).authorities == 'operation_manager'
? this.devCount.alarmCount + this.devCount.runCount
: 0)
// console.log('🚀 ~ messagePage:', messagePage)
let minePage = this.devCount.feedBackCount
if (messagePage) {
@@ -220,6 +217,11 @@ export default {
})
},
// 动态配置导航栏按钮
jump() {
uni.navigateTo({
url: `/pages/index/comp/monitoringPoint`,
})
}
},
onLoad() {
// 页面加载时,动态配置导航栏按钮
@@ -300,8 +302,8 @@ export default {
.canneng-index-title {
padding: 0 20rpx;
font-size: 28rpx;
font-weight: 500;
display: flex;
}
/deep/ .uni-card {
@@ -311,4 +313,28 @@ export default {
/deep/ .uni-drawer__content {
width: 100vw !important;
}
.nav-menu {
height: 40rpx;
padding: 4rpx 20rpx;
// margin-left: 20rpx;
// margin-bottom: 20rpx;
line-height: 38rpx;
font-size: 24rpx;
border-radius: 8rpx;
background: #ebeaec;
color: #666;
&-active {
background: #dfe5f7;
color: $uni-theme-color;
}
&-btn {
background: $uni-theme-color;
color: #fff;
}
margin-left: auto;
}
</style>

View File

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

View File

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

View File

@@ -1,5 +1,6 @@
<template>
<view :loading="loading" class="report" style="padding-top: 10px">
<view class="navReport">
<view class="tabsBox">
<uni-segmented-control
@@ -14,6 +15,7 @@
<!-- 稳态报表 -->
<SteadyState
v-if="curTabs == 0"
ref="SteadyStateRef"
:indexList="indexList"
:total="total"
:status="status"
@@ -23,6 +25,7 @@
<!-- 暂态报表 -->
<Transient
v-if="curTabs == 1"
ref="TransientRef"
:indexList="indexList"
:total="total"
:status="status"
@@ -51,58 +54,25 @@ export default {
navHeight: 0,
indexList: [
{
name: '测试监测点',
item: '2022-01-01至2022-01-01',
type: '1',
status: '1',
},
{
name: '测试监测点',
item: '2022-01-01至2022-01-01',
type: '2',
status: '1',
},
{
name: '测试监测点',
item: '2022-01-01至2022-01-01',
type: '1',
status: '1',
},
{
name: '测试监测点',
item: '2022-01-01至2022-01-01',
type: '1',
status: '0',
},
{
name: '测试监测点',
item: '2022-01-01至2022-01-01',
type: '1',
status: '0',
},
{
name: '测试监测点',
item: '2022-01-01至2022-01-01',
type: '1',
status: '0',
},
],
indexList: [],
}
},
created() {},
onPullDownRefresh() {
this.refresh()
},
mounted() {
uni.createSelectorQuery()
.select('.navReport')
.boundingClientRect((rect) => {
//
// #ifdef H5
this.navHeight = rect.height + 65
// #endif
// #ifdef APP-PLUS
this.navHeight = rect.height + 25
// #endif
this.navHeight = rect.height
// // #ifdef H5
// // #endif
// // #ifdef APP-PLUS
// this.navHeight = rect.height
// // #endif
})
.exec()
},
@@ -127,6 +97,16 @@ export default {
this.status = 'more'
}, 1000)
},
refresh() {
switch (this.curTabs) {
case 0:
this.$refs.SteadyStateRef.store.reload()
break
case 1:
this.$refs.TransientRef.reload()
break
}
},
},
computed: {},

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,102 +6,75 @@
<view>{{ detail.date }}</view>
</view>
<view class="detail-content" style="padding: 0px">
<view class="detail-content-title mb20 pt20 pl20">终端告警列表</view>
<view class="detail-content-title pb20 pt20 pl20">终端告警列表</view>
</view>
<!-- <uni-collapse accordion v-model="collapseValue">
<uni-collapse-item :title="item.devName" v-for="item in list">
<template v-slot:title>
<view class="collapseTop">
<view class="mb5 name"> {{ item.devName }}</view>
<view class="mb5 frequency">
<view class="mr20"> 告警次数: {{ item.warnCounts }} </view>
<view> 通讯中断: {{ item.interruptCounts }} </view>
</view>
<view class="event-list">
<uni-card class="event-item" :class="item.type" v-for="(item, index) in list" :key="index">
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view class="event-icon"
:class="item.devType == 'Direct_Connected_Device' ? 'zl-bgc' : 'jc-bgc'">
<!-- 动态图标根据类型切换 -->
<!-- <uni-icons
custom-prefix="iconfont"
type="icon-terminal-box-fill"
size="35"
color="#FF0000"
></uni-icons> -->
<!-- <Cn-icon-transient :name="`运行告警`" /> -->
<Cn-icon-transient :name="item.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备'" />
<view class="badge1" v-if="item.status == 0"> </view>
</view>
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.devName }}</text>
<text class="event-tag"
:class="item.devType == 'Direct_Connected_Device' ? 'zl-tag' : 'jc-tag'">{{
item.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备' }}</text>
</view>
</template>
<view class="event-desc">
<text>工程名称{{ item.engineeringName }}</text>
<text>项目名称{{ item.projectName }}</text>
<!-- <text v-if="item.dataDetails.onlineRate.isAbnormal">在线率{{
item.dataDetails.onlineRate.value }}% 限值{{ item.dataDetails.onlineRate.threshold
}}% </text> -->
<!-- <text>事件时间{{ item.startTime }}</text> -->
</view>
</view>
</view>
<!-- 详情区域 -->
<view class="event-detail">
<view v-if="item.dataDetails.onlineRate.isAbnormal">
<text>在线率
{{item.dataDetails.onlineRate.value }}% 
</text>
<view>
<view class="mb10 ml12 frequency">
<view>项目名称{{ item.projectName }} </view></view
>
<view class="mb10 ml12 frequency">
<view>工程名称{{ item.engineeringName }}</view></view
>
<view class="mb10 ml12 frequency">
<view>通讯信息</view>
<view style="flex: 1">
<view v-if="item.interruptCounts == 0">通讯正常</view>
<view v-else>通讯中断{{ item.interruptCounts }}具体如下所示:</view
><view v-for="date in item.interruptDetails" class="mt15 textBox">{{
date
}}</view></view
></view
>
<view class="mb10 ml12 frequency">
<view>告警信息</view>
<view style="flex: 1">
<view v-if="item.warnCounts == 0">暂无终端告警信息</view>
<view v-else>终端告警{{ item.warnCounts }}具体如下所示:</view
><view v-for="val in item.warnDetails" class="mt15 textBox">
{{ val.warnEventTime + '发生' + val.warnEventDesc }}
</view></view
></view
>
</view>
</uni-collapse-item>
</uni-collapse> -->
<view class="event-list">
<uni-card class="event-item" :class="item.type" v-for="(item, index) in list" :key="index">
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view class="event-icon">
<!-- 动态图标根据类型切换 -->
<uni-icons
custom-prefix="iconfont"
type="icon-terminal-box-fill"
size="35"
color="#FF0000"
></uni-icons>
<view class="badge1" v-if="item.status == 0"> </view>
</view>
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.devName }}</text>
<view v-if="hasIntegrityAbnormal(item)" class="mt10">
数据完整性
<view class="data-table">
<view class="table-header">
<text>监测点名称</text>
<text>完整性</text>
</view>
<view class="event-desc">
<text>工程名称{{ item.engineeringName }}</text>
<text>项目名称{{ item.projectName }}</text>
<!-- <text>事件时间{{ item.startTime }}</text> -->
<view class="table-row"
v-for="value in item.dataDetails.integrity.monitorPoints.filter((p) => p.isAbnormal === true)">
<text>{{ value.monitorName }}</text>
<text>{{ value.value }}%</text>
</view>
</view>
</view>
<!-- 详情区域 -->
<view class="event-detail">
<uni-collapse>
<uni-collapse-item
:title="
item.interruptCounts == 0 ? '通讯正常' : `通讯中断 ${item.interruptCounts} 次`
"
>
<view
v-for="date in String(item.interruptDetails || '').split('')"
class="textBox mb10"
>{{ date }}</view
>
</uni-collapse-item>
<uni-collapse-item
:title="
item.warnCounts == 0 ? '暂无终端告警信息' : `终端告警 ${item.warnCounts} 次`
"
>
<view v-for="val in item.warnDetails" class="textBox mb10">
{{ val.warnEventTime + '发生' + val.warnEventDesc }}
</view>
</uni-collapse-item>
</uni-collapse>
<view v-if="item.warnCounts" class="mt10">
终端告警 {{ item.warnCounts }} 详情如下
<view class="textBox">
<view v-for="val in item.warnDetails" class="textBox mb5">
{{ val.warnEventTime + '发生' + val.warnEventDesc }}
</view>
</view>
</view>
</uni-card>
</view>
</view>
</uni-card>
</view>
</view>
</Cn-page>
@@ -131,6 +104,11 @@ export default {
}
},
methods: {
hasIntegrityAbnormal(item) {
const points = item?.dataDetails?.integrity?.monitorPoints
if (!Array.isArray(points) || !points.length) return false
return points.every((p) => p.isAbnormal === true)
},
init() {
queryAlarmDetail({
devList: this.detail.devIds,
@@ -149,6 +127,7 @@ export default {
</script>
<style lang="scss" scoped>
@import '../index.scss';
.detail {
padding: 20rpx 0;
@@ -156,7 +135,7 @@ export default {
padding: 20rpx;
background: #fff;
margin-bottom: 20rpx;
font-size: 26rpx;
font-size: 28rpx;
.detail-content-title {
font-size: 30rpx;
@@ -164,44 +143,102 @@ export default {
font-weight: 700;
}
}
.collapseTop {
padding: 10rpx 0;
margin-left: 15px;
.name {
font-size: 28rpx;
font-weight: 700;
color: #333333;
}
}
.frequency {
display: flex;
font-size: 26rpx;
font-size: 28rpx;
// color: #666666;
}
}
.textBox {
border-bottom: 1px solid #eee;
font-size: 26rpx;
// border-bottom: 1px solid #eee;
font-size: 28rpx;
color: #666666;
text-indent: 2em;
}
.event-list {
background: #fff;
// background: #fff;
padding-bottom: 10rpx;
.event-icon {
width: 90rpx;
height: 90rpx;
background-color: #ff000020;
// .event-icon {
// background-color: #376cf320;
// }
.zl-bgc {
background-color: #376cf320;
}
.jc-bgc {
background-color: #376cf320;
}
.zl-tag {
background-color: #007aff20;
color: #007aff;
}
.jc-tag {
background-color: #007aff20;
color: #007aff;
}
}
/deep/ .uni-collapse-item__title-box {
padding: 0 15px 0 0;
height: 56rpx;
line-height: 56rpx;
font-size: 26rpx !important;
color: #666666;
span {
font-size: 26rpx !important;
}
}
.textBox {
max-height: 120rpx;
overflow-y: auto;
}
.data-table {
margin-top: 10rpx;
background-color: #fff;
overflow: hidden;
.table-header,
.table-row {
display: flex;
justify-content: space-between;
padding: 15rpx 0rpx;
border-bottom: 1rpx solid #eee;
height: 20px;
text {
text-align: center;
font-size: 28rpx;
flex: 1;
}
}
.table-header {
padding: 0rpx;
padding-bottom: 10rpx;
}
}
</style>

View File

@@ -24,8 +24,8 @@
class="movable-view"
direction="all"
:scale="true"
:scale-min="0.5"
:scale-max="3"
:scale-min="0.2"
:scale-max="0.5"
:scale-value="scaleValue"
@touchstart="onTouchStart"
@@ -76,7 +76,7 @@ export default {
return {
imageUrl: '',
// 缩放相关 - 默认0.5
scaleValue: 0.6,
scaleValue: 0.2,
x: 0,
y: 0,
// 图片原始尺寸
@@ -92,7 +92,7 @@ export default {
windowWidth: 0,
windowHeight: 0,
// 缩放步长
zoomStep: 0.2,
zoomStep: 0.1,
// 动画控制
isTouching: false,
animationTimer: null
@@ -160,14 +160,14 @@ export default {
// 放大
zoomIn() {
// 计算新的缩放值,不超过最大值
const newScale = Math.min(this.scaleValue + this.zoomStep, 3)
const newScale = Math.min(this.scaleValue + this.zoomStep, 0.5)
this.setScaleWithAnimation(newScale)
},
// 缩小
zoomOut() {
// 计算新的缩放值,不低于最小值
const newScale = Math.max(this.scaleValue - this.zoomStep, 0.5)
const newScale = Math.max(this.scaleValue - this.zoomStep, 0.2)
this.setScaleWithAnimation(newScale)
},

View File

@@ -7,19 +7,17 @@
</view>
<view class="detail-content">
<view class="detail-content-title mb20">基础信息</view>
<view class="mb5"> 监测点名称{{ detail.lineName }}</view>
<view class="mb5"> 设备名称{{ detail.devName }} </view>
<view class="mb5"> 项目名称{{ detail.projectName }} </view>
<view class="mb5"> 工程名称{{ detail.engineeringName }} </view>
<view class="mb5"> 项目名称{{ detail.projectName }} </view>
<view class="mb5"> 设备名称{{ detail.devName }} </view>
<view class="mb5"> 监测点名称{{ detail.lineName }}</view>
<view class="mb5" style="display: flex">
越限详情
<view style="flex: 1">{{ detail.overLimitDesc }}</view></view
>
<view style="flex: 1" class="details">{{ detail.overLimitDesc }}</view>
</view>
</view>
<view class="detail-content">
<view class="detail-content-title mb20"
>指标越限详情<text class="prompt">仅显示较为严重的10次</text></view
>
<view class="detail-content-title mb20">指标越限详情<text class="prompt">仅显示最严重的10组数据</text></view>
<uni-collapse accordion v-model="collapseValue">
<uni-collapse-item :title="item.targetName" v-for="item in list">
@@ -35,7 +33,7 @@
</view>
<view class="table-row" v-for="value in item.harmDetailList">
<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.dataB }}</text>
<text v-if="!value.hasT">{{ value.dataC }}</text>
@@ -97,7 +95,7 @@ export default {
padding: 20rpx;
background: #fff;
margin-bottom: 20rpx;
font-size: 26rpx;
font-size: 28rpx;
.detail-content-title {
font-size: 30rpx;
@@ -105,6 +103,7 @@ export default {
font-weight: 700;
}
}
.limit {
display: flex;
align-items: center;
@@ -112,42 +111,60 @@ export default {
width: 450rpx;
margin-left: auto;
}
.prompt {
font-size: 24rpx;
color: #111;
font-weight: 500;
}
}
.data-table {
margin-top: 20rpx;
background-color: #fff;
overflow: hidden;
color: #666;
.table-header,
.table-row {
display: flex;
justify-content: space-between;
padding: 20rpx 0rpx;
padding: 15rpx 0rpx;
height: 20px;
border-bottom: 1rpx solid #eee;
text {
flex: 1;
width: 100rpx;
text-align: center;
font-size: 26rpx;
font-size: 28rpx;
// color: #333;
&:first-child {
// text-align: left;
flex: 1.2;
&:nth-child(1) {
flex: 1;
}
&:nth-child(2) {
flex: 1;
}
}
}
.table-header {
padding: 0rpx;
padding-bottom: 10rpx;
}
}
/deep/ .uni-collapse-item__title-text {
font-weight: 700;
span {
font-size: 28rpx;
}
}
.details {
max-height: 70px;
overflow-y: auto;
}
</style>

View File

@@ -1,98 +1,138 @@
<template>
<Cn-page :loading="loading">
<view class="detail" slot="body">
<view class="detail-content" style="font-size: 32rpx">
<!-- <view class="detail-content-title mb20">发生时间</view> -->
<view>{{ detail.startTime }}</view>
</view>
<view class="detail-content">
<view class="detail-content-title mb20">基础信息</view>
<view class="mb5"> 设备名称{{ detail.equipmentName }}</view>
<view class="mb5"> 项目名称{{ detail.projectName }} </view>
<view class="mb5"> 工程名称{{ detail.engineeringName }} </view>
<view class="mb5"> 暂态类型{{ detail.showName }}</view>
<view class="mb5"> 持续时间{{ detail.evtParamTm }}</view>
<view class="mb5"> 幅值{{ detail.evtParamVVaDepth }}</view>
<view class="mb5"> 相别{{ detail.evtParamPhase }}</view>
<!-- <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 class="detail-content">
<view class="detail-content-title mb20">瞬时波形图</view>
<image
style="width: 100%"
:src="detail.instantPics"
mode="widthFix"
v-if="detail.instantPics"
@click="previewImage(detail.instantPics)"
/>
<text v-else>暂无</text>
</view>
<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>
</view>
</Cn-page>
</template>
<script>
import { updateStatus } from '@/common/api/message'
export default {
data() {
return {
loading: true,
detail: {},
}
},
onLoad(options) {
// console.log(options.detail)
this.detail = JSON.parse(decodeURIComponent(options.detail).replace(/百分比/g, '%'))
this.detail.rmsPics && (this.detail.rmsPics = this.$config.static + this.detail.rmsPics)
this.detail.instantPics && (this.detail.instantPics = this.$config.static + this.detail.instantPics)
this.loading = false
if (this.detail.status != 1) {
updateStatus({
eventIds: [this.detail.id],
})
}
},
methods: {
previewImage(url) {
// uni.previewImage({
// urls: [url],
// })
uni.navigateTo({
url: `/pages/message1/comp/preview?url=${encodeURIComponent(url)}`,
})
},
},
}
</script>
<style lang="scss">
.detail {
padding: 20rpx 0;
.detail-content {
padding: 20rpx;
background: #fff;
margin-bottom: 20rpx;
font-size: 26rpx;
.detail-content-title {
font-size: 30rpx;
color: #111;
font-weight: 700;
}
}
}
</style>
<template>
<Cn-page :loading="loading">
<view class="detail" slot="body">
<view class="detail-content" style="font-size: 32rpx">
<view>{{ detail.startTime }}</view>
</view>
<view class="detail-content">
<view class="detail-content-title mb20">基础信息</view>
<view class="mb5"> 工程名称{{ detail.engineeringName }} </view>
<view class="mb5"> 项目名称{{ detail.projectName }} </view>
<view class="mb5"> 设备名称{{ detail.equipmentName }}</view>
<view class="mb5"> 监测点名称{{ detail.lineName }}</view>
<view class="mb5"> 暂态类型{{ detail.showName }}</view>
<view class="mb5" v-if="detail.evtParamTm"> 持续时间{{ detail.evtParamTm }}s</view>
<view class="mb5" v-if="detail.evtParamVVaDepth"> 幅值{{ detail.evtParamVVaDepth }}%</view>
<view class="mb5" v-if="detail.evtParamPhase"> 相别{{ detail.evtParamPhase }}</view>
</view>
<view class="detail-tabs">
<uni-segmented-control :current="detailTab" active-color="#376cf3" :values="['波形图', 'ITIC', 'F47']"
@clickItem="onDetailTabChange" />
</view>
<view v-if="detailTab == 0">
<view class="detail-content">
<view class="detail-content-title mb20">瞬时波形图</view>
<image style="width: 100%" :src="detail.instantPics" mode="widthFix" v-if="detail.instantPics"
@click="previewImage(detail.instantPics)" />
<text v-else>暂无</text>
</view>
<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>
</view>
<view v-if="detailTab == 1" class="chart-wrapper">
<ITIC :store="eventStore" style="height: calc(100vh - 360px);" />
</view>
<view v-if="detailTab == 2" class="chart-wrapper">
<F47 :store="eventStore" style="height: calc(100vh - 360px);" />
</view>
</view>
</Cn-page>
</template>
<script>
import { updateStatus } from '@/common/api/message'
import ITIC from './ITIC.vue'
import F47 from './F47.vue'
export default {
components: { ITIC, F47 },
data() {
return {
loading: true,
detail: {},
detailTab: 0,
}
},
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) {
this.detail = JSON.parse(decodeURIComponent(options.detail).replace(/百分比/g, '%'))
this.detail.rmsPics && (this.detail.rmsPics = this.$config.static + this.detail.rmsPics)
this.detail.instantPics && (this.detail.instantPics = this.$config.static + this.detail.instantPics)
this.loading = false
if (this.detail.status != 1) {
updateStatus({
eventIds: [this.detail.id],
})
}
},
methods: {
onDetailTabChange(e) {
this.detailTab = e.currentIndex
},
previewImage(url) {
uni.navigateTo({
url: `/pages/message1/comp/preview?url=${encodeURIComponent(url)}`,
})
},
},
}
</script>
<style lang="scss">
.detail {
padding: 20rpx 0;
.detail-content {
padding: 20rpx;
background: #fff;
margin-bottom: 20rpx;
font-size: 28rpx;
.detail-content-title {
font-size: 30rpx;
color: #111;
font-weight: 700;
}
}
.detail-tabs {
padding: 0 20rpx;
margin-bottom: 20rpx;
}
.chart-container {
min-height: 600rpx;
}
.chart-wrapper {
background: #fff;
margin-bottom: 20rpx;
padding: 20rpx;
}
}
.segmented-control {
flex: 1;
margin-right: 24rpx;
height: 60rpx;
}
</style>

View File

@@ -18,7 +18,7 @@
.box:first-child {
flex: 1.7;
}
.boxClick {
.boxClick1 {
background-color: $uni-theme-color;
color: #ffffff;
}
@@ -58,8 +58,8 @@
/* 图标区域(按类型区分背景色) */
.event-icon {
position: relative;
width: 120rpx;
height: 120rpx;
width: 110rpx;
height: 110rpx;
border-radius: 12rpx;
display: flex;
justify-content: center;
@@ -109,7 +109,7 @@
flex-wrap: wrap; /* 适配小屏,防止文字溢出 */
}
.event-id {
font-size: 28rpx;
font-size: 30rpx;
font-weight: 700;
color: #333333;
margin-right: 16rpx;
@@ -120,7 +120,8 @@
padding: 0rpx 10rpx;
border-radius: 8rpx;
color: #ffffff;
height: 38rpx;
height: 34rpx;
line-height: 38rpx;
}
.sag-tag {
background-color: #2563eb20;
@@ -149,7 +150,7 @@
gap: 8rpx;
}
.event-desc text {
font-size: 26rpx;
font-size: 28rpx;
color: #666666;
line-height: 1.2;
}
@@ -171,7 +172,7 @@
/* 详情文本 */
.event-detail {
font-size: 26rpx;
font-size: 28rpx;
color: #666666;
line-height: 1.5;
padding-top: 10rpx;

View File

@@ -3,37 +3,31 @@
<!-- 运行事件 -->
<!-- 卡片 -->
<scroll-view
scroll-y="true"
@refresherrefresh="refresherrefresh"
:refresher-triggered="triggered"
refresher-enabled="true"
class="event-list"
:style="{ height: 'calc(100vh - ' + (navHeight + 10) + 'px)', overflow: 'auto' }"
>
<scroll-view scroll-y="true" @refresherrefresh="refresherrefresh" @scrolltolower="scrolltolower"
:refresher-triggered="triggered" refresher-enabled="true" class="event-list"
:style="{ height: 'calc(100vh - ' + (navHeight + 10) + 'px)', overflow: 'auto' }">
<!-- 循环渲染事件项 -->
<uni-card
class="event-item"
:class="item.type"
v-for="(item, index) in store.data"
:key="index"
@click="jump(item)"
>
<uni-card class="event-item " :class="item.type" v-for="(item, index) in store.data" :key="index"
@click="jump(item)">
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view class="event-icon">
<view class="event-icon" :class="item.devType == 'Direct_Connected_Device' ? 'zl-bgc' : 'jc-bgc'">
<!-- 动态图标根据类型切换 -->
<uni-icons custom-prefix="iconfont" type="icon-shebei" size="35" color="#10B981"></uni-icons>
<!-- <uni-icons custom-prefix="iconfont" type="icon-shebei3" size="35" color="#376cf3"></uni-icons> -->
<Cn-icon-transient :name="item.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备'" />
<view class="badge1" v-if="item.status == 0"> </view>
</view>
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.equipmentName }}</text>
<text class="event-tag"
:class="item.devType == 'Direct_Connected_Device' ? 'zl-tag' : 'jc-tag'">{{ item.devType
== 'Direct_Connected_Device' ? '治理设备' : '监测设备' }}</text>
</view>
<view class="event-desc">
<text>工程名称{{ item.engineeringName }}</text>
<text>项目名称{{ item.projectName }}</text>
<text>事件时间{{ item.startTime }}</text>
<text>事件时间{{ item.startTime2 }}</text>
</view>
</view>
</view>
@@ -42,10 +36,8 @@
<text> {{ item.showName }} </text>
</view>
</uni-card>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
></uni-load-more>
<uni-load-more v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty>
</scroll-view>
</view>
@@ -68,17 +60,17 @@ export default {
mixins: [list],
data() {
return {
triggered: true,
triggered: true,
}
},
mounted() {},
mounted() { },
methods: {
// 查詢
init() {
this.store = this.DataSource('/cs-harmonic-boot/eventUser/queryEventpage')
this.store.params.type = 2
this.store.params.pageSize = 10000
// this.store.params.pageSize = 10000
this.store.params.sortField = this.sort
this.store.params.engineeringid = this.selectValue.engineeringId
this.store.params.projectId = this.selectValue.projectId
@@ -108,6 +100,12 @@ export default {
this.triggered = false
}, 500)
},
// 上拉
scrolltolower() {
if (this.store.status != 'noMore') {
this.store.next && this.store.next()
}
},
},
computed: {},
@@ -127,6 +125,7 @@ export default {
<style lang="scss" scoped>
@import './index.scss';
/* 列表容器 */
.event-list {
margin-top: 20rpx;
@@ -134,13 +133,25 @@ export default {
/* 头部:图标 + 信息 + 操作 */
/* 图标区域(按类型区分背景色) */
.event-icon {
// width: 90rpx;
// height: 90rpx;
.zl-bgc {
background-color: #376cf320;
}
background-color: #10b98120;
.jc-bgc {
background-color: #376cf320;
}
.zl-tag {
background-color: #007aff20;
color: #007aff;
}
.jc-tag {
background-color: #007aff20;
color: #007aff;
}
}
/deep/ .uni-scroll-view-refresher {
display: none;
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,38 +1,16 @@
<template>
<view :loading="loading">
<!-- <uni-nav-bar left-icon="left" right-icon="cart" title="标题" /> -->
<uni-nav-bar
dark
:fixed="true"
status-bar
left-icon="left"
:rightIcon="
userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'
? 'plusempty'
: ''
"
background-color="#fff"
color="#111"
title="项目管理"
@clickLeft="back"
@clickRight="add"
/>
<uni-search-bar
v-model="store.params.searchValue"
clearButton="none"
bgColor="#fff"
placeholder="请输入关键词"
@input="store.search()"
></uni-search-bar>
<uni-nav-bar dark :fixed="true" status-bar left-icon="left" :rightIcon="userInfo.authorities === 'app_vip_user' || userInfo.authorities === 'engineering_user'
? 'plusempty'
: ''
" background-color="#fff" color="#111" title="项目管理" @clickLeft="back" @clickRight="add" />
<uni-search-bar v-model="store.params.searchValue" clearButton="none" bgColor="#fff" placeholder="请输入关键词"
@input="store.search()"></uni-search-bar>
<view class="message">
<uni-card
:title="item.name"
@click="jump(item)"
extra="🔍"
v-for="(item, index) in store.data"
:key="index"
:style="{ marginTop: index === 0 ? '0' : '' }"
>
<!-- 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' : '' }">
<view class="term-list-bottom">
<view class="term-list-bottom-item">
<view>设备个数</view>
@@ -45,10 +23,8 @@
</view>
</uni-card>
<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)"
:status="store.status"
></uni-load-more>
<uni-load-more v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"></uni-load-more>
</view>
</view>
</template>
@@ -168,7 +144,7 @@ export default {
.term-list-bottom {
.term-list-bottom-item {
font-size: 28rpx;
margin-bottom: 20rpx;
// margin-bottom: 20rpx;
display: flex;
justify-content: space-between;
// view:first-of-type{
@@ -180,4 +156,12 @@ export default {
margin-bottom: 0;
}
}
/deep/ .uni-card__content {
padding: 5px 10px 10px !important;
}
/deep/ .uni-card__header-content-title {
font-weight: 700;
}
</style>

View File

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

View File

@@ -93,7 +93,7 @@ import { sm3Digest } from '@/common/js/sm3.js'
export default {
data() {
return {
checkbox: false,
checkbox: true,
loading: false,
loginType: 'pwd',
phone: '',

View File

@@ -77,7 +77,7 @@ export default {
name: 'jiaban',
data() {
return {
checkbox: false,
checkbox: true,
step: 1,
loading: false,
waitTime: 0,

826
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

111
readme.md Normal file
View File

@@ -0,0 +1,111 @@
# 字母索引列表组件 (yxt-letterIndex)
用于uni-app项目的字母索引列表组件支持按拼音首字母分组展示数据右侧字母快速导航适用于通讯录、学员列表等场景。
## 功能特点
- 支持按拼音首字母自动分组展示数据
- 右侧快速字母导航,点击可快速滚动到对应区域
- 滚动时自动高亮当前字母位置
- 支持签到状态显示和补签操作
- 空数据状态优化展示
- 适配小程序环境
## 安装方式
在uni-app项目中通过uni_modules直接导入使用。
## 使用示例
```vue
<template>
<view class="container">
<yxt-letterIndex
:items="studentList"
name-key="name"
:show-letter-title="true"
current-status="pending"
@help-sign="handleHelpSign"
@letter-click="handleLetterClick"
@scroll-position-change="handleScrollPositionChange"
/>
</view>
</template>
<script>
export default {
data() {
return {
studentList: [
{ name: '张三', id: '1' },
{ name: '李四', id: '2' },
{ name: '王五', id: '3' },
{ name: '赵六', id: '4' },
// 更多数据...
]
};
},
methods: {
// 处理帮TA补签事件
handleHelpSign(item) {
console.log('帮TA补签:', item);
// 执行补签操作
},
// 处理字母点击事件
handleLetterClick(letter) {
console.log('点击字母:', letter);
},
// 处理滚动位置变化事件
handleScrollPositionChange(letter) {
console.log('当前滚动到字母:', letter);
}
}
};
</script>
<style scoped>
.container {
height: 100vh; /* 确保组件有足够的高度显示 */
}
</style>
```
## 属性说明
| 属性名 | 类型 | 默认值 | 必填 | 说明 |
| --- | --- | --- | --- | --- |
| items | Array | [] | 是 | 要展示的数据列表 |
| name-key | String | "name" | 否 | 用于获取姓名的字段名 |
| show-letter-title | Boolean | true | 否 | 是否显示字母标题 |
| current-status | String | "pending" | 否 | 当前状态pending表示未签到signed表示已签到 |
## 事件说明
| 事件名 | 说明 | 回调参数 |
| --- | --- | --- |
| help-sign | 点击帮TA补签按钮时触发 | item: 当前点击的项目对象 |
| letter-click | 点击右侧字母导航时触发 | letter: 点击的字母 |
| scroll-position-change | 滚动位置发生变化时触发 | letter: 当前滚动到的字母 |
## 依赖说明
- 需要引入拼音工具 `pinyinUtil.js` 用于获取汉字的拼音首字母
- 默认使用 `/static/icon-success.png``/static/img_no_content.png` 作为图标资源
## 注意事项
1. 组件需要一个固定高度的容器,建议设置为全屏或适当高度
2. 确保数据格式正确,包含姓名字段
3. 如需要自定义样式可通过覆盖CSS变量或使用深度选择器修改
4. 在小程序环境中使用时,请确保已配置相关的静态资源路径
## 兼容性
- 支持uni-app项目的Vue 2版本
- 支持微信小程序环境
## 更新日志
详情请查看 [changelog.md](./changelog.md)

BIN
static/tongji.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -136,7 +136,7 @@
.uni-card {
margin: $uni-card-spacing;
padding: 0 $uni-spacing-sm;
border-radius: 4px;
border-radius: 20rpx;
overflow: hidden;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif;
background-color: #fff;

503
yarn.lock
View File

@@ -2,64 +2,29 @@
# yarn lockfile v1
"@babel/parser@^7.23.5":
version "7.24.0"
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.24.0.tgz#26a3d1ff49031c53a97d03b604375f028746a9ac"
integrity sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==
"@babel/runtime@^7.17.2":
version "7.24.0"
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz#584c450063ffda59697021430cb47101b085951e"
integrity sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==
dependencies:
regenerator-runtime "^0.14.0"
"@types/html5plus@^1.0.2":
version "1.0.5"
resolved "https://registry.npmjs.org/@types/html5plus/-/html5plus-1.0.5.tgz#aa6fdd5adaabf0ec9227de451e1e9c0838950319"
integrity sha512-qt5z+3WYkARL/rWnJRcB2fCDOZLKa/hEOkse9sjA6FFkXZtKb+OPxKqo8bDgix4+ufahOff0adarVfaUaK1mfw==
"@types/uni-app@^1.4.4":
version "1.4.8"
resolved "https://registry.npmjs.org/@types/uni-app/-/uni-app-1.4.8.tgz#9d34931c2841863b1b42af3964a0f910342ce9f8"
integrity sha512-plxwi9MvGDrekCsDKuNlCN3ZXIv9zkqHsKZJOsc8FQqLSHveDBOm11qOaswe4QyNWVHpvwZMViii/Ni1/d40LA==
dependencies:
vue "^2.6.8"
"@vue/compiler-sfc@2.7.16":
version "2.7.16"
resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz#ff81711a0fac9c68683d8bb00b63f857de77dc83"
integrity sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==
dependencies:
"@babel/parser" "^7.23.5"
postcss "^8.4.14"
source-map "^0.6.1"
optionalDependencies:
prettier "^1.18.2 || ^2.0.0"
async-limiter@~1.0.0:
version "1.0.1"
resolved "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
resolved "https://registry.npmmirror.com/async-limiter/-/async-limiter-1.0.1.tgz"
integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
base64-arraybuffer@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc"
resolved "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz"
integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==
base64-js@^1.3.0, base64-js@^1.3.1:
version "1.5.1"
resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
resolved "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
bl@^4.0.2:
version "4.1.0"
resolved "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
resolved "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz"
integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
dependencies:
buffer "^5.5.0"
@@ -67,40 +32,29 @@ bl@^4.0.2:
readable-stream "^3.4.0"
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
version "1.1.12"
resolved "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.12.tgz"
integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
buffer-from@^1.0.0:
version "1.1.2"
resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
resolved "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz"
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
buffer@^5.5.0:
version "5.7.1"
resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
resolved "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz"
integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
dependencies:
base64-js "^1.3.1"
ieee754 "^1.1.13"
call-bind@^1.0.7:
version "1.0.7"
resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
dependencies:
es-define-property "^1.0.0"
es-errors "^1.3.0"
function-bind "^1.1.2"
get-intrinsic "^1.2.4"
set-function-length "^1.2.1"
callback-stream@^1.0.2:
version "1.1.0"
resolved "https://registry.npmjs.org/callback-stream/-/callback-stream-1.1.0.tgz#4701a51266f06e06eaa71fc17233822d875f4908"
resolved "https://registry.npmmirror.com/callback-stream/-/callback-stream-1.1.0.tgz"
integrity sha512-sAZ9kODla+mGACBZ1IpTCAisKoGnv6PykW7fPk1LrM+mMepE18Yz0515yoVcrZy7dQsTUp3uZLQ/9Sx1RnLoHw==
dependencies:
inherits "^2.0.1"
@@ -108,7 +62,7 @@ callback-stream@^1.0.2:
commist@^1.0.0:
version "1.1.0"
resolved "https://registry.npmjs.org/commist/-/commist-1.1.0.tgz#17811ec6978f6c15ee4de80c45c9beb77cee35d5"
resolved "https://registry.npmmirror.com/commist/-/commist-1.1.0.tgz"
integrity sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==
dependencies:
leven "^2.1.0"
@@ -116,12 +70,12 @@ commist@^1.0.0:
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
resolved "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
concat-stream@^1.6.2:
version "1.6.2"
resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
resolved "https://registry.npmmirror.com/concat-stream/-/concat-stream-1.6.2.tgz"
integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
dependencies:
buffer-from "^1.0.0"
@@ -129,65 +83,39 @@ concat-stream@^1.6.2:
readable-stream "^2.2.2"
typedarray "^0.0.6"
copy-text-to-clipboard@^3.0.1:
version "3.2.0"
resolved "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz#0202b2d9bdae30a49a53f898626dcc3b49ad960b"
integrity sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==
core-js@^3.11.0:
version "3.36.0"
resolved "https://registry.npmjs.org/core-js/-/core-js-3.36.0.tgz#e752fa0b0b462a0787d56e9d73f80b0f7c0dde68"
integrity sha512-mt7+TUBbTFg5+GngsAxeKBTl5/VS0guFeJacYge9OmHb+m058UwwIm41SE9T4Den7ClatV57B6TYTuJ0CX1MAw==
core-util-is@~1.0.0:
version "1.0.3"
resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
resolved "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz"
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
crypto-js@^4.1.1:
crypto-js@^4.2.0:
version "4.2.0"
resolved "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==
css-line-break@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz#bfef660dfa6f5397ea54116bb3cb4873edbc4fa0"
resolved "https://registry.npmmirror.com/css-line-break/-/css-line-break-2.1.0.tgz"
integrity sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==
dependencies:
utrie "^1.0.2"
csstype@^3.1.0:
version "3.1.3"
resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
d@1, d@^1.0.1, d@^1.0.2:
d@^1.0.1, d@^1.0.2, d@1:
version "1.0.2"
resolved "https://registry.npmjs.org/d/-/d-1.0.2.tgz#2aefd554b81981e7dccf72d6842ae725cb17e5de"
resolved "https://registry.npmmirror.com/d/-/d-1.0.2.tgz"
integrity sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==
dependencies:
es5-ext "^0.10.64"
type "^2.7.2"
debug@^4.1.1:
version "4.3.4"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
version "4.4.1"
resolved "https://registry.npmmirror.com/debug/-/debug-4.4.1.tgz"
integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==
dependencies:
ms "2.1.2"
define-data-property@^1.1.2:
version "1.1.4"
resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
dependencies:
es-define-property "^1.0.0"
es-errors "^1.3.0"
gopd "^1.0.1"
ms "^2.1.3"
duplexify@^3.5.1, duplexify@^3.6.0:
version "3.7.1"
resolved "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
resolved "https://registry.npmmirror.com/duplexify/-/duplexify-3.7.1.tgz"
integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==
dependencies:
end-of-stream "^1.0.0"
@@ -195,28 +123,22 @@ duplexify@^3.5.1, duplexify@^3.6.0:
readable-stream "^2.0.0"
stream-shift "^1.0.0"
echarts@^5.6.0:
version "5.6.0"
dependencies:
tslib "2.3.0"
zrender "5.6.1"
end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1:
version "1.4.4"
resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
version "1.4.5"
resolved "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.5.tgz"
integrity sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==
dependencies:
once "^1.4.0"
es-define-property@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
dependencies:
get-intrinsic "^1.2.4"
es-errors@^1.3.0:
version "1.3.0"
resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
es5-ext@^0.10.35, es5-ext@^0.10.62, es5-ext@^0.10.64, es5-ext@~0.10.14:
version "0.10.64"
resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz#12e4ffb48f1ba2ea777f1fcdd1918ef73ea21714"
resolved "https://registry.npmmirror.com/es5-ext/-/es5-ext-0.10.64.tgz"
integrity sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==
dependencies:
es6-iterator "^2.0.3"
@@ -226,7 +148,7 @@ es5-ext@^0.10.35, es5-ext@^0.10.62, es5-ext@^0.10.64, es5-ext@~0.10.14:
es6-iterator@^2.0.3, es6-iterator@~2.0.1, es6-iterator@~2.0.3:
version "2.0.3"
resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
resolved "https://registry.npmmirror.com/es6-iterator/-/es6-iterator-2.0.3.tgz"
integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==
dependencies:
d "1"
@@ -235,7 +157,7 @@ es6-iterator@^2.0.3, es6-iterator@~2.0.1, es6-iterator@~2.0.3:
es6-map@^0.1.5:
version "0.1.5"
resolved "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0"
resolved "https://registry.npmmirror.com/es6-map/-/es6-map-0.1.5.tgz"
integrity sha512-mz3UqCh0uPCIqsw1SSAkB/p0rOzF/M0V++vyN7JqlPtSW/VsYgQBvVvqMLmfBuyMzTpLnNqi6JmcSizs4jy19A==
dependencies:
d "1"
@@ -247,7 +169,7 @@ es6-map@^0.1.5:
es6-set@~0.1.5:
version "0.1.6"
resolved "https://registry.npmjs.org/es6-set/-/es6-set-0.1.6.tgz#5669e3b2aa01d61a50ba79964f733673574983b8"
resolved "https://registry.npmmirror.com/es6-set/-/es6-set-0.1.6.tgz"
integrity sha512-TE3LgGLDIBX332jq3ypv6bcOpkLO0AslAQo7p2VqX/1N46YNsvIWgvjojjSEnWEGWMhr1qUbYeTSir5J6mFHOw==
dependencies:
d "^1.0.1"
@@ -259,7 +181,7 @@ es6-set@~0.1.5:
es6-symbol@^3.1.1, es6-symbol@^3.1.3, es6-symbol@~3.1.1:
version "3.1.4"
resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz#f4e7d28013770b4208ecbf3e0bf14d3bcb557b8c"
resolved "https://registry.npmmirror.com/es6-symbol/-/es6-symbol-3.1.4.tgz"
integrity sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==
dependencies:
d "^1.0.2"
@@ -267,7 +189,7 @@ es6-symbol@^3.1.1, es6-symbol@^3.1.3, es6-symbol@~3.1.1:
esniff@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308"
resolved "https://registry.npmmirror.com/esniff/-/esniff-2.0.1.tgz"
integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==
dependencies:
d "^1.0.1"
@@ -277,48 +199,37 @@ esniff@^2.0.1:
event-emitter@^0.3.5, event-emitter@~0.3.5:
version "0.3.5"
resolved "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
resolved "https://registry.npmmirror.com/event-emitter/-/event-emitter-0.3.5.tgz"
integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==
dependencies:
d "1"
es5-ext "~0.10.14"
exif-js@^2.3.0:
version "2.3.0"
resolved "https://registry.npmmirror.com/exif-js/-/exif-js-2.3.0.tgz"
integrity sha512-1Og9pAzG2FZRVlaavH8bB8BTeHcjMdJhKmeQITkX+uLRCD0xPtKAdZ2clZmQdJ56p9adXtJ8+jwrGp/4505lYg==
ext@^1.7.0:
version "1.7.0"
resolved "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f"
resolved "https://registry.npmmirror.com/ext/-/ext-1.7.0.tgz"
integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==
dependencies:
type "^2.7.2"
extend@^3.0.0:
version "3.0.2"
resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
resolved "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
resolved "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz"
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
function-bind@^1.1.2:
version "1.1.2"
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
get-intrinsic@^1.1.3, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4:
version "1.2.4"
resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
dependencies:
es-errors "^1.3.0"
function-bind "^1.1.2"
has-proto "^1.0.1"
has-symbols "^1.0.3"
hasown "^2.0.0"
glob-parent@^3.1.0:
version "3.1.0"
resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
resolved "https://registry.npmmirror.com/glob-parent/-/glob-parent-3.1.0.tgz"
integrity sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==
dependencies:
is-glob "^3.1.0"
@@ -326,7 +237,7 @@ glob-parent@^3.1.0:
glob-stream@^6.1.0:
version "6.1.0"
resolved "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz#7045c99413b3eb94888d83ab46d0b404cc7bdde4"
resolved "https://registry.npmmirror.com/glob-stream/-/glob-stream-6.1.0.tgz"
integrity sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==
dependencies:
extend "^3.0.0"
@@ -342,7 +253,7 @@ glob-stream@^6.1.0:
glob@^7.1.1:
version "7.2.3"
resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
resolved "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz"
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
dependencies:
fs.realpath "^1.0.0"
@@ -352,40 +263,9 @@ glob@^7.1.1:
once "^1.3.0"
path-is-absolute "^1.0.0"
gopd@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
dependencies:
get-intrinsic "^1.1.3"
has-property-descriptors@^1.0.1:
version "1.0.2"
resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
dependencies:
es-define-property "^1.0.0"
has-proto@^1.0.1:
version "1.0.3"
resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd"
integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==
has-symbols@^1.0.3:
version "1.0.3"
resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
hasown@^2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz#26f48f039de2c0f8d3356c223fb8d50253519faa"
integrity sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==
dependencies:
function-bind "^1.1.2"
help-me@^1.0.1:
version "1.1.0"
resolved "https://registry.npmjs.org/help-me/-/help-me-1.1.0.tgz#8f2d508d0600b4a456da2f086556e7e5c056a3c6"
resolved "https://registry.npmmirror.com/help-me/-/help-me-1.1.0.tgz"
integrity sha512-P/IZ8yOMne3SCTHbVY429NZ67B/2bVQlcYGZh2iPPbdLrEQ/qY5aGChn0YTDmt7Sb4IKRI51fypItav+lNl76w==
dependencies:
callback-stream "^1.0.2"
@@ -395,7 +275,7 @@ help-me@^1.0.1:
html2canvas@^1.4.1:
version "1.4.1"
resolved "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz#7cef1888311b5011d507794a066041b14669a543"
resolved "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz"
integrity sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==
dependencies:
css-line-break "^2.1.0"
@@ -403,30 +283,35 @@ html2canvas@^1.4.1:
ieee754@^1.1.13:
version "1.2.1"
resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
resolved "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
image-tool@^1.0.2:
version "1.0.2"
dependencies:
exif-js "^2.3.0"
image-tools@^1.4.0:
version "1.4.0"
resolved "https://registry.npmjs.org/image-tools/-/image-tools-1.4.0.tgz#66aacbafad677af7f3fd7f32f8fa1e0881b83783"
resolved "https://registry.npmjs.org/image-tools/-/image-tools-1.4.0.tgz"
integrity sha512-TKtvJ6iUwM0mfaD4keMnk1ENHFC470QEjBfA3IlvKdEOufzvWbjbaoNcoyYq6HlViF8+d5tOS1ooE6j7CHf1lQ==
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
resolved "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz"
integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
dependencies:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@2:
version "2.0.4"
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
resolved "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
is-absolute@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576"
resolved "https://registry.npmmirror.com/is-absolute/-/is-absolute-1.0.0.tgz"
integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==
dependencies:
is-relative "^1.0.0"
@@ -434,85 +319,81 @@ is-absolute@^1.0.0:
is-extglob@^2.1.0:
version "2.1.1"
resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
resolved "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz"
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
is-glob@^3.1.0:
version "3.1.0"
resolved "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
resolved "https://registry.npmmirror.com/is-glob/-/is-glob-3.1.0.tgz"
integrity sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==
dependencies:
is-extglob "^2.1.0"
is-negated-glob@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2"
resolved "https://registry.npmmirror.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz"
integrity sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==
is-relative@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d"
resolved "https://registry.npmmirror.com/is-relative/-/is-relative-1.0.0.tgz"
integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==
dependencies:
is-unc-path "^1.0.0"
is-unc-path@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d"
resolved "https://registry.npmmirror.com/is-unc-path/-/is-unc-path-1.0.0.tgz"
integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==
dependencies:
unc-path-regex "^0.1.2"
is-windows@^1.0.1:
version "1.0.2"
resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
resolved "https://registry.npmmirror.com/is-windows/-/is-windows-1.0.2.tgz"
integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
resolved "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz"
integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==
json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
resolved "https://registry.npmmirror.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz"
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
jsrsasign@^10.8.6:
version "10.9.0"
resolved "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.9.0.tgz#cc3f316e7e4c112a976193f9d2c93deb5a0745ee"
integrity sha512-QWLUikj1SBJGuyGK8tjKSx3K7Y69KYJnrs/pQ1KZ6wvZIkHkWjZ1PJDpuvc1/28c1uP0KW9qn1eI1LzHQqDOwQ==
jsrsasign@^11.1.0:
version "11.1.0"
leven@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580"
resolved "https://registry.npmmirror.com/leven/-/leven-2.1.0.tgz"
integrity sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA==
minimatch@^3.1.1:
version "3.1.2"
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
resolved "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
minimist@^1.1.0, minimist@^1.2.0:
version "1.2.8"
resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
resolved "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
mqtt-packet@^6.0.0:
version "6.10.0"
resolved "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-6.10.0.tgz#c8b507832c4152e3e511c0efa104ae4a64cd418f"
resolved "https://registry.npmmirror.com/mqtt-packet/-/mqtt-packet-6.10.0.tgz"
integrity sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA==
dependencies:
bl "^4.0.2"
debug "^4.1.1"
process-nextick-args "^2.0.1"
mqtt@3.0.0:
mqtt@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/mqtt/-/mqtt-3.0.0.tgz#7961e5f61efba3eec37d5aa9c4cbcdeb6f841380"
integrity sha512-0nKV6MAc1ibKZwaZQUTb3iIdT4NVpj541BsYrqrGBcQdQ7Jd0MnZD1/6/nj1UFdGTboK9ZEUXvkCu2nPCugHFA==
dependencies:
base64-js "^1.3.0"
commist "^1.0.0"
@@ -530,119 +411,78 @@ mqtt@3.0.0:
websocket-stream "^5.1.2"
xtend "^4.0.1"
ms@2.1.2:
version "2.1.2"
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
mutation-observer@^1.0.3:
version "1.0.3"
resolved "https://registry.npmjs.org/mutation-observer/-/mutation-observer-1.0.3.tgz#42e9222b101bca82e5ba9d5a7acf4a14c0f263d0"
integrity sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA==
nanoid@^3.3.7:
version "3.3.7"
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
ms@^2.1.3:
version "2.1.3"
resolved "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
next-tick@^1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb"
resolved "https://registry.npmmirror.com/next-tick/-/next-tick-1.1.0.tgz"
integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==
object-inspect@^1.13.1:
version "1.13.1"
resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"
integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==
once@^1.3.0, once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
resolved "https://registry.npmmirror.com/once/-/once-1.4.0.tgz"
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
dependencies:
wrappy "1"
ordered-read-streams@^1.0.0:
version "1.0.1"
resolved "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz#77c0cb37c41525d64166d990ffad7ec6a0e1363e"
resolved "https://registry.npmmirror.com/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz"
integrity sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==
dependencies:
readable-stream "^2.0.1"
path-dirname@^1.0.0:
version "1.0.2"
resolved "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
resolved "https://registry.npmmirror.com/path-dirname/-/path-dirname-1.0.2.tgz"
integrity sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
resolved "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
pinyin-pro@^3.13.2:
version "3.19.6"
resolved "https://registry.npmjs.org/pinyin-pro/-/pinyin-pro-3.19.6.tgz#ed5eebcd43d84f8eaa32d40452b2cca55760e58c"
integrity sha512-oWb34orr12+DjXf6gtGMB+gIpjRi7DZzyJE66ultbmNzVhpimM/utGtMI8GcbOy/lb26Ph/nogwNYriRPu+SGQ==
postcss@^8.4.14:
version "8.4.35"
resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz#60997775689ce09011edf083a549cea44aabe2f7"
integrity sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==
dependencies:
nanoid "^3.3.7"
picocolors "^1.0.0"
source-map-js "^1.0.2"
"prettier@^1.18.2 || ^2.0.0":
version "2.8.8"
resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
pinyin-pro@^3.28.1:
version "3.28.1"
resolved "https://registry.npmmirror.com/pinyin-pro/-/pinyin-pro-3.28.1.tgz"
integrity sha512-oqz8ulwRgtUXRi0vbqEfGNly19zpyCxYrjhkk5TibGcgSW6eNwS5woajCXRwqURi8Ehc2yOFTiB4uNoZ+NJOnA==
process-nextick-args@^2.0.1, process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
resolved "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
pump@^2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
resolved "https://registry.npmmirror.com/pump/-/pump-2.0.1.tgz"
integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==
dependencies:
end-of-stream "^1.1.0"
once "^1.3.1"
pump@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
version "3.0.3"
resolved "https://registry.npmmirror.com/pump/-/pump-3.0.3.tgz"
integrity sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==
dependencies:
end-of-stream "^1.1.0"
once "^1.3.1"
pumpify@^1.3.5:
version "1.5.1"
resolved "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce"
resolved "https://registry.npmmirror.com/pumpify/-/pumpify-1.5.1.tgz"
integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==
dependencies:
duplexify "^3.6.0"
inherits "^2.0.3"
pump "^2.0.0"
qs@^6.11.2:
version "6.12.0"
resolved "https://registry.npmjs.org/qs/-/qs-6.12.0.tgz#edd40c3b823995946a8a0b1f208669c7a200db77"
integrity sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==
dependencies:
side-channel "^1.0.6"
"readable-stream@> 1.0.0 < 3.0.0", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, "readable-stream@> 1.0.0 < 3.0.0", readable-stream@~2.3.6:
version "2.3.8"
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b"
resolved "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz"
integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
dependencies:
core-util-is "~1.0.0"
@@ -653,108 +493,68 @@ qs@^6.11.2:
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readable-stream@^3.0.0, readable-stream@^3.4.0:
readable-stream@^3.0.0:
version "3.6.2"
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
resolved "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz"
integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
dependencies:
inherits "^2.0.3"
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
regenerator-runtime@^0.14.0:
version "0.14.1"
resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
readable-stream@^3.4.0:
version "3.6.2"
resolved "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz"
integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
dependencies:
inherits "^2.0.3"
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
reinterval@^1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz#3361ecfa3ca6c18283380dd0bb9546f390f5ece7"
resolved "https://registry.npmmirror.com/reinterval/-/reinterval-1.1.0.tgz"
integrity sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==
remove-trailing-separator@^1.0.1:
version "1.1.0"
resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
resolved "https://registry.npmmirror.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz"
integrity sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==
safe-buffer@^5.1.2, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
resolved "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
set-function-length@^1.2.1:
version "1.2.1"
resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz#47cc5945f2c771e2cf261c6737cf9684a2a5e425"
integrity sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==
dependencies:
define-data-property "^1.1.2"
es-errors "^1.3.0"
function-bind "^1.1.2"
get-intrinsic "^1.2.3"
gopd "^1.0.1"
has-property-descriptors "^1.0.1"
side-channel@^1.0.6:
version "1.0.6"
resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
dependencies:
call-bind "^1.0.7"
es-errors "^1.3.0"
get-intrinsic "^1.2.4"
object-inspect "^1.13.1"
source-map-js@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
source-map@^0.6.1:
version "0.6.1"
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
split2@^3.1.0:
version "3.2.2"
resolved "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f"
resolved "https://registry.npmmirror.com/split2/-/split2-3.2.2.tgz"
integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==
dependencies:
readable-stream "^3.0.0"
stream-shift@^1.0.0:
version "1.0.3"
resolved "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz#85b8fab4d71010fc3ba8772e8046cc49b8a3864b"
resolved "https://registry.npmmirror.com/stream-shift/-/stream-shift-1.0.3.tgz"
integrity sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==
string_decoder@^1.1.1:
version "1.3.0"
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
dependencies:
safe-buffer "~5.2.0"
string_decoder@~1.1.1:
string_decoder@^1.1.1, string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
resolved "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz"
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
dependencies:
safe-buffer "~5.1.0"
text-segmentation@^1.0.3:
version "1.0.3"
resolved "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz#52a388159efffe746b24a63ba311b6ac9f2d7943"
resolved "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz"
integrity sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==
dependencies:
utrie "^1.0.2"
through2-filter@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254"
resolved "https://registry.npmmirror.com/through2-filter/-/through2-filter-3.0.0.tgz"
integrity sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==
dependencies:
through2 "~2.0.0"
@@ -762,7 +562,7 @@ through2-filter@^3.0.0:
through2@^2.0.1, through2@~2.0.0:
version "2.0.5"
resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
resolved "https://registry.npmmirror.com/through2/-/through2-2.0.5.tgz"
integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
dependencies:
readable-stream "~2.3.6"
@@ -770,35 +570,40 @@ through2@^2.0.1, through2@~2.0.0:
to-absolute-glob@^2.0.0:
version "2.0.2"
resolved "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz#1865f43d9e74b0822db9f145b78cff7d0f7c849b"
resolved "https://registry.npmmirror.com/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz"
integrity sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==
dependencies:
is-absolute "^1.0.0"
is-negated-glob "^1.0.0"
tslib@2.3.0:
version "2.3.0"
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz"
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
type@^2.7.2:
version "2.7.2"
resolved "https://registry.npmjs.org/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0"
integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==
version "2.7.3"
resolved "https://registry.npmmirror.com/type/-/type-2.7.3.tgz"
integrity sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==
typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
resolved "https://registry.npmmirror.com/typedarray/-/typedarray-0.0.6.tgz"
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
ultron@~1.1.0:
version "1.1.1"
resolved "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c"
resolved "https://registry.npmmirror.com/ultron/-/ultron-1.1.1.tgz"
integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==
unc-path-regex@^0.1.2:
version "0.1.2"
resolved "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
resolved "https://registry.npmmirror.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz"
integrity sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==
unique-stream@^2.0.2:
version "2.3.1"
resolved "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz#c65d110e9a4adf9a6c5948b28053d9a8d04cbeac"
resolved "https://registry.npmmirror.com/unique-stream/-/unique-stream-2.3.1.tgz"
integrity sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==
dependencies:
json-stable-stringify-without-jsonify "^1.0.1"
@@ -806,37 +611,24 @@ unique-stream@^2.0.2:
util-deprecate@^1.0.1, util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
resolved "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
utrie@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz#d42fe44de9bc0119c25de7f564a6ed1b2c87a645"
resolved "https://registry.npmmirror.com/utrie/-/utrie-1.0.2.tgz"
integrity sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==
dependencies:
base64-arraybuffer "^1.0.2"
vconsole@^3.15.1:
version "3.15.1"
resolved "https://registry.npmjs.org/vconsole/-/vconsole-3.15.1.tgz#569a8ab15f353259527bbcf004f02946b4482cff"
integrity sha512-KH8XLdrq9T5YHJO/ixrjivHfmF2PC2CdVoK6RWZB4yftMykYIaXY1mxZYAic70vADM54kpMQF+dYmvl5NRNy1g==
dependencies:
"@babel/runtime" "^7.17.2"
copy-text-to-clipboard "^3.0.1"
core-js "^3.11.0"
mutation-observer "^1.0.3"
vue@^2.6.8:
version "2.7.16"
resolved "https://registry.npmjs.org/vue/-/vue-2.7.16.tgz#98c60de9def99c0e3da8dae59b304ead43b967c9"
integrity sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==
dependencies:
"@vue/compiler-sfc" "2.7.16"
csstype "^3.1.0"
uview-ui@^2.0.38:
version "2.0.38"
resolved "https://registry.npmmirror.com/uview-ui/-/uview-ui-2.0.38.tgz"
integrity sha512-6egHDf9lXHKpG3hEjRE0vMx4+VWwKk/ReTf5x18KrIKqdvdPRqO3+B8Unh7vYYwrIxzAWIlmhZ9RJpKI/4UqPQ==
websocket-stream@^5.1.2:
version "5.5.2"
resolved "https://registry.npmjs.org/websocket-stream/-/websocket-stream-5.5.2.tgz#49d87083d96839f0648f5513bbddd581f496b8a2"
resolved "https://registry.npmmirror.com/websocket-stream/-/websocket-stream-5.5.2.tgz"
integrity sha512-8z49MKIHbGk3C4HtuHWDtYX8mYej1wWabjthC/RupM9ngeukU4IWoM46dgth1UOS/T4/IqgEdCDJuMe2039OQQ==
dependencies:
duplexify "^3.5.1"
@@ -848,12 +640,12 @@ websocket-stream@^5.1.2:
wrappy@1:
version "1.0.2"
resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
resolved "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz"
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
ws@^3.2.0:
version "3.3.3"
resolved "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2"
resolved "https://registry.npmmirror.com/ws/-/ws-3.3.3.tgz"
integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==
dependencies:
async-limiter "~1.0.0"
@@ -862,5 +654,12 @@ ws@^3.2.0:
xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1:
version "4.0.2"
resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
resolved "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
zrender@5.6.1:
version "5.6.1"
resolved "https://registry.npmmirror.com/zrender/-/zrender-5.6.1.tgz"
integrity sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==
dependencies:
tslib "2.3.0"