|
@@ -0,0 +1,514 @@
|
|
|
+<template>
|
|
|
+ <view class="device-info-wrap info-wrap">
|
|
|
+ <panel>
|
|
|
+ <template v-slot:header>
|
|
|
+ <up-icon size="28rpx" :name="list"></up-icon>
|
|
|
+ 告警信息
|
|
|
+ <up-tag
|
|
|
+ :text="state.deviceInfo.statusName"
|
|
|
+ plain
|
|
|
+ size="mini"
|
|
|
+ :bgColor="valueToConst(DeviceState,state.deviceInfo.status).color"
|
|
|
+ class="tag-stat"/>
|
|
|
+ </template>
|
|
|
+ <template v-slot:content>
|
|
|
+ <view class="order-info" style="width: 100%">
|
|
|
+ <view class="mix-wrap">
|
|
|
+ <view class="info-column">
|
|
|
+ <label-text
|
|
|
+ label="所属产品"
|
|
|
+ :text="formatTxt(state.deviceInfo.productName)"
|
|
|
+ />
|
|
|
+ <label-text
|
|
|
+ label="设备编码"
|
|
|
+ :line="2"
|
|
|
+ :text="formatTxt(state.deviceInfo.name)"
|
|
|
+ />
|
|
|
+ <label-text
|
|
|
+ label="设备类型"
|
|
|
+ :text="formatTxt(state.deviceInfo.deviceTypeName)"
|
|
|
+ />
|
|
|
+ <label-text
|
|
|
+ label="设备厂家"
|
|
|
+ :text="formatTxt(state.deviceInfo.manufactor)"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <u--image
|
|
|
+ :showLoading="true"
|
|
|
+ :src="getDevImg(state.deviceInfo.devImg)"
|
|
|
+ width="160rpx"
|
|
|
+ height="150rpx"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="line-info-wrap">
|
|
|
+ <label-text
|
|
|
+ label="第三方设备编码"
|
|
|
+ :text="formatTxt(state.deviceInfo.thirdDevCode)"
|
|
|
+ />
|
|
|
+ <label-text
|
|
|
+ label="最新在线时间"
|
|
|
+ :text="formatTxt(state.deviceInfo.lastOnlineTime)"
|
|
|
+ />
|
|
|
+ <label-text
|
|
|
+ label="最后通讯时间"
|
|
|
+ :text="formatTxt(state.deviceInfo.lastReportTime)"
|
|
|
+ />
|
|
|
+ <label-text
|
|
|
+ label="位置"
|
|
|
+ :line="2"
|
|
|
+ :text="formatTxt(state.deviceInfo.locationStr)"
|
|
|
+ />
|
|
|
+ <label-text
|
|
|
+ label="描述"
|
|
|
+ :line="3"
|
|
|
+ :text="formatTxt(state.deviceInfo.description)"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
+ </panel>
|
|
|
+ <panel>
|
|
|
+ <template v-slot:header>
|
|
|
+ <up-icon size="28rpx" :name="list"></up-icon>
|
|
|
+ 设备调试
|
|
|
+ </template>
|
|
|
+ <template v-slot:content>
|
|
|
+ <up-cell-group :border="false">
|
|
|
+ <up-cell title="选择服务" :isLink="true" arrow-direction="left-arrow" @click="state.serviceShow = true">
|
|
|
+ <template v-slot:value>
|
|
|
+ <up-text v-if="state.selectedService" :lines="1" align="right" :text="state.selectedService.name"/>
|
|
|
+ </template>
|
|
|
+ </up-cell>
|
|
|
+ <up-cell
|
|
|
+ v-if="state.selectedService && state.selectedService.inputData"
|
|
|
+ v-for="item in state.selectedService.inputData"
|
|
|
+ :key="item.identifier"
|
|
|
+ :title="item.name"
|
|
|
+ :isLink="false"
|
|
|
+ >
|
|
|
+ <template #value>
|
|
|
+ <up-input
|
|
|
+ :placeholder="`请输入${item.name}`"
|
|
|
+ v-model="state.orderInfo[item.identifier]"
|
|
|
+ ></up-input>
|
|
|
+ </template>
|
|
|
+ </up-cell>
|
|
|
+ <up-cell :border="false">
|
|
|
+ <template v-slot:value>
|
|
|
+ <up-button type="primary" size="small" text="下发指令" @click="onCommand"></up-button>
|
|
|
+ </template>
|
|
|
+ </up-cell>
|
|
|
+ </up-cell-group>
|
|
|
+ </template>
|
|
|
+ </panel>
|
|
|
+ <panel>
|
|
|
+ <template v-slot:header>
|
|
|
+ <up-icon size="28rpx" :name="list"></up-icon>
|
|
|
+ 运行状态
|
|
|
+ </template>
|
|
|
+ <template v-slot:content>
|
|
|
+ <up-cell-group :border="false">
|
|
|
+ <up-cell
|
|
|
+ v-for="(item,index) in state.metaInfo.dataMetaRunInfo"
|
|
|
+ :title="`${item.name}(${item.identifier})`"
|
|
|
+ :key="index"
|
|
|
+ size="small"
|
|
|
+ >
|
|
|
+ <template v-slot:label>
|
|
|
+ <view class="meta-data">
|
|
|
+ <up-text
|
|
|
+ :lines="1"
|
|
|
+ :text="`${item.data}${item.data && JSON.parse(item.dataType).specs.unit ? JSON.parse(item.dataType).specs.unit:''}`"
|
|
|
+ size="30rpx"
|
|
|
+ :bold="true"
|
|
|
+ >
|
|
|
+ </up-text>
|
|
|
+ <up-text
|
|
|
+ :lines="1"
|
|
|
+ :text="formatTxt(item.timeStamp)"
|
|
|
+ size="20rpx"
|
|
|
+ >
|
|
|
+ </up-text>
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
+ </up-cell>
|
|
|
+ </up-cell-group>
|
|
|
+ </template>
|
|
|
+ </panel>
|
|
|
+ <up-tabbar
|
|
|
+ :fixed="true"
|
|
|
+ :placeholder="false"
|
|
|
+ :safeAreaInsetBottom="false"
|
|
|
+ >
|
|
|
+ <view class="warning-btn" @click="state.handleForm=true">报废</view>
|
|
|
+ <view class="def-btn"
|
|
|
+ v-if="DeviceState.UNACTIVATED.value !== state.deviceInfo.status"
|
|
|
+ @click="state.showDisableModal = true">禁用
|
|
|
+ </view>
|
|
|
+ <view
|
|
|
+ class="def-btn"
|
|
|
+ v-if="DeviceState.UNACTIVATED.value === state.deviceInfo.status"
|
|
|
+ @click="state.showEnableModal = true"
|
|
|
+ >激活
|
|
|
+ </view>
|
|
|
+ </up-tabbar>
|
|
|
+ <up-action-sheet
|
|
|
+ :show="state.handleForm"
|
|
|
+ @close="state.handleForm = false"
|
|
|
+ title="报废设备"
|
|
|
+ :round="10"
|
|
|
+ >
|
|
|
+ <view class="action-content common-form">
|
|
|
+ <up-form
|
|
|
+ labelPosition="left"
|
|
|
+ :model="state.model"
|
|
|
+ :rules="state.rules"
|
|
|
+ ref="formRef"
|
|
|
+ labelWidth="120"
|
|
|
+ >
|
|
|
+ <up-form-item
|
|
|
+ label="设备名称"
|
|
|
+ borderBottom
|
|
|
+ :required="true"
|
|
|
+ >
|
|
|
+ <up-input
|
|
|
+ :modelValue="state.deviceInfo.deviceNickname"
|
|
|
+ border="none"
|
|
|
+ disabled
|
|
|
+ ></up-input>
|
|
|
+ </up-form-item>
|
|
|
+ <up-form-item
|
|
|
+ label="设备编码"
|
|
|
+ borderBottom
|
|
|
+ :required="true"
|
|
|
+ >
|
|
|
+ <up-input
|
|
|
+ :modelValue="state.deviceInfo.name"
|
|
|
+ border="none"
|
|
|
+ disabled
|
|
|
+ ></up-input>
|
|
|
+ </up-form-item>
|
|
|
+
|
|
|
+ <up-form-item
|
|
|
+ label="报废时间"
|
|
|
+ prop="order.startDate"
|
|
|
+ borderBottom
|
|
|
+ :required="true"
|
|
|
+ @click="state.showStartClendar = true; hideKeyboard()"
|
|
|
+ >
|
|
|
+ <up-input
|
|
|
+ :modelValue="timestampToDate(state.model.order.startDate)"
|
|
|
+ disabled
|
|
|
+ disabledColor="#ffffff"
|
|
|
+ placeholder="请选择预计开始日期"
|
|
|
+ border="none"
|
|
|
+ ></up-input>
|
|
|
+ <template #right>
|
|
|
+ <up-icon
|
|
|
+ name="arrow-right"
|
|
|
+ ></up-icon>
|
|
|
+ </template>
|
|
|
+ </up-form-item>
|
|
|
+ <up-form-item
|
|
|
+ label="报废原因"
|
|
|
+ borderBottom
|
|
|
+ >
|
|
|
+ <up-textarea
|
|
|
+ placeholder="报废原因"
|
|
|
+ v-model="state.model.order.desc"
|
|
|
+ ></up-textarea>
|
|
|
+ </up-form-item>
|
|
|
+ <up-button @click="submit" style="margin-top: 20rpx;">提交</up-button>
|
|
|
+ </up-form>
|
|
|
+ </view>
|
|
|
+ </up-action-sheet>
|
|
|
+ <up-action-sheet
|
|
|
+ :actions="state.serviceList"
|
|
|
+ @select="selectClick"
|
|
|
+ title="选择服务"
|
|
|
+ :show="state.serviceShow"
|
|
|
+ @close="state.serviceShow = false"
|
|
|
+ :closeOnClickOverlay="true"
|
|
|
+ />
|
|
|
+ <up-modal
|
|
|
+ :show="state.showDisableModal"
|
|
|
+ title="禁用设备"
|
|
|
+ :closeOnClickOverlay="true"
|
|
|
+ :showCancelButton="true"
|
|
|
+ @close="state.showDisableModal = false"
|
|
|
+ @cancel="state.showDisableModal = false"
|
|
|
+ @confirm="onConfirmDisable"
|
|
|
+ >
|
|
|
+ <view class="modal-content">
|
|
|
+ 设备禁用后将导致该设备无法连接
|
|
|
+ </view>
|
|
|
+ </up-modal>
|
|
|
+ <up-modal
|
|
|
+ :show="state.showEnableModal"
|
|
|
+ title="启用设备"
|
|
|
+ :closeOnClickOverlay="true"
|
|
|
+ :showCancelButton="true"
|
|
|
+ @close="state.showEnableModal = false"
|
|
|
+ @cancel="state.showEnableModal = false"
|
|
|
+ @confirm="onConfirmEnable"
|
|
|
+ >
|
|
|
+ <view class="modal-content">
|
|
|
+ 设备禁用后将导致该设备无法连接
|
|
|
+ </view>
|
|
|
+ </up-modal>
|
|
|
+ <up-datetime-picker
|
|
|
+ :show="state.showStartClendar"
|
|
|
+ v-model="state.model.order.startDate"
|
|
|
+ mode="datetime"
|
|
|
+ @close="state.showStartClendar = false"
|
|
|
+ :closeOnClickOverlay="true"
|
|
|
+ @confirm="(e)=>confirm(e,'showStartClendar')"
|
|
|
+ @cancel="state.showStartClendar = false"
|
|
|
+ ></up-datetime-picker>
|
|
|
+ <up-toast ref="uToastRef"></up-toast>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+
|
|
|
+import list from "@/static/aiot/list.svg";
|
|
|
+import Panel from "@/components/pannel/index.vue";
|
|
|
+import LabelText from "@/components/labeltext/index.vue";
|
|
|
+import {onMounted, reactive, ref} from 'vue';
|
|
|
+import {
|
|
|
+ deviceServiceApply,
|
|
|
+ forbidDevice,
|
|
|
+ getDeviceDetail,
|
|
|
+ getDeviceMeta,
|
|
|
+ getDeviceService,
|
|
|
+ scrapDevice,
|
|
|
+ startDevice
|
|
|
+} from "@/api/device.js";
|
|
|
+import {onLoad} from "@dcloudio/uni-app";
|
|
|
+import {DateFormat, formatTxt, getDevImg, hideKeyboard, reloadPage, timestampToDate} from "@/util/index.js";
|
|
|
+import {valueToConst} from "@/common/consts/CommonConst.js";
|
|
|
+import {DeviceState} from "@/common/consts/DeviceConst.js";
|
|
|
+import dayjs from "dayjs";
|
|
|
+
|
|
|
+const uToastRef = ref(null)
|
|
|
+const state = reactive({
|
|
|
+ handleForm: false,
|
|
|
+ showDisableModal: false,
|
|
|
+ showEnableModal: false,
|
|
|
+ deviceInfo: {},
|
|
|
+ serviceShow: false,
|
|
|
+ metaInfo: {
|
|
|
+ dataMetaRunInfo: [],
|
|
|
+ dataOnlineRunInfo: [],
|
|
|
+ },
|
|
|
+ model: {
|
|
|
+ order: {
|
|
|
+ startDate: dayjs().valueOf(),
|
|
|
+ desc: '',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ rules: {
|
|
|
+ 'order.startDate': [
|
|
|
+ {required: true, message: '请选择报废日期'},
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ serviceDic: {},
|
|
|
+ serviceList: [],
|
|
|
+ selectedService: null,
|
|
|
+ orderInfo: {}
|
|
|
+});
|
|
|
+const deviceId = ref('')
|
|
|
+onLoad((option) => {
|
|
|
+ deviceId.value = option.id
|
|
|
+});
|
|
|
+onMounted(() => {
|
|
|
+ getDeviceDetail(deviceId.value).then((data) => {
|
|
|
+ state.deviceInfo = data
|
|
|
+
|
|
|
+ if (data.metadataId) {
|
|
|
+ qryDeviceService(data.metadataId);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ getDeviceMeta(deviceId.value).then((res) => {
|
|
|
+ if (res.metadataList) {
|
|
|
+ state.metaInfo.dataMetaRunInfo = res.metadataList.filter((item) => item.disply !== false);
|
|
|
+ }
|
|
|
+ if (res.onlineList.type) {
|
|
|
+ state.metaInfo.dataOnlineRunInfo = res.onlineList
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+});
|
|
|
+const onConfirmDisable = () => {
|
|
|
+ forbidDevice([deviceId.value]).then(() => {
|
|
|
+ uni.showToast({title: '操作成功', icon: "success"});
|
|
|
+ state.showDisableModal = false;
|
|
|
+ })
|
|
|
+};
|
|
|
+const qryDeviceService = (metaId) => {
|
|
|
+ getDeviceService({
|
|
|
+ metadataId: metaId
|
|
|
+ }).then((res) => {
|
|
|
+ if (res && res.length > 0) {
|
|
|
+ state.serviceList = res.map((item) => {
|
|
|
+ const {identifier, inputData, name} = item;
|
|
|
+ const inputDataFormat = JSON.parse(inputData);
|
|
|
+ state.serviceDic[identifier] = {
|
|
|
+ identifier,
|
|
|
+ name,
|
|
|
+ inputData: inputDataFormat
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ name: name,
|
|
|
+ value: identifier,
|
|
|
+ inputData: inputDataFormat
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+const onConfirmEnable = () => {
|
|
|
+ state.showEnableModal = false;
|
|
|
+ startDevice([deviceId.value]).then(() => {
|
|
|
+ uni.showToast({title: '操作成功', icon: "success"});
|
|
|
+ state.showEnableModal = false;
|
|
|
+ })
|
|
|
+}
|
|
|
+const confirm = (e, type) => {
|
|
|
+ state[type] = false;
|
|
|
+};
|
|
|
+const submit = () => {
|
|
|
+ hideKeyboard()
|
|
|
+ let formData = {
|
|
|
+ id: deviceId.value,
|
|
|
+ isScrap: true,
|
|
|
+ scrapReason: state.model.order.desc,
|
|
|
+ scrapTimeStr: timestampToDate(state.model.order.startDate, DateFormat.YYYYMMDDHHMMSS),
|
|
|
+ };
|
|
|
+
|
|
|
+ scrapDevice(formData).then(() => {
|
|
|
+ state.handleForm = false;
|
|
|
+ uToastRef.value.show({
|
|
|
+ type: 'default',
|
|
|
+ message: "操作成功",
|
|
|
+ complete() {
|
|
|
+ uni.$emit('refreshData', {refresh: true});
|
|
|
+ uni.navigateBack({
|
|
|
+ delta: 1
|
|
|
+ })
|
|
|
+ }
|
|
|
+ });
|
|
|
+ })
|
|
|
+}
|
|
|
+const selectClick = (e) => {
|
|
|
+ state.serviceShow = false;
|
|
|
+ state.selectedService = e;
|
|
|
+ state.orderInfo = {};
|
|
|
+}
|
|
|
+
|
|
|
+const onCommand = () => {
|
|
|
+ if (!state.orderInfo) {
|
|
|
+ uToastRef.value.show({
|
|
|
+ type: 'error',
|
|
|
+ message: "请输入指令",
|
|
|
+ });
|
|
|
+ return
|
|
|
+ }
|
|
|
+ deviceServiceApply(deviceId.value, state.selectedService.value, state.orderInfo).then(() => {
|
|
|
+ uToastRef.value.show({
|
|
|
+ type: 'default',
|
|
|
+ message: "操作成功",
|
|
|
+ complete() {
|
|
|
+ reloadPage();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ })
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+
|
|
|
+<style lang="scss">
|
|
|
+.device-info-wrap {
|
|
|
+ padding-bottom: 140rpx;
|
|
|
+
|
|
|
+ .panel-wrap {
|
|
|
+ margin-bottom: $uni-block-gap;
|
|
|
+ }
|
|
|
+
|
|
|
+ .mix-wrap {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+
|
|
|
+ .info-column {
|
|
|
+ display: flex;
|
|
|
+ flex: 1;
|
|
|
+ align-items: flex-start;
|
|
|
+ justify-content: flex-start;
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .panel-content {
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 15px 15px 15px 15px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .label-text-wrap {
|
|
|
+ margin-top: $uni-text-gap;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stepper-container {
|
|
|
+ .title-date {
|
|
|
+ margin-left: auto;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .u-tabbar__content__item-wrapper {
|
|
|
+ padding-bottom: 40rpx;
|
|
|
+
|
|
|
+
|
|
|
+ > view {
|
|
|
+ box-sizing: border-box;
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ color: $uni-bg-color;
|
|
|
+
|
|
|
+ &:not(:last-child) {
|
|
|
+ border-right: 2rpx solid #fefefe47;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .warning-btn {
|
|
|
+ background-color: $uni-color-error;
|
|
|
+ }
|
|
|
+
|
|
|
+ .def-btn {
|
|
|
+ background-color: $uni-color-primary;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .u-cell-group {
|
|
|
+ .u-cell {
|
|
|
+ margin-bottom: $uni-text-gap;
|
|
|
+
|
|
|
+ .u-cell__body {
|
|
|
+ padding: 0;
|
|
|
+ min-height: 70rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .meta-data {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ }
|
|
|
+
|
|
|
+ .action-content {
|
|
|
+ padding: 0 $uni-pop-padding;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|