ChannelList.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  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.$refs.devicePlayer) {
  261. console.log('子组件引用成功');
  262. } else {
  263. console.log('子组件引用失败');
  264. }
  265. if (this.deviceId) {
  266. this.deviceService.getDevice(this.deviceId, (result) => {
  267. this.device = result;
  268. }, (error) => {
  269. console.log("获取设备信息失败")
  270. console.error(error)
  271. })
  272. }
  273. this.initData();
  274. },
  275. destroyed() {
  276. this.$destroy('videojs');
  277. clearTimeout(this.updateLooper);
  278. },
  279. methods: {
  280. initData: function () {
  281. if (typeof (this.parentChannelId) == "undefined" || this.parentChannelId == 0) {
  282. this.getDeviceChannelList();
  283. } else {
  284. this.showSubchannels();
  285. }
  286. },
  287. initParam: function () {
  288. this.deviceId = this.$route.params.deviceId;
  289. this.parentChannelId = this.$route.params.parentChannelId;
  290. this.currentPage = 1;
  291. this.count = 15;
  292. if (this.parentChannelId == "" || this.parentChannelId == 0) {
  293. this.beforeUrl = "/deviceList"
  294. }
  295. },
  296. currentChange: function (val) {
  297. this.currentPage = val;
  298. this.initData();
  299. },
  300. handleSizeChange: function (val) {
  301. this.count = val;
  302. this.getDeviceChannelList();
  303. },
  304. getDeviceChannelList: function () {
  305. let that = this;
  306. if (typeof (this.$route.params.deviceId) == "undefined") return;
  307. this.$axios({
  308. method: 'get',
  309. url: `/api/device/query/devices/${this.$route.params.deviceId}/channels`,
  310. params: {
  311. page: that.currentPage,
  312. count: that.count,
  313. query: that.searchSrt,
  314. online: that.online,
  315. channelType: that.channelType
  316. }
  317. }).then(function (res) {
  318. if (res.data.code === 0) {
  319. that.total = res.data.data.total;
  320. that.deviceChannelList = res.data.data.list;
  321. that.deviceChannelList.forEach(e => {
  322. e.ptzType = e.ptzType + "";
  323. that.$set(e, "edit", false);
  324. that.$set(e, "location", "");
  325. if (e.customLongitude && e.customLatitude) {
  326. that.$set(e, "location", e.customLongitude + "," + e.customLatitude);
  327. }else if (e.longitude && e.latitude) {
  328. that.$set(e, "location", e.longitude + "," + e.latitude);
  329. }
  330. });
  331. // 防止出现表格错位
  332. that.$nextTick(() => {
  333. that.$refs.channelListTable.doLayout();
  334. })
  335. }
  336. }).catch(function (error) {
  337. console.log(error);
  338. });
  339. },
  340. //通知设备上传媒体流
  341. sendDevicePush: function (itemData) {
  342. let deviceId = this.deviceId;
  343. this.isLoging = true;
  344. let channelId = itemData.channelId;
  345. // let deviceName=itemData.name;
  346. console.log("通知设备推流1:" + deviceId + " : " + channelId);
  347. let that = this;
  348. this.$axios({
  349. method: 'get',
  350. url: '/api/play/start/' + deviceId + '/' + channelId,
  351. params: {
  352. isSubStream: this.isSubStream
  353. }
  354. }).then(function (res) {
  355. // console.log(res)
  356. that.isLoging = false;
  357. if (res.data.code === 0) {
  358. setTimeout(() => {
  359. let snapId = deviceId + "_" + channelId;
  360. that.loadSnap[deviceId + channelId] = 0;
  361. that.getSnapErrorEvent(snapId)
  362. }, 5000)
  363. itemData.streamId = res.data.data.stream;
  364. that.$refs.devicePlayer.openDialog("media", deviceId, channelId, {
  365. streamInfo: res.data.data,
  366. hasAudio: itemData.hasAudio,
  367. deviceName: itemData.name
  368. });
  369. setTimeout(() => {
  370. that.initData();
  371. }, 1000)
  372. } else {
  373. that.$message.error(res.data.msg);
  374. }
  375. }).catch(function (e) {
  376. console.error(e)
  377. that.isLoging = false;
  378. // that.$message.error("请求超时");
  379. });
  380. },
  381. moreClick: function (command, itemData) {
  382. if (command === "records") {
  383. this.queryRecords(itemData)
  384. }else if (command === "cloudRecords") {
  385. this.queryCloudRecords(itemData)
  386. }
  387. },
  388. queryRecords: function (itemData) {
  389. let deviceId = this.deviceId;
  390. let channelId = itemData.channelId;
  391. this.$router.push(`/gbRecordDetail/${deviceId}/${channelId}`)
  392. },
  393. queryCloudRecords: function (itemData) {
  394. let deviceId = this.deviceId;
  395. let channelId = itemData.channelId;
  396. this.$router.push(`/cloudRecordDetail/rtp/${deviceId}_${channelId}`)
  397. },
  398. stopDevicePush: function (itemData) {
  399. var that = this;
  400. this.$axios({
  401. method: 'get',
  402. url: '/api/play/stop/' + this.deviceId + "/" + itemData.channelId,
  403. params: {
  404. isSubStream: this.isSubStream
  405. }
  406. }).then(function (res) {
  407. that.initData();
  408. }).catch(function (error) {
  409. if (error.response.status === 402) { // 已经停止过
  410. that.initData();
  411. } else {
  412. console.log(error)
  413. }
  414. });
  415. },
  416. getSnap: function (row) {
  417. let baseUrl = window.baseUrl ? window.baseUrl : "";
  418. return ((process.env.NODE_ENV === 'development') ? process.env.BASE_API : baseUrl) + '/api/device/query/snap/' + row.deviceId + '/' + row.channelId;
  419. },
  420. getBigSnap: function (row) {
  421. return [this.getSnap(row)]
  422. },
  423. getSnapErrorEvent: function (deviceId, channelId) {
  424. if (typeof (this.loadSnap[deviceId + channelId]) != "undefined") {
  425. console.log("下载截图" + this.loadSnap[deviceId + channelId])
  426. if (this.loadSnap[deviceId + channelId] > 5) {
  427. delete this.loadSnap[deviceId + channelId];
  428. return;
  429. }
  430. setTimeout(() => {
  431. let url = (process.env.NODE_ENV === 'development' ? "debug" : "") + '/api/device/query/snap/' + deviceId + '/' + channelId
  432. this.loadSnap[deviceId + channelId]++
  433. document.getElementById(deviceId + channelId).setAttribute("src", url + '?' + new Date().getTime())
  434. }, 1000)
  435. }
  436. },
  437. showDevice: function () {
  438. this.$router.push(this.beforeUrl).then(() => {
  439. this.initParam();
  440. this.initData();
  441. })
  442. },
  443. changeSubchannel(itemData) {
  444. this.beforeUrl = this.$router.currentRoute.path;
  445. var url = `/${this.$router.currentRoute.name}/${this.$router.currentRoute.params.deviceId}/${itemData.channelId}`
  446. this.$router.push(url).then(() => {
  447. this.searchSrt = "";
  448. this.channelType = "";
  449. this.online = "";
  450. this.initParam();
  451. this.initData();
  452. })
  453. },
  454. showSubchannels: function (channelId) {
  455. if (!this.showTree) {
  456. this.$axios({
  457. method: 'get',
  458. url: `/api/device/query/sub_channels/${this.deviceId}/${this.parentChannelId}/channels`,
  459. params: {
  460. page: this.currentPage,
  461. count: this.count,
  462. query: this.searchSrt,
  463. online: this.online,
  464. channelType: this.channelType
  465. }
  466. }).then((res) => {
  467. if (res.data.code === 0) {
  468. this.total = res.data.data.total;
  469. this.deviceChannelList = res.data.data.list;
  470. this.deviceChannelList.forEach(e => {
  471. e.ptzType = e.ptzType + "";
  472. this.$set(e, "edit", false);
  473. this.$set(e, "location", "");
  474. if (e.customLongitude && e.customLatitude) {
  475. this.$set(e, "location", e.customLongitude + "," + e.customLatitude);
  476. }else if (e.longitude && e.latitude) {
  477. this.$set(e, "location", e.longitude + "," + e.latitude);
  478. }
  479. });
  480. // 防止出现表格错位
  481. this.$nextTick(() => {
  482. this.$refs.channelListTable.doLayout();
  483. })
  484. }
  485. }).catch(function (error) {
  486. console.log(error);
  487. });
  488. } else {
  489. this.$axios({
  490. method: 'get',
  491. url: `/api/device/query/tree/channel/${this.deviceId}`,
  492. params: {
  493. parentId: this.parentChannelId,
  494. page: this.currentPage,
  495. count: this.count,
  496. }
  497. }).then((res) => {
  498. if (res.data.code === 0) {
  499. this.total = res.data.total;
  500. this.deviceChannelList = res.data.list;
  501. // 防止出现表格错位
  502. this.$nextTick(() => {
  503. this.$refs.channelListTable.doLayout();
  504. })
  505. }
  506. }).catch(function (error) {
  507. console.log(error);
  508. });
  509. }
  510. },
  511. search: function () {
  512. this.currentPage = 1;
  513. this.total = 0;
  514. this.initData();
  515. },
  516. updateChannel: function (row) {
  517. this.$axios({
  518. method: 'post',
  519. url: `/api/device/query/channel/update/${this.deviceId}`,
  520. params: row
  521. }).then(function (res) {
  522. console.log(JSON.stringify(res));
  523. });
  524. },
  525. subStreamChange: function () {
  526. this.$confirm('确定重置所有通道的码流类型?', '提示', {
  527. confirmButtonText: '确定',
  528. cancelButtonText: '取消',
  529. type: 'warning'
  530. }).then(() => {
  531. this.$axios({
  532. method: 'post',
  533. url: `/api/device/query/channel/stream/identification/update/`,
  534. params: {
  535. deviceId: this.deviceId,
  536. streamIdentification: this.subStream
  537. }
  538. }).then((res)=> {
  539. console.log(JSON.stringify(res));
  540. this.initData()
  541. }).finally(()=>{
  542. this.subStream = ""
  543. })
  544. }).catch(() => {
  545. this.subStream = ""
  546. });
  547. },
  548. channelSubStreamChange: function (row) {
  549. this.$axios({
  550. method: 'post',
  551. url: `/api/device/query/channel/stream/identification/update/`,
  552. params: {
  553. deviceId: this.deviceId,
  554. channelId: row.channelId,
  555. streamIdentification: row.streamIdentification
  556. }
  557. }).then(function (res) {
  558. console.log(JSON.stringify(res));
  559. });
  560. },
  561. refresh: function () {
  562. this.initData();
  563. },
  564. switchTree: function () {
  565. this.showTree = true;
  566. this.deviceChannelList = [];
  567. this.parentChannelId = 0;
  568. this.currentPage = 1;
  569. },
  570. switchList: function () {
  571. this.showTree = false;
  572. this.deviceChannelList = [];
  573. this.parentChannelId = 0;
  574. this.currentPage = 1;
  575. this.initData();
  576. },
  577. treeNodeClickEvent: function (device, data, isCatalog) {
  578. console.log(device)
  579. if (!!!data.channelId) {
  580. this.parentChannelId = device.deviceId;
  581. } else {
  582. this.parentChannelId = data.channelId;
  583. }
  584. this.initData();
  585. },
  586. // 保存
  587. handleSave(row) {
  588. if (row.location) {
  589. const segements = row.location.split(",");
  590. if (segements.length !== 2) {
  591. this.$message.warning("位置信息格式有误,例:117.234,36.378");
  592. return;
  593. } else {
  594. row.customLongitude = parseFloat(segements[0]);
  595. row.custom_latitude = parseFloat(segements[1]);
  596. if (!(row.longitude && row.latitude)) {
  597. this.$message.warning("位置信息格式有误,例:117.234,36.378");
  598. return;
  599. }
  600. }
  601. } else {
  602. delete row.longitude;
  603. delete row.latitude;
  604. }
  605. Object.keys(row).forEach(key => {
  606. const value = row[key];
  607. if (value === null || value === undefined || (typeof value === "string" && value.trim() === "")) {
  608. delete row[key];
  609. }
  610. });
  611. this.$axios({
  612. method: 'post',
  613. url: `/api/device/query/channel/update/${this.deviceId}`,
  614. params: row
  615. }).then(response => {
  616. if (response.data.code === 0) {
  617. this.$message.success("修改成功!");
  618. this.initData();
  619. } else {
  620. this.$message.error("修改失败!");
  621. }
  622. }).catch(_ => {
  623. this.$message.error("修改失败!");
  624. })
  625. },
  626. // 是否正在编辑
  627. isEdit() {
  628. let editing = false;
  629. this.deviceChannelList.forEach(e => {
  630. if (e.edit) {
  631. editing = true;
  632. }
  633. });
  634. return editing;
  635. },
  636. // 编辑
  637. handleEdit(row) {
  638. if (this.isEdit()) {
  639. this.$message.warning('请保存当前编辑项!');
  640. } else {
  641. row.edit = true;
  642. }
  643. }
  644. }
  645. };
  646. </script>
  647. <style>
  648. .videoList {
  649. display: flex;
  650. flex-wrap: wrap;
  651. align-content: flex-start;
  652. }
  653. .video-item {
  654. position: relative;
  655. width: 15rem;
  656. height: 10rem;
  657. margin-right: 1rem;
  658. background-color: #000000;
  659. }
  660. .video-item-img {
  661. position: absolute;
  662. top: 0;
  663. bottom: 0;
  664. left: 0;
  665. right: 0;
  666. margin: auto;
  667. width: 100%;
  668. height: 100%;
  669. }
  670. .video-item-img:after {
  671. content: "";
  672. display: inline-block;
  673. position: absolute;
  674. z-index: 2;
  675. top: 0;
  676. bottom: 0;
  677. left: 0;
  678. right: 0;
  679. margin: auto;
  680. width: 3rem;
  681. height: 3rem;
  682. background-image: url("../assets/loading.png");
  683. background-size: cover;
  684. background-color: #000000;
  685. }
  686. .video-item-title {
  687. position: absolute;
  688. bottom: 0;
  689. color: #000000;
  690. background-color: #ffffff;
  691. line-height: 1.5rem;
  692. padding: 0.3rem;
  693. width: 14.4rem;
  694. }
  695. </style>