zhuguifei
2024-12-25 576d28de6be2d75bfd5a213874dd8d06657635b5
1.添加实时报警和历史报警 2.添加云服务和局域网模式切换界面
已修改19个文件
已添加4个文件
2372 ■■■■ 文件已修改
App.vue 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
common/api.js 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
common/constant.js 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
common/loadshget.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
common/request/fly.js 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/drop-down-menu/index.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main.js 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
manifest.json 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
mqtt/MqttView.vue 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages.json 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/charts/charts.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/device/control.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/login/login.vue 89 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/login/switchMode.vue 169 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/tabBar/components/hisWarning.vue 599 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/tabBar/components/realWarning.vue 455 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/tabBar/device.vue 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/tabBar/formula.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/tabBar/general.vue 173 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/tabBar/me.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/tabBar/warning.vue 706 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
readMe.txt 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
store/index.js 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
App.vue
@@ -2,8 +2,13 @@
    import Vue from 'vue'
    export default {
        //全局变量(同步数据可用全局变量,异步数据使用vuex)
        globalData: {
            token: ""
            token: "",
            //当前选择tab
            selectTab: 0,
            //当前网络模式(cloud-云服务、lan-局域网)
            mode: "",
        },
        onLaunch: function() {
             
@@ -27,19 +32,17 @@
            //推送仅支持Android ios原生平台
            // #ifdef APP-PLUS
            console.log('APP-PLUS:')
            // æ­¤å¤„为unipush1.0的推送方法
            plus.push.getClientInfoAsync((info) => {
                let cid = info["clientid"];
                console.log('客户端推送标识:', cid)
                this.$store.dispatch('setCid', cid); // ä½¿ç”¨ action æ›´æ–° cid
                this.$store.dispatch('setClientPushId', cid); // ä½¿ç”¨ action æ›´æ–° cid
            });
            // #endif
            uni.onPushMessage((res) => {
                console.log("收到推送消息:", res) //监听推送消息
            })
            uni.getSystemInfo({
                success: function(e) {
@@ -96,12 +99,7 @@
                if (this.$mqttTool.client) {
                    console.log(this.$mqttTool.client.connected)
                }
                // if(this.$mqttTool.client){
                //     this.$mqttTool.end().then(res =>{
                //         console.log('终止:')
                //     })
                // }
            }
        },
common/api.js
@@ -2,13 +2,13 @@
    fly
} from '@/common/request/fly.js'
//配置请求基地址
fly.config.baseURL = "http://192.168.12.20:9999"
const url = uni.getStorageSync('baseurl');
if (url) {
    fly.config.baseURL = url + "/herb"
fly.config.baseURL = "http://192.168.12.47:9999"
const ip = uni.getStorageSync('lan_ip');
if (ip) {
    fly.config.baseURL = "http://" + ip + ":9999"
}
const mqttBaseUrl = "223.241.221.20";
const mqttBaseUrl = "192.168.2.3";
const emqxBaseUrl = "http://"+mqttBaseUrl +":18083/api/v5"
// æµ‹è¯•
@@ -44,6 +44,12 @@
    return fly.get('/mobile/equ/list', params);
}
//仅用作下拉刷新,无实际意义
function querySampleList(params) {
    fly.config.loading = true
    return fly.get('/mobile/sample/list', params);
}
//
function getMonth(params) {
    fly.config.loading = true
@@ -53,6 +59,18 @@
function sendCommand(params) {
    fly.config.loading = true
    return fly.post('/dry/real/sendCommand', params);
}
//历史故障,查询最近数据
function queryHisFaultList(params) {
    fly.config.loading = true
    return fly.get('/mobile/fault/list', params);
}
//历史故障,查询图表需要数据
function queryHisFaultChartList(params) {
    fly.config.loading = true
    return fly.get('/mobile/fault/chart', params);
}
@@ -79,6 +97,9 @@
    getAnalyList,
    getOrderList,
    queryEquList,
    querySampleList,
    queryHisFaultList,
    queryHisFaultChartList,
    getMonth,
    sendCommand,
    
common/constant.js
@@ -2,6 +2,9 @@
const MOBILE_UP = "mobile/up"
//请求查询设备状态
const MOBILE_QUERY_EQU_STATU = MOBILE_UP + "/query/equ/statu"
//请求查询设备实时故障
const MOBILE_REQ_EQU_REAL_FAULT = MOBILE_UP + "/req/real/fault"
//发送操作指令
const MOBILE_REQ_EQU_CMD = MOBILE_UP + "/req/equ/cmd"
@@ -30,6 +33,9 @@
const SERVICE_BROADCAST_TENANT_REAL_FAULT = SERVICE_BROADCAST + "/real/fault/%s"
const SERVICE_ONECE_TENANT_REAL_FAULT = "service/onece" + "/real/fault/%s"
/***********************EventBus function********************************/
@@ -40,12 +46,16 @@
export default {
    MOBILE_QUERY_EQU_STATU,
    MOBILE_REQ_EQU_REAL_FAULT,
    SERVICE_RES_EQU_STATU,
    SERVICE_DOWN,
    MOBILE_REQ_EQU_CMD,
    SERVICE_RES_EQU_CMD,
    SERVICE_BROADCAST_TENANT_REAL_FAULT,
    SERVICE_ONECE_TENANT_REAL_FAULT,
    
    MQTT_TOPIC_MESSAGE,
common/loadshget.js
@@ -4,6 +4,6 @@
    if(!data || data == null) return "--";
    if(data & (!item || item == null)) return data;
    let res  =  get(data, item)
    return res == null ? "--" :res
    return (res == null || res == "")  ? "--" :res
}
common/request/fly.js
@@ -1,5 +1,6 @@
var Fly = require("./wx.umd.min")
var fly = new Fly
const log = false
fly.config.loading = true;
@@ -7,7 +8,6 @@
fly.config.timeout=10000;
//添加拦截器
fly.interceptors.request.use((config, promise) => {
    console.info(fly.config.loading)
    if (fly.config.loading) {
        uni.showLoading({
            title: '加载中'
@@ -24,9 +24,11 @@
    if (userinfo) {
        config.headers["X-Tenant-Id"] = userinfo.loginTenantId;
    }
    if(log){
    console.log('========================================== ')
    console.log('==    è¯·æ±‚数据:' + JSON.stringify(config))
    console.log('=========================================== ')
    }
    return config;
})
@@ -34,10 +36,12 @@
fly.interceptors.response.use(
    (response) => {
        if(log){
        console.log('========================================')
        console.log('==    å“åº”数据:' + JSON.stringify(response.request.url))
        console.log('==    ' + JSON.stringify(response.data))
        console.log('======================================== ')
        }
        //只将请求结果的data字段返回
components/drop-down-menu/index.vue
@@ -1,7 +1,10 @@
<template>
    <view class="dropdown">
        <view class="item">
            <view class="item-title">设备</view>
            <view class="item-title" style="display: flex;justify-content: space-between;">
                <text>设备</text>
                <text @click="closeMenu"><u-icon name="close"></u-icon></text>
            </view>
            <view class="item-box">
                <view v-for="(item,index) in menuList" :key="item.code" :class="['item-menu',item.ck?'active':'']"
                    @click="changeMenu(index)">{{item.name}}
@@ -196,6 +199,9 @@
                    }
                }
                this.selectData.endTime = val;
            },
            closeMenu(){
                this.$emit('closeMenu')
            }
        }
    }
main.js
@@ -34,15 +34,13 @@
Vue.prototype.$mqttTool = mqttTool
const EventBus = new Vue();
Vue.prototype.$eventBus = EventBus
//全局监控定时器(在页面使用局部定时器会出现无法关闭问题)
Vue.prototype.$monitorTimer = null
Vue.config.productionTip = false
App.mpType = 'app'
manifest.json
@@ -1,5 +1,5 @@
{
    "name" : "智能中草药干燥机",
    "name" : "兰浦智能干燥",
    "appid" : "__UNI__1E83F66",
    "description" : "",
    "versionName" : "1.0.0",
@@ -54,11 +54,11 @@
                    "unipush" : {
                        "icons" : {
                            "small" : {
                                "ldpi" : "static/push/push_small_18.png",
                                "mdpi" : "static/push/push_small_24.png",
                                "hdpi" : "static/push/push_small_36.png",
                                "xhdpi" : "static/push/push_small_48.png",
                                "xxhdpi" : "static/push/push_small_72.png"
                                "ldpi" : "static/logo.png",
                                "mdpi" : "static/logo.png",
                                "hdpi" : "static/logo.png",
                                "xhdpi" : "static/logo.png",
                                "xxhdpi" : "static/logo.png"
                            }
                        }
                    }
mqtt/MqttView.vue
@@ -4,7 +4,6 @@
</template>
<script>
    export default {
        name: 'MqttView',
        data() {
@@ -13,6 +12,7 @@
            }
        },
        onReady() {
             
        },
        methods: {
@@ -23,7 +23,8 @@
                        if (!deviceId) {
                            deviceId = 'mobile-' + this.tenantId + '-' + Date.parse(new Date())
                        }
                        uni.setStorageSync(this.$constant.DEVICE_ID, 'mobile-' + this.tenantId + '-' + res.deviceId);
                        uni.setStorageSync(this.$constant.DEVICE_ID, 'mobile-' + this.tenantId + '-' + res
                            .deviceId);
                    }
                })
                    this.startConnect();
@@ -50,7 +51,7 @@
                     password: account.password
                 }
                 if (!this.$mqttTool.client) {
                     var client = await this.$mqttTool.connect(opts);
                    this.$mqttTool.client = await this.$mqttTool.connect(opts);
                 }
                 //订阅查询设备状态返回数据
                 this.$mqttTool.subscribe({
@@ -67,6 +68,15 @@
                 }).then(res => {
                     console.error(res)
                 })
                //订阅设备实时故障(主动请求只发给请求设备)
                this.$mqttTool.subscribe({
                    topic: this.$constant.SERVICE_ONECE_TENANT_REAL_FAULT.replace('%s', deviceid),
                    qos: 0
                }).then(res => {
                    console.error(res)
                })
                 //订阅发送指令返回结果
                 // this.$mqttTool.subscribe({
                 //     topic: this.$constant.SERVICE_RES_EQU_CMD,
@@ -78,6 +88,7 @@
                 //     return false
                 // }
                let that = this
                let client = this.$mqttTool.client
             
                 client.on('connect', function(res) {
                     console.error('连接成功')
@@ -94,8 +105,9 @@
             
                 })
                 client.on('message', function(topic, message, buffer) {
                    that.$eventBus.$emit(that.$constant.MQTT_TOPIC_MESSAGE, message);
                     console.info(message)
                    uni.$emit(that.$constant.MQTT_TOPIC_MESSAGE, message);
                    console.error("收到message(总):"+topic)
                
                 })
             },
pages.json
@@ -116,8 +116,7 @@
        },
        {
            "path" : "pages/tabBar/device",
            "style" :
            {
            "style": {
                "navigationStyle": "custom",
                "app-plus": {
                    "titleNView": false
@@ -126,8 +125,7 @@
        },
        {
            "path" : "pages/tabBar/warning",
            "style" :
            {
            "style": {
                "navigationStyle": "custom",
                "app-plus": {
                    "titleNView": false
@@ -136,8 +134,16 @@
        },
        {
            "path" : "pages/device/control",
            "style" :
            "style": {
                "navigationStyle": "custom",
                "app-plus": {
                    "titleNView": false
                }
            }
        },
            {
            "path": "pages/login/switchMode",
            "style": {
                "navigationStyle": "custom",
                "app-plus": {
                    "titleNView": false
@@ -167,17 +173,17 @@
            "pagePath": "pages/tabBar/device",
            "iconPath": "static/tabBar/shop.png",
            "selectedIconPath": "static/tabBar/shop_cur.png",
            "text": "监控"
            "text": "机台监控"
        }, {
            "pagePath": "pages/tabBar/warning",
            "iconPath": "static/tabBar/analy.png",
            "selectedIconPath": "static/tabBar/analy_cur.png",
            "text": "报警"
            "text": "报警通知"
        }, {
            "pagePath": "pages/tabBar/formula",
            "iconPath": "static/tabBar/order.png",
            "selectedIconPath": "static/tabBar/order_cur.png",
            "text": "配方"
            "text": "干燥配方"
        }, {
            "pagePath": "pages/tabBar/me",
            "iconPath": "static/tabBar/me.png",
pages/charts/charts.vue
@@ -113,7 +113,7 @@
    export default {
        data() {
            return {
                text: '智能中草药干燥设备配套系统',
                text: '兰浦智能干燥',
                cWidth: '',
                cHeight: '',
                pixelRatio: 1,
pages/device/control.vue
@@ -292,11 +292,7 @@
            let _this = this
            this.$mqttTool.client.on('message', function(topic, message, buffer) {
                console.error("解析数据")
                const msg = JSON.parse(message);
                console.error(topic)
                console.error(msg)
                console.error(msg.success)
                if (topic == _this.$constant.SERVICE_RES_EQU_STATU.replace('equ', _this.deviceId)) {
                    if (msg.success) {
                        _this.connected = msg.connected
pages/login/login.vue
@@ -2,7 +2,7 @@
<template>
    <view class="contaier">
        <view class="top-bg">
            <view class="text-white text-bold text-xxxl">智能中草药干燥设备配套系统</view>
            <view class="text-white text-bold text-xxxl">兰浦<text @longpress="showModal">智能</text>干燥</view>
            <view class="margin-top-xs text-white">欢迎使用,请先登录</view>
        </view>
        <u-form labelPosition="left" :model="model" ref="form">
@@ -22,17 +22,27 @@
            <view class="padding margin-top-xs">
                <button @click="submit" class="cu-btn block round bg-login-zl margin-tb-sm lg">立即登录</button>
                <view class="text-gray flex justify-between padding-lr-sm">
                    <text>注册账号</text>
                    <text>忘记密码</text>
                    <!-- <text @click="switchMode">局域网模式</text> -->
                    <!-- <text>忘记密码</text> -->
                </view>
            </view>
        </u-form>
        <u-modal :show="show" title="提示" @confirm="handleSwitchMode">
            <view class="slot-content">
                <u-input v-model="pass" style="width: 100%;" placeholder="请输入管理员密码" border="surround" password
                    clearable></u-input>
            </view>
        </u-modal>
    </view>
</template>
<script>
    export default {
        data() {
            return {
                show: false,
                pass: "",
                model: {
                    username: "tongjitang",
                    password: "123456"
@@ -54,52 +64,56 @@
            };
        },
        onLoad() {
            const account = uni.getStorageSync('account');
            if (account) {
                this.model = account
            }
            let _that = this
            // uni-app客户端获取push客户端标记
            // uni.getPushClientId({
            //     success: (res) => {
            //         let push_clientid = res.cid
            //         _that.model.username  = push_clientid
            //         console.log('客户端推送标识:', push_clientid)
            //     },
            //     fail(err) {
            //         _that.model.username  = err
            //         console.log(err)
            //     }
            // })
            // uni.onPushMessage((res) => {
            //     _that.model.username  = JSON.stringify(res)
            //     console.log("收到推送消息:", res) //监听推送消息
            // })
        },
        mounted() {
            setTimeout(() => {
                this.model.username = this.clientPushId
            }, 1000)
        },
        computed: {
            cid() {
                return this.$store.getters.getCid; // ä½¿ç”¨ getter èŽ·å– cid
            clientPushId() {
                return this.$store.getters.getClientPushId;
            },
        },
        methods: {
            showModal() {
                this.pass = ""
                this.show = true
            },
            handleSwitchMode() {
                this.show = false
                if (this.pass === 'lanbaoit') {
                    this.switchMode()
                }
            },
            switchMode() {
                uni.navigateTo({
                    url: "/pages/login/switchMode"
                })
            },
            forget() {
                uni.navigateTo({
                    url: "/pages/tabBar/demo"
                })
            },
            submit() {
                if (this.model.username.startsWith("http")) {
                    uni.setStorageSync('baseurl', this.model.username);
                    this.model.username = null
                    uni.$u.toast('配置baseUrl成功,请退出程序重新启动~')
                    return false;
                const mode = uni.getStorageSync('mode');
                //首次登录没有配置,默认为云服务模式
                if (!mode) {
                    uni.setStorageSync('mode', 'cloud');
                }
                const curMode = uni.getStorageSync('mode');
                getApp().globalData.mode = curMode;
                this.$refs.form.validate().then(res => {
                    this.login()
@@ -111,20 +125,15 @@
            login() {
                this.$api.login(this.model).then((res) => {
                    if (res.success) {
                        console.log('request success', res)
                        uni.showToast({
                            title: '登录成功',
                            icon: 'success',
                            mask: true
                        });
                        //缓存信息
                        uni.setStorageSync('account', this.model);
                        uni.setStorageSync('userinfo', res.result.userInfo);
                        uni.setStorageSync('token', res.result.token);
                        uni.switchTab({
                            url: '/pages/tabBar/general'
@@ -143,9 +152,7 @@
                    console.log('request fail', err);
                })
            },
            onReset(e) {
                console.log(e)
            }
        },
        onReady() {
            //onReady ä¸ºuni-app支持的生命周期之一
pages/login/switchMode.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,169 @@
<template>
    <view class="app">
        <cu-custom bgColor="bg-gradual-blue" :isBack="true">
            <block slot="content">切换模式</block>
        </cu-custom>
        <view class="cu-bar bg-white margin-top">
            <view class="action sub-title">
                <text class="text-xl text-bold text-blue text-shadow">当前模式</text>
                <text class="text-ABC text-blue">current</text>
            </view>
        </view>
        <u-form labelPosition="left" ref="form">
            <view class="padding-lr info-box">
                <view class="cover-view" @tap.catch="showSelect">
                </view>
                <view style="position: relative;">
                    <u-form-item label="模式" prop="username" borderBottom>
                        <u-input v-model="sModel" border="none" suffixIcon="arrow-right" readonly></u-input>
                    </u-form-item>
                </view>
                <u-form-item label="地址" prop="password" borderBottom v-show="showIp">
                    <u-input v-model="ip" placeholder="请输入IP地址,如:192.168.1.1" border="none" clearable>
                    </u-input>
                </u-form-item>
                <view class="submitBtn" @click="saveMode">保存</view>
                <view style="height: 20rpx;background-color: white"></view>
            </view>
        </u-form>
        <u-action-sheet :closeOnClickAction="true" @close="show=false" @select="selectMode" :safeAreaInsetBottom="true"
            :actions="switchList" title="选择模式" cancelText="取消" :show="show"></u-action-sheet>
    </view>
</template>
<script>
    import {
        vShow
    } from "vue";
    export default {
        data() {
            return {
                switchList: [{
                    name: '云服务',
                    index: 0
                }, {
                    name: '局域网',
                    index: 1
                }],
                show: false,
                sModel: '云服务',
                ip: '',
                showIp: false,
                selectModeIndex: 0,
            };
        },
        mounted() {
            const mode = uni.getStorageSync('mode');
            const lan_ip = uni.getStorageSync('lan_ip');
            if (mode) {
                if (mode == 'cloud') {
                    this.sModel = '云服务'
                    this.showIp = false
                } else if (mode == 'lan') {
                    this.sModel = '局域网'
                    this.showIp = true
                }
                if (this.sModel == '局域网') {
                    this.ip = lan_ip
                }
            }
        },
        methods: {
            showSelect() {
                this.show = true
            },
            selectMode(item) {
                this.sModel = item.name
                console.error(item.index)
                this.showIp = item.index === 1
                this.selectModeIndex = item.index
            },
            saveMode() {
                if (!this.ip | !this.isValidIPv4(this.ip)) {
                    uni.$u.toast('请输入正确IP地址~')
                    return false
                }
                if (this.selectModeIndex === 0) {
                    uni.removeStorageSync('lan_ip')
                    uni.setStorageSync('mode', 'cloud');
                } else if (this.selectModeIndex === 1) {
                    uni.setStorageSync('mode', 'lan');
                    uni.setStorageSync('lan_ip', this.ip);
                }
                uni.$u.toast('配置成功,请完全退出程序后重新启动~')
            },
            isValidIPv4(ip) {
                const ipv4Regex =
                    /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
                return ipv4Regex.test(ip);
            }
        }
    }
</script>
<style lang="scss">
    .cover-view {
        position: absolute;
        /* å¿…须是相对定位或绝对定位 */
        z-index: 10;
        /* ç¡®ä¿ z-index å€¼é«˜äºŽ u-input */
        width: 100%;
        height: 80rpx;
        background-color: transparent;
    }
    .info-box {
        position: relative;
        background-color: white;
    }
    .distinguishBox {
        padding: 5rpx 30rpx 20rpx;
        background: white;
        view {
            margin-bottom: 20rpx;
        }
    }
    .disLabel {
        text-align-last: justify;
        text-align: justify;
        text-justify: distribute-all-lines;
        min-width: 142rpx;
        display: inline-block;
        margin-right: 5rpx;
    }
    .submitBtn {
        width: 90%;
        height: 90rpx;
        background: #007aec;
        line-height: 90rpx;
        margin: 50rpx auto;
        text-align: center;
        font-size: 34rpx;
        color: #fff;
        border-radius: 12rpx;
    }
</style>
pages/tabBar/components/hisWarning.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,599 @@
<template>
    <view>
        <view class="card-box center dynamic shadow">
            <view class="title-box margin-bottom-sm">
                <view style="width: 100vw;" class="left justify-between">
                    <view class="flex align-center">
                        <uni-text class="cuIcon-titles text-blue"></uni-text>
                        <view class="title">最近报警</view>
                    </view>
                    <view>
                        <text class="text-blue text-sm">更多></text>
                    </view>
                </view>
            </view>
            <view class="borderTop">
                <view class="h-table">
                    <view class="h-tr h-tr-2 ">
                        <view class="h-td">机台</view>
                        <view class="h-td">故障</view>
                        <view class="h-td">时间</view>
                        <view class="h-td">类型</view>
                    </view>
                    <view class="h-tr h-tr-2" v-for="(item,index) in faultList">
                        <view class="h-td">{{item.equName}}</view>
                        <view class="h-td text-ellipsis">{{item.faultName}}</view>
                        <view class="h-td text-ellipsis">{{item.faultTimeStr}}</view>
                        <view class="h-td">{{item.faultType===1?'故障':'告警'}}</view>
                    </view>
                </view>
            </view>
        </view>
        <view class="card-box center dynamic shadow">
            <view class="title-box margin-bottom-sm">
                <view style="width: 100vw;" class="left justify-between">
                    <view class="flex align-center">
                        <uni-text class="cuIcon-titles text-blue"></uni-text>
                        <view class="title">报警统计</view>
                    </view>
                    <view>
                        <text class="text-gray text-sm"></text>
                    </view>
                </view>
            </view>
            <view class="chartsMain" style="height: 400rpx;">
                <!-- <qiun-data-charts type="mount" :opts="opts" :ontouch='true' :animation="true" :chartData="mountData" /> -->
                <qiun-data-charts canvasId="chat1"  type="column" :errorMessage="errorMessage1"
                    :opts="opts" :ontouch='true' :animation="true" :chartData="statisData" />
            </view>
        </view>
        <view class="card-box center dynamic shadow">
            <view class="title-box margin-bottom-sm">
                <view style="width: 100vw;" class="left justify-between">
                    <view class="flex align-center">
                        <uni-text class="cuIcon-titles text-blue"></uni-text>
                        <view class="title">报警对比</view>
                    </view>
                    <view>
                        <text class="text-gray text-sm"></text>
                    </view>
                </view>
            </view>
            <view class="chartsMain">
                <qiun-data-charts canvasId="chat2" type="pie"   :errorMessage="errorMessage2"
                    :opts="optsPie" :ontouch='true' :animation="true" :chartData="pieData" />
            </view>
        </view>
        <view class="card-box center dynamic shadow">
            <view class="title-box margin-bottom-sm">
                <view style="width: 100vw;" class="left justify-between">
                    <view class="flex align-center">
                        <uni-text class="cuIcon-titles text-blue"></uni-text>
                        <view class="title">报警频率</view>
                    </view>
                    <view>
                        <text class="text-gray text-sm"></text>
                    </view>
                </view>
            </view>
            <view class="chartsMain" style="height: 500rpx;">
                <!-- <qiun-data-charts type="mount" :opts="{extra:{mount:{type:'mount',widthRatio:1.5}}}"
                :chartData="Mount" /> -->
                <qiun-data-charts canvasId="chat3" type="word"  :errorMessage="errorMessage3"
                    :chartData="wordData" />
            </view>
        </view>
        <view class="card-box bot dynamic shadow">
            <view class="title-box margin-bottom-sm">
                <view style="width: 100vw;" class="left justify-between">
                    <view class="flex align-center">
                        <uni-text class="cuIcon-titles text-blue"></uni-text>
                        <view class="title">报警分析</view>
                    </view>
                    <view>
                        <text class="text-gray text-sm"></text>
                    </view>
                </view>
            </view>
            <view class="chartsMain" style="height: 500rpx;">
                <qiun-data-charts canvasId="chat4" type="line"   :opts="optsStep"
                    :errorMessage="errorMessage4" :ontouch='true' :animation="true" :chartData="statisData" />
                <!-- <qiun-data-charts type="radar" :opts="optsRadar" :chartData="dataRadar" /> -->
            </view>
        </view>
    </view>
</template>
<script>
    import dayjs from 'dayjs'
    export default {
        data() {
            return {
                "PieA": {
                    "series": [{
                        "data": [
                        ]
                    }]
                },
                errorMessage1: "",
                errorMessage2: "",
                errorMessage3: "",
                errorMessage4: "",
                faultList: [],
                pieData: {
                    "series": [{
                        "data": []
                    }]
                },
                statisData: {
                    series: [],
                    categories: []
                },
                wordData: {
                    series: []
                },
                optsStep: {
                    enableScroll: true,
                    xAxis: {
                        marginTop: 10,
                        itemCount: 8,
                        rotateLabel: true
                    },
                    extra: {
                        line: {
                            type: 'step'
                        }
                    }
                },
                opts: {
                    enableScroll: true,
                    xAxis: {
                        marginTop: 10,
                        itemCount: 8,
                        rotateLabel: true
                    },
                    legend: {
                        show: false
                    },
                    yAxis: {
                        data: [{
                            min: 0
                        }]
                    },
                    extra: {
                        column: {
                            width: 12,
                            seriesGap: 5,
                            barBorderRadius: [6, 6, 6, 6]
                        }
                    }
                },
                optsPie: {
                    padding: [5, 5, 5, 5],
                    legend: {
                        show: false
                    },
                    fontSize: 12,
                    extra: {
                        pie: {
                            activeOpacity: 0.5,
                            activeRadius: 10,
                            offsetAngle: 0,
                            labelWidth: 1,
                            border: true,
                            borderWidth: 3,
                            borderColor: "#FFFFFF",
                            linearType: "custom"
                        }
                    }
                },
            }
        },
        mounted() {
            setTimeout(() => {
                this.init()
            }, 300)
        },
        methods: {
            init() {
                // èŽ·å–N天前的0点0分0秒
                let daysAgo = dayjs().subtract(3, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss');
                // èŽ·å–ä»Šå¤©çš„23点59分59秒
                let today = dayjs().endOf('day').format('YYYY-MM-DD HH:mm:ss');
                let params = {
                    column: 'createTime',
                    order: 'desc',
                    startTime_begin: daysAgo,
                    startTime_end: today,
                    pageNo: 1,
                    pageSize: 3
                }
                this.$api.queryHisFaultList(params).then((res) => {
                    this.faultList = res.result.records
                }).catch(res => {
                })
                let chartParam = {
                    startTime_begin: daysAgo,
                    startTime_end: today,
                }
                this.statisData = {}
                this.pieData = {}
                this.wordData = {}
                this.$api.queryHisFaultChartList(chartParam).then((res) => {
                    // æŸ±çж图
                    const statis = {
                        series: [],
                        categories: []
                    };
                    //饼图
                    const pieData = {
                        series: [{
                            data: []
                        }]
                    };
                    //词云图
                    const wordData = {
                        series: []
                    };
                    this.$emit('handleData', res)
                    // æ£€æŸ¥ res æ˜¯å¦ä¸º null æˆ–者不是一个数组
                    if (!Array.isArray(res) || res === null || res.length === 0) {
                        this.errorMessage1 = "暂无数据"+ dayjs().format('HH:mm:ss');
                        this.errorMessage2 = "暂无数据"+ dayjs().format('HH:mm:ss');
                        this.errorMessage3 = "暂无数据"+ dayjs().format('HH:mm:ss');
                        this.errorMessage4 = "暂无数据"+ dayjs().format('HH:mm:ss');
                        return;
                    }
                   console.error(res)
                    // å•次遍历 res,同时寻找最大 ecount å¹¶æž„建 categories、data å’Œ pieData
                    const result = res.reduce((acc, item) => {
                        if (item.faultType === 1) {
                            acc.categories.push(item.faultName);
                            const value = item.ecount;
                            acc.data.push({
                                value,
                                color: undefined // å…ˆä¸è®¾å®šé¢œè‰²
                            });
                        }
                        // æ›´æ–°æœ€å¤§ ecount
                        if (item.ecount > acc.maxEcount) {
                            acc.maxEcount = item.ecount;
                        }
                        return acc;
                    }, {
                        maxEcount: 0,
                        categories: [],
                        data: []
                    });
                    // ç¬¬äºŒæ¬¡éåކ data æ•°ç»„,为所有最大 ecount è®¾ç½®é¢œè‰²
                    result.data.forEach((item, index) => {
                        if (item.value === result.maxEcount) {
                            result.data[index].color = '#f04864';
                        }
                    });
                    // å°†å¤„理结果赋值给 statis
                    statis.series.push({
                        name: "故障",
                        data: result.data.map(item => 'color' in item ? item : item.value)
                    });
                    statis.categories = result.categories;
                    res.filter(item => item.faultType == 1).forEach(item => {
                        // æž„建 pieData
                        pieData.series[0].data.push({
                            name: item.faultName,
                            value: item.ecount,
                            labelText: item.faultName + ":" + item.ecount + "次"
                        });
                    })
                    // è®¾ç½®åˆ°ç»„件属性
                    this.statisData = statis;
                    this.pieData = pieData;
                    if (this.statisData.series.length === 0) {
                        this.errorMessage1 = "暂无数据"+ dayjs().format('HH:mm:ss');
                        this.errorMessage4 = "暂无数据"+ dayjs().format('HH:mm:ss');
                    }
                    if (this.pieData.series[0].data.length === 0) {
                        this.errorMessage2 = "暂无数据"+ dayjs().format('HH:mm:ss');
                    }
                    const cdata = res.filter(item => item.faultType === 1).map(item => ({
                        faultName: item.faultName,
                        ecount: item.ecount
                    }));
                    console.error(cdata)
                    const wordCloudData = this.generateWordCloudData(cdata)
                    wordData.series = wordCloudData
                    this.wordData = wordData
                    console.error(this.wordData)
                    if (this.wordData.series.length === 0) {
                        this.errorMessage3 = "暂无数据"+ dayjs().format('HH:mm:ss');
                    }
                }).catch(res => {
                })
            },
            generateWordCloudData(data) {
                // å®šä¹‰å­—体大小范围
                const minFontSize = 10;
                const maxFontSize = 20;
                // å¦‚果数据为空或不是数组,则返回空数组
                if (!Array.isArray(data) || data.length === 0) {
                    return [];
                }
                // æ‰¾åˆ°æœ€å¤§å’Œæœ€å°çš„æ•…障次数
                let minCount = Infinity;
                let maxCount = -Infinity;
                data.forEach(item => {
                    if (item.ecount < minCount) minCount = item.ecount;
                    if (item.ecount > maxCount) maxCount = item.ecount;
                });
                // å¦‚果所有故障次数都相同,则直接为每个条目设置相同的字体大小
                if (minCount === maxCount) {
                    return data.map(item => ({
                        name: item.faultName,
                        textSize: maxFontSize
                    }));
                }
                // è®¡ç®—每个条目的字体大小
                const wordCloudData = data.map(item => {
                    const fontSize = ((maxFontSize - minFontSize) * (item.ecount - minCount)) / (maxCount -
                        minCount) + minFontSize;
                    return {
                        name: item.faultName,
                        textSize: Math.round(fontSize) // å¯é€‰ï¼šå››èˆäº”入到最接近的整数
                    };
                });
                return wordCloudData;
            },
        }
    }
</script>
<style lang="scss" scoped>
    @import "components/table/helang-table";
    .app {}
    .card-box {
        margin: 20rpx;
        padding: 20rpx;
        box-sizing: border-box;
        background-color: white;
        border-radius: 20rpx;
        font-family: Helvetica Neue, Helvetica, sans-serif;
    }
    .text-ellipsis {
        white-space: nowrap;
        /* é˜²æ­¢æ–‡æœ¬æ¢è¡Œ */
        overflow: hidden;
        /* è¶…出部分隐藏 */
        text-overflow: ellipsis;
        /* è¶…出部分用省略号表示 */
        max-width: 100%;
        /* è®¾ç½®æœ€å¤§å®½åº¦ */
    }
    .top {
        margin: 0 20rpx;
        border-radius: 0;
        border-top-left-radius: 20rpx;
        border-top-right-radius: 20rpx;
        border-bot-left-radius: 0;
        border-bot-right-radius: 0;
    }
    .center {
        margin: 0 20rpx;
        border-radius: 0;
    }
    .bot {
        margin: 0 20rpx 20rpx 20rpx;
        border-top-left-radius: 0;
        border-top-right-radius: 0;
        border-bot-left-radius: 20rpx;
        border-bot-right-radius: 20rpx;
    }
    .title-box {
        display: flex;
        flex-direction: row;
        align-items: center;
        .left {
            display: flex;
            align-items: center;
            .title {
                margin: 0 10rpx;
                font-weight: bold;
            }
        }
        .right {
            display: flex;
            align-items: center;
            .title {
                margin: 0 10rpx;
                font-weight: bold;
            }
        }
    }
    .info-box {
        margin-top: 20rpx;
        display: flex;
        flex-direction: row;
        align-items: center;
        .left {
            display: flex;
            align-items: center;
            .title {
                margin: 0 10rpx;
            }
        }
        .right {
            display: flex;
            align-items: center;
            .title {
                margin: 0 10rpx;
            }
        }
    }
    .chartsMain {
        width: 100%;
        height: 320rpx;
        padding-top: 15rpx;
        background: #fff;
        margin-bottom: 24rpx;
        border-top: 2rpx solid #f2f2f2;
        .charts {
            width: 50%;
            height: 450rpx;
            box-sizing: border-box;
        }
    }
    .tab-box {
        display: flex;
        justify-content: center;
        /* å¼ºåˆ¶æ°´å¹³å±…中 */
    }
    .swiper {
        height: 2116rpx;
    }
    .swiper-item-view {
        height: 2116rpx;
    }
    .picBox {
        margin: 0 20rpx;
        background-color: white;
        image {
            border-radius: 8rpx;
            width: 100%;
        }
    }
    .borderTop {
        border-top: 2rpx solid #f2f2f2;
        padding-top: 20rpx;
    }
    // å¼¹å‡ºå±‚背景遮罩start
    .dropdown-mask {
        background: rgba(0, 0, 0, 0.5);
    }
    .lock-page {
        height: 100vh;
        width: 100vw;
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 998;
    }
    // å¼¹å‡ºå±‚背景遮罩end
</style>
pages/tabBar/components/realWarning.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,455 @@
<template>
    <view>
        <view class="card-box center dynamic shadow">
            <view class="title-box margin-bottom-sm">
                <view style="width: 100vw;" class="left justify-between">
                    <view class="flex align-center">
                        <uni-text class="cuIcon-titles text-blue"></uni-text>
                        <view class="title">设备 </view>
                    </view>
                    <view>
                        <!-- <text class="text-blue text-sm">更多></text> -->
                    </view>
                </view>
            </view>
            <view class="fault-box">
                <image style="width: 100%;border-radius: 20rpx; " src="../../../static/image/ganzaoji-x.png"
                    mode="aspectFit">
                </image>
                <view class="fault-inner">
                    <view  class="fault-info"   v-for="(item,index) in realFaults" :style="getFaultItemStyle(item)">
                        <view :class="['fault-animal', item.type === 1 ? 'fault-marker' : 'warn-marker']"></view>
                        <view :class="['fault-tag', item.type === 1 ? 'fault-text' : 'warn-text']">{{item.name}}</view>
                    </view>
                </view>
            </view>
        </view>
        <view class="card-box center dynamic shadow">
            <view class="title-box margin-bottom-sm">
                <view style="width: 100vw;" class="left justify-between">
                    <view class="flex align-center">
                        <uni-text class="cuIcon-titles text-blue"></uni-text>
                        <view class="title">实时报警 </view>
                    </view>
                    <view>
                        <text class="text-blue text-sm">{{refreshTime}}</text>
                    </view>
                </view>
            </view>
            <view class="borderTop" v-for="(item,index) in     dataList">
                <view style="height: 180rpx;display: flex;align-items: center;">
                    <view>
                        <image style="width: 80rpx;height: 80rpx;margin:20rpx;border-radius: 20rpx; "
                            src="../../../static/image/pic_gz.jpg"></image>
                    </view>
                    <view
                        style="display: flex;flex: 1;flex-direction: column; justify-content: space-between;  ;height: 100%;padding: 20rpx;">
                        <view class="text-bold">
                            {{$lget(item,'faultName')}}
                        </view>
                        <view class="text-gray text-sm">
                            è®¾å¤‡:{{$lget(item,'equName')}}
                        </view>
                        <view class="text-gray text-sm">
                            ç±»åž‹:{{checkFaultType($lget(item,'faultType'))}}
                        </view>
                        <view class="text-gray text-sm">
                            æ•…障时间:{{coverTime($lget(item,'startTime'))}}
                        </view>
                    </view>
                    <view style="width: 100rpx;"></view>
                </view>
            </view>
        </view>
    </view>
</template>
<script>
    import dayjs from 'dayjs'
    export default {
        data() {
            return {
                dataList: [],
                //实时报警数据更新时间(一般10s)
                refreshTime: '',
                realFaults:[],
                allFaults: [{ id: 1, name: '设备急停(总)', type: 1, position: {top: 70,left: 230},show: false},
                 { id: 2, name: '左前急停', type: 1, position: {top: 100,left: 250},show: false},
                 { id: 3, name: '出料急停', type: 1, position: {top: 130,left: 230},show: false},
                 { id: 4, name: '面板急停', type: 1, position: {top: 160,left: 250},show: false},
                 { id: 5, name: '风箱升超时', type: 1, position: {top: 190,left: 230},show: false},
                 { id: 6, name: '风箱降超时', type: 1, position: {top: 220,left: 250},show: false},
                 { id: 7, name: '风机过流', type: 1, position: {top: 250,left: 230},show: false},
                 { id: 8, name: '滚筒升超时', type: 1, position: {top: 280,left: 250},show: false},
                 { id: 9, name: '滚筒降超时', type: 1, position: {top: 310,left: 230},show: false},
                 { id: 10, name: '滚筒电机过流', type: 1, position: {top: 340,left: 250},show: false},
                 { id: 11, name: '温度失控', type: 1, position: {top: 370,left: 230},show: false},
                 { id: 12, name: '左前门报警', type: 2, position: {top: 100,left: 0},show: false},
                 { id: 13, name: '左后门报警', type: 2, position: {top: 130,left: 20},show: false},
                 { id: 14, name: '右前门报警', type: 2, position: {top: 160,left: 0},show: false},
                 { id: 15, name: '右后门报警', type: 2, position: {top: 190,left: 20},show: false},
                 { id: 16, name: '滚筒不在高位', type: 2, position: {top: 220,left: 0},show: false},
                 { id: 17, name: '风箱不在高位', type: 2, position: {top: 250,left: 20},show: false},
                 { id: 18, name: '风箱不在低位', type: 2, position: {top: 280,left: 0},show: false},
                 { id: 19, name: '加热位传感器报警', type: 2, position: {top: 310,left: 20},show: false},
                 { id: 20, name: '左前风箱高位', type: 2, position: {top: 340,left: 0},show: false},
                 { id: 21, name: '左前风箱低位', type: 2, position: {top: 370,left: 20},show: false},
                 { id: 22, name: '左后风箱高位', type: 2, position: {top: 100,left: 430},show: false},
                 { id: 23, name: '左后风箱低位', type: 2, position: {top: 130,left: 450},show: false},
                 { id: 24, name: '右前风箱高位', type: 2, position: {top: 160,left: 430},show: false},
                 { id: 25, name: '右前风箱低位', type: 2, position: {top: 190,left: 450},show: false},
                 { id: 26, name: '右后风箱高位', type: 2, position: {top: 220,left: 430},show: false},
                 { id: 27, name: '右后风箱低位', type: 2, position: {top: 250,left: 450},show: false},
                 { id: 28, name: '左前滚筒低位', type: 2, position: {top: 280,left: 430},show: false},
                 { id: 29, name: '左后滚筒低位', type: 2, position: {top: 310,left: 450},show: false},
                 { id: 30, name: '右前滚筒低位', type: 2, position: {top: 340,left: 430},show: false},
                 { id: 31, name: '右后滚筒低位', type: 2, position: {top: 370,left: 450},show: false},
                  ],
            }
        },
        mounted() {
            this.mqttData()
        },
        methods: {
            mqttData() {
                //处理实时报警数据
                uni.$on(this.$constant.MQTT_TOPIC_MESSAGE, (data) => {
                    let json = JSON.parse(data);
                    if (json == null || json.data == null || json.topic == null) return false
                    let wdata = json.data
                    let topic = json.topic
                    const realFaultTopic = this.$constant.SERVICE_BROADCAST_TENANT_REAL_FAULT.replace('%s', this
                        .tenantId)
                    const oneceFaultTopic = this.$constant.SERVICE_ONECE_TENANT_REAL_FAULT.replace('%s', this
                        .deviceId)
                    switch (topic) {
                        //topic å®žæ—¶æŠ¥è­¦
                        case realFaultTopic:
                        case oneceFaultTopic:
                            if (wdata.length === 0) return false;
                            this.dataList = wdata
                            this.refreshTime = "更新时间:" + dayjs().format('HH:mm:ss');
                            const realFaultNames =  this.dataList.map(item => item.faultName);
                            const realFaults =    this.allFaults.filter(item=>
                                                realFaultNames.some(name =>
                                                name.startsWith(item.name)
                                                ))
                            this.realFaults = realFaults
                            //处理数据统计
                            this.$emit('handleData', this.dataList)
                            break
                    }
                });
            },
            getFaultItemStyle(item) {
                return {
                    position: 'absolute',
                    top: `${item.position.top}rpx`,
                    left: `${item.position.left}rpx`,
                    fontSize: '24rpx',
                };
            },
            checkFaultType(type) {
                if (type === 1) {
                    return "故障";
                } else if (type === 2) {
                    return "报警";
                }
            },
            coverTime(timestamp) {
                if (timestamp) {
                    return dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')
                }
            },
        },
        computed: {
            tenantId() {
                const userinfo = uni.getStorageSync('userinfo');
                const tenantid = userinfo.loginTenantId
                return tenantid + "";
            },
            deviceId() {
                return uni.getStorageSync(this.$constant.DEVICE_ID);
            }
        },
    }
</script>
<style lang="scss" scoped>
    @import "components/table/helang-table";
    .app {}
    .card-box {
        margin: 20rpx;
        padding: 20rpx;
        box-sizing: border-box;
        background-color: white;
        border-radius: 20rpx;
        font-family: Helvetica Neue, Helvetica, sans-serif;
    }
    .top {
        margin: 0 20rpx;
        border-radius: 0;
        border-top-left-radius: 20rpx;
        border-top-right-radius: 20rpx;
        border-bot-left-radius: 0;
        border-bot-right-radius: 0;
    }
    .center {
        margin: 0 20rpx;
        border-radius: 0;
    }
    .bot {
        margin: 0 20rpx 20rpx 20rpx;
        border-top-left-radius: 0;
        border-top-right-radius: 0;
        border-bot-left-radius: 20rpx;
        border-bot-right-radius: 20rpx;
    }
    .title-box {
        display: flex;
        flex-direction: row;
        align-items: center;
        .left {
            display: flex;
            align-items: center;
            .title {
                margin: 0 10rpx;
                font-weight: bold;
            }
        }
        .right {
            display: flex;
            align-items: center;
            .title {
                margin: 0 10rpx;
                font-weight: bold;
            }
        }
    }
    .info-box {
        margin-top: 20rpx;
        display: flex;
        flex-direction: row;
        align-items: center;
        .left {
            display: flex;
            align-items: center;
            .title {
                margin: 0 10rpx;
            }
        }
        .right {
            display: flex;
            align-items: center;
            .title {
                margin: 0 10rpx;
            }
        }
    }
    .chartsMain {
        width: 100%;
        height: 320rpx;
        padding-top: 15rpx;
        background: #fff;
        margin-bottom: 24rpx;
        border-top: 2rpx solid #f2f2f2;
        .charts {
            width: 50%;
            height: 450rpx;
            box-sizing: border-box;
        }
    }
    .tab-box {
        display: flex;
        justify-content: center;
        /* å¼ºåˆ¶æ°´å¹³å±…中 */
    }
    .swiper {
        height: 2116rpx;
    }
    .swiper-item-view {
        height: 2116rpx;
    }
    .fault-box {
        width: 100%;
        height: 460rpx;
        position: relative;
        .fault-inner {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            padding: 20rpx 0;
            background: transparent;
            overflow: hidden;
            .fault-info {
                position: absolute;
                display: flex;
                align-items: center;
                justify-content: center;
            }
            .fault-tag {
                display: flex;
                align-items: center;
                margin-left: 6rpx;
                height: 28rpx;
                padding: 0 10rpx;
                background: gray;
                border-radius: 5rpx;
                font-size: 22rpx;
                font-weight: bold;
                color: red;
                 white-space: nowrap; /* ä¸æ¢è¡Œ */
                   overflow: hidden; /* è¶…出部分隐藏 */
                   text-overflow: ellipsis; /* è¶…出部分用省略号表示 */
            }
            .fault-marker{
                width: 20rpx;
                height: 20rpx;
                background: red;
                border-radius: 50%;
            }
            .warn-marker{
                width: 24rpx;
                height: 24rpx;
                background: orange;
                border-radius: 50%;
            }
            .fault-text{
                color: red;
            }
            .warn-text{
                color: orange;
            }
            .fault-animal {
                -webkit-animation: scaleout 2s infinite ease-in-out;
                animation: scaleout 2s infinite ease-in-out;
            }
            @-webkit-keyframes scaleout {
                0% {
                    -webkit-transform: scale(1);
                }
                100% {
                    -webkit-transform: scale(1.1);
                    opacity: 0;
                }
            }
            @keyframes scaleout {
                0% {
                    transform: scale(1);
                    -webkit-transform: scale(1);
                }
                100% {
                    transform: scale(1.1);
                    -webkit-transform: scale(1.1);
                    opacity: 0;
                }
            }
        }
    }
    .picBox {
        margin: 0 20rpx;
        background-color: white;
        image {
            border-radius: 8rpx;
            width: 100%;
        }
    }
    .borderTop {
        border-top: 2rpx solid #f2f2f2;
        padding-top: 20rpx;
    }
    // å¼¹å‡ºå±‚背景遮罩start
    .dropdown-mask {
        background: rgba(0, 0, 0, 0.5);
    }
    .lock-page {
        height: 100vh;
        width: 100vw;
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 998;
    }
    // å¼¹å‡ºå±‚背景遮罩end
</style>
pages/tabBar/device.vue
@@ -62,7 +62,7 @@
            <u-skeleton class=" " rows="20" :loading="loading" :title="false">
            <u-skeleton   rows="20" :loading="loading" :title="false">
                <!-- å¦‚果希望其他view跟着页面滚动,可以放在z-paging标签内 -->
                <view class="card-box dynamic shadow" v-for="(item,index) in dataList" :key="index"
                    @click="itemClick(item)">
@@ -133,6 +133,9 @@
                curDate:uni.$u.timeFormat(new Date(), 'yyyy-mm-dd'),
            }
        },
        onTabItemTap : function(e) {
        getApp().globalData.selectTab = e.index
        },
        methods: {
            queryList(pageNo, pageSize) {
                this.loading = true;
pages/tabBar/formula.vue
@@ -54,6 +54,9 @@
    computed: {
    },
    onTabItemTap : function(e) {
    getApp().globalData.selectTab = e.index
    },
    methods: {
      showItem(item){
        console.info(item)
pages/tabBar/general.vue
@@ -1,76 +1,10 @@
<template>
    <view class="app">
        <!--     <view class="cu-custom custom-bar" :style="[{height:CustomBar + 'px'}]">
            <view class="select-equ-box">
                <u-icon name="setting" color="rgb(255,255,255)" :size="20"></u-icon>
                <text style="margin-left: 10rpx;" @click="show">1号干燥机</text>
                <u-icon name="arrow-right" color="rgb(255,255,255)" :size="12"></u-icon>
            </view>
        </view>
         <view class="blank" :style="[{height:CustomBar + 'px'}]">
         </view>
         -->
        <cu-custom  bgColor="bg-gradual-blue" :isBack="false">
            <block slot="content">智能中草药</block>
            <block slot="content">兰浦智能干燥</block>
        </cu-custom>
        <mqtt-view  ref="mqttView"></mqtt-view>
        <u-toast ref="uToast"></u-toast>
        <!--         <view class="card-box dynamic shadow cu-list menu">
            <view class="title-box">
                <view class="left">
                    <uni-text class="cuIcon-titles text-blue"></uni-text>
                    <view class="title">统计</view>
                </view>
            </view>
            <view class="cu-item" style="padding: 0;">
                <view class="content">
                    <image src='/static/me/icon/bianqian.png' class='png' mode='aspectFit'></image>
                    <text class="text-lg">烘干总量</text>
                </view>
                <view class="action">
                    <view class="cu-tag radius bg-blue light">
                        1200kg
                    </view>
                </view>
            </view>
            <view class="cu-item" style="padding: 0;">
                <view class="content">
                    <image src='/static/me/icon/bianqian.png' class='png' mode='aspectFit'></image>
                    <text class="text-lg">烘干时长</text>
                </view>
                <view class="action">
                    <view class="cu-tag radius bg-blue light">
                        300分钟
                    </view>
                </view>
            </view>
            <view class="bxBox">
                <image src="/static/me/icon/bianqian.png" class="png" style="width: 48upx;
    height: 48upx;" mode="aspectFit"></image>
                <view style="padding-left: 10rpx;" class="text-lg">烘干药材</view>
            </view>
            <view class='padding-bottom-sm flex flex-wrap bg-white' style="justify-content: flex-end;">
                <view class="cu-tag margin-right-xs bg-blue light radius">
                    å½“å½’
                </view>
                <view class="cu-tag bg-purple light radius">
                    äººå‚
                </view>
                <view class="cu-tag bg-brown light radius">
                    é¾™é¡»è‰
                </view>
            </view>
        </view> -->
        <view class="card-box dynamic shadow">
            <view class="title-box margin-bottom-sm">
                <view class="left justify-between">
@@ -172,7 +106,7 @@
                    <view class="title">明细</view>
                </view>
            </view>
            <u-skeleton rows="20" :loading="loading" :title="false">
            <view class="data-item" v-for="(item, index) in herbList" :key="item.id" style="padding: 0 10rpx;">
                <view class="flex justify-between text-lg align-center padding-tb-xs">
                    <view class="flex">
@@ -234,7 +168,13 @@
                <u-line color="#f1f1f1" margin="15rpx 0 15rpx 0"></u-line>
            </view>
        
            </u-skeleton>
        </view>
        <mqtt-view ref="mqttView"></mqtt-view>
        <!-- 
        <view class="page-box" v-show="false">
            <view class="order" v-for="(res, index) in dataList" :key="res.id">
@@ -283,7 +223,7 @@
</template>
<script>
    import get from 'lodash.get'
    export default {
     
@@ -302,6 +242,7 @@
                }],
                StatusBar: this.StatusBar,
                CustomBar: this.CustomBar,
                loading: true,
                percent: 50,
                activeColor: '#0081ff',
                monthList: [],
@@ -357,11 +298,6 @@
            }
        },
        onShow() {
            console.info('onShow')
            uni.showTabBarRedDot({
                index: 2 // æ˜¾ç¤ºç¬¬2个tabbar项(索引从0开始)的红点
            });
        },
        mounted() {
@@ -370,20 +306,36 @@
        },
        onReady() {
            //接收报警信息,数据预处理(未打开tab无法接收数据)
            uni.$on(this.$constant.MQTT_TOPIC_MESSAGE, (data) => {
                let json = JSON.parse(data);
                if (json == null || json.data == null || json.topic == null) {
                    return false
                }
                //在报警页面时不显示红点
                if (getApp().globalData.selectTab === 2) {
                    uni.hideTabBarRedDot({
                        index: 2
                    });
                    return false
                }
                let wdata = json.data
                let topic = json.topic
                switch (topic) {
                    //topic å®žæ—¶æŠ¥è­¦
                    case this.$constant.SERVICE_BROADCAST_TENANT_REAL_FAULT.replace('%s', this.tenantId):
                        if (wdata.length > 0) {
                            uni.showTabBarRedDot({
                                index: 2 // æ˜¾ç¤ºç¬¬2个tabbar项(索引从0开始)的红点
                            });
                        }
                        break
                }
            });
            this.$refs.mqttView.initMqtt()
            // uni.getSystemInfo({
            //     success: (res) => {
            //         let deviceId = res.deviceId
            //         if (!deviceId) {
            //             deviceId = 'mobile-' + this.tenantId + '-' + Date.parse(new Date())
            //         }
            //         uni.setStorageSync(this.$constant.DEVICE_ID, 'mobile-' + this.tenantId + '-' + res.deviceId);
            //     }
            // })
            // this.startConnect();
            let month = uni.$u.timeFormat(new Date(), 'yyyy-mm')
            this.getMonth(month)
@@ -393,8 +345,9 @@
        },
        onLoad() {
        onLoad() {},
        onTabItemTap: function(e) {
            getApp().globalData.selectTab = e.index
        },
        methods: {
             
@@ -402,7 +355,7 @@
            async startConnect() {
                var _this = this
                const account = uni.getStorageSync('account');
                const deviceid = uni.getStorageSync(this.$constant.DEVICE_ID);
                if (!account) {
@@ -415,7 +368,7 @@
                    // #ifdef APP-PLUS
                    url: 'wx://' + this.$api.mqttBaseUrl + ':8083/mqtt',
                    // #endif
                    clientId: deviceid,
                    clientId: this.deviceId,
                    username: account.username,
                    password: account.password
                }
@@ -430,9 +383,17 @@
                    console.error(res)
                })
 
                //订阅设备故障广播(广播不在乎客户端id,发送给租户下所有在线的设备)
                //订阅设备实时故障广播(广播不在乎客户端id,发送给租户下所有在线的设备)
                this.$mqttTool.subscribe({
                    topic: this.$constant.SERVICE_BROADCAST_TENANT_REAL_FAULT.replace('%s', this.tenantId),
                    qos: 0
                }).then(res => {
                    console.error(res)
                })
                //订阅设备实时故障(主动请求只发给请求设备)
                this.$mqttTool.subscribe({
                    topic: this.$constant.SERVICE_BROADCAST_TENANT_REAL_FAULT.replace('%s', this.deviceId),
                    qos: 0
                }).then(res => {
                    console.error(res)
@@ -477,17 +438,14 @@
            },
            dayChange(dayInfo) { // ç‚¹å‡»æ—¥æœŸ
                this.model.date = dayInfo.date
                console.log("点击日期", JSON.parse(JSON.stringify(dayInfo)));
                this.getOrderList(dayInfo.date, dayInfo.date);
            },
            monthChange(monthInfo) { // åˆ‡æ¢æœˆä»½
                console.log("切换月份", JSON.parse(JSON.stringify(monthInfo)));
                let m = monthInfo.month
                if (m < 10) {
                    m = '0' + m
                }
                let month = monthInfo.year + '-' + m
                console.info(month)
                this.getMonth(month)
            },
            showValue(value) {
@@ -495,10 +453,6 @@
                    return "--"
                }
                return value
            },
            show(e) {
                console.info(this.CustomBar)
            },
            goCharts(e) {
                uni.navigateTo({
@@ -510,7 +464,11 @@
                    "orderTime_begin": date1 + " 00:00:00",
                    "orderTime_end": date2 + " 23:59:59",
                }
                this.loading = true;
                this.$api.getOrderList(params).then((res) => {
                    setTimeout(()=>{
                        this.loading = false
                    },200)
                    if (res.success) {
                        this.herbList = res.result.records
@@ -533,8 +491,6 @@
                        this.model.batch = this.herbList.length
                        this.model.weight = weight
                        this.model.dryTime = dryTime
                        console.info(this.model)
                    }
                })
            },
@@ -602,7 +558,12 @@
                const userinfo = uni.getStorageSync('userinfo');
                const tenantid = userinfo.loginTenantId
                return   tenantid;
            }
            },
            deviceId() {
                return uni.getStorageSync(this.$constant.DEVICE_ID);
            },
            
        }
@@ -610,7 +571,11 @@
</script>
<style lang="scss" scoped>
    .app {}
    .app {
        width: 100%;
        max-height: 100vh;
        overflow: hidden;
    }
    .custom-bar {
        background-image: linear-gradient(to right, #0381FF, #0381FF);
pages/tabBar/me.vue
@@ -218,6 +218,10 @@
            }
        },
        mounted() {     
        },
        onTabItemTap: function(e) {
            getApp().globalData.selectTab = e.index
        },
        methods: {
            itemClick(mode){
@@ -249,6 +253,9 @@
                uni.reLaunch({
                    url: '/pages/login/login'
                });
                this.$mqttTool.end().then(res => {
                    console.error(res)
                })
            },
            cancel() {
                this.show = false
pages/tabBar/warning.vue
@@ -1,17 +1,21 @@
<template>
    <view class="app">
        <z-paging ref="paging" v-model="dataList" show-refresher-update-time @query="queryList">
            <!-- éœ€è¦å›ºå®šåœ¨é¡¶éƒ¨ä¸æ»šåŠ¨çš„view放在slot="top"的view中,如果需要跟着滚动,则不要设置slot="top" -->
            <template #top>
        <cu-custom bgColor="bg-gradual-blue" :isBack="false" :isRight="true" @rightclick="rclick">
            <block slot="content">报警</block>
        </cu-custom>
        <u-notice-bar text="12:20:10 1车间GM001机台电机过流(电气)报警" mode="closable"></u-notice-bar>
        <!--弹出层start-->
        <view style="width: 100%; position: absolute;z-index: 1000;top:300rpx;padding: 20rpx;" @touchmove.prevent >
            <dropdown-menu v-show="filterMenuShow"@reset='resetMenu'  @change='changeMenu' :list='equList' ref='dropdownMenuRef'/>
                <view style="width: 100%; position: absolute;z-index: 1000;top:300rpx;padding: 20rpx;"
                    @touchmove.prevent>
                    <dropdown-menu v-show="filterMenuShow" @closeMenu="filterMenuShow = false " @reset='resetMenu' @change='changeMenu' :list='equList'
                        ref='dropdownMenuRef' />
            
        </view>
        <view class="lock-page dropdown-mask" @touchmove.prevent @click.stop="1==1" v-if="filterMenuShow"></view>
                <view class="lock-page dropdown-mask" @touchmove.prevent v-if="filterMenuShow"></view>
        
        <!--弹出层end-->
@@ -23,7 +27,7 @@
                        <view class="title">总览</view>
                    </view>
                    <view>
                        <text class="text-gray text-sm">2024-10-01 è‡³ 2024-12-01</text>
                                <text class="text-gray text-sm">{{curDate}}</text>
                    </view>
                </view>
@@ -33,7 +37,7 @@
                <view class="flex">
                    <view class="flex-sub flex flex-direction">
                        <text class="text-df">报警总数</text>
                        <text class="text-bold text-sl margin-top-xs text-red margin-top-sm">10
                                <text class="text-bold text-sl margin-top-xs text-red margin-top-sm">{{count}}
                            <text class="text-gray text-sm margin-left-xs">次</text></text>
                    </view>
@@ -41,41 +45,40 @@
                        <view class="flex-sub flex">
                            <view class="flex flex-direction flex-sub">
                                <text class="text-gray text-xs">报警信息</text>
                                <text class="text-black">
                                    <text class="text-black">机械故障:</text>
                                    <text class="margin-lr-xs text-orange">0</text>
                                    <text class="text-gray text-xs">次</text>
                                </text>
                                        <text class="text-black">故障次数:</text>
                                        <text class="margin-lr-xs text-red text-bold text-xl">{{faultCount}}</text>
                                        <text class="text-gray text-xs"></text>
                            </view>
                            <view class="flex flex-direction flex-sub">
                                <text class="text-white text-xs">电气故障</text>
                                <text class="text-black">
                                    <text class="text-black">电气故障:</text>
                                    <text class="margin-lr-xs text-orange">1</text>
                                    <text class="text-gray text-xs">次</text>
                                </text>
                                        <text class="text-gray text-xs">机台信息</text>
                                        <text class="text-black">故障机台:</text>
                                        <text class="margin-lr-xs text-red">{{faultEqus}}</text>
                                        <text class="text-gray text-xs"></text>
                            </view>
                        </view>
                        <view class="flex-sub flex margin-top-sm">
                                <view class="flex-sub flex">
                            <view class="flex flex-direction flex-sub">
                                <text class="text-gray text-xs">报警信息</text>
                                <text>
                                    <text class="text-black">通信故障:</text>
                                    <text class="margin-lr-xs text-orange">4</text>
                                    <text class="text-gray text-xs">次</text>
                                </text>
                                        <text class="text-white text-xs">报警信息</text>
                                        <text class="text-black">告警次数:</text>
                                        <text class="margin-lr-xs text-orange text-bold text-xl">{{alarmCount}}</text>
                                        <text class="text-gray text-xs"></text>
                            </view>
                            <view class="flex flex-direction flex-sub">
                                <text class="text-white text-xs">其他故障</text>
                                <text class="text-cyan">
                                    <text class="text-black">其他故障:</text>
                                    <text class="margin-lr-xs text-orange">5</text>
                                    <text class="text-gray text-xs">次</text>
                                </text>
                                        <text class="text-white text-xs">机台信息</text>
                                        <text class="text-black">告警机台:</text>
                                        <text class="margin-lr-xs text-orange">{{alarmEqus}}</text>
                                        <text class="text-gray text-xs"></text>
                            </view>
                        </view>
@@ -83,7 +86,7 @@
                    </view>
                </view>
                <view class="margin-top">
                        <view>
                    <u-scroll-list>
                    </u-scroll-list>
@@ -96,258 +99,54 @@
        </view>
        <u-sticky>
            </template>
            <view class="tab-box card-box top dynamic shadow">
                <z-tabs ref="tabs" :active-style="{'font-size':'30rpx','font-weight':'bold'}" :current="tabCurrent"
                    :list="tabList" @change="tabsChange">
                <u-tabs :list="tabList" @click="tabsChange"></u-tabs>
                <!-- <z-tabs ref="tabs" :active-style="{'font-size':'30rpx','font-weight':'bold'}" :current="tabCurrent"
                        :list="tabList" @change="tabsChange"> -->
                    <!-- è‡ªå®šä¹‰å³ä¾§æ’æ§½ -->
                    <!-- <template v-slot:right>
                        <u-icon name="setting"  ></u-icon>
                    </template> -->
                </z-tabs>
            </view>
        </u-sticky>
        <!-- å¯é€šè¿‡è®¾ç½®bar-animate-mode="worm"开启毛毛虫模式-->
        <swiper :style="'height:' + swiperItemHeight[tabCurrent] + 'rpx;'" :current="tabCurrent"
            @transition="swiperTransition" @animationfinish="swiperAnimationfinish">
            <swiper-item :key="0">
                <view :style="'height:' + swiperItemHeight[0] + 'rpx;'">
                    <view class="card-box center dynamic shadow">
                        <view class="title-box margin-bottom-sm">
                            <view style="width: 100vw;" class="left justify-between">
                                <view class="flex align-center">
                                    <uni-text class="cuIcon-titles text-blue"></uni-text>
                                    <view class="title">设备 </view>
                                </view>
                                <view>
                                    <!-- <text class="text-blue text-sm">更多></text> -->
                                </view>
                            </view>
                        </view>
                        <view class="borderTop">
                            <image style="width: 100%;border-radius: 20rpx; " src="../../static/image/pic_gz.jpg"
                                mode="aspectFit"></image>
                        </view>
                    </view>
                    <view class="card-box center dynamic shadow">
                        <view class="title-box margin-bottom-sm">
                            <view style="width: 100vw;" class="left justify-between">
                                <view class="flex align-center">
                                    <uni-text class="cuIcon-titles text-blue"></uni-text>
                                    <view class="title">实时报警 </view>
                                </view>
                                <view>
                                    <!-- <text class="text-blue text-sm">更多></text> -->
                                </view>
                            </view>
                        </view>
                        <view class="borderTop"  v-for="i in 10">
                            <view style="height: 180rpx;display: flex;align-items: center;">
                                <view>
                                    <image style="width: 80rpx;height: 80rpx;margin:20rpx;border-radius: 20rpx; "
                                        src="../../static/image/pic_gz.jpg"></image>
                                </view>
                                <view
                                    style="display: flex;flex: 1;flex-direction: column; justify-content: space-between;  ;height: 100%;padding: 20rpx;">
                                    <view class="text-bold">
                                        æ»šç­’电机过流报警
                                    </view>
                                    <view class="text-gray text-sm">
                                        è®¾å¤‡:1号干燥机
                                    </view>
                                    <view class="text-gray text-sm">
                                        æè¿°:同济堂1号滚筒电机过流报警,需要xxxx处理,东方航空的恢复很快的回复
                                    </view>
                                </view>
                                <view style="width: 100rpx;">{{i}}</view>
                            </view>
                        </view>
                    </view>
                    <view class="card-box bot dynamic shadow">
                        <view style="height: 20rpx;"></view>
                    </view>
                </view>
            </swiper-item>
            <swiper-item :key="1">
                <view :style="'height:' + swiperItemHeight[1] + 'rpx;'">
                    <view class="card-box center dynamic shadow">
                        <view class="title-box margin-bottom-sm">
                            <view style="width: 100vw;" class="left justify-between">
                                <view class="flex align-center">
                                    <uni-text class="cuIcon-titles text-blue"></uni-text>
                                    <view class="title">最近报警</view>
                                </view>
                                <view>
                                    <text class="text-blue text-sm">更多></text>
                                </view>
                            </view>
                        </view>
            <!-- å¦‚果希望其他view跟着页面滚动,可以放在z-paging标签内 -->
            <real-warning ref="realWarining" v-if="tabCurrent === 0" @handleData="realHandleData"></real-warning>
            <his-warning ref="hisWarining" v-else @handleData="hisHandleData"></his-warning>
                        <view class="borderTop">
                            <view class="h-table">
                                <view class="h-tr h-tr-2 ">
                                    <view class="h-td">车间</view>
                                    <view class="h-td">机台</view>
                                    <view class="h-td">时间</view>
                                    <view class="h-td">类型</view>
                                    <view class="h-td">等级</view>
                                </view>
                                <view class="h-tr h-tr-2">
                                    <view class="h-td">001</view>
                                    <view class="h-td">GM001</view>
                                    <view class="h-td">12:00:00</view>
                                    <view class="h-td">机械</view>
                                    <view class="h-td">高</view>
                                </view>
                                <view class="h-tr h-tr-2">
                                    <view class="h-td">001</view>
                                    <view class="h-td">GM001</view>
                                    <view class="h-td">12:00:00</view>
                                    <view class="h-td">通信</view>
                                    <view class="h-td">中</view>
                                </view>
                                <view class="h-tr h-tr-2">
                                    <view class="h-td">001</view>
                                    <view class="h-td">GM001</view>
                                    <view class="h-td">12:00:00</view>
                                    <view class="h-td">电气</view>
                                    <view class="h-td">高</view>
                                </view>
                            </view>
                        </view>
                    </view>
                    <view class="card-box center dynamic shadow">
                        <view class="title-box margin-bottom-sm">
                            <view style="width: 100vw;" class="left justify-between">
                                <view class="flex align-center">
                                    <uni-text class="cuIcon-titles text-blue"></uni-text>
                                    <view class="title">报警统计</view>
                                </view>
                                <view>
                                    <text class="text-gray text-sm"></text>
                                </view>
                            </view>
                        </view>
                        <view class="chartsMain">
                            <qiun-data-charts type="mount" :opts="opts" :animation="true" :chartData="Mount" />
                        </view>
                    </view>
                    <view class="card-box center dynamic shadow">
                        <view class="title-box margin-bottom-sm">
                            <view style="width: 100vw;" class="left justify-between">
                                <view class="flex align-center">
                                    <uni-text class="cuIcon-titles text-blue"></uni-text>
                                    <view class="title">报警对比</view>
                                </view>
                                <view>
                                    <text class="text-gray text-sm"></text>
                                </view>
                            </view>
                        </view>
                        <view class="chartsMain">
                            <qiun-data-charts type="pie" :opts="optsPie" :chartData="PieA" />
                        </view>
                    </view>
                    <view class="card-box center dynamic shadow">
                        <view class="title-box margin-bottom-sm">
                            <view style="width: 100vw;" class="left justify-between">
                                <view class="flex align-center">
                                    <uni-text class="cuIcon-titles text-blue"></uni-text>
                                    <view class="title">报警频率</view>
                                </view>
                                <view>
                                    <text class="text-gray text-sm"></text>
                                </view>
                            </view>
                        </view>
                        <view class="chartsMain">
                            <!-- <qiun-data-charts type="mount" :opts="{extra:{mount:{type:'mount',widthRatio:1.5}}}"
                    :chartData="Mount" /> -->
                            <qiun-data-charts type="word" :chartData="Word" />
                        </view>
                    </view>
                    <view class="card-box bot dynamic shadow">
                        <view class="title-box margin-bottom-sm">
                            <view style="width: 100vw;" class="left justify-between">
                                <view class="flex align-center">
                                    <uni-text class="cuIcon-titles text-blue"></uni-text>
                                    <view class="title">报警分析</view>
                                </view>
                                <view>
                                    <text class="text-gray text-sm"></text>
                                </view>
                            </view>
                        </view>
                        <view class="chartsMain">
                            <qiun-data-charts type="radar" :opts="optsRadar" :chartData="dataRadar" />
                        </view>
                    </view>
                </view>
            </swiper-item>
        </swiper>
        </z-paging>
    </view>
</template>
<script>
    import dropdownMenu from '@/components/drop-down-menu/index.vue'
    import realWarning from './components/realWarning.vue'
    import hisWarning from './components/hisWarning.vue'
    import dayjs from 'dayjs'
    export default {
        components: {
            dropdownMenu
            dropdownMenu,
            realWarning,
            hisWarning
        },
        data() {
            return {
                loading: true,
                // v-model绑定的这个变量不要在分页请求结束中自己赋值!!!
                dataList: [],
                curDate: dayjs().format('YYYY-MM-DD'),
                tabList: [{
                    name: '实时报警',
                    // badge: {
                    //     count: 6
                    // }
                }, {
                    name: '报警统计',
                }],
                equList: [{
                        code: 1,
                        name: '1#干燥机'
@@ -357,206 +156,148 @@
                        name: '2#干燥机'
                    } 
                ],
                model: {},
                //筛选框
                filterMenuShow: false,
                //当前选中tab
                tabCurrent: 0,
                swiperItemHeight: [2800, 2140],
                tabList: [{
                    name: '实时报警',
                    badge: {
                        count: 6
                    }
                }, {
                    name: '报警统计',
                }],
                PieA: {
                    "series": [{
                        "data": [{
                            "name": "机械",
                            "value": 50,
                            "labelText": "机械:50次"
                        }, {
                            "name": "电气",
                            "value": 30,
                            "labelText": "电气:30次"
                        }, {
                            "name": "通信",
                            "value": 20,
                            "labelText": "通信:20次"
                        }, {
                            "name": "其他",
                            "value": 18,
                            "labelText": "其他:18次"
                        }]
                    }]
                },
                dataRadar: {
                    categories: ["机械", "电气", "通信", "其他"],
                    series: [{
                        name: "报警占比",
                        data: [99, 30, 18, 73]
                    }]
                },
                Mount: {
                    "series": [{
                        "data": [{
                            "name": "机械",
                            "value": 82
                        }, {
                            "name": "电气",
                            "value": 63
                        }, {
                            "name": "通信",
                            "value": 86
                        }, {
                            "name": "其他",
                            "value": 65
                        }]
                    }]
                },
                Word: {
                    "series": [{
                        "name": "风机过流",
                        "textSize": 25
                    }, {
                        "name": "后门未关闭",
                        "textSize": 20
                    }, {
                        "name": "风箱升异常",
                        "textSize": 20
                    }, {
                        "name": "电机过流",
                        "textSize": 20
                    }, {
                        "name": "加热位传感器",
                        "textSize": 20
                    }, {
                        "name": "加热时间异常",
                        "textSize": 20
                    }, {
                        "name": "滚筒升异常",
                        "textSize": 20
                    }, {
                        "name": "风箱不在加热位",
                        "textSize": 20
                    }, {
                        "name": "滚筒不在加热位",
                        "textSize": 10
                    }]
                },
                opts: {
                    color: ["#1890FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4",
                        "#ea7ccc"
                    ],
                    padding: [15, 15, 0, 5],
                    enableScroll: false,
                    legend: {
                        show: true
                    },
                    xAxis: {
                        disableGrid: true
                    },
                    yAxis: {
                        gridColor: "rgba(230,230,230,0.6)",
                        data: [
                            {
                                min: 0
                            }
                        ]
                    },
                    extra: {
                        mount: {
                            type: "bar",
                            widthRatio: 0.3,
                            borderWidth: 0,
                            barBorderRadius: [
                                50,
                                50,
                                50,
                                50
                            ],
                            linearType: "custom"
                        }
                //实时报警数据更新时间(一般10s)
                refreshTime: '',
                //报警总数
                count: 0,
                //告警总数
                alarmCount: 0,
                //故障总数
                faultCount: 0,
                //故障机台
                faultEqus: "",
                //告警机台
                alarmEqus: "",
                    }
                },
                optsPie: {
                    color: ["#1890FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4",
                        "#ea7ccc"
                    ],
                    padding: [5, 5, 5, 5],
                    enableScroll: false,
                    extra: {
                        pie: {
                            activeOpacity: 0.5,
                            activeRadius: 10,
                            offsetAngle: 0,
                            labelWidth: 1,
                            border: true,
                            borderWidth: 3,
                            borderColor: "#FFFFFF",
                            linearType: "custom"
        onTabItemTap: function(e) {
            getApp().globalData.selectTab = e.index
        },
        onShow() {
            // //实时故障
            // if(this.tabCurrent === 0){
            //     this.$nextTick(()=>{
            //         this.$refs.realWarining.queryRealFaultData()
            //     })
            // }
            //实时故障
            if (this.tabCurrent === 0) {
                this.queryRealFaultData()
                        }
                    }
                },
                optsRadar: {
                    color: ["#1890FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4",
                        "#ea7ccc"
                    ],
                    padding: [5, 5, 5, 5],
                    dataLabel: true,
                    dataPointShape: false,
                    enableScroll: false,
                    legend: {
                        show: false,
                        position: "right",
                        lineHeight: 25
                    },
                    extra: {
                        radar: {
                            gridType: "circle",
                            gridColor: "#CCCCCC",
                            gridCount: 3,
                            opacity: 1,
                            max: 100,
                            labelShow: true,
                            linearType: "custom",
                            border: false
                        }
                    }
                },
            }
        },
        computed: {
        },
        created() {
        },
        beforeDestroy() {
        onReady() {
            
        },
        methods: {
            mqttTopicMessage(){
            //处理消息逻辑
            switch(topic){
                case _this.$constant.SERVICE_BROADCAST_TENANT_REAL_FAULT.replace('%s', that.tenantId):
                   console.error(that.$constant.SERVICE_BROADCAST_TENANT_REAL_FAULT.replace('%s', that.tenantId))
                   console.error("收到广播")
                   
                break
            queryList(pageNo, pageSize) {
                this.loading = true;
                // ç»„件加载时会自动触发此方法,因此默认页面加载时会自动触发,无需手动调用
                // è¿™é‡Œçš„pageNo和pageSize会自动计算好,直接传给服务器即可
                // æ¨¡æ‹Ÿè¯·æ±‚服务器获取分页数据,请替换成自己的网络请求
                const params = {
                    pageNo: pageNo,
                    pageSize: pageSize,
            }    
                //
                this.$api.querySampleList(params).then((res) => {
                    //     // å°†è¯·æ±‚的结果数组传递给z-paging
                    //实时故障
                    if (this.tabCurrent === 0) {
                        this.queryRealFaultData()
                    }else if(this.tabCurrent === 1){
                        this.$refs.hisWarining.init();
                    }
                    this.$refs.paging.complete(res.result.records);
                    this.loading = false
                }).catch(res => {
                    // å¦‚果请求失败写this.$refs.paging.complete(false);
                    // æ³¨æ„ï¼Œæ¯æ¬¡éƒ½éœ€è¦åœ¨catch中写这句话很麻烦,z-paging提供了方案可以全局统一处理
                    // åœ¨åº•层的网络请求抛出异常时,写uni.$emit('z-paging-error-emit');即可
                    this.$refs.paging.complete(false);
                    this.loading = false
                })
            },
            //tabs通知swiper切换
            tabsChange(item) {
                this.tabCurrent = item.index;
                //重置故障统计数据
                this.count = 0;
                this.alarmCount = 0;
                this.faultCount = 0;
                this.faultEqus = "";
                this.alarmEqus = "";
                //实时故障
                if (this.tabCurrent === 0) {
                    // this.$nextTick(()=>{
                    //     this.$refs.realWarining.queryRealFaultData()
                    // })
                    this.queryRealFaultData()
                    this.curDate = dayjs().format('YYYY-MM-DD');
                }else if(this.tabCurrent === 1){
                    this.curDate = dayjs().subtract(3, 'day').format('YYYY-MM-DD') +" - "+ dayjs().format('YYYY-MM-DD');
                }
            },
            realHandleData(data) {
                if (!data) return false
                this.count = data.length
                this.faultCount = data.filter(item => item.faultType === 1).length;
                this.alarmCount = data.filter(item => item.faultType === 2).length;
                const faultEquList = [...new Set(
                    data
                    .filter(item => item.faultType === 1) // æ ¹æ®æ•…障类型过滤
                    .map(item => {
                        const match = item.equName.match(/(\d+#)/);
                        return match ? match[0] : null; // å¦‚果匹配成功,则返回匹配的编号;否则返回null
                    })
                    .filter(Boolean) // å†æ¬¡è¿‡æ»¤æŽ‰å¯èƒ½å­˜åœ¨çš„null值
                )];
                if (faultEquList) {
                    this.faultEqus = faultEquList.join(',');
                }
                const alarmEquList = [...new Set(
                    data
                    .filter(item => item.faultType === 2) // æ ¹æ®æ•…障类型过滤
                    .map(item => {
                        const match = item.equName.match(/(\d+#)/);
                        return match ? match[0] : null; // å¦‚果匹配成功,则返回匹配的编号;否则返回null
                    })
                    .filter(Boolean) // å†æ¬¡è¿‡æ»¤æŽ‰å¯èƒ½å­˜åœ¨çš„null值
                )];
                if (alarmEquList) {
                    this.alarmEqus = alarmEquList.join(',')
                }
            },
            hisHandleData(data){
               if (!data) return false
               this.count = data.reduce((sum, item) => sum + item.ecount, 0);
               this.faultCount = data.filter(item => item.faultType === 1).reduce((sum, item) => sum + item.ecount, 0);
               this.alarmCount = data.filter(item => item.faultType === 2).reduce((sum, item) => sum + item.ecount, 0);
            },
            changeMenu(selectData){
                console.info(selectData)
@@ -570,22 +311,50 @@
            },
            rclick() {
                this.filterMenuShow=!this.filterMenuShow
            },
            //tabs通知swiper切换
            tabsChange(index) {
                this.tabCurrent = index;
            },
            //swiper滑动中
            swiperTransition(e) {
                this.$refs.tabs.setDx(e.detail.dx);
            },
            //swiper滑动结束
            swiperAnimationfinish(e) {
                this.tabCurrent = e.detail.current;
                this.$refs.tabs.unlockDx();
                if (this.filterMenuShow) {
                    uni.pageScrollTo({
                        scrollTop: 0,
                        duration: 300 // æ»šåŠ¨åŠ¨ç”»æŒç»­æ—¶é—´ï¼Œå•ä½ä¸ºæ¯«ç§’
                    });
                }
            },
            queryRealFaultData() {
                //发送数据
                const message = {
                    req: this.deviceId,
                    tenantId: this.tenantId,
                    timeStamp: new Date(),
        }
                let opts = {
                    topic: this.$constant.MOBILE_REQ_EQU_REAL_FAULT,
                    message: JSON.stringify(message),
                }
                this.$mqttTool.publish(opts).then(res => {
                    //console.error(res)
                })
            },
        },
        onReady() {
        },
        computed: {
            tenantId() {
                const userinfo = uni.getStorageSync('userinfo');
                const tenantid = userinfo.loginTenantId
                return tenantid + "";
            },
            deviceId() {
                return uni.getStorageSync(this.$constant.DEVICE_ID);
            },
        },
    }
</script>
@@ -593,8 +362,13 @@
    @import "components/table/helang-table";
    .app {
        position: relative;
        width: 100%;
        max-height: 100vh;
        overflow: hidden;
    }
    .card-box {
        margin: 20rpx;
@@ -741,6 +515,7 @@
    .dropdown-mask {
        background: rgba(0, 0, 0, 0.5);
    }
    .lock-page {
        height: 100vh;
        width: 100vw;
@@ -751,5 +526,6 @@
        bottom: 0;
        z-index: 998;
    }
    // å¼¹å‡ºå±‚背景遮罩end
</style>
readMe.txt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,3 @@
注意事项
一、《云服务》和《局域网》不同模式下部分接口有所不同
1.
store/index.js
@@ -4,23 +4,27 @@
 
const store = new Vuex.Store({
  state: {
    // å®šä¹‰cid默认值
    cid: null
    // è®¾å¤‡å”¯ä¸€æ ‡è¯†ï¼ŒæŽ¨é€ä½¿ç”¨
    clientPushId: null,
  },
  mutations: {
    setCid(state, cid) {
          state.cid = cid;
    setClientPushId(state, clientPushId) {
          state.clientPushId = clientPushId;
    },
  },
  actions: {
    setCid({ commit }, cid) {
         commit('setCid', cid);
    setClientPushId({ commit }, clientPushId) {
         commit('setClientPushId', clientPushId);
       },
  },
  getters: {
   getCid(state) {
         return state.cid;
       }
   getClientPushId(state) {
         return state.clientPushId;
       },
  }
});