channelList.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. <template>
  2. <div id="channelList" style="width: 100%">
  3. <div class="page-header">
  4. <div class="page-title">
  5. <el-button icon="el-icon-back" size="mini" style="font-size: 20px; color: #000;" type="text" @click="showDevice" ></el-button>
  6. <el-divider direction="vertical"></el-divider>
  7. 通道列表
  8. </div>
  9. <div class="page-header-btn">
  10. <div v-if="!showTree" style="display: inline;">
  11. 搜索:
  12. <el-input @input="search" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字"
  13. prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input>
  14. 通道类型:
  15. <el-select size="mini" @change="search" style="width: 8rem; margin-right: 1rem;" v-model="channelType" placeholder="请选择"
  16. default-first-option>
  17. <el-option label="全部" value=""></el-option>
  18. <el-option label="设备" value="false"></el-option>
  19. <el-option label="子目录" value="true"></el-option>
  20. </el-select>
  21. 在线状态:
  22. <el-select size="mini" style="width: 8rem; margin-right: 1rem;" @change="search" v-model="online" placeholder="请选择"
  23. default-first-option>
  24. <el-option label="全部" value=""></el-option>
  25. <el-option label="在线" value="true"></el-option>
  26. <el-option label="离线" value="false"></el-option>
  27. </el-select>
  28. 码流类型重置:
  29. <el-select size="mini" style="width: 16rem; margin-right: 1rem;" @change="subStreamChange" v-model="subStream"
  30. placeholder="请选择码流类型" default-first-option >
  31. <el-option label="stream:0(主码流)" value="stream:0"></el-option>
  32. <el-option label="stream:1(子码流)" value="stream:1"></el-option>
  33. <el-option label="streamnumber:0(主码流-2022)" value="streamnumber:0"></el-option>
  34. <el-option label="streamnumber:1(子码流-2022)" value="streamnumber:1"></el-option>
  35. <el-option label="streamprofile:0(主码流-大华)" value="streamprofile:0"></el-option>
  36. <el-option label="streamprofile:1(子码流-大华)" value="streamprofile:1"></el-option>
  37. <el-option label="streamMode:main(主码流-水星+TP-LINK)" value="streamMode:main"></el-option>
  38. <el-option label="streamMode:sub(子码流-水星+TP-LINK)" value="streamMode:sub"></el-option>
  39. </el-select>
  40. </div>
  41. <el-button icon="el-icon-refresh-right" circle size="mini" @click="refresh()"></el-button>
  42. <el-button v-if="showTree" icon="iconfont icon-list" circle size="mini" @click="switchList()"></el-button>
  43. <el-button v-if="!showTree" icon="iconfont icon-tree" circle size="mini" @click="switchTree()"></el-button>
  44. </div>
  45. </div>
  46. <devicePlayer ref="devicePlayer"></devicePlayer>
  47. <el-container v-loading="isLoging" style="height: 82vh;">
  48. <el-aside width="auto" style="height: 82vh; background-color: #ffffff; overflow: auto" v-if="showTree">
  49. <DeviceTree ref="deviceTree" :device="device" :onlyCatalog="true" :clickEvent="treeNodeClickEvent"></DeviceTree>
  50. </el-aside>
  51. <el-main style="padding: 5px;">
  52. <el-table ref="channelListTable" :data="deviceChannelList" :height="winHeight" style="width: 100%"
  53. header-row-class-name="table-header">
  54. <el-table-column prop="channelId" label="通道编号" min-width="180">
  55. </el-table-column>
  56. <el-table-column prop="deviceId" label="设备编号" min-width="180">
  57. </el-table-column>
  58. <el-table-column prop="name" label="通道名称" min-width="180">
  59. <template v-slot:default="scope">
  60. <el-input
  61. v-show="scope.row.edit"
  62. v-model="scope.row.name"
  63. placeholder="通道名称"
  64. :maxlength="255"
  65. show-word-limit
  66. clearable
  67. />
  68. <span v-show="!scope.row.edit">{{ scope.row.name }}</span>
  69. </template>
  70. </el-table-column>
  71. <el-table-column label="快照" min-width="100">
  72. <template v-slot:default="scope">
  73. <el-image
  74. :src="getSnap(scope.row)"
  75. :preview-src-list="getBigSnap(scope.row)"
  76. @error="getSnapErrorEvent(scope.row.deviceId, scope.row.channelId)"
  77. :fit="'contain'"
  78. style="width: 60px">
  79. <div slot="error" class="image-slot">
  80. <i class="el-icon-picture-outline"></i>
  81. </div>
  82. </el-image>
  83. </template>
  84. </el-table-column>
  85. <el-table-column prop="subCount" label="子节点数" min-width="100">
  86. </el-table-column>
  87. <el-table-column prop="manufacture" label="厂家" min-width="100">
  88. </el-table-column>
  89. <el-table-column label="位置信息" min-width="120">
  90. <template v-slot:default="scope">
  91. <el-input
  92. v-show="scope.row.edit"
  93. v-model="scope.row.location"
  94. placeholder="例:117.234,36.378"
  95. :maxlength="30"
  96. show-word-limit
  97. clearable
  98. />
  99. <span v-show="!scope.row.edit">{{ scope.row.location }}</span>
  100. </template>
  101. </el-table-column>
  102. <el-table-column prop="ptzType" label="云台类型" min-width="100">
  103. <template v-slot:default="scope">
  104. <el-select v-show="scope.row.edit" v-model="scope.row.ptzType"
  105. placeholder="云台类型" filterable>
  106. <el-option
  107. v-for="(value, key) in ptzTypes"
  108. :key="key"
  109. :label="value"
  110. :value="key"
  111. />
  112. </el-select>
  113. <div v-show="!scope.row.edit">{{ scope.row.ptzTypeText }}</div>
  114. </template>
  115. </el-table-column>
  116. <el-table-column label="开启音频" min-width="100">
  117. <template slot-scope="scope">
  118. <el-switch @change="updateChannel(scope.row)" v-model="scope.row.hasAudio" active-color="#409EFF">
  119. </el-switch>
  120. </template>
  121. </el-table-column>
  122. <el-table-column label="码流类型" min-width="180">
  123. <template slot-scope="scope">
  124. <el-select size="mini" style="margin-right: 1rem;" @change="channelSubStreamChange(scope.row)" v-model="scope.row.streamIdentification"
  125. placeholder="请选择码流类型" default-first-option >
  126. <el-option label="stream:0(主码流)" value="stream:0"></el-option>
  127. <el-option label="stream:1(子码流)" value="stream:1"></el-option>
  128. <el-option label="streamnumber:0(主码流-2022)" value="streamnumber:0"></el-option>
  129. <el-option label="streamnumber:1(子码流-2022)" value="streamnumber:1"></el-option>
  130. <el-option label="streamprofile:0(主码流-大华)" value="streamprofile:0"></el-option>
  131. <el-option label="streamprofile:1(子码流-大华)" value="streamprofile:1"></el-option>
  132. <el-option label="streamMode:main(主码流-水星+TP-LINK)" value="streamMode:main"></el-option>
  133. <el-option label="streamMode:sub(子码流-水星+TP-LINK)" value="streamMode:sub"></el-option>
  134. </el-select>
  135. </template>
  136. </el-table-column>
  137. <el-table-column label="状态" min-width="100">
  138. <template slot-scope="scope">
  139. <div slot="reference" class="name-wrapper">
  140. <el-tag size="medium" v-if="scope.row.status === true">在线</el-tag>
  141. <el-tag size="medium" type="info" v-if="scope.row.status === false">离线</el-tag>
  142. </div>
  143. </template>
  144. </el-table-column>
  145. <el-table-column label="操作" min-width="340" fixed="right">
  146. <template slot-scope="scope">
  147. <el-button size="medium" v-bind:disabled="device == null || device.online === 0" icon="el-icon-video-play"
  148. type="text" @click="sendDevicePush(scope.row)">播放
  149. </el-button>
  150. <el-button size="medium" v-bind:disabled="device == null || device.online === 0"
  151. icon="el-icon-switch-button"
  152. type="text" style="color: #f56c6c" v-if="!!scope.row.streamId"
  153. @click="stopDevicePush(scope.row)">停止
  154. </el-button>
  155. <el-divider direction="vertical"></el-divider>
  156. <el-button
  157. v-if="scope.row.edit"
  158. size="medium"
  159. type="text"
  160. icon="el-icon-edit-outline"
  161. @click="handleSave(scope.row)"
  162. >
  163. 保存
  164. </el-button>
  165. <el-button
  166. v-else
  167. size="medium"
  168. type="text"
  169. icon="el-icon-edit"
  170. @click="handleEdit(scope.row)"
  171. >
  172. 编辑
  173. </el-button>
  174. <el-divider direction="vertical"></el-divider>
  175. <el-button size="medium" icon="el-icon-s-open" type="text"
  176. v-if="scope.row.subCount > 0 || scope.row.parental === 1"
  177. @click="changeSubchannel(scope.row)">查看
  178. </el-button>
  179. <el-divider v-if="scope.row.subCount > 0 || scope.row.parental === 1" direction="vertical"></el-divider>
  180. <!-- <el-button size="medium" v-bind:disabled="device == null || device.online === 0"-->
  181. <!-- icon="el-icon-video-camera"-->
  182. <!-- type="text" @click="queryRecords(scope.row)">设备录像-->
  183. <!-- </el-button>-->
  184. <!-- <el-button size="medium" v-bind:disabled="device == null || device.online === 0" icon="el-icon-cloudy"-->
  185. <!-- type="text" @click="queryCloudRecords(scope.row)">云端录像-->
  186. <!-- </el-button>-->
  187. <el-dropdown @command="(command)=>{moreClick(command, scope.row)}">
  188. <el-button size="medium" type="text" >
  189. 更多功能<i class="el-icon-arrow-down el-icon--right"></i>
  190. </el-button>
  191. <el-dropdown-menu slot="dropdown">
  192. <el-dropdown-item command="records" v-bind:disabled="device == null || device.online === 0">
  193. 设备录像</el-dropdown-item>
  194. <el-dropdown-item command="cloudRecords" v-bind:disabled="device == null || device.online === 0" >
  195. 云端录像</el-dropdown-item>
  196. </el-dropdown-menu>
  197. </el-dropdown>
  198. </template>
  199. </el-table-column>
  200. </el-table>
  201. <el-pagination
  202. style="float: right"
  203. @size-change="handleSizeChange"
  204. @current-change="currentChange"
  205. :current-page="currentPage"
  206. :page-size="count"
  207. :page-sizes="[15, 25, 35, 50]"
  208. layout="total, sizes, prev, pager, next"
  209. :total="total">
  210. </el-pagination>
  211. </el-main>
  212. </el-container>
  213. <!--设备列表-->
  214. </div>
  215. </template>
  216. <script>
  217. import devicePlayer from './dialog/devicePlayer.vue'
  218. import uiHeader from '../layout/UiHeader.vue'
  219. import DeviceService from "./service/DeviceService";
  220. import DeviceTree from "./common/DeviceTree";
  221. export default {
  222. name: 'channelList',
  223. components: {
  224. devicePlayer,
  225. uiHeader,
  226. DeviceTree
  227. },
  228. data() {
  229. return {
  230. deviceService: new DeviceService(),
  231. device: null,
  232. deviceId: this.$route.params.deviceId,
  233. parentChannelId: this.$route.params.parentChannelId,
  234. deviceChannelList: [],
  235. videoComponentList: [],
  236. currentPlayerInfo: {}, //当前播放对象
  237. updateLooper: 0, //数据刷新轮训标志
  238. searchSrt: "",
  239. channelType: "",
  240. online: "",
  241. subStream: "",
  242. winHeight: window.innerHeight - 200,
  243. currentPage: 1,
  244. count: 15,
  245. total: 0,
  246. beforeUrl: "/deviceList",
  247. isLoging: false,
  248. showTree: false,
  249. loadSnap: {},
  250. ptzTypes: {
  251. 0: "未知",
  252. 1: "球机",
  253. 2: "半球",
  254. 3: "固定枪机",
  255. 4: "遥控枪机"
  256. }
  257. };
  258. },
  259. mounted() {
  260. if (this.deviceId) {
  261. this.deviceService.getDevice(this.deviceId, (result) => {
  262. this.device = result;
  263. }, (error) => {
  264. console.log("获取设备信息失败")
  265. console.error(error)
  266. })
  267. }
  268. this.initData();
  269. },
  270. destroyed() {
  271. this.$destroy('videojs');
  272. clearTimeout(this.updateLooper);
  273. },
  274. methods: {
  275. initData: function () {
  276. if (typeof (this.parentChannelId) == "undefined" || this.parentChannelId == 0) {
  277. this.getDeviceChannelList();
  278. } else {
  279. this.showSubchannels();
  280. }
  281. },
  282. initParam: function () {
  283. this.deviceId = this.$route.params.deviceId;
  284. this.parentChannelId = this.$route.params.parentChannelId;
  285. this.currentPage = 1;
  286. this.count = 15;
  287. if (this.parentChannelId == "" || this.parentChannelId == 0) {
  288. this.beforeUrl = "/deviceList"
  289. }
  290. },
  291. currentChange: function (val) {
  292. this.currentPage = val;
  293. this.initData();
  294. },
  295. handleSizeChange: function (val) {
  296. this.count = val;
  297. this.getDeviceChannelList();
  298. },
  299. getDeviceChannelList: function () {
  300. let that = this;
  301. if (typeof (this.$route.params.deviceId) == "undefined") return;
  302. this.$axios({
  303. method: 'get',
  304. url: `/api/device/query/devices/${this.$route.params.deviceId}/channels`,
  305. params: {
  306. page: that.currentPage,
  307. count: that.count,
  308. query: that.searchSrt,
  309. online: that.online,
  310. channelType: that.channelType
  311. }
  312. }).then(function (res) {
  313. if (res.data.code === 0) {
  314. that.total = res.data.data.total;
  315. that.deviceChannelList = res.data.data.list;
  316. that.deviceChannelList.forEach(e => {
  317. e.ptzType = e.ptzType + "";
  318. that.$set(e, "edit", false);
  319. that.$set(e, "location", "");
  320. if (e.longitude && e.latitude) {
  321. that.$set(e, "location", e.longitude + "," + e.latitude);
  322. }
  323. });
  324. // 防止出现表格错位
  325. that.$nextTick(() => {
  326. that.$refs.channelListTable.doLayout();
  327. })
  328. }
  329. }).catch(function (error) {
  330. console.log(error);
  331. });
  332. },
  333. //通知设备上传媒体流
  334. sendDevicePush: function (itemData) {
  335. let deviceId = this.deviceId;
  336. this.isLoging = true;
  337. let channelId = itemData.channelId;
  338. console.log("通知设备推流1:" + deviceId + " : " + channelId);
  339. let that = this;
  340. this.$axios({
  341. method: 'get',
  342. url: '/api/play/start/' + deviceId + '/' + channelId,
  343. params: {
  344. isSubStream: this.isSubStream
  345. }
  346. }).then(function (res) {
  347. console.log(res)
  348. that.isLoging = false;
  349. if (res.data.code === 0) {
  350. setTimeout(() => {
  351. let snapId = deviceId + "_" + channelId;
  352. that.loadSnap[deviceId + channelId] = 0;
  353. that.getSnapErrorEvent(snapId)
  354. }, 5000)
  355. itemData.streamId = res.data.data.stream;
  356. that.$refs.devicePlayer.openDialog("media", deviceId, channelId, {
  357. streamInfo: res.data.data,
  358. hasAudio: itemData.hasAudio
  359. });
  360. setTimeout(() => {
  361. that.initData();
  362. }, 1000)
  363. } else {
  364. that.$message.error(res.data.msg);
  365. }
  366. }).catch(function (e) {
  367. console.error(e)
  368. that.isLoging = false;
  369. // that.$message.error("请求超时");
  370. });
  371. },
  372. moreClick: function (command, itemData) {
  373. if (command === "records") {
  374. this.queryRecords(itemData)
  375. }else if (command === "cloudRecords") {
  376. this.queryCloudRecords(itemData)
  377. }
  378. },
  379. queryRecords: function (itemData) {
  380. let deviceId = this.deviceId;
  381. let channelId = itemData.channelId;
  382. this.$router.push(`/gbRecordDetail/${deviceId}/${channelId}`)
  383. },
  384. queryCloudRecords: function (itemData) {
  385. let deviceId = this.deviceId;
  386. let channelId = itemData.channelId;
  387. this.$router.push(`/cloudRecordDetail/rtp/${deviceId}_${channelId}`)
  388. },
  389. stopDevicePush: function (itemData) {
  390. var that = this;
  391. this.$axios({
  392. method: 'get',
  393. url: '/api/play/stop/' + this.deviceId + "/" + itemData.channelId,
  394. params: {
  395. isSubStream: this.isSubStream
  396. }
  397. }).then(function (res) {
  398. that.initData();
  399. }).catch(function (error) {
  400. if (error.response.status === 402) { // 已经停止过
  401. that.initData();
  402. } else {
  403. console.log(error)
  404. }
  405. });
  406. },
  407. getSnap: function (row) {
  408. let baseUrl = window.baseUrl ? window.baseUrl : "";
  409. return ((process.env.NODE_ENV === 'development') ? process.env.BASE_API : baseUrl) + '/api/device/query/snap/' + row.deviceId + '/' + row.channelId;
  410. },
  411. getBigSnap: function (row) {
  412. return [this.getSnap(row)]
  413. },
  414. getSnapErrorEvent: function (deviceId, channelId) {
  415. if (typeof (this.loadSnap[deviceId + channelId]) != "undefined") {
  416. console.log("下载截图" + this.loadSnap[deviceId + channelId])
  417. if (this.loadSnap[deviceId + channelId] > 5) {
  418. delete this.loadSnap[deviceId + channelId];
  419. return;
  420. }
  421. setTimeout(() => {
  422. let url = (process.env.NODE_ENV === 'development' ? "debug" : "") + '/api/device/query/snap/' + deviceId + '/' + channelId
  423. this.loadSnap[deviceId + channelId]++
  424. document.getElementById(deviceId + channelId).setAttribute("src", url + '?' + new Date().getTime())
  425. }, 1000)
  426. }
  427. },
  428. showDevice: function () {
  429. this.$router.push(this.beforeUrl).then(() => {
  430. this.initParam();
  431. this.initData();
  432. })
  433. },
  434. changeSubchannel(itemData) {
  435. this.beforeUrl = this.$router.currentRoute.path;
  436. var url = `/${this.$router.currentRoute.name}/${this.$router.currentRoute.params.deviceId}/${itemData.channelId}`
  437. this.$router.push(url).then(() => {
  438. this.searchSrt = "";
  439. this.channelType = "";
  440. this.online = "";
  441. this.initParam();
  442. this.initData();
  443. })
  444. },
  445. showSubchannels: function (channelId) {
  446. if (!this.showTree) {
  447. this.$axios({
  448. method: 'get',
  449. url: `/api/device/query/sub_channels/${this.deviceId}/${this.parentChannelId}/channels`,
  450. params: {
  451. page: this.currentPage,
  452. count: this.count,
  453. query: this.searchSrt,
  454. online: this.online,
  455. channelType: this.channelType
  456. }
  457. }).then((res) => {
  458. if (res.data.code === 0) {
  459. this.total = res.data.data.total;
  460. this.deviceChannelList = res.data.data.list;
  461. this.deviceChannelList.forEach(e => {
  462. e.ptzType = e.ptzType + "";
  463. this.$set(e, "edit", false);
  464. this.$set(e, "location", "");
  465. if (e.longitude && e.latitude) {
  466. this.$set(e, "location", e.longitude + "," + e.latitude);
  467. }
  468. });
  469. // 防止出现表格错位
  470. this.$nextTick(() => {
  471. this.$refs.channelListTable.doLayout();
  472. })
  473. }
  474. }).catch(function (error) {
  475. console.log(error);
  476. });
  477. } else {
  478. this.$axios({
  479. method: 'get',
  480. url: `/api/device/query/tree/channel/${this.deviceId}`,
  481. params: {
  482. parentId: this.parentChannelId,
  483. page: this.currentPage,
  484. count: this.count,
  485. }
  486. }).then((res) => {
  487. if (res.data.code === 0) {
  488. this.total = res.data.total;
  489. this.deviceChannelList = res.data.list;
  490. // 防止出现表格错位
  491. this.$nextTick(() => {
  492. this.$refs.channelListTable.doLayout();
  493. })
  494. }
  495. }).catch(function (error) {
  496. console.log(error);
  497. });
  498. }
  499. },
  500. search: function () {
  501. this.currentPage = 1;
  502. this.total = 0;
  503. this.initData();
  504. },
  505. updateChannel: function (row) {
  506. this.$axios({
  507. method: 'post',
  508. url: `/api/device/query/channel/update/${this.deviceId}`,
  509. params: row
  510. }).then(function (res) {
  511. console.log(JSON.stringify(res));
  512. });
  513. },
  514. subStreamChange: function () {
  515. this.$confirm('确定重置所有通道的码流类型?', '提示', {
  516. confirmButtonText: '确定',
  517. cancelButtonText: '取消',
  518. type: 'warning'
  519. }).then(() => {
  520. this.$axios({
  521. method: 'post',
  522. url: `/api/device/query/channel/stream/identification/update/`,
  523. params: {
  524. deviceId: this.deviceId,
  525. streamIdentification: this.subStream
  526. }
  527. }).then((res)=> {
  528. console.log(JSON.stringify(res));
  529. this.initData()
  530. }).finally(()=>{
  531. this.subStream = ""
  532. })
  533. }).catch(() => {
  534. this.subStream = ""
  535. });
  536. },
  537. channelSubStreamChange: function (row) {
  538. this.$axios({
  539. method: 'post',
  540. url: `/api/device/query/channel/stream/identification/update/`,
  541. params: {
  542. deviceId: this.deviceId,
  543. channelId: row.channelId,
  544. streamIdentification: row.streamIdentification
  545. }
  546. }).then(function (res) {
  547. console.log(JSON.stringify(res));
  548. });
  549. },
  550. refresh: function () {
  551. this.initData();
  552. },
  553. switchTree: function () {
  554. this.showTree = true;
  555. this.deviceChannelList = [];
  556. this.parentChannelId = 0;
  557. this.currentPage = 1;
  558. },
  559. switchList: function () {
  560. this.showTree = false;
  561. this.deviceChannelList = [];
  562. this.parentChannelId = 0;
  563. this.currentPage = 1;
  564. this.initData();
  565. },
  566. treeNodeClickEvent: function (device, data, isCatalog) {
  567. console.log(device)
  568. if (!!!data.channelId) {
  569. this.parentChannelId = device.deviceId;
  570. } else {
  571. this.parentChannelId = data.channelId;
  572. }
  573. this.initData();
  574. },
  575. // 保存
  576. handleSave(row) {
  577. if (row.location) {
  578. const segements = row.location.split(",");
  579. if (segements.length !== 2) {
  580. this.$message.warning("位置信息格式有误,例:117.234,36.378");
  581. return;
  582. } else {
  583. row.longitude = parseFloat(segements[0]);
  584. row.latitude = parseFloat(segements[1]);
  585. if (!(row.longitude && row.latitude)) {
  586. this.$message.warning("位置信息格式有误,例:117.234,36.378");
  587. return;
  588. }
  589. }
  590. } else {
  591. delete row.longitude;
  592. delete row.latitude;
  593. }
  594. Object.keys(row).forEach(key => {
  595. const value = row[key];
  596. if (value === null || value === undefined || (typeof value === "string" && value.trim() === "")) {
  597. delete row[key];
  598. }
  599. });
  600. this.$axios({
  601. method: 'post',
  602. url: `/api/device/query/channel/update/${this.deviceId}`,
  603. params: row
  604. }).then(response => {
  605. if (response.data.code === 0) {
  606. this.$message.success("修改成功!");
  607. this.initData();
  608. } else {
  609. this.$message.error("修改失败!");
  610. }
  611. }).catch(_ => {
  612. this.$message.error("修改失败!");
  613. })
  614. },
  615. // 是否正在编辑
  616. isEdit() {
  617. let editing = false;
  618. this.deviceChannelList.forEach(e => {
  619. if (e.edit) {
  620. editing = true;
  621. }
  622. });
  623. return editing;
  624. },
  625. // 编辑
  626. handleEdit(row) {
  627. if (this.isEdit()) {
  628. this.$message.warning('请保存当前编辑项!');
  629. } else {
  630. row.edit = true;
  631. }
  632. }
  633. }
  634. };
  635. </script>
  636. <style>
  637. .videoList {
  638. display: flex;
  639. flex-wrap: wrap;
  640. align-content: flex-start;
  641. }
  642. .video-item {
  643. position: relative;
  644. width: 15rem;
  645. height: 10rem;
  646. margin-right: 1rem;
  647. background-color: #000000;
  648. }
  649. .video-item-img {
  650. position: absolute;
  651. top: 0;
  652. bottom: 0;
  653. left: 0;
  654. right: 0;
  655. margin: auto;
  656. width: 100%;
  657. height: 100%;
  658. }
  659. .video-item-img:after {
  660. content: "";
  661. display: inline-block;
  662. position: absolute;
  663. z-index: 2;
  664. top: 0;
  665. bottom: 0;
  666. left: 0;
  667. right: 0;
  668. margin: auto;
  669. width: 3rem;
  670. height: 3rem;
  671. background-image: url("../assets/loading.png");
  672. background-size: cover;
  673. background-color: #000000;
  674. }
  675. .video-item-title {
  676. position: absolute;
  677. bottom: 0;
  678. color: #000000;
  679. background-color: #ffffff;
  680. line-height: 1.5rem;
  681. padding: 0.3rem;
  682. width: 14.4rem;
  683. }
  684. </style>