1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315 |
- <template>
- <div class="page bg page-full">
- <div class="content">
- <div class="cont_box" style="align-items: center">
- <!-- 设备 -->
- <div class="title">{{$t('message.device.formI18nOption.device')}}:{{ detail.name }}</div>
- <!-- 未启用 -->
- <el-tag v-if="areaData.status === 0" type="info" style="margin-left: 20px">{{ $t('message.device.formI18nOption.off') }}</el-tag>
- <!-- 离线 -->
- <el-tag v-else-if="areaData.status === 1" type="danger" style="margin-left: 20px">{{ $t('message.device.formI18nOption.offline') }}</el-tag>
- <!-- 在线 -->
- <el-tag v-else-if="areaData.status === 2" type="success" style="margin-left: 20px">{{ $t('message.device.formI18nOption.online') }}</el-tag>
- </div>
- </div>
- <div class="content-box page-full-part page-full">
- <el-tabs v-model="activeName" @tab-click="handleClick">
- <!-- 运行状态 -->
- <el-tab-pane :label="$t('message.device.runStatus')" name="3">
- <div style="display: flex; flex-wrap: wrap">
- <div class="ant-card">
- <div class="ant-card-body">
- <div class="cardflex">
- <div>{{ $t('message.device.deviceStatus') }}</div>
- <div @click="getrunData()" style="cursor: pointer">
- <el-icon style="font-size: 18px">
- <ele-Refresh />
- </el-icon>
- </div>
- </div>
- <!-- 未启用 -->
- <div class="statusname" v-if="areaData.status == 0">{{ $t('message.device.formI18nOption.off') }}</div>
- <!-- 离线 -->
- <div class="statusname" v-if="areaData.status == 1">{{ $t('message.device.formI18nOption.offline') }}</div>
- <!-- 在线 -->
- <div class="statusname" v-if="areaData.status == 2">{{ $t('message.device.formI18nOption.online') }}</div>
- <div class="cardflex comtest">
- <div>{{$t('message.device.dataTime')}}</div>
- <div>{{ areaData.lastOnlineTime || $t('message.device.formI18nOption.off') }}</div>
- </div>
- </div>
- </div>
- <div class="ant-card" v-for="(item, index) in areaData.properties" :key="index">
- <div class="ant-card-body">
- <div class="cardflex">
- <div>{{ item.name }}</div>
- <div style="cursor: pointer">
- <el-icon style="font-size: 18px" @click="getrunData()">
- <ele-Refresh />
- </el-icon>
- <el-icon style="font-size: 18px; margin-left: 10px" @click="onOpenListDetail(item)">
- <ele-Expand />
- </el-icon>
- <el-icon style="font-size: 18px; margin-left: 10px" @click="onOpenChartDetail(item)">
- <ele-DataLine />
- </el-icon>
- </div>
- </div>
- <div class="statusname" v-if="item.type != 'object'">
- {{ getValueText(item.key, item.value) }}
- <!-- {{ item.value }}{{ item.unit }} -->
- </div>
- <div v-else>
- <div class="oblist" v-for="(vare, name) in item.value">
- <div>{{ getStatusText(name, vare) }}</div>
- <!-- <div class="name">{{ name }}:</div>
- <div class="name">{{ vare }}</div> -->
- </div>
- </div>
- <div>
- <devantd :json="item.list" :antdid="item.key" v-if="item.type == 'int' || item.type == 'float' || item.type == 'string' || item.type == 'double'" />
- </div>
- </div>
- </div>
- </div>
- </el-tab-pane>
- <!-- 设备信息 -->
- <el-tab-pane :label="$t('message.device.deviceInfo')" name="1">
- <div class="pro-box">
- <div class="protitle">{{$t('message.device.deviceInfo')}}</div>
- <div>
- <el-button size="small" :disabled="!canEdit" type="primary" v-auth="'edit'" @click="onOpenEditDic(detail)">{{ $t('message.tableI18nAction.edit') }}</el-button>
- </div>
- </div>
- <el-descriptions class="margin-top" :column="3" border>
- <!-- 设备标识 -->
- <el-descriptions-item :label="$t('message.device.deviceIdentifier')">
- <copy :text="detail.key"></copy>
- </el-descriptions-item>
- <!-- 设备名称 -->
- <el-descriptions-item :label="$t('message.device.tableI18nColumn.deviceName')">{{ detail.name }}</el-descriptions-item>
- <!-- 消息协议 -->
- <el-descriptions-item :label="$t('message.device.formI18nLabel.messageProtocol')">{{ prodetail.messageProtocol }}</el-descriptions-item>
- <!-- 产品标识 -->
- <el-descriptions-item :label="$t('message.device.formI18nLabel.productKey')">
- <copy :text="prodetail.key"></copy>
- </el-descriptions-item>
- <!-- 产品名称 -->
- <el-descriptions-item :label="$t('message.device.formI18nLabel.productName')">
- <router-link :to="'/iotmanager/device/product/detail/' + prodetail.key" class="link-type">{{ detail.productName }} </router-link>
- </el-descriptions-item>
- <!-- 链接协议 -->
- <el-descriptions-item :label="$t('message.device.linkProtocol')">{{ prodetail.transportProtocol }}</el-descriptions-item>
- <!-- 设备类型 -->
- <el-descriptions-item :label="$t('message.device.tableI18nColumn.deviceType2')">{{ prodetail.deviceType }}</el-descriptions-item>
- <!-- 固件版本 -->
- <el-descriptions-item :label="$t('message.device.firmwareVersion')">{{ detail.version }}</el-descriptions-item>
- <!-- 注册时间 -->
- <el-descriptions-item :label="$t('message.device.registryTime')">{{ detail.registryTime }}</el-descriptions-item>
- <!-- 最后上线时间 -->
- <el-descriptions-item :label="$t('message.device.tableI18nColumn.lastOnlineTime')">{{ detail.lastOnlineTime || "" }}</el-descriptions-item>
- <!-- 详细地址 -->
- <el-descriptions-item :label="$t('message.device.address')">{{ detail.address }}</el-descriptions-item>
- <!-- 说明 -->
- <el-descriptions-item :label="$t('message.device.tableI18nColumn.desc2')">{{ detail.desc }}</el-descriptions-item>
- <el-descriptions-item :label="item.name" v-for="(item, index) in detail.tags" :key="index">{{ item.value }}</el-descriptions-item>
- <!-- <el-descriptions-item label="标签">
- <div class="capsule-wrapper">
- <div v-for="(item, index) in detail.tags" :key="index" class="capsule mr-3">
- <div class="label">{{ item.name }}</div>
- <div class="value">{{ item.value }}</div>
- </div>
- </div>
- </el-descriptions-item> -->
- </el-descriptions>
- <div class="flex" style="margin-top: 20px">
- <el-input type="number" style="width: 380px; margin-right: 20px" v-model.number="detail.onlineTimeout">
- <!-- 设备超时时间 -->
- <template #prepend>{{$t('message.device.deviceTimeout')}}</template>
- <!-- 秒 -->
- <template #append>{{ $t('message.device.unitSecond') }}</template>
- </el-input>
- <!-- 更新 -->
- <el-button type="primary" :disabled="!canEdit" @click="onlineTimeoutUpdate">
- <el-icon style="font-size: 18px"><ele-Refresh /></el-icon>
- {{ $t('message.device.update') }}
- </el-button>
- </div>
- </el-tab-pane>
- <!-- 物模型 -->
- <el-tab-pane :label="$t('message.device.thingModel')" name="2">
- <el-tabs type="border-card" v-model="activetab" @tab-click="wuhandleClick">
- <el-tab-pane label="属性定义" name="attr">
- <div class="wu-title">
- <div class="title"></div>
- <div>
- <el-button size="small" :disabled="!canEdit" type="primary" v-auth="'add'" @click="onOpenEditAttr()">添加</el-button>
- </div>
- </div>
- <el-table style="width: 100%" :data="tableData.data" v-loading="tableLoading" v-if="activetab == 'attr'">
- <el-table-column label="属性标识" align="center" prop="key" />
- <el-table-column label="属性名称" prop="name" show-overflow-tooltip />
- <el-table-column prop="valueType" label="数据类型" width="100" align="center">
- <template #default="scope">
- <span>{{ scope.row.valueType?.type }}</span>
- </template>
- </el-table-column>
- <el-table-column prop="decimals" label="精度" width="60" align="center">
- <template #default="scope">
- <span>{{ scope.row.valueType?.decimals }}</span>
- </template>
- </el-table-column>
- <el-table-column prop="unit" label="单位" width="60" align="center">
- <template #default="scope">
- <span>{{ scope.row.valueType.unit }}</span>
- </template>
- </el-table-column>
- <el-table-column prop="accessMode" label="是否只读" width="120" align="center">
- <template #default="scope">
- <el-tag type="info" size="small" v-if="scope.row.accessMode">只读</el-tag>
- <el-tag type="success" size="small" v-else>读写</el-tag>
- </template>
- </el-table-column>
- <el-table-column label="说明" prop="desc" show-overflow-tooltip />
- <el-table-column label="操作" width="150" align="center" fixed="right">
- <template #default="scope">
- <el-button size="small" text type="primary" :disabled="!canEdit" v-auth="'edit'" v-if="!scope.row.accessMode" @click="setAttr(scope.row)">设置属性</el-button>
- <el-button size="small" text type="warning" :disabled="!canEdit" v-auth="'edit'" @click="onEditAttr(scope.row)">修改</el-button>
- <el-button size="small" text type="danger" :disabled="!canEdit" v-auth="'del'" @click="onRowDel(scope.row.key, 'attr')">删除</el-button>
- </template>
- </el-table-column>
- </el-table>
- </el-tab-pane>
- <el-tab-pane label="功能定义" name="fun">
- <div class="wu-title">
- <div class="title"></div>
- <div>
- <el-button size="small" type="primary" v-auth="'add'" :disabled="!canEdit" @click="onOpenEditFun()">添加</el-button>
- </div>
- </div>
- <el-table style="width: 100%" :data="tableData.data" v-loading="tableLoading" v-if="activetab == 'fun'">
- <el-table-column label="功能标识" align="center" prop="key" />
- <el-table-column label="名称" prop="name" show-overflow-tooltip />
- <el-table-column label="描述" prop="desc" show-overflow-tooltip />
- <el-table-column label="操作" width="300" align="center" fixed="right">
- <template #default="scope">
- <el-button size="small" text type="warning" v-auth="'edit'" :disabled="!canEdit" @click="onEditFun(scope.row)">修改</el-button>
- <el-button size="small" text type="danger" v-auth="'del'" :disabled="!canEdit" @click="onRowDel(scope.row.key, 'fun')">删除</el-button>
- </template>
- </el-table-column>
- </el-table>
- </el-tab-pane>
- <el-tab-pane label="事件定义" name="event">
- <div class="wu-title">
- <div class="title"></div>
- <div>
- <el-button type="primary" size="small" v-auth="'add'" :disabled="!canEdit" @click="onOpenEditEvent()">添加</el-button>
- </div>
- </div>
- <el-table style="width: 100%" :data="tableData.data" v-loading="tableLoading" v-if="activetab == 'event'">
- <el-table-column label="事件标识" align="center" prop="key" />
- <el-table-column label="名称" prop="name" show-overflow-tooltip />
- <el-table-column prop="level" label="事件级别" width="120" align="center">
- <template #default="scope">
- <el-tag size="small" v-if="scope.row.level == 0">普通</el-tag>
- <el-tag type="warning" size="small" v-if="scope.row.level == 1">警告</el-tag>
- <el-tag type="danger" size="small" v-if="scope.row.level == 2">紧急</el-tag>
- </template>
- </el-table-column>
- <el-table-column label="描述" prop="desc" show-overflow-tooltip />
- <el-table-column label="操作" width="300" align="center" fixed="right">
- <template #default="scope">
- <el-button size="small" text type="warning" v-auth="'edit'" :disabled="!canEdit" @click="onEditEvent(scope.row)">修改</el-button>
- <el-button size="small" text type="danger" v-auth="'del'" :disabled="!canEdit" @click="onRowDel(scope.row.key, 'event')">删除</el-button>
- </template>
- </el-table-column>
- </el-table>
- </el-tab-pane>
- <el-tab-pane label="标签定义" name="tab">
- <div class="wu-title">
- <div class="title"></div>
- <div>
- <el-button size="small" type="primary" v-auth="'add'" :disabled="!canEdit" @click="onOpenEditTab()">添加</el-button>
- </div>
- </div>
- <el-table style="width: 100%" :data="tableData.data" v-loading="tableLoading" v-if="activetab == 'tab'">
- <el-table-column label="属性标识" align="center" prop="key" />
- <el-table-column label="属性名称" prop="name" show-overflow-tooltip />
- <el-table-column prop="valueType" label="数据类型" width="120" align="center">
- <template #default="scope">
- <span>{{ scope.row.valueType?.type }}</span>
- </template>
- </el-table-column>
- <el-table-column prop="accessMode" label="是否只读" width="120" align="center">
- <template #default="scope">
- <el-tag type="info" size="small" v-if="scope.row.accessMode">只读</el-tag>
- <el-tag type="success" size="small" v-else>读写</el-tag>
- </template>
- </el-table-column>
- <el-table-column label="描述" prop="desc" show-overflow-tooltip />
- <el-table-column label="操作" width="300" align="center" fixed="right">
- <template #default="scope">
- <el-button size="small" text type="warning" v-auth="'edit'" :disabled="!canEdit" @click="onEditTag(scope.row)">修改</el-button>
- <el-button size="small" text type="danger" v-auth="'del'" :disabled="!canEdit" @click="onRowDel(scope.row.key, 'tab')">删除</el-button>
- </template>
- </el-table-column>
- </el-table>
- </el-tab-pane>
- </el-tabs>
- <pagination v-show="tableData.total > 0" :total="tableData.total" v-model:page="tableData.param.pageNum" v-model:limit="tableData.param.pageSize" @pagination="getList()" />
- </el-tab-pane>
- <!-- 设备功能 -->
- <el-tab-pane :label="$t('message.device.deviceFunction')" name="5">
- <functionCom :status="areaData.status" :device-key="detail.key" :product-key="prodetail.key" v-if="detail.key && prodetail.key && activeName === '5'"></functionCom>
- </el-tab-pane>
- <!-- 日志管理 -->
- <el-tab-pane :label="$t('message.device.logManagement')" name="4">
- <div class="system-user-search mb15">
- <el-form :model="logtableData.param" ref="logqueryRef" inline label-width="68px">
- <el-form-item label="日志类型" prop="types">
- <el-select v-model="logtableData.param.types" placeholder="日志类型" clearable>
- <el-option v-for="item in logTypeData" :key="item" :label="item" :value="item" />
- </el-select>
- </el-form-item>
- <el-form-item label="创建时间" prop="dateRange">
- <el-date-picker v-model="logtableData.param.dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" class="ml10" @click="getlog">
- <el-icon>
- <ele-Search />
- </el-icon>
- 查询
- </el-button>
- <el-button @click="resetQuery(logqueryRef)">
- <el-icon>
- <ele-Refresh />
- </el-icon>
- 重置
- </el-button>
- </el-form-item>
- </el-form>
- </div>
- <el-table style="width: 100%" :data="logtableData.data">
- <el-table-column label="类型" align="center" prop="type" />
- <el-table-column label="时间" prop="ts" show-overflow-tooltip />
- <el-table-column label="内容" prop="content" show-overflow-tooltip />
- <el-table-column label="操作" width="300" align="center" fixed="right">
- <template #default="scope">
- <el-button size="small" text type="warning" @click="onLogDetail(scope.row)">查看</el-button>
- </template>
- </el-table-column>
- </el-table>
- <pagination v-show="logtableData.total > 0" :total="logtableData.total" v-model:page="logtableData.param.pageNum" v-model:limit="logtableData.param.pageSize" @pagination="getlog" />
- </el-tab-pane>
- <!-- Topic列表 -->
- <el-tab-pane :label="$t('message.device.topicList')" name="topic">
- SagooMqtt协议 ,涉及的topic如下:
- <el-table style="width: 100%; margin-top: 20px" :data="topicData" border>
- <el-table-column label="描述" prop="info" width="250" />
- <el-table-column label="类型" prop="type" width="80" align="center" />
- <el-table-column label="Topic类" prop="url">
- <template #default="{ row }">
- <copy :text="row.url"></copy>
- </template>
- </el-table-column>
- </el-table>
- <pagination v-show="logtableData.total > 0" :total="logtableData.total" v-model:page="logtableData.param.pageNum" v-model:limit="logtableData.param.pageSize" @pagination="getlog" />
- </el-tab-pane>
- <el-tab-pane v-if="prodetail.deviceType == '网关'" label="子设备" name="6">
- <div class="wu-box">
- <div class="wu-title">
- <div class="title">子设备列表</div>
- <div>
- <el-button v-auth="'mutipleBind'" type="primary" @click="onOpenMutipleBind()">批量绑定</el-button>
- <el-button v-auth="'cancleMutipleBind'" :disabled="!deviceKeyList.length" type="primary" @click="mutipleUnbind()">批量解绑</el-button>
- </div>
- </div>
- <el-table :data="deviceTableData.data" style="width: 100%" @selection-change="handleSelectionChange" v-loading="deviceTableData.loading">
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column label="标识" prop="key" width="130" show-overflow-tooltip>
- <template #default="{ row }">
- <copy :text="row.key"></copy>
- </template>
- </el-table-column>
- <el-table-column label="设备名称" prop="name" show-overflow-tooltip />
- <el-table-column label="产品名称" prop="productName" show-overflow-tooltip />
- <el-table-column prop="status" label="状态" width="100" align="center">
- <template #default="scope">
- <el-tag type="info" size="small" v-if="scope.row.status == 1">离线</el-tag>
- <el-tag type="success" size="small" v-if="scope.row.status == 2">在线</el-tag>
- <el-tag type="info" size="small" v-if="scope.row.status == 0">未启用</el-tag>
- </template>
- </el-table-column>
- <el-table-column prop="registryTime" label="激活时间" align="center" width="150"></el-table-column>
- <el-table-column prop="desc" label="说明"></el-table-column>
- <el-table-column label="操作" width="160" align="center" fixed="right">
- <template #default="scope">
- <el-button size="small" text type="danger" v-auth="'del'" @click="deleteSubDevice(scope.row)">删除</el-button>
- <el-button size="small" text type="warning" v-auth="'detail'" @click="onOpenDetail(scope.row)">详情</el-button>
- </template>
- </el-table-column>
- </el-table>
- <pagination v-show="deviceTableData.total > 0" :total="deviceTableData.total" v-model:page="deviceTableData.param.pageNum" v-model:limit="deviceTableData.param.pageSize" @pagination="getDeviceTableData" />
- </div>
- </el-tab-pane>
- <!-- 设备档案 -->
- <el-tab-pane :label="$t('message.device.deviceArchive')" name="7" v-if="deviceAssetData">
- <el-form label-width="110px">
- <div class="pro-box">
- <div class="protitle">设备档案</div>
- <div>
- <el-button size="small" type="primary" v-auth="'edit'" @click="onOpenEditAsset" :disabled="!canEdit">编辑</el-button>
- </div>
- </div>
- <el-descriptions class="margin-top" :column="3" border>
- <view v-for="(item, index) in dataList" :key="index">
- <el-descriptions-item :label="item.title">
- <view v-if="item.types === 'file'">
- <img :src="deviceAssetMetadata[item.name]" class="avatar" />
- </view>
- <view v-else>
- <view v-if="item.pattern">
- <el-link :href="deviceAssetMetadata[item.name]" type="primary" target="_blank">{{ deviceAssetMetadata[item.name] }}</el-link>
- </view>
- <view v-else>
- {{ deviceAssetMetadata[item.name] }}
- </view>
- </view>
- </el-descriptions-item>
- </view>
- </el-descriptions>
- </el-form>
- </el-tab-pane>
- </el-tabs>
- </div>
- <EditDic ref="editDicRef" @typeList="initData" />
- <EditAttr ref="editAttrRef" @typeList="getproperty" />
- <EditFun ref="editFunRef" @typeList="getfunction" />
- <EditEvent ref="editEventRef" @typeList="getevent" />
- <EditTab ref="editTabRef" @typeList="gettab" />
- <ListDic ref="listDicRef" />
- <ChartDic ref="chartDicRef" />
- <SubDevice ref="subDeviceRef" />
- <setAttr :device-key="detail.key" ref="setAttrRef" />
- <!-- 子设备-批量绑定弹窗 -->
- <SubDeviceMutipleBind ref="mutipleBindRef" @bindSuccess="getDeviceTableData" />
- <!-- 编辑设备档案 -->
- <EditAssetRef ref="editAssetRef" @getList="getDeviceAssetMetadata"></EditAssetRef>
- <el-dialog v-model="dialogVisible" title="日志数据内容" width="30%">
- <JsonViewer :value="jsonData" boxed sort theme="jv-dark" />
- <template #footer>
- <span class="dialog-footer">
- <el-button @click="dialogVisible = false">关闭</el-button>
- </span>
- </template>
- </el-dialog>
- </div>
- </template>
- <script lang="ts">
- import { toRefs, reactive, onMounted, ref, defineComponent, nextTick, onUnmounted, computed } from "vue";
- import { ElMessageBox, ElMessage, FormInstance } from "element-plus";
- import functionCom from "./component/function.vue";
- import "vue3-json-viewer/dist/index.css";
- import EditDic from "./component/edit.vue";
- import EditAttr from "../product/component/editAttr.vue";
- import EditFun from "../product/component/editFun.vue";
- import EditEvent from "../product/component/editEvent.vue";
- import EditTab from "../product/component/editTab.vue";
- import devantd from "/@/components/devantd/index.vue";
- import ListDic from "./component/list.vue";
- import ChartDic from "./component/chart.vue";
- import SubDevice from "./component/subDevice.vue";
- import setAttr from "./component/setAttr.vue";
- import SubDeviceMutipleBind from "./component/subDeviceMutipleBind.vue";
- import api from "/@/api/device";
- import datahub from "/@/api/datahub";
- import FromData from "/@/views/iot/property/dossier/component/from.vue";
- import EditAssetRef from "/@/views/iot/property/dossier/edit.vue";
- import { useRoute } from "vue-router";
- interface TableDataState {
- isShowDialog: boolean;
- dialogVisible: boolean;
- phone: any[];
- certificate: any[];
- logTypeData: any[];
- prodetail: any;
- areaData: any;
- activetab: string;
- activeName: string;
- productKey: string;
- jsonData: string;
- intro: string;
- developer_status: number;
- detail: any;
- deviceKeyList: string[];
- deviceTableData: any;
- tableData: {
- data: [];
- total: number;
- loading: boolean;
- param:
- | {
- pageNum: number;
- pageSize: number;
- name: string;
- deviceType: string;
- status: string;
- dateRange: string[];
- }
- | any;
- };
- logtableData: {
- data: [];
- total: number;
- loading: boolean;
- param: any;
- };
- }
- export default defineComponent({
- name: "deviceEditPro",
- components: { EditAssetRef, FromData, SubDeviceMutipleBind, SubDevice, EditDic, EditAttr, EditFun, EditEvent, EditTab, devantd, ListDic, functionCom, setAttr, ChartDic },
- props: {
- deviceKey: String,
- },
- setup(props, context) {
- const canEdit = computed(() => state.areaData.status===0);
- let timer: any;
- onUnmounted(() => clearInterval(timer));
- const logqueryRef = ref();
- const topicData = ref<any[]>([]);
- // 属性列表,查询保留小数位使用
- const propertyMap = new Map();
- const array_list = ref([]);
- const tableLoading = ref(false);
- const route = useRoute();
- const editDicRef = ref();
- const setAttrRef = ref();
- const editAttrRef = ref();
- const editFunRef = ref();
- const listDicRef = ref();
- const chartDicRef = ref();
- const editEventRef = ref();
- const editTabRef = ref();
- const subDeviceRef = ref();
- const mutipleBindRef = ref();
- const editAssetRef = ref();
- const dataList = ref();
- const deviceAssetData = ref();
- const deviceAssetMetadata = ref<any>({});
- const state = reactive<TableDataState>({
- certificate: [],
- phone: [],
- intro: "",
- deviceKeyList: [],
- areaData: {},
- isShowDialog: false,
- dialogVisible: false,
- logTypeData: [],
- jsonData: "",
- activeName: "3", // 分类数据
- activetab: "attr", // 分类数据
- detail: {},
- prodetail: [],
- productKey: "",
- developer_status: 0,
- deviceTableData: {
- data: [],
- total: 0,
- loading: false,
- param: {
- pageNum: 1,
- gatewayKey: "",
- pageSize: 20,
- dateRange: [],
- },
- },
- tableData: {
- data: [],
- total: 0,
- loading: false,
- param: {
- pageNum: 1,
- productKey: "",
- pageSize: 20,
- status: "",
- dateRange: [],
- },
- },
- logtableData: {
- data: [],
- total: 0,
- loading: false,
- param: {
- pageNum: 1,
- productKey: "",
- pageSize: 20,
- status: "",
- dateRange: [],
- },
- },
- });
- onMounted(() => {
- initData();
- });
- function initData() {
- // 如果是嵌入的就是子设备,看子设备详情,否则看页面参数
- const deviceKey = props.deviceKey || route.params?.id;
- api.instance.detail(deviceKey).then((res: any) => {
- state.detail = res.data;
- state.developer_status = res.data.status;
- state.tableData.param.productKey = res.data.productKey;
- state.productKey = res.data.product.key;
- api.product.detail(res.data.product.key).then((res: any) => {
- state.prodetail = res.data;
- });
- const { phone, certificate, intro } = JSON.parse(res.data.extensionInfo || "{}");
- state.phone = phone || [];
- state.certificate = certificate || [];
- state.intro = intro;
- //加载全部属性
- datahub.node.getpropertyList({ productKey: state.detail.productKey }).then((re: any) => {
- array_list.value = re;
- re.forEach((item: any) => propertyMap.set(item.key, item?.valueType));
- });
- const deviceType = res.data?.product?.deviceType;
- topicData.value =
- deviceType === "网关"
- ? [
- {
- url: `/sys/${res.data.productKey}/${deviceKey}/thing/event/property/pack/post`,
- info: "网关批量上传事件和属性(网关发起)",
- type: "请求",
- },
- {
- url: `/sys/${res.data.productKey}/${deviceKey}/thing/event/property/pack/post_reply`,
- info: "网关批量上传事件和属性(网关发起)",
- type: "响应",
- },
- ]
- : [
- {
- url: `/sys/${res.data.productKey}/${deviceKey}/thing/event/property/post`,
- info: "设备上报属性(设备端发起)",
- type: "请求",
- },
- {
- url: `/sys/${res.data.productKey}/${deviceKey}/thing/event/property/post_reply`,
- info: "设备上报属性(设备端发起)",
- type: "响应",
- },
- {
- url: `/sys/${res.data.productKey}/${deviceKey}/thing/event/${"${eventIdentifier}"}/post`,
- info: "设备上报事件(设备端发起)",
- type: "请求",
- },
- {
- url: `/sys/${res.data.productKey}/${deviceKey}/thing/event/${"${eventIdentifier}"}/post_reply`,
- info: "设备上报事件(设备端发起)",
- type: "响应",
- },
- ];
- // 加载对应设备档案 (企业版功能)
- sessionStorage.isEnterprise && getDeviceAssetMetadata();
- getrunData();
- timer = setInterval(getrunData, 3000);
- getDeviceTableData();
- });
- }
- const getDeviceAssetMetadata = () => {
- nextTick(() => {
- const urlRegex = /^(http-s-?:\/\/)?(a-zA\.)?[a-zA-Z0-9@:%._\+~#?&//=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%._\+~#?&//=]*)$/;
- //获取设备档案
- api.dev_asset.detail({ deviceKey: state.detail.key }).then((resde: any) => {
- // 存储设备档案信息
- deviceAssetData.value = resde;
- const newArray = (resde?.data || []).map((obj: any) => {
- const { name, value, ...rest } = obj;
- const newObj = { name, value, ...rest };
- newObj[name] = value ? value : "";
- return newObj;
- });
- dataList.value = newArray;
- for (const item of dataList.value) {
- item.pattern = false;
- if (item.types == "input" || item.types == "textarea") {
- if (urlRegex.test(item.value)) {
- item.pattern = true;
- }
- }
- // 根据属性返回键获取对应档案对应的内容
- deviceAssetMetadata.value[item.name] = item.value ? item.value : "";
- }
- });
- });
- };
- const mutipleUnbind = () => {
- let msg = "是否进行批量解绑?";
- if (state.deviceKeyList.length === 0) {
- ElMessage.error("请选择要批量解绑的数据。");
- return;
- }
- ElMessageBox.confirm(msg, "提示", {
- confirmButtonText: "确认",
- cancelButtonText: "取消",
- type: "warning",
- })
- .then(() => {
- api.device
- .mutipleUnbind({
- gatewayKey: state.deviceTableData.param.gatewayKey,
- subKeys: state.deviceKeyList,
- })
- .then(() => {
- ElMessage.success("解绑成功");
- // typeList();
- getDeviceTableData();
- });
- })
- .catch(() => {});
- };
- const getDeviceTableData = () => {
- state.deviceTableData.data = [];
- state.deviceTableData.param.gatewayKey = state.detail.key;
- api.device.getList(state.deviceTableData.param).then((res: any) => {
- state.deviceTableData.data = res.list;
- state.deviceTableData.total = res.Total;
- });
- };
- // 多选框选中数据
- const handleSelectionChange = (selection: any[]) => {
- state.deviceKeyList = selection.map((item) => item.key);
- };
- // 打开修改产品弹窗
- const onOpenDetail = (row: any) => {
- subDeviceRef.value.openDialog(row);
- };
- // 删除子设备
- const deleteSubDevice = (row: any) => {
- ElMessageBox.confirm(`此操作将永久删除该子设备:${row.name}, 是否继续?`, "提示", {
- confirmButtonText: "删除",
- cancelButtonText: "取消",
- type: "warning",
- }).then(() => {
- api.product.deleteSubDevice(row.id).then(() => {
- ElMessage.success("删除成功");
- getDeviceTableData();
- });
- });
- };
- const onLogDetail = (row: any) => {
- state.jsonData = JSON.parse(row.content);
- state.dialogVisible = true;
- };
- const onOpenMutipleBind = () => {
- mutipleBindRef.value.openDialog(state.deviceTableData.param.gatewayKey);
- };
- //编辑属性
- const onEditAttr = (row: any) => {
- editAttrRef.value.openDialog(row, state.productKey);
- };
- //编辑功能
- const onEditFun = (row: any) => {
- editFunRef.value.openDialog(row, state.productKey);
- };
- //编辑事件
- const onEditEvent = (row: any) => {
- editEventRef.value.openDialog(row, state.productKey);
- };
- //编辑标签
- const onEditTag = (row: any) => {
- editTabRef.value.openDialog(row, state.productKey);
- };
- //打开添加属性弹窗
- const onOpenEditAttr = () => {
- editAttrRef.value.openDialog({ productKey: state.productKey, id: 0, accessMode: 0, deviceKey: state.detail.key });
- };
- //打开添加功能弹窗
- const onOpenEditFun = () => {
- editFunRef.value.openDialog({ productKey: state.productKey, id: 0 });
- };
- //打开添加事件弹窗
- const onOpenEditEvent = () => {
- editEventRef.value.openDialog({ productKey: state.productKey, id: 0, level: 0 });
- };
- //打开添加事件弹窗
- const onOpenEditTab = () => {
- editTabRef.value.openDialog({ productKey: state.productKey, id: 0, accessMode: 0 });
- };
- //查看日志列表
- const onOpenListDetail = (row: any) => {
- listDicRef.value.openDialog(row, state.detail.key);
- };
- //查看日志图形
- const onOpenChartDetail = (row: any) => {
- chartDicRef.value.openDialog(row, state.detail.key, state.productKey);
- };
- // 打开修改产品弹窗
- const onOpenEditDic = (row: any) => {
- editDicRef.value.openDialog(row);
- };
- // 打开修改设备档案弹窗
- const onOpenEditAsset = () => {
- editAssetRef.value.open(deviceAssetData.value, state.detail.product);
- };
- // 删除产品
- const onRowDel = (key: string, type: string) => {
- let msg = `此操作将永久删除该数据,是否继续?`;
- if (key.length === 0) {
- ElMessage.error("请选择要删除的数据。");
- return;
- }
- ElMessageBox.confirm(msg, "提示", {
- confirmButtonText: "确认",
- cancelButtonText: "取消",
- type: "warning",
- })
- .then(() => {
- if (type == "attr") {
- api.model.propertydel(state.productKey, key).then(() => {
- ElMessage.success("删除成功");
- getproperty();
- });
- }
- if (type == "fun") {
- api.model.functiondel(state.productKey, key).then(() => {
- ElMessage.success("删除成功");
- getfunction();
- });
- }
- if (type == "event") {
- api.model.eventdel(state.productKey, key).then(() => {
- ElMessage.success("删除成功");
- getevent();
- });
- }
- if (type == "tab") {
- api.model.tagdel(state.productKey, key).then(() => {
- ElMessage.success("删除成功");
- gettab();
- });
- }
- })
- .catch(() => {});
- };
- //根据不同类型获取列表
- const getList = () => {
- switch (state.activetab) {
- case "attr":
- getproperty();
- break;
- case "fun":
- getfunction();
- break;
- case "event":
- getevent();
- break;
- case "tab":
- gettab();
- break;
- }
- };
- const getproperty = () => {
- state.tableData.data = [];
- tableLoading.value = true;
- api.model
- .property(state.tableData.param)
- .then((res: any) => {
- state.tableData.data = res.Data;
- state.tableData.total = res.Total;
- })
- .finally(() => (tableLoading.value = false));
- };
- const getfunction = () => {
- state.tableData.data = [];
- tableLoading.value = true;
- api.model
- .function(state.tableData.param)
- .then((res: any) => {
- state.tableData.data = res.Data;
- state.tableData.total = res.Total;
- })
- .finally(() => (tableLoading.value = false));
- };
- const getevent = () => {
- state.tableData.data = [];
- tableLoading.value = true;
- api.model
- .event(state.tableData.param)
- .then((res: any) => {
- state.tableData.data = res.Data;
- state.tableData.total = res.Total;
- })
- .finally(() => (tableLoading.value = false));
- };
- const gettab = () => {
- state.tableData.data = [];
- tableLoading.value = true;
- api.model
- .tag(state.tableData.param)
- .then((res: any) => {
- state.tableData.data = res.Data;
- state.tableData.total = res.Total;
- })
- .finally(() => (tableLoading.value = false));
- };
- const wuhandleClick = (tab: any) => {
- state.activetab = tab.props.name;
- switch (tab.props.name) {
- case "attr":
- getproperty();
- break;
- case "fun":
- getfunction();
- break;
- case "event":
- getevent();
- break;
- case "tab":
- gettab();
- break;
- }
- };
- const handleClick = (tab: any, event: Event) => {
- if (tab.props.name == 4) {
- //获取日志
- getlog();
- getlogtype();
- } else if (tab.props.name == 2) {
- getList();
- } else if (tab.props.name == 3) {
- getrunData();
- } else if (tab.props.name == 7) {
- getDeviceAssetMetadata();
- }
- };
- const getValueText = (key: String, value: String) => {
- const item = propertyMap.get(key);
- if (!item) return value;
- if (item.type === "enum") {
- const option = item.elements.find((element: any) => element.value === value);
- if (option) {
- return option.text;
- }
- } else if (["float", "double"].includes(item?.type) && item?.decimals) {
- // 根据属性确定保留小数位数
- return Number(value).toFixed(item.decimals);
- } else {
- return value;
- }
- };
- const getStatusText = (name: any, value: string) => {
- let data = array_list.value as any;
- for (let i = 0; i < data.length; i++) {
- const field = data[i];
- if (field.valueType.type === "object") {
- for (let j = 0; j < field.valueType.properties.length; j++) {
- const property = field.valueType.properties[j];
- if (property.key === name) {
- if (property.valueType.type === "enum") {
- const element = property.valueType.elements.find((element: any) => element.value === value);
- if (element) {
- return `${property.name}: ${element.text}`;
- } else {
- return `${property.name}: ${value}`;
- }
- } else {
- return `${property.name}: ${value}`;
- }
- }
- }
- } else if (field.key === name) {
- if (field.valueType.type === "enum") {
- const element = field.valueType.elements.find((element: any) => element.value === value);
- if (element) {
- return `${field.name}: ${element.text}`;
- }
- } else {
- return `${field.name}: ${value}`;
- }
- }
- }
- return name + ":" + value;
- };
- const getrunData = () => {
- api.instance.getrun_status({ deviceKey: state.detail.key }).then((res: any) => {
- state.areaData = res;
- let properties = state.areaData.properties || [];
- var temp = new Array();
- properties.forEach(function (item: any, index: number) {
- let datalist = item.list || [];
- temp[index] = [];
- var temps = new Array();
- datalist.forEach(function (a: any, b: number) {
- if (b < 15) {
- temps.push(a);
- }
- });
- if (item.type == "object") {
- item.value = JSON.parse(item.value);
- }
- temp[index]["name"] = item.name;
- temp[index]["key"] = item.key;
- temp[index]["type"] = item.type;
- temp[index]["unit"] = item.unit;
- temp[index]["value"] = item.value;
- temp[index]["list"] = temps;
- });
- state.areaData.properties = temp;
- });
- };
- const getlogtype = () => {
- api.instance.getlogcate({}).then((res: any) => {
- state.logTypeData = res.list;
- });
- };
- const getlog = () => {
- state.logtableData.param.deviceKey = state.detail.key;
- api.instance.getLogList(state.logtableData.param).then((res: any) => {
- state.logtableData.data = res.list;
- state.logtableData.total = res.Total;
- });
- };
- /** 重置按钮操作 */
- const resetQuery = (formEl: FormInstance | undefined) => {
- if (!formEl) return;
- formEl.resetFields();
- getlog();
- };
- const CkOption = () => {
- if (state.developer_status == 2) {
- api.instance.devoffline({ id: state.detail.id }).then((res: any) => {
- ElMessage.success("操作成功");
- state.developer_status = 1;
- });
- } else {
- api.instance.devonline({ id: state.detail.id }).then((res: any) => {
- ElMessage.success("操作成功");
- state.developer_status = 2;
- });
- }
- };
- const onlineTimeoutUpdate = () => {
- if (!state.detail.onlineTimeout) return ElMessage("请先输入设备超时时间");
- api.device.updateOnlineTimeout({ deviceKey: state.detail.key, onlineTimeout: state.detail.onlineTimeout }).then(() => {
- ElMessage.success("设置成功");
- });
- };
- const setAttr = (row: any) => {
- setAttrRef.value.show(row);
- };
- return {
- canEdit,
- topicData,
- initData,
- logqueryRef,
- resetQuery,
- getStatusText,
- getValueText,
- onlineTimeoutUpdate,
- setAttr,
- setAttrRef,
- editDicRef,
- editAttrRef,
- listDicRef,
- chartDicRef,
- editFunRef,
- editEventRef,
- editTabRef,
- subDeviceRef,
- mutipleBindRef,
- tableLoading,
- editAssetRef,
- dataList,
- deviceAssetMetadata,
- deviceAssetData,
- onOpenChartDetail,
- onOpenListDetail,
- getrunData,
- getlog,
- getlogtype,
- onLogDetail,
- CkOption,
- onRowDel,
- onEditFun,
- onEditEvent,
- onEditTag,
- onEditAttr,
- getList,
- getproperty,
- getDeviceTableData,
- handleSelectionChange,
- getfunction,
- getevent,
- gettab,
- getDeviceAssetMetadata,
- wuhandleClick,
- onOpenEditTab,
- onOpenEditEvent,
- onOpenEditAttr,
- onOpenEditFun,
- onOpenEditDic,
- onOpenDetail,
- deleteSubDevice,
- handleClick,
- onOpenMutipleBind,
- mutipleUnbind,
- onOpenEditAsset,
- ...toRefs(state),
- };
- },
- });
- </script>
- <style scoped lang="scss">
- .capsule-wrapper {
- display: flex;
- align-items: center;
- .capsule {
- display: flex;
- flex-direction: row;
- align-items: center;
- border: 1px solid var(--el-color-primary);
- border-radius: 20px;
- font-size: 12px;
- .label {
- height: 24px;
- display: flex;
- align-items: center;
- border-top-left-radius: 20px;
- border-bottom-left-radius: 20px;
- background-color: var(--el-color-primary);
- padding: 0px 10px;
- text-indent: 2px;
- color: var(--el-color-white) !important;
- }
- .value {
- height: 24px;
- display: flex;
- align-items: center;
- border-top-right-radius: 20px;
- border-bottom-right-radius: 20px;
- text-indent: -2px;
- padding: 0px 10px;
- }
- }
- }
- .oblist {
- display: flex;
- flex-direction: row;
- align-items: center;
- padding-right: 5px;
- flex: 1;
- margin-top: 10px;
- margin-left: 10px;
- }
- .content {
- width: 100%;
- padding: 20px 20px;
- }
- .content-box {
- width: 100%;
- padding: 0 20px;
- }
- .cont_box {
- display: flex;
- }
- .cont_box .title {
- font-size: 24px;
- }
- .cont_box .pro-status {
- line-height: 40px;
- margin-left: 30px;
- }
- .cont_box .pro-status .on {
- background: #52c41a;
- }
- .cont_box .pro-status .off {
- background: #c41a1a;
- }
- .cont_box .pro-status span {
- position: relative;
- top: -1px;
- display: inline-block;
- width: 6px;
- height: 6px;
- vertical-align: middle;
- border-radius: 50%;
- margin-right: 5px;
- }
- .cont_box .pro-option {
- line-height: 40px;
- margin-left: 10px;
- color: #1890ff;
- cursor: pointer;
- }
- .content-box .pro-box {
- display: flex;
- padding: 10px;
- justify-content: space-between;
- }
- .content-box .pro-box .protitle {
- font-size: 18px;
- font-weight: bold;
- line-height: 35px;
- }
- .content-box .pro-box .buttonedit {
- border: 0px;
- color: #1890ff;
- }
- table {
- border-collapse: collapse;
- text-indent: initial;
- border-spacing: 2px;
- }
- tbody {
- box-sizing: border-box;
- display: table-row-group;
- vertical-align: middle;
- border-color: inherit;
- }
- tr {
- display: table-row;
- vertical-align: inherit;
- border-color: inherit;
- }
- .wu-title {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- padding: 20px;
- border-bottom: #e8e8e8 1px solid;
- }
- .wu-title .title {
- font-size: 18px;
- }
- .ant-card {
- box-sizing: border-box;
- margin: 10px;
- width: 23.2%;
- font-size: 14px;
- font-variant: tabular-nums;
- border: 1px solid var(--next-border-color-light);
- line-height: 1.5;
- list-style: none;
- font-feature-settings: "tnum";
- position: relative;
- border-radius: 2px;
- transition: all 0.3s;
- }
- .ant-card-body {
- padding: 12px;
- zoom: 1;
- }
- .cardflex {
- display: flex;
- justify-content: space-between;
- }
- .statusname {
- font-size: 30px;
- margin-top: 10px;
- margin-bottom: 15px;
- }
- .comtest {
- margin-top: 20px;
- height: 30px;
- line-height: 30px;
- }
- </style>
|