detail.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773
  1. <template>
  2. <div class="box equipment-detail">
  3. <el-page-header @back="goBack" content="设备详情"></el-page-header>
  4. <el-divider></el-divider>
  5. <el-tabs v-loading="loading" v-model="state.activeName" @tab-click="handleClick">
  6. <el-tab-pane label="基本信息" name="base">
  7. <el-row :gutter="20" v-if="state.activeName === 'base'">
  8. <el-col :span="12">
  9. <el-descriptions :column="1" border :labelStyle="{ 'font-weight': 'bold' }">
  10. <el-descriptions-item label="设备ID">{{
  11. state.deviceDetail.deviceId
  12. }}</el-descriptions-item>
  13. <el-descriptions-item label="产品productKey">{{
  14. state.deviceDetail.productKey
  15. }}</el-descriptions-item>
  16. <el-descriptions-item label="设备deviceName">{{
  17. state.deviceDetail.deviceName
  18. }}</el-descriptions-item>
  19. <el-descriptions-item label="设备密钥">{{
  20. state.deviceDetail.secret
  21. }}</el-descriptions-item>
  22. <el-descriptions-item label="创建时间">{{
  23. formatDate(state.deviceDetail.createAt)
  24. }}</el-descriptions-item>
  25. <el-descriptions-item label="设备状态">{{
  26. state.deviceDetail.state
  27. ? state.deviceDetail.state.online
  28. ? "在线"
  29. : "离线"
  30. : "离线"
  31. }}</el-descriptions-item>
  32. <el-descriptions-item label="最后上线时间">{{
  33. formatDate(state.deviceDetail.onlineTime)
  34. }}</el-descriptions-item>
  35. </el-descriptions></el-col
  36. >
  37. <el-col v-if="state.showDeviceMap" :span="12">
  38. <Map :center="state.mapLnglat" />
  39. </el-col>
  40. </el-row>
  41. <div style="margin: 10px 10px">设备标签&nbsp;<el-button size="small" icon="Plus" @click="addTag"></el-button></div>
  42. <el-descriptions :column="2" border :labelStyle="{ 'font-weight': 'bold' }">
  43. <el-descriptions-item v-for="tag in state.tags" :key="tag.name" :label="tag.name + '(' + tag.id + ')'">{{ tag.value
  44. }}</el-descriptions-item>
  45. </el-descriptions>
  46. </el-tab-pane>
  47. <el-tab-pane label="属性" name="property">
  48. <el-table v-if="state.activeName === 'property'" :data="state.properties" border v-loading="state.loading" style="width: 100%">
  49. <el-table-column prop="name" label="属性名" width="250">
  50. <template v-slot="scope"> {{ scope.row.name }}({{ scope.row.identifier }}) </template>
  51. </el-table-column>
  52. <el-table-column prop="value" label="属性值">
  53. <template v-slot="scope">
  54. <span>{{ scope.row.value }} &nbsp;</span>
  55. <el-button @click="showPropertyHistory(scope.row)" size="small">历史</el-button>
  56. </template>
  57. </el-table-column>
  58. <el-table-column prop="occurred" label="修改时间">
  59. <template v-slot="scope">
  60. <span>{{ formatDate(scope.row.occurred)}} </span>
  61. </template>
  62. </el-table-column>
  63. <el-table-column label="可读写" width="80">
  64. <template v-slot="scope">
  65. <el-tag v-if="!scope.row.write" type="info" size="small" effect="plain">只读</el-tag>
  66. <el-button @click="showWriteProperty(scope.row)" v-if="scope.row.write" size="small" type="success" plain>可写</el-button>
  67. </template>
  68. </el-table-column>
  69. </el-table>
  70. <div v-if="!!state.propertyHistory.name">
  71. <el-divider></el-divider>
  72. <el-row>
  73. <el-col :span="2">
  74. <h5>历史数据</h5>
  75. </el-col>
  76. <!-- <el-col :span="9">-->
  77. <!-- <el-date-picker-->
  78. <!-- v-model="state.historyTime"-->
  79. <!-- type="datetimerange"-->
  80. <!-- :picker-options="state.pickerOptions"-->
  81. <!-- range-separator="至"-->
  82. <!-- start-placeholder="开始日期"-->
  83. <!-- end-placeholder="结束日期"-->
  84. <!-- align="right"-->
  85. <!-- @change="timeRangeChange"-->
  86. <!-- >-->
  87. <!-- </el-date-picker>-->
  88. <!-- </el-col>-->
  89. <!-- <el-col :span="4">-->
  90. <!-- <el-radio-group v-model="state.dataType">-->
  91. <!-- <el-radio-button label="">无</el-radio-button>-->
  92. <!-- <el-radio-button label="stats">统计</el-radio-button>-->
  93. <!-- </el-radio-group>-->
  94. <!-- </el-col>-->
  95. </el-row>
  96. <PropertyChart :name="state.propertyHistory.name" :properties="state.propertyHistory.data"></PropertyChart>
  97. </div>
  98. </el-tab-pane>
  99. <el-tab-pane label="服务" name="service">
  100. <el-table v-if="state.activeName === 'service'" :data="state.services" border v-loading="state.loading" style="width: 100%">
  101. <el-table-column label="服务名称" width="180">
  102. <template v-slot="scope"> {{ scope.row.name }}({{ scope.row.identifier }}) </template>
  103. </el-table-column>
  104. <el-table-column label="操作" width="100">
  105. <template v-slot="scope">
  106. <el-button @click="showInvokeService(scope.row)" type="success" size="small" plain>调用</el-button>
  107. </template>
  108. </el-table-column>
  109. <el-table-column label="参数">
  110. <template v-slot="scope">
  111. <pre class="equipment-param">{{ scope.row.inputData }}</pre>
  112. </template>
  113. </el-table-column>
  114. </el-table>
  115. </el-tab-pane>
  116. <el-tab-pane label="日志" name="event">
  117. <el-form v-if="state.activeName === 'event'" :inline="true" :model="state.formInline" class="user-search">
  118. <el-form-item>
  119. <el-select v-model="state.formInline.type" placeholder="请选择日志类型">
  120. <el-option label="所有" value="" />
  121. <el-option label="状态" value="state" />
  122. <el-option label="事件" value="event" />
  123. <el-option label="属性" value="property" />
  124. <el-option label="服务" value="service" />
  125. </el-select>
  126. </el-form-item>
  127. <el-form-item label="搜索:">
  128. <el-input v-model="state.formInline.identifier" placeholder="日志识符" />
  129. </el-form-item>
  130. <el-form-item>
  131. <el-button type="primary" icon="Search" @click="logSearch">搜索</el-button>
  132. </el-form-item>
  133. </el-form>
  134. <el-table :data="state.events" border v-loading="state.loading" style="width: 100%">
  135. <el-table-column label="时间" width="180">
  136. <template v-slot="scope">
  137. {{formatDate(scope.row.time) }}
  138. </template>
  139. </el-table-column>
  140. <el-table-column prop="type" label="类型" width="80" />
  141. <el-table-column prop="name" label="名称(标识符)" width="180" />
  142. <el-table-column label="内容">
  143. <template v-slot="scope">
  144. <pre class="equipment-param">{{ scope.row.content.data }}</pre>
  145. </template>
  146. </el-table-column>
  147. </el-table>
  148. <Pagination :data="state.formInline" @onPagePaging="getEvents" />
  149. </el-tab-pane>
  150. <el-tab-pane label="模拟上报" name="report">
  151. <el-table
  152. v-if="state.activeName === 'report'"
  153. :data="state.modelFunctions"
  154. highlight-current-row
  155. v-loading="state.loading"
  156. border
  157. element-loading-text="拼命加载中"
  158. style="width: 100%"
  159. >
  160. <el-table-column type="expand" label="上报">
  161. <template v-slot="fun">
  162. <el-form inline v-model="fun.row" label-width="80px">
  163. <el-form-item label="值" v-if="fun.row.type == 'property'">
  164. <el-input v-model="fun.row.value" size="small" />
  165. </el-form-item>
  166. <el-form-item label="内容" v-else>
  167. <el-input type="textarea" v-model="fun.row.content" size="small" rows="4" />
  168. </el-form-item>
  169. <el-form-item>
  170. <el-button type="primary" size="small" @click="sendDeviceMsg(fun.row)">发送</el-button>
  171. </el-form-item>
  172. </el-form>
  173. </template>
  174. </el-table-column>
  175. <el-table-column sortable prop="type" label="功能类型" width="100" />
  176. <el-table-column sortable prop="name" label="功能名称" width="180" />
  177. <el-table-column sortable prop="identifier" label="标识符" width="150" />
  178. <el-table-column sortable prop="dataTypeName" label="数据类型" width="100" />
  179. <el-table-column sortable prop="params" label="数据定义" />
  180. </el-table>
  181. </el-tab-pane>
  182. <el-tab-pane label="设备配置" name="config">
  183. <DeviceConfig v-if="state.activeName === 'config'" :deviceId="state.deviceId" />
  184. </el-tab-pane>
  185. <el-tab-pane label="模拟设备" name="simulator">
  186. <DeviceSimulator v-if="state.activeName === 'simulator'" :thingModelFunctions="state.modelFunctions" :deviceDetail="state.deviceDetail" />
  187. </el-tab-pane>
  188. </el-tabs>
  189. <el-dialog
  190. :title="state.title"
  191. v-model="state.propertyWriteFormVisible"
  192. width="40%"
  193. @close="closeDialog"
  194. :close-on-press-escape="false"
  195. :close-on-click-modal="false"
  196. append-to-body
  197. destroy-on-close
  198. >
  199. <el-form v-if="state.propertyWriteFormVisible" label-width="120px" :model="state.propertyWriteForm" ref="propertyWriteForm">
  200. <div style="display: none">
  201. <el-input v-model="state.propertyWriteForm.identifier" type="hidden" />
  202. </div>
  203. <el-form-item label="属性值" prop="value">
  204. <el-input v-model="state.propertyWriteForm.value" auto-complete="off" />
  205. </el-form-item>
  206. </el-form>
  207. <template #footer>
  208. <div class="dialog-footer">
  209. <el-button @click="closeDialog">取消</el-button>
  210. <el-button type="primary" :loading="state.loading" class="title" @click="submitPropertyWriteForm">保存</el-button>
  211. </div>
  212. </template>
  213. </el-dialog>
  214. <el-dialog
  215. :title="state.title"
  216. v-model="state.serviceFormVisible"
  217. width="40%"
  218. @close="closeDialog"
  219. :close-on-press-escape="false"
  220. :close-on-click-modal="false"
  221. append-to-body
  222. destroy-on-close
  223. >
  224. <el-form v-if="state.serviceFormVisible" label-width="120px" :model="state.serviceForm" ref="serviceForm">
  225. <div>
  226. <el-input v-model="state.serviceForm.identifier" type="hidden" />
  227. <el-input v-model="state.serviceForm.productKey" type="hidden" />
  228. <el-input v-model="state.serviceForm.deviceName" type="hidden" />
  229. </div>
  230. <div v-if="state?.serviceForm?.params.length === 0">是否确认调用?</div>
  231. <el-form-item v-for="param in state.serviceForm.params" :key="param.identifier" :label="param.identifier" prop="params">
  232. <el-input v-model="param.value" auto-complete="off" />
  233. <div class="form-tips">{{ param.name }}</div>
  234. </el-form-item>
  235. </el-form>
  236. <template #footer>
  237. <div class="dialog-footer">
  238. <el-button @click="closeDialog">取消</el-button>
  239. <el-button type="primary" :loading="state.loading" class="title" @click="submitServiceForm">确认</el-button>
  240. </div>
  241. </template>
  242. </el-dialog>
  243. <el-dialog
  244. title="添加设备标签"
  245. v-model="state.showAddTag"
  246. width="400px"
  247. :close-on-press-escape="false"
  248. :close-on-click-modal="false"
  249. append-to-body
  250. destroy-on-close
  251. >
  252. <el-form v-if="state.showAddTag" ref="formRef" :model="state.tagForm" :rules="state.rules" label-width="80px">
  253. <el-form-item label="标签名称" prop="name">
  254. <el-input v-model="state.tagForm.name" />
  255. </el-form-item>
  256. <el-form-item label="标识符" prop="id">
  257. <el-input v-model="state.tagForm.id" />
  258. </el-form-item>
  259. <el-form-item label="标签值" prop="value">
  260. <el-input v-model="state.tagForm.value" />
  261. </el-form-item>
  262. <el-form-item>
  263. <el-button type="primary" @click="submitAddTag">提交</el-button>
  264. </el-form-item>
  265. </el-form>
  266. </el-dialog>
  267. </div>
  268. </template>
  269. <script lang="ts" setup>
  270. import { formatDate } from '@/utils/formatTime'
  271. import { getObjectModel } from '@/views/iot/equipment/api/products.api'
  272. import {
  273. getDevicesDetail,
  274. devicesTagAdd,
  275. deviceSimulateSend,
  276. propertySet,
  277. deviceLogs,
  278. serviceInvoke,
  279. devicePropertyLogs,
  280. } from '@/views/iot/equipment/api/devices.api'
  281. import PropertyChart from './modules/PropertyChart.vue'
  282. import DeviceConfig from './modules/detail/DeviceConfig.vue'
  283. import Map from '@/components/Map/index.vue'
  284. import DeviceSimulator from './modules/detail/DeviceSimulator.vue'
  285. const route = useRoute()
  286. const router = useRouter()
  287. const { id } = route.params
  288. const { showMap } = route.query || false
  289. const goBack = () => {
  290. router.back()
  291. }
  292. const formRef = ref()
  293. const state = reactive<any>({
  294. loading: false,
  295. activeName: 'base',
  296. title: '',
  297. propertyWriteFormVisible: false,
  298. propertyWriteForm: {
  299. identifier: '',
  300. productKey: '',
  301. deviceName: '',
  302. value: '',
  303. },
  304. serviceFormVisible: false,
  305. serviceForm: {
  306. identifier: '',
  307. productKey: '',
  308. deviceName: '',
  309. params: [],
  310. },
  311. showAddTag: false,
  312. showDeviceMap: false,
  313. tagForm: {
  314. name: '',
  315. identifier: '',
  316. value: '',
  317. },
  318. rules: {
  319. id: [{ required: true, message: '请输入标识符', trigger: 'blur' }],
  320. name: [{ required: true, message: '请输入标签名称', trigger: 'blur' }],
  321. value: [{ required: true, message: '请输入标签值', trigger: 'blur' }],
  322. },
  323. deviceId: '',
  324. deviceDetail: {},
  325. thingModel: null,
  326. modelFunctions: [],
  327. properties: [],
  328. services: [],
  329. events: [],
  330. eventMap: {},
  331. mapLnglat:'',
  332. tags: [],
  333. formInline: {
  334. type: '',
  335. identifier: '',
  336. page: 1,
  337. size: 10,
  338. total: 0,
  339. },
  340. deviceLogs: [],
  341. typeMap: {
  342. lifetime: '生命周期',
  343. state: '设备状态',
  344. property: '属性',
  345. event: '事件',
  346. service: '服务',
  347. },
  348. propertyHistory: {
  349. name: '',
  350. data: [],
  351. },
  352. dataType: '',
  353. currHistoryProperty: {},
  354. historyTime: [
  355. new Date(new Date().getTime() - 24 * 3600 * 1000),
  356. new Date(new Date().getTime() + 24 * 3600 * 1000),
  357. ],
  358. pickerOptions: {
  359. shortcuts: [
  360. {
  361. text: '最近1小时',
  362. onClick(picker) {
  363. const end = new Date()
  364. const start = new Date()
  365. start.setTime(start.getTime() - 3600 * 1000)
  366. picker.$emit('pick', [start, end])
  367. },
  368. },
  369. {
  370. text: '最近6小时',
  371. onClick(picker) {
  372. const end = new Date()
  373. const start = new Date()
  374. start.setTime(start.getTime() - 3600 * 1000 * 6)
  375. picker.$emit('pick', [start, end])
  376. },
  377. },
  378. {
  379. text: '最近1天',
  380. onClick(picker) {
  381. const end = new Date()
  382. const start = new Date()
  383. start.setTime(start.getTime() - 3600 * 1000 * 24)
  384. picker.$emit('pick', [start, end])
  385. },
  386. },
  387. {
  388. text: '最近5天',
  389. onClick(picker) {
  390. const end = new Date()
  391. const start = new Date()
  392. start.setTime(start.getTime() - 3600 * 1000 * 24 * 5)
  393. picker.$emit('pick', [start, end])
  394. },
  395. },
  396. ],
  397. },
  398. })
  399. const getdata = () => {
  400. state.deviceId = id
  401. getDevicesDetail(state.deviceId).then((res: any) => {
  402. if (res.code !== 200) return
  403. const { data } = res
  404. if (data.state && data.state.onlineTime) {
  405. data.onlineTime = data.state.onlineTime
  406. } else {
  407. data.onlineTime = ''
  408. }
  409. let prop = data.property || {}
  410. state.deviceDetail = data
  411. if (data?.locate.longitude && data.locate.latitude) {
  412. state.mapLnglat = data.locate.longitude + ',' + data.locate.latitude
  413. }
  414. state.showDeviceMap = JSON.parse(showMap as string)
  415. //取设备物模型信息
  416. console.log('state.thingModel', state.thingModel)
  417. if (!state.thingModel) {
  418. getObjectModel(data.productKey).then((objRes: any) => {
  419. const data = objRes.data || {}
  420. //取物模型功能列表
  421. data.model = data.model || {
  422. properties: [],
  423. events: [],
  424. services: [],
  425. }
  426. let model = data.model
  427. console.log('model', model)
  428. state.thingModel = model
  429. state.services = model.services
  430. fillProperty(prop)
  431. data.model.properties = data.model.properties || []
  432. data.model.events = data.model.events || []
  433. data.model.services = data.model.services || []
  434. data.model = JSON.parse(JSON.stringify(data.model))
  435. model = data.model || {}
  436. let modelFuncs: any[] = []
  437. model.properties.forEach((p) => {
  438. let params = JSON.stringify(p.dataType.specs || '{}', null, 4)
  439. modelFuncs.push({
  440. raw: p,
  441. type: 'property',
  442. name: p.name,
  443. identifier: p.identifier,
  444. dataTypeName: p.dataType.type,
  445. params: params == '{}' ? '' : params,
  446. value: '',
  447. occurred: ''
  448. })
  449. })
  450. model.events.forEach((e) => {
  451. let output = {}
  452. e.outputData.forEach((p) => {
  453. output[p.identifier] = p.name
  454. })
  455. modelFuncs.push({
  456. raw: e,
  457. type: 'event',
  458. name: e.name,
  459. identifier: e.identifier,
  460. dataTypeName: '-',
  461. params: JSON.stringify(output, null, 4),
  462. content: JSON.stringify(output, null, 4),
  463. })
  464. })
  465. model.services.forEach((s) => {
  466. let input = {};
  467. (s.inputData || []).forEach((p) => {
  468. input[p.identifier] = p.name
  469. })
  470. let output = {};
  471. (s.outputData || []).forEach((p) => {
  472. output[p.identifier] = p.name
  473. })
  474. modelFuncs.push({
  475. raw: s,
  476. type: 'service',
  477. name: s.name + '回复',
  478. identifier: s.identifier + '_reply',
  479. dataTypeName: '-',
  480. params: JSON.stringify(output, null, 4),
  481. content: JSON.stringify(output, null, 4),
  482. })
  483. })
  484. state.modelFunctions = modelFuncs
  485. })
  486. } else {
  487. fillProperty(prop)
  488. }
  489. let deviceTag = res.tag
  490. state.tags = []
  491. for (var p in deviceTag) {
  492. var tag = deviceTag[p]
  493. state.tags.push({ id: tag.id, name: tag.name, value: tag.value })
  494. }
  495. })
  496. }
  497. const fillProperty = (prop) => {
  498. let model = state.thingModel
  499. let props: any[] = []
  500. model.properties.forEach((p) => {
  501. props.push({
  502. identifier: p.identifier,
  503. name: p.name,
  504. value: prop[p.identifier]?.value?? prop[p.identifier],
  505. occurred: prop[p.identifier]?.occurred??'' ,
  506. write: p.accessMode != 'r',
  507. })
  508. })
  509. state.properties = props
  510. }
  511. const addTag = () => {
  512. state.showAddTag = true
  513. }
  514. const submitAddTag = () => {
  515. state.tagForm.deviceId = state.deviceId
  516. formRef.value.validate((valid) => {
  517. if (valid) {
  518. devicesTagAdd(state.tagForm).then(() => {
  519. ElMessage({
  520. type: 'success',
  521. message: '添加成功',
  522. })
  523. getdata()
  524. state.showAddTag = false
  525. })
  526. }
  527. })
  528. }
  529. const logSearch = () => {
  530. state.formInline.page = 1
  531. getEvents()
  532. }
  533. const getEvents = () => {
  534. console.log('deviceLogs')
  535. deviceLogs({
  536. deviceId: state.deviceId,
  537. ...state.formInline
  538. }).then((res) => {
  539. state.formInline.total = res.total
  540. let logs: any[] = []
  541. console.log('res.data', res.data)
  542. res.data.rows.map((de) => {
  543. let row = {
  544. time: de.time,
  545. type: state.typeMap[de.type],
  546. name: '未知事件',
  547. content: de,
  548. }
  549. logs.push(row)
  550. if (!state.thingModel) return
  551. let modeEvents = state.thingModel.events
  552. if (modeEvents && modeEvents.length > 0) {
  553. modeEvents.forEach((e) => {
  554. if (de.identifier == e.identifier) {
  555. row.name = e.name
  556. return
  557. }
  558. })
  559. }
  560. let modeServices = state.thingModel.services
  561. if (de.type == 'property') {
  562. if (de.identifier == 'set_reply') {
  563. row.name = '设置回复'
  564. } else if (de.identifier == 'report') {
  565. row.name = '上报'
  566. } else if (de.identifier == 'set') {
  567. row.name = '设置'
  568. }
  569. } else if (de.type == 'state') {
  570. if (de.identifier == 'online') {
  571. row.name = '上线'
  572. } else {
  573. row.name = '下线'
  574. }
  575. } else if (de.type == 'lifetime') {
  576. if (de.identifier == 'register') {
  577. row.name = '注册'
  578. }
  579. } else if (modeServices && modeServices.length > 0) {
  580. var ids = de.identifier.split('_reply')
  581. modeServices.forEach((e) => {
  582. if (ids[0] == e.identifier) {
  583. row.name = e.name + (ids.length > 1 ? '回复' : '')
  584. return
  585. }
  586. })
  587. }
  588. row.name = row.name + '(' + de.identifier + ')'
  589. return de
  590. })
  591. state.events = logs
  592. })
  593. }
  594. const showPropertyHistory = (row) => {
  595. state.currHistoryProperty = row
  596. refreshPropertyHistory()
  597. }
  598. const loading = ref(false)
  599. const refreshPropertyHistory = () => {
  600. var end = state.historyTime[1]
  601. var start = state.historyTime[0]
  602. loading.value = true
  603. devicePropertyLogs({
  604. deviceId: state.deviceId,
  605. name: state.currHistoryProperty.identifier,
  606. start: start.getTime(),
  607. end: end.getTime()
  608. }).then((res) => {
  609. state.propertyHistory.name = state.currHistoryProperty.name
  610. state.propertyHistory.data = res.data
  611. }).finally(() => {
  612. loading.value = false
  613. })
  614. }
  615. const timeRangeChange = () => {
  616. refreshPropertyHistory()
  617. }
  618. const handleClick = (tab) => {
  619. tab.name == 'event' ? getEvents() : getdata()
  620. }
  621. const showWriteProperty = (prop) => {
  622. state.propertyWriteFormVisible = true
  623. state.title = '设置属性'
  624. state.propertyWriteForm.identifier = prop.identifier
  625. state.propertyWriteForm.productKey = state.deviceDetail.productKey
  626. state.propertyWriteForm.deviceName = state.deviceDetail.deviceName
  627. state.propertyWriteForm.value = prop.value?.value ? prop.value.value : prop.value
  628. }
  629. const submitPropertyWriteForm = () => {
  630. let form = state.propertyWriteForm
  631. let prop = {}
  632. prop[form.identifier] = form.value
  633. propertySet({
  634. deviceId: state.deviceId,
  635. args: prop,
  636. }).then((res) => {
  637. if (res.code === 200) {
  638. ElMessage({
  639. type: 'success',
  640. message: '操作成功',
  641. })
  642. } else {
  643. ElMessage.error(res.message)
  644. }
  645. })
  646. }
  647. const showInvokeService = (service) => {
  648. state.serviceFormVisible = true
  649. state.title = '服务调用'
  650. state.serviceForm.identifier = service.identifier
  651. state.serviceForm.deviceId = state.deviceDetail.deviceId
  652. let params: any[] = []
  653. service.inputData.forEach((p) => {
  654. params.push({
  655. identifier: p.identifier,
  656. name: p.name,
  657. value: '',
  658. })
  659. })
  660. state.serviceForm.params = params
  661. }
  662. const submitServiceForm = () => {
  663. let form = state.serviceForm
  664. let param = {}
  665. state.serviceForm.params.forEach((p) => {
  666. param[p.identifier] = p.value
  667. })
  668. serviceInvoke({
  669. deviceId: state.deviceId,
  670. service: form.identifier,
  671. args: param,
  672. }).then((res) => {
  673. if (res.code === 200) {
  674. state.serviceFormVisible = false
  675. ElMessage({
  676. type: 'info',
  677. message: '操作成功',
  678. })
  679. } else {
  680. ElMessage({
  681. type: 'error',
  682. message: res.message,
  683. })
  684. }
  685. })
  686. }
  687. const sendDeviceMsg = (fun) => {
  688. //发送模拟设备消息
  689. let data = {}
  690. if (fun.type == 'property') {
  691. let val = fun.value
  692. switch (fun.dataTypeName) {
  693. case 'int32':
  694. case 'bool':
  695. case 'enum':
  696. val = parseInt(val)
  697. break
  698. case 'float':
  699. val = parseFloat(val)
  700. break
  701. }
  702. data[fun.identifier] = val
  703. } else {
  704. data = JSON.parse(fun.content)
  705. }
  706. deviceSimulateSend({
  707. deviceId: state.deviceId,
  708. productKey: state.deviceDetail.productKey,
  709. deviceName: state.deviceDetail.deviceName,
  710. type: fun.type,
  711. identifier: fun.type == 'property' ? 'report' : fun.identifier,
  712. data: data,
  713. }).then(() => {
  714. ElMessage({
  715. type: 'info',
  716. message: '操作成功',
  717. })
  718. })
  719. }
  720. const closeDialog = () => {
  721. state.propertyWriteFormVisible = false
  722. state.serviceFormVisible = false
  723. }
  724. const locateChange = (e) => {
  725. state.propertyWriteForm.value=e[0] * 1+','+e[1] * 1
  726. }
  727. getdata()
  728. logSearch()
  729. </script>
  730. <style lang="scss" scoped>
  731. .box {
  732. padding: 15px;
  733. background: #fff;
  734. }
  735. .form-tips {
  736. font-size: 12px;
  737. line-height: 14px;
  738. }
  739. .equipment-param {
  740. max-height: 160px;
  741. overflow: hidden auto;
  742. word-wrap: break-word;
  743. white-space: pre-wrap;
  744. font-size: 12px;
  745. line-height: 14px;
  746. }
  747. </style>