addOrEditCamera.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. <!--
  2. * @Author: your name
  3. * @Date: 2020-11-27 18:53:33
  4. * @LastEditTime: 2021-05-31 09:02:15
  5. * @LastEditors: Please set LastEditors
  6. * @Description: In User Settings Edit
  7. * @FilePath: \WEB\dispatchingManagement\src\views\videoMonitor\cameraManage\popups\addOrEditCamera.vue
  8. -->
  9. <template>
  10. <div class="alert-body__main_content">
  11. <zz-form :cols="formCols" :data="formData" :rules="formRules" :errors="formErrors" labelWidth="120" ref="form">
  12. >
  13. <select-tree
  14. :props="defaultProps"
  15. slot="companyOrgId"
  16. class="new-select-tree"
  17. selectTreeTitle="组织机构"
  18. placeholder="请选择所属公司"
  19. :options="organListCompany"
  20. @selected="selectedcompanyOrgId"
  21. v-model="formData.companyOrgId"
  22. :labelModel="formData.companyOrgName"
  23. />
  24. <select-tree
  25. :props="defaultProps"
  26. slot="deptOrgId"
  27. class="new-select-tree"
  28. selectTreeTitle="组织机构"
  29. placeholder="请选择所属部门"
  30. :options="organListdepartment"
  31. @selected="selectedDepartOrgId"
  32. v-model="formData.deptOrgId"
  33. />
  34. <select-tree
  35. :props="defaultPropsscene"
  36. slot="sceneId"
  37. class="new-select-tree"
  38. selectTreeTitle="所属场景"
  39. placeholder="请选择所属场景"
  40. :options="allServiceScene"
  41. v-model="formData.sceneId"
  42. />
  43. <!-- 地址 -->
  44. <el-input slot="address" clearable v-model.trim="formData.address" placeholder="请输入地址">
  45. <i class="iconfont location-icon" slot="suffix" @click="openMapSelect">&#xe663;</i>
  46. </el-input>
  47. <el-dialog :visible.sync="dialogVisible">
  48. <img width="100%" :src="dialogImageUrl" alt="" />
  49. </el-dialog>
  50. <p slot="sceneId" class="scene-tip-style" >
  51. <i class="iconfont tips">&#xe639;</i>
  52. <span>如需正常播放视频,请完整填写视频预览地址、视频回放地址、视频回放地址、APPKEY、SCRERT、设备序列号、通道号等信息</span>
  53. </p>
  54. </zz-form>
  55. <el-dialog :append-to-body="true" title="选择地址" :visible.sync="dialogMapVisible" width="1000" :before-close="cancellocation">
  56. <div class="doalogmap">
  57. <div class="addressSearch">
  58. <i class="iconfont location-icon-16" slot="suffix">&#xe663;</i>
  59. <el-autocomplete
  60. class="map-input-filter"
  61. v-model="mapInputFilter"
  62. :fetch-suggestions="querySearchAsync"
  63. placeholder="请输入地址"
  64. @select="handleSelect"
  65. value-key="text"
  66. ref="querySearchAsyncInput"
  67. ></el-autocomplete>
  68. <!-- 经度 longitude -->
  69. <!-- 纬度 latitude -->
  70. <el-input class="w100" v-model.trim="inputlongitude" @keyup.native="inputlongitude = oninput(inputlongitude,'x')" placeholder="请输入经度"></el-input>
  71. <el-input class="w100" v-model.trim="inputlatitude" @keyup.native="inputlatitude = oninput(inputlatitude,'y')" placeholder="请输入纬度"></el-input>
  72. <el-button class="map-input-btn" type="primary" @click="querySearchAsyncBtn"
  73. ><i class="iconfont">&#xe6fc;</i>查询</el-button
  74. >
  75. </div>
  76. <map-init ref="mapInit" v-on:getCityNamevalfn="getCityNameval" @getwkidfn='getwkid' @getmoveXYfn='getmoveXY'></map-init>
  77. </div>
  78. <span slot="footer" class="dialog-footer">
  79. <el-button @click="cancellocation">取 消</el-button>
  80. <el-button type="primary" @click="saveAddress">保 存</el-button>
  81. </span>
  82. </el-dialog>
  83. </div>
  84. </template>
  85. <script>
  86. import CoordConver from '@/utils/CoordConver.js';
  87. export default {
  88. mixin: [CoordConver],
  89. props: ['params'],
  90. data() {
  91. return {
  92. organList: [
  93. {
  94. id: 1,
  95. tenantId: 'string123',
  96. orgName: '公司',
  97. parentOrgId: 0,
  98. orgs: [{ id: 2, tenantId: 'string123', orgName: '部门', parentOrgId: 1, orgs: null, display: true }],
  99. display: true
  100. }
  101. ],
  102. scenetypeList: [],
  103. allServiceScene: [],
  104. organListCompany: [],
  105. organListdepartment: [],
  106. formData: {
  107. address: '',
  108. companyOrgId: 0,
  109. deptOrgId: 0,
  110. deviceCode: 0,
  111. deviceMode: '',
  112. name: '', //摄像头名称
  113. scrert: '', //萤石scrert
  114. appkey: '', //萤石appkey
  115. deviceSerial: '', //设备序列号
  116. channelNo: '', //通道号
  117. deviceType: '',
  118. deviceTypeId: 0,
  119. enableState: 1,
  120. id: 0,
  121. manufacturerId: 0,
  122. pointX: 0,
  123. pointY: 0,
  124. remark: '',
  125. sceneId: 0,
  126. sceneName: '',
  127. status: 0,
  128. tenantId: '',
  129. channelNo: '' , //通道号
  130. palyUrl: '' //视频预览地址
  131. },
  132. mapInputFilter: '',
  133. inputlongitude:'',
  134. inputlatitude:'',
  135. dialogMapVisible: false,
  136. defaultProps: {
  137. value: 'id', // 唯一标识
  138. label: 'orgName', // 标签显示
  139. children: 'orgs' // 子级
  140. },
  141. defaultPropsscene: {
  142. value: 'id', // 唯一标识
  143. label: 'sceneName', // 标签显示
  144. children: 'children' // 子级
  145. },
  146. formCols: [
  147. [
  148. {
  149. label: '名称',
  150. prop: 'name',
  151. input: true
  152. },
  153. {
  154. label: '所属公司',
  155. prop: 'companyOrgId',
  156. slot: 'companyOrgId'
  157. },
  158. {
  159. label: '所属部门',
  160. prop: 'deptOrgId',
  161. slot: 'deptOrgId'
  162. },
  163. {
  164. label: '所属场景',
  165. prop: 'sceneId',
  166. slot: 'sceneId'
  167. },
  168. {
  169. label: '地址',
  170. prop: 'address',
  171. slot: 'address'
  172. },
  173. {
  174. label: '视频预览地址',
  175. prop: 'palyUrl',
  176. input: true
  177. },
  178. {
  179. label: 'APPKEY',
  180. prop: 'appkey',
  181. input: true
  182. },
  183. {
  184. label: 'SCRERT',
  185. prop: 'scrert',
  186. input: true
  187. },
  188. {
  189. label: '设备序列号',
  190. prop: 'deviceSerial',
  191. input: true
  192. },
  193. {
  194. label: '通道号',
  195. prop: 'channelNo',
  196. input: true
  197. }
  198. ]
  199. ],
  200. formRules: {
  201. name: [this.$valid.inputRequired('名称'),this.$valid.limitVideoNumber20()],
  202. companyOrgId: [this.$valid.selectRequired('所属公司')],
  203. sceneId: [this.$valid.selectRequired('所属场景')],
  204. address: [this.$valid.inputRequired('地址'),this.$valid.limitVideo(), { trigger: 'change' }],
  205. palyUrl: [this.$valid.inputRequired('视频预览地址')],
  206. appkey: [this.$valid.inputRequired('APPKEY'),this.$valid.limitVideoNumber()],
  207. scrert: [this.$valid.inputRequired('SCRERT'),this.$valid.limitVideoNumber()],
  208. deviceSerial: [this.$valid.inputRequired('设备序列号'),this.$valid.limitVideoNumber()],
  209. channelNo: [this.$valid.inputRequired('通道号'),this.$valid.cameraChannel()]
  210. },
  211. formErrors: {},
  212. getCityName: '',
  213. getWkidVal:''
  214. };
  215. },
  216. created() {
  217. this.__setValue('formData');
  218. // this.formData = this.params.data ? this.params.data : this.formData;
  219. this.organList = this.params.organList ? this.params.organList : this.organList;
  220. this.scenetypeList = this.params.scenetypeList ? this.params.scenetypeList : this.scenetypeList;
  221. this.allServiceScene = this.params.allServiceScene ? this.params.allServiceScene : this.allServiceScene;
  222. this.organListCompany = this.params.organListCompany ? this.params.organListCompany : this.organListCompany;
  223. this.organListdepartment = this.params.organListdepartment ? this.params.organListdepartment : this.organListdepartment;
  224. this.deviceTypeIdoptions = this.params.deviceTypeIdoptions ? this.params.deviceTypeIdoptions : this.deviceTypeIdoptions;
  225. this.allRoleId = this.params.allRoleId ? this.params.allRoleId : this.allRoleId;
  226. this.allUserType = this.params.allUserType ? this.params.allUserType : this.allUserType;
  227. if(!this.formData.id){
  228. this.formData.enableState = 1
  229. }
  230. },
  231. methods: {
  232. getmoveXY(val){
  233. this.getmoveXYVal = val;
  234. },
  235. getwkid(val){
  236. this.getWkidVal = val;
  237. },
  238. // 获取子级传的值
  239. getCityNameval(val) {
  240. this.getCityName = val;
  241. },
  242. selectedcompanyOrgId(e) {
  243. this.formData.deptOrgId = '';
  244. this.organListdepartment = [];
  245. this.formData.sceneId = '';
  246. this.allServiceScene = [];
  247. if (!e) return;
  248. // 获取 部门树e
  249. this.$http.postForm('/sc-user-center/org/getOrgUserTree', { orgType: 'department', id: e }).then(({ status, data, msg }) => {
  250. if (status === 0) {
  251. this.organListdepartment = data ? data : [];
  252. this.selectedSceneOrgId();
  253. } else {
  254. this.$message.error(msg);
  255. }
  256. });
  257. },
  258. selectedDepartOrgId(e) {
  259. this.formData.sceneId = ''; //选择部门时,清空场景原有值
  260. this.allServiceScene = []; //选择部门时,清空场景原有值
  261. // if (e ==='') return ;
  262. this.selectedSceneOrgId(e);
  263. },
  264. selectedSceneOrgId(e) {
  265. // if(!e)return
  266. // 获取 上级场景列表
  267. this.$http
  268. .get('/sc-zoniot-water/scene/selectListForParm', { comId: this.formData.companyOrgId, deptId: this.formData.deptOrgId })
  269. .then(({ status, data, msg }) => {
  270. if (status === 0) {
  271. this.allServiceScene = data ? data : [];
  272. } else {
  273. this.$message.error(msg);
  274. }
  275. });
  276. },
  277. // GCJ-02 => 墨卡托
  278. //经度转墨卡托
  279. handle_x(x) {
  280. return (x / 180.0) * 20037508.34;
  281. },
  282. //纬度转墨卡托
  283. handle_y(y) {
  284. if (y > 85.05112) {
  285. y = 85.05112;
  286. }
  287. if (y < -85.05112) {
  288. y = -85.05112;
  289. }
  290. y = (Math.PI / 180.0) * y;
  291. var tmp = Math.PI / 4.0 + y / 2.0;
  292. return (20037508.34 * Math.log(Math.tan(tmp))) / Math.PI;
  293. },
  294. /**
  295. * 调用高德地图执行模糊查询
  296. * @param {Number} page 当前页
  297. * @param {String} inputval 关键字
  298. * @param {Function} cb 回调函数
  299. * @param {Boolean} isMark 是否在地图上标记点
  300. */
  301. AmapSearch(page, inputval, cb, isMark) {
  302. var keywords = inputval;
  303. AMap.plugin('AMap.PlaceSearch', () => {
  304. var autoOptions = {
  305. city: this.getCityName,
  306. citylimit: true,
  307. pageIndex: page
  308. };
  309. var placeSearch = new AMap.PlaceSearch(autoOptions);
  310. placeSearch.search(keywords, (status, result) => {
  311. if (status != 'complete') {
  312. return;
  313. }
  314. var datas = result.poiList;
  315. let count = datas.count;
  316. let crupage = datas.pageIndex;
  317. let arr = datas.pois;
  318. var pointData = [];
  319. var returnObjectList = [];
  320. for (let i = 0; i < arr.length; i++) {
  321. const element = arr[i];
  322. var xy = [];
  323. var x = element.location.lng; //经度
  324. var y = element.location.lat; // 纬度
  325. x = this.handle_x(x);
  326. y = this.handle_y(y);
  327. xy.push(x);
  328. xy.push(y);
  329. var returnObject = new Object();
  330. returnObject.id = element.id;
  331. returnObject.text = element.name;
  332. returnObject.address = element.address;
  333. returnObject.XY = xy;
  334. var marksData = {
  335. json: xy
  336. };
  337. pointData = pointData.concat(marksData);
  338. returnObjectList.push(returnObject);
  339. }
  340. // var symbol = new PictureMarkSymbolArgs();
  341. // symbol.url = 'images/amap_l_gray.png';
  342. // symbol.height = 36;
  343. // symbol.width = 36;
  344. // symbol.yoffset = 15;
  345. // symbol.xoffset = 3;
  346. // if (isMark) {
  347. // createMarkLayer(pointData, 'vagueQueryLyr', symbol);
  348. // }
  349. var resDatasObj = {
  350. keywords: keywords,
  351. page: crupage,
  352. count: count,
  353. list: returnObjectList
  354. };
  355. cb(resDatasObj);
  356. });
  357. });
  358. },
  359. querySearchAsyncBtn() {
  360. if(this.mapInputFilter){
  361. this.$refs.querySearchAsyncInput.handleFocus();
  362. }else{
  363. this.$http.post('/sc-operation-manager/track/TaskTrack/convertXY', {
  364. "moveXY": this.getmoveXYVal,
  365. "wkid": this.getWkidVal,
  366. "xy": [`${this.inputlongitude},${this.inputlatitude}`]
  367. })
  368. .then(({ status, data, msg }) => {
  369. this.handleSelect({
  370. 'XY':data.convertXY[0].split(','),
  371. 'text':''
  372. })
  373. })
  374. }
  375. },
  376. querySearchAsync(queryString, cb) {
  377. if (!queryString) return;
  378. if(this.getWkidVal===2360){
  379. this.$refs.mapInit.fuzzyQueryLocation(queryString,(res)=>{
  380. let newarr = []
  381. res.map(item=>{
  382. var itemobj = {
  383. XY:[item.feature.geometry.x,item.feature.geometry.y],
  384. address:item.feature.attributes.TEXTSTRING,
  385. id:item.feature.attributes.OBJECTID,
  386. text:item.value
  387. }
  388. newarr.push(itemobj)
  389. })
  390. cb(newarr);
  391. });
  392. }else if(this.getWkidVal===3857){
  393. this.AmapSearch(
  394. 1,
  395. queryString,
  396. (result) => {
  397. //
  398. console.log(result.list);
  399. cb(result.list);
  400. },
  401. false
  402. );
  403. }
  404. },
  405. /**
  406. * 调用高德地图执行模糊查询
  407. * @param {Number} page 当前页
  408. * @param {String} inputval 关键字
  409. * @param {Function} cb 回调函数
  410. * @param {Boolean} isMark 是否在地图上标记点
  411. */
  412. AmapSearch(page, inputval, cb, isMark) {
  413. var keywords = inputval;
  414. AMap.plugin('AMap.PlaceSearch', () => {
  415. var autoOptions = {
  416. city: this.getCityName,
  417. citylimit: true,
  418. pageIndex: page
  419. };
  420. var placeSearch = new AMap.PlaceSearch(autoOptions);
  421. placeSearch.search(keywords, (status, result) => {
  422. if (status != 'complete') {
  423. return;
  424. }
  425. var datas = result.poiList;
  426. let count = datas.count;
  427. let crupage = datas.pageIndex;
  428. let arr = datas.pois;
  429. var pointData = [];
  430. var returnObjectList = [];
  431. for (let i = 0; i < arr.length; i++) {
  432. const element = arr[i];
  433. var xy = [];
  434. var x = element.location.lng; //经度
  435. var y = element.location.lat; // 纬度
  436. x = this.handle_x(x);
  437. y = this.handle_y(y);
  438. xy.push(x);
  439. xy.push(y);
  440. var returnObject = new Object();
  441. returnObject.id = element.id;
  442. returnObject.text = element.name;
  443. returnObject.address = element.address;
  444. returnObject.XY = xy;
  445. var marksData = {
  446. json: xy
  447. };
  448. pointData = pointData.concat(marksData);
  449. returnObjectList.push(returnObject);
  450. }
  451. // var symbol = new PictureMarkSymbolArgs();
  452. // symbol.url = 'images/amap_l_gray.png';
  453. // symbol.height = 36;
  454. // symbol.width = 36;
  455. // symbol.yoffset = 15;
  456. // symbol.xoffset = 3;
  457. // if (isMark) {
  458. // createMarkLayer(pointData, 'vagueQueryLyr', symbol);
  459. // }
  460. var resDatasObj = {
  461. keywords: keywords,
  462. page: crupage,
  463. count: count,
  464. list: returnObjectList
  465. };
  466. cb(resDatasObj);
  467. });
  468. });
  469. },
  470. openMapSelect() {
  471. this.dialogMapVisible = true;
  472. let item = {
  473. XY: '',
  474. address: '',
  475. id: '',
  476. text: ''
  477. };
  478. if (this.formData.pointX && this.formData.pointY) {
  479. item.XY = [this.formData.pointX, this.formData.pointY];
  480. item.text = this.formData.address;
  481. }
  482. this.$store.commit('setSearchPointInfo', item);
  483. },
  484. handleSelect(item) {
  485. this.formData.pointX = item.XY[0];
  486. this.formData.pointY = item.XY[1];
  487. this.formData.address = item.text;
  488. this.$store.commit('setSearchPointInfo', item);
  489. this.$refs.mapInit.centerAtByPoint(item.XY[0], item.XY[1]);
  490. },
  491. //地址地图取消
  492. cancellocation() {
  493. // this.$store.commit('setSearchPointInfo', '');
  494. // this.formData.pointX = '';
  495. // this.formData.pointY = '';
  496. // this.formData.address = '';
  497. this.dialogMapVisible = false;
  498. },
  499. //地址保存
  500. saveAddress() {
  501. this.formData.pointX = this.$store.getters['getSearchPointInfo'].XY[0];
  502. this.formData.pointY = this.$store.getters['getSearchPointInfo'].XY[1];
  503. this.formData.address = this.$store.getters['getSearchPointInfo'].text;
  504. this.dialogMapVisible = false;
  505. },
  506. oninput(value,tip) {
  507. if(!value){return}
  508. if(tip==='x'){
  509. if(value>180||value<-180){
  510. this.$message.warning('请输入正确的经度')
  511. return value.substring(0,value.length-1);
  512. }
  513. }else{
  514. if(value>90||value<-90){
  515. this.$message.warning('请输入正确的纬度')
  516. return value.substring(0,value.length-1);
  517. }
  518. }
  519. let str = value;
  520. let len1 = str.substr(0, 1);
  521. let len2 = str.substr(1, 1);
  522. //如果第一位是0,第二位不是点,就用数字把点替换掉
  523. if (str.length > 1 && len1 == 0 && len2 != ".") {
  524. str = str.substr(1, 1);
  525. }
  526. //第一位不能是.
  527. if (len1 == ".") {
  528. str = "";
  529. }
  530. if (len1 == "+") {
  531. str = "";
  532. }
  533. if (len1 == "-") {
  534. str = "";
  535. }
  536. //限制只能输入一个小数点
  537. if (str.indexOf(".") != -1) {
  538. let str_ = str.substr(str.indexOf(".") + 1);
  539. if (str_.indexOf(".") != -1) {
  540. str = str.substr(0, str.indexOf(".") + str_.indexOf(".") + 1);
  541. }
  542. }
  543. //正则替换
  544. str = str.replace(/[^\d^\.]+/g, ""); // 保留数字和小数点
  545. str = str.replace(/^\D*([0-9]\d*\.?\d{0,11})?.*$/, "$1"); // 小数点后只能输 11 位
  546. return str;
  547. },
  548. submit() {
  549. new Promise((resolve) => {
  550. this.$refs.form.validate(resolve);
  551. }).then(() => {
  552. var loading = this.$loading();
  553. var posturl = '';
  554. if(this.params.todo === 'edit'){
  555. posturl = '/sc-zoniot-water/cameraManage/update';
  556. }else {
  557. posturl = '/sc-zoniot-water/cameraManage/insert'
  558. }
  559. this.formData.status = 1;
  560. this.$http.post(posturl, this.formData).then(({ status, data, msg}) => {
  561. loading.close();
  562. if(0 == status) {
  563. this.$message.success(msg);
  564. this.params.callback && this.params.callback();
  565. this.$emit('close');
  566. } else {
  567. this.$message.error(msg);
  568. }
  569. })
  570. .catch((err) => {
  571. loading.close();
  572. })
  573. })
  574. }
  575. }
  576. };
  577. </script>
  578. <style lang="scss" scoped>
  579. @import '@assets/css/public-style.scss';
  580. .scene-tip-style {
  581. text-align: left;
  582. position: absolute;
  583. top: 380px;
  584. i {
  585. font-size: 16px;
  586. color: #fe7271;
  587. vertical-align: middle;
  588. text-indent: -20px;
  589. display: inline-block;
  590. }
  591. span {
  592. font-size: 12px;
  593. margin-left: 10px;
  594. }
  595. .jumpbtn {
  596. color: $mainTextColor;
  597. padding: 10px 0px 10px 10px;
  598. cursor: pointer;
  599. }
  600. }
  601. .location-icon {
  602. font-size: 12px;
  603. color: #7B7F86;
  604. }
  605. .doalogmap {
  606. width: 910px;
  607. height: 460px;
  608. position: relative;
  609. .addressSearch {
  610. position: absolute;
  611. z-index: 10;
  612. width: 570px;
  613. height: 40px;
  614. background: #ffffff;
  615. box-shadow: 0px 5px 20px #d1d6dd;
  616. opacity: 1;
  617. border-radius: 6px;
  618. padding: 5px 6px;
  619. box-sizing: border-box;
  620. .w100{
  621. width: 100px;
  622. margin-right: 10px;
  623. }
  624. .location-icon-16 {
  625. font-size: 16px;
  626. color: #7d7f87;
  627. }
  628. .map-input-filter {
  629. width: 240px;
  630. height: 30px;
  631. background: #f5f5f5;
  632. opacity: 1;
  633. border-radius: 4px;
  634. margin: 0 10px;
  635. }
  636. .map-input-btn {
  637. width: 60px;
  638. height: 30px;
  639. background: $mainTextColor;
  640. opacity: 1;
  641. border-radius: 4px;
  642. padding: 0;
  643. vertical-align: top;
  644. i {
  645. margin-right: 4px;
  646. }
  647. }
  648. }
  649. }
  650. </style>