CameraManagement.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. <template>
  2. <div class="CameraManagement">
  3. <el-row :gutter="20">
  4. <!-- <el-col :span="2">
  5. <span style="line-height:32px;">工具栏:</span>
  6. </el-col>
  7. <el-col :span="12">
  8. <el-input
  9. placeholder="请输入内容"
  10. v-model="searchParams"
  11. class="input-with-select"
  12. @keyup.enter.native="getDeviceList"
  13. >
  14. <el-button slot="append" icon="el-icon-search" @click="getDeviceList"></el-button>
  15. </el-input>
  16. </el-col>-->
  17. <el-col :span="8">
  18. <el-button @click="add" type="primary" icon="el-icon-document-add">新建</el-button>
  19. </el-col>
  20. </el-row>
  21. <hr style="border-top: 2px solid #eee;margin: 10px 0;" />
  22. <el-row>
  23. <el-table :data="deviceList">
  24. <el-table-column prop="id" label="序号" width="120px"></el-table-column>
  25. <el-table-column prop="name" label="名称"></el-table-column>
  26. <el-table-column prop="deviceNo" label="设备序列号"></el-table-column>
  27. <el-table-column prop="status" label="摄像头状态"></el-table-column>
  28. <el-table-column prop="description" label="描述"></el-table-column>
  29. <el-table-column label="最后一次">
  30. <template slot-scope="scope">
  31. <span>{{ new Date(scope.row.updated).toLocaleDateString() }}</span>
  32. </template>
  33. </el-table-column>
  34. <el-table-column fixed="right" label="操作" width="200">
  35. <template slot-scope="scope">
  36. <el-button
  37. @click="handlePlay(scope.row)"
  38. type="text"
  39. v-if="isCamera(scope.row.categoryId)"
  40. >播放</el-button>
  41. <el-button @click="edit(scope.row)" type="text" size="small">编辑</el-button>
  42. <el-popconfirm title="是否删除此设备的信息?" @onConfirm="del(scope.row)">
  43. <el-button slot="reference" type="text" size="small">删除</el-button>
  44. </el-popconfirm>
  45. </template>
  46. </el-table-column>
  47. </el-table>
  48. </el-row>
  49. <!-- 设备信息新建、编辑 -->
  50. <el-dialog :title="isAdd?'新建设备信息':'编辑设备信息'" :visible.sync="isShowDialog" append-to-body>
  51. <el-form :model="formData" ref="cameraForm" :rules="rules" label-width="100px">
  52. <el-form-item label="名称:" prop="name">
  53. <el-input v-model="formData.name" placeholder="请输入名称"></el-input>
  54. </el-form-item>
  55. <el-form-item label="摄像头类型:">
  56. <el-cascader
  57. :options="cameraInfoTree"
  58. :props="{ checkStrictly: true, children: 'childs', label: 'nodeName' ,value:'id'}"
  59. v-model="formData.categoryId"
  60. clearable
  61. >
  62. <template slot-scope="{ node, data }">
  63. <span>{{ data.nodeName }}</span>
  64. <span v-if="!node.isLeaf">({{ data.childs.length }})</span>
  65. </template>
  66. </el-cascader>
  67. </el-form-item>
  68. <el-form-item label="设备序列号:" prop="deviceNo">
  69. <el-input v-model="formData.deviceNo" placeholder="设备序列号"></el-input>
  70. </el-form-item>
  71. <el-form-item label="配置信息:">
  72. <el-row
  73. type="flex"
  74. justify="space-between"
  75. :gutter="20"
  76. style="margin-bottom:10px"
  77. v-for="(item,index) in meta"
  78. :key="index"
  79. >
  80. <el-col :span="3" style="text-align:right">rtsp:</el-col>
  81. <el-col :span="7">
  82. <el-input placeholder="请输入内容" v-model="item.rtsp"></el-input>
  83. </el-col>
  84. <el-col :span="3" style="text-align:right">ws:</el-col>
  85. <el-col :span="7">
  86. <el-input placeholder="请输入内容" v-model="item.ws"></el-input>
  87. </el-col>
  88. <el-col :span="4">
  89. <el-button
  90. v-show="index==meta.length-1"
  91. @click="plus"
  92. type="primary"
  93. icon="el-icon-plus"
  94. circle
  95. ></el-button>
  96. <el-button
  97. v-show="index==meta.length-1&meta.length>1"
  98. @click="minus"
  99. type="primary"
  100. icon="el-icon-minus"
  101. circle
  102. ></el-button>
  103. </el-col>
  104. </el-row>
  105. </el-form-item>
  106. <el-form-item label="状态:">
  107. <el-select v-model="formData.status" placeholder="请选择">
  108. <el-option label="链接中" :value="0"></el-option>
  109. <el-option label="链接中" :value="1"></el-option>
  110. <el-option label="链接中" :value="2"></el-option>
  111. <el-option label="链接中" :value="3"></el-option>
  112. </el-select>
  113. </el-form-item>
  114. <el-form-item label="描述:">
  115. <el-input
  116. type="textarea"
  117. :rows="2"
  118. v-model="formData.description"
  119. placeholder="输入描述"
  120. ></el-input>
  121. </el-form-item>
  122. </el-form>
  123. <div slot="footer">
  124. <el-button @click="isShowDialog=false">取 消</el-button>
  125. <el-button type="primary" @click="submitForm('cameraForm')">保 存</el-button>
  126. </div>
  127. </el-dialog>
  128. <!-- 摄像头播放 -->
  129. <el-dialog :title="videoData.title" @close="handleStop" :visible.sync="isShowVideo">
  130. <rtsp-player ref="rtspPlayer" :rtspData="videoData"></rtsp-player>
  131. </el-dialog>
  132. </div>
  133. </template>
  134. <script>
  135. import { mapActions } from "vuex";
  136. import rtspPlayer from "../common/rtsp-player/index";
  137. // 表单验证规则
  138. const rules = {
  139. name: [{ required: true, message: "请输入摄像头名称", trigger: "blur" }],
  140. deviceNo: [{ required: true, message: "请输入设备序列号", trigger: "blur" }]
  141. };
  142. export default {
  143. name: "CameraManagement",
  144. components: { rtspPlayer },
  145. data() {
  146. return {
  147. id: "",
  148. cameraInfoTree: [],
  149. deviceList: [],
  150. isShowDialog: false,
  151. formData: {
  152. name: "",
  153. categoryId: [],
  154. deviceNo: "",
  155. status: "",
  156. description: ""
  157. },
  158. meta: [{ rtsp: "", ws: "" }],
  159. isShowVideo: false,
  160. videoData: {
  161. title: null,
  162. rtsp: null,
  163. ws: null
  164. },
  165. configItems: 2, // 配置项的通道配置项数
  166. isAdd: true,
  167. rules
  168. };
  169. },
  170. created() {
  171. // 获取摄像头 树
  172. this.getTreeByCode("ip-cam");
  173. },
  174. methods: {
  175. ...mapActions(["fetch"]),
  176. submitForm(formName) {
  177. this.$refs[formName].validate(valid => {
  178. if (valid) {
  179. this.save();
  180. } else {
  181. return false;
  182. }
  183. });
  184. },
  185. // 通过code获取树
  186. getTreeByCode(code) {
  187. this.fetch({
  188. api: "/publics/treenode/getTreeByCode",
  189. method: "POST",
  190. data: { code }, //目前只有一个组织,其他参数调整钟
  191. success: res => {
  192. this.id = res.id;
  193. this.getDeviceList(res.id);
  194. this.getCameraList(res.id);
  195. },
  196. fail: err => {
  197. console.log(err);
  198. if (err.errCode == "request_not_authorize") {
  199. this.$message({
  200. message: "请重新登录",
  201. type: "warning"
  202. });
  203. }
  204. }
  205. });
  206. },
  207. getDeviceList(categoryId) {
  208. this.fetch({
  209. api: "/device/device/list",
  210. method: "POST",
  211. data: { categoryId }, //目前只有一个组织,其他参数调整钟 732971735112749056
  212. success: res => {
  213. this.deviceList = res.content;
  214. },
  215. fail: err => {
  216. if (err.errCode == "request_not_authorize") {
  217. this.$message({
  218. message: "请重新登录",
  219. type: "warning"
  220. });
  221. }
  222. console.log(err);
  223. }
  224. });
  225. },
  226. // 请求 拿到摄像头列表
  227. getCameraList(parentId) {
  228. this.fetch({
  229. api: "/publics/treenode/listNodeByParent",
  230. method: "POST",
  231. data: {
  232. parentId,
  233. hasSub: true
  234. },
  235. success: res => {
  236. this.cameraInfoTree = res;
  237. },
  238. fail: err => {
  239. if (err.errMsg) this.$message.error(err.errMsg);
  240. else this.$message.error("服务器发生异常");
  241. }
  242. });
  243. },
  244. // 编辑的保存按钮
  245. save() {
  246. this.formData.meta = { channel: JSON.stringify(this.meta) };
  247. let categoryId = this.formData.categoryId;
  248. if (categoryId instanceof Array) {
  249. this.formData.categoryId = categoryId[categoryId.length - 1];
  250. }
  251. let api = this.isAdd
  252. ? "/device/device/add"
  253. : "/device/device/update";
  254. this.fetch({
  255. api,
  256. data: this.formData,
  257. success: res => {
  258. this.getDeviceList(this.id); //重新加载
  259. // this.isShowDialog = false;
  260. this.$message.success(
  261. this.isAdd
  262. ? "添加摄像头数据成功!"
  263. : "修改摄像头数据成功!"
  264. );
  265. },
  266. fail: err => {
  267. console.log(err);
  268. if (err.errMsg) this.$message.error(err.errMsg);
  269. else this.$message.error("服务器发生异常");
  270. }
  271. });
  272. },
  273. // 请求删除
  274. reqDelete(id) {
  275. this.fetch({
  276. api: "/device/delete",
  277. data: { id },
  278. success: res => {
  279. this.getDeviceList(this.id); //重新加载
  280. },
  281. fail: err => {
  282. console.log(err);
  283. if (err.errMsg) this.$message.error(err.errMsg);
  284. else this.$message.error("服务器发生异常");
  285. }
  286. });
  287. },
  288. add() {
  289. this.isAdd = true;
  290. // this.formData = {
  291. // name: "",
  292. // categoryId: "",
  293. // deviceNo: "",
  294. // status: "",
  295. // sVer: "",
  296. // hVer: "",
  297. // description: ""
  298. // };
  299. // this.meta = [{ rtsp: "", ws: "" }]
  300. if (this.formData.id) delete this.formData.id;
  301. this.isShowDialog = true;
  302. },
  303. isCamera(hid) {
  304. return true;
  305. },
  306. // 播放
  307. handlePlay(row) {
  308. console.log(row);
  309. if (row.meta.channel && row.meta.channel.length > 0) {
  310. let channals = JSON.parse(row.meta.channel);
  311. let rtsp = channals[0].rtsp;
  312. let ws = channals[0].ws;
  313. console.log("rtsp==>> " + rtsp);
  314. console.log("ws==>> " + ws);
  315. if(row.data && row.data["curr-ip"]){//要更换IP
  316. ws = ws.replace("ip-addr",row.data["curr-ip"])
  317. }
  318. this.videoData = {
  319. rtsp,
  320. ws,
  321. title: row.name
  322. };
  323. this.isShowVideo = true;
  324. } else this.$message.info("配置信息不正确");
  325. },
  326. handleStop(done) {
  327. console.log(this.$refs.rtspPlayer)
  328. // if (this.$refs.rtspPlayer) this.$refs.rtspPlayer.close();
  329. },
  330. // 编辑
  331. edit(row) {
  332. console.log(row);
  333. this.isAdd = false;
  334. this.isShowDialog = true;
  335. this.formData = row;
  336. this.meta = JSON.parse(row.meta.channel);
  337. // this.createArr(row.categoryId);
  338. },
  339. // 删除
  340. del(row) {
  341. console.log(row);
  342. this.reqDelete(row.id);
  343. },
  344. // 配置项增加
  345. plus() {
  346. this.meta.push({ rtsp: "", ws: "" });
  347. },
  348. // 配置项减少
  349. minus() {
  350. if (this.meta.length <= 1) return;
  351. this.meta.splice(this.meta.length - 1, 1);
  352. },
  353. show() {
  354. this.deviceList.forEach;
  355. }
  356. // 传入一个id 生成树( cameraInfoTree )的id数组 "732971850158313472" "732997784550772736"
  357. /* createArr(id) {
  358. let tmpArr = [id]
  359. let tree = this.cameraInfoTree;
  360. aa(id)
  361. console.log(tmpArr);
  362. function aa(id) {
  363. recursion(tree);
  364. function recursion(tree) {
  365. tree.forEach(item => {
  366. if (item.id == id) {
  367. let rse = isWarp(item.parentId)
  368. console.log(rse)
  369. if(rse == 0) {
  370. tmpArr.unshift(item.parentId)
  371. } else if(rse == 1) {
  372. tmpArr.unshift(item.parentId)
  373. aa(item.parentId)
  374. }
  375. return;
  376. } else {
  377. if (item.childs && item.childs.length > 0) {
  378. // debugger
  379. return recursion(item.childs);
  380. } else {
  381. // tmpArr = []
  382. return;
  383. }
  384. }
  385. });
  386. }
  387. }
  388. // 判断是否到最外层
  389. function isWarp(parentId) {
  390. let res = null
  391. tree.forEach(item => {
  392. if(item.id == parentId){
  393. res = 0 // 刚好到
  394. } else if(item.parentId == parentId){
  395. res = -1 // 已经到外面一层了
  396. } else {
  397. res = 1 // 还在内层
  398. }
  399. })
  400. return res
  401. }
  402. } */
  403. }
  404. };
  405. </script>
  406. <style lang="scss" scoped>
  407. .CameraManagement {
  408. .dialog {
  409. .item_row {
  410. display: flex;
  411. }
  412. }
  413. }
  414. </style>