Novecane
2025-02-15 d13e470cf0256e3ffbc3b0ad34df27ce0b0b5e5f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
<template>
    <view class="container">
        <view class="info-section">
            <image src="/assets/device.png" mode="aspectFit" class="device-image"></image>
            <view class="device-info">
                <text class="title">{{state.facilityName}}</text>
                <text class="sn">SN: {{state.facilityCode}}</text>
            </view>
            <view class="status-grid">
                <view class="status-item">
                    <text class="status-label" style="color: #38b231;" v-if="state.isOnLine==1">在线</text>
                    <text class="status-label" style="color: red;" v-else>离线</text>
                </view>
                <view class="status-item">
                    <text class="status-label">太阳能{{ state.dcInputVolt }}</text>
                </view>
                <view class="status-item">
                    <text class="status-label">信号{{state.rssi}}</text>
                </view>
            </view>
        </view>
        <view class="control-section">
            <text class="section-title">实时控制</text>
            <slider @change="handleControlChange" min="100" max="200" step="25" active-color="#007aff"
                :value="controlValue" style="width: 650rpx;
                 margin-left: 0rpx;
                 " :disabled="flag" />
            <view class="scale-labels">
                <text style="color: #38b231;">开</text>
                <text>125</text>
                <text>150</text>
                <text>175</text>
                <text style="color: red;
                margin-right: 10rpx;
                ">关</text>
            </view>
        </view>
        <view class="log-section">
            <text class="section-title">设备操作记录</text>
            <scroll-view class="log-box" scroll-y="true">
                <view class="log-entry" v-for="(item,index) in logEntry" :key="index">
                    <view class="opName">{{item.operateName}}</view>
                    <view class="opSta">{{item.operateStatus }}</view>
                    <view class="opTime">{{item.createTimeView}}</view>
                </view>
            </scroll-view>
        </view>
        <button class="remove-btn" @click="removeSharedDevice">移除设备</button>
    </view>
</template>
 
<script setup>
    import {
        ref,
        onMounted,
        watch
    } from 'vue';
    import {
        getDeviceInfoByDeviceId,
        deleteDevice,
        deviceControlInfo,
        getOpeInfo,
        getControlInfo
    } from '@/api/index.js';
 
    const state = ref({});
    const controlValue = ref(100); // 初始化控制值
    const logEntry = ref([]);
    const temp = ref({});
    const controInfo = ref({});
    // 看是否禁止使用滑动条
    const flag = ref(false);
    // 定义一个变量来存储定时器ID
    let positionInterval;
 
    // 生命周期钩子 - 相当于 Vue 2 的 onLoad
    onMounted(async () => {
        const option = getCurrentPages()[getCurrentPages().length - 1].options;
        const deviceInfo = JSON.parse(decodeURIComponent(option.device));
        state.value = deviceInfo;
        // 获取操作记录
        getOpeHistory();
        // 获取实时控制数据
        getControlData();
        try {
            const res = await getDeviceInfoByDeviceId(deviceInfo.facilityCode);
            state.value = {
                ...res.data,
                ...deviceInfo
            };
        } catch (error) {
            console.error('Failed to fetch device info:', error);
        }
    }, );
 
    const startGetPosition = () => {
        // 如果定时器已经存在,则先清除它
        if (positionInterval) {
            clearInterval(positionInterval);
        }
        uni.showToast({
            title:"操作设备中",
            icon:"loading",
            mask:true,
            duration:3500
        })
        // 设置定时器
        positionInterval = setInterval(() => {
            getControlInfo(state.value.facilityCode).then((res) => {
                if (res.data.position >= 100) {
                    flag.value = false;
                    clearInterval(positionInterval); // 使用存储的定时器ID来清除定时器
                }
            }).catch((error) => {
                console.error('Error fetching control info:', error); // 错误处理
                clearInterval(positionInterval); // 如果请求失败,清除定时器
            });
        }, 2000);
    }
 
 
    /**
     * 方法
     */
    const removeSharedDevice = async () => {
        temp.value = {
            facilityCode: state.value.facilityCode
        };
        try {
            const res = await deleteDevice(temp.value);
            if (res.code === 200) {
                // 删除成功 返回首页面
                uni.redirectTo({
                    url: "/pages/layout/index"
                });
            } else {
                // 删除失败 提示失败信息
                uni.showToast({
                    title: '设备删除失败',
                    icon: 'fail'
                });
            }
        } catch (error) {
            console.error('Failed to delete device:', error);
        }
    };
    // 实时控制
    const handleControlChange = (e) => {
        controInfo.value = {
            sn: state.value.facilityCode,
            destinationPosition: e.detail.value
        };
        deviceControlInfo(controInfo.value).then((res) => {
            if (res.code === 200) {
                //  禁止使用滑动条
                flag.value = true;
                // 启动定时器
                startGetPosition();
            }
        }).catch((error) => {
            console.error('Failed to control device:', error);
        });
 
    };
 
 
    //操作记录
    const getOpeHistory = () => {
        getOpeInfo(state.value.facilityCode).then((res) => {
            if (res.code === 200) {
                // 渲染列表数据到页面上
                logEntry.value = res.data
            }
        }).catch((e) => {
            console.log("fail info", e);
        })
    }
    // 获取上一次设备的实时控制信息
    const getControlData = () => {
        getControlInfo(state.value.facilityCode).then((res) => {
            controlValue.value = res.data.position;
        })
    }
</script>
 
 
<style scoped lang="scss">
    .container {
        padding: 20rpx;
        background-color: #f5f5f5;
    }
 
    .info-section {
        background: white;
        border-radius: 12rpx;
        padding: 20rpx;
        margin-bottom: 20rpx;
    }
 
    .device-image {
        width: 100%;
        height: 300rpx;
        margin-bottom: 20rpx;
    }
 
    .device-info {
        margin-bottom: 30rpx;
 
        .title {
            font-size: 36rpx;
            font-weight: bold;
            display: block;
            text-align: center;
            margin-bottom: 10rpx;
        }
 
        .sn {
            font-size: 28rpx;
            color: #666;
            display: block;
            text-align: center;
        }
    }
 
    .status-grid {
        display: flex;
        justify-content: space-between;
 
        .status-item {
            flex: 1;
            text-align: center;
            padding: 15rpx;
            background: #f8f8f8;
            border-radius: 8rpx;
            margin: 0 5rpx;
 
            .status-label {
 
                font-size: 28rpx;
                color: #333;
            }
        }
    }
 
    .control-section {
        background: white;
        padding: 20rpx;
        border-radius: 12rpx;
        margin-bottom: 20rpx;
 
        .section-title {
            font-size: 32rpx;
            font-weight: bold;
            display: block;
            margin-bottom: 20rpx;
        }
 
        .scale-labels {
            display: flex;
            justify-content: space-between;
            margin-top: 10rpx;
            padding: 0rpx;
            color: #666;
            font-size: 26rpx;
        }
    }
 
    .log-section {
        background: white;
        padding: 20rpx;
        border-radius: 12rpx;
        height: 450rpx;
 
        .section-title {
            font-size: 32rpx;
            font-weight: bold;
            display: block;
            margin-bottom: 20rpx;
        }
 
        .log-box {
            height: 80%;
            width: 95%;
            padding: 15rpx;
            background: #f8f8f8;
            border-radius: 8rpx;
            display: flex;
            flex-direction: row;
 
            .log-entry {
                display: flex;
                flex-direction: row;
                justify-content: space-between;
                font-size: 26rpx;
                color: #333;
 
                .opName {}
 
                .opSta {}
 
                .opTime {}
            }
        }
    }
 
    .remove-btn {
        margin-top: 40rpx;
        background: #ff3b30;
        color: white;
        border-radius: 50rpx;
        font-size: 32rpx;
        height: 80rpx;
        line-height: 80rpx;
    }
</style>