vehicleConfigurationDetail.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. <template>
  2. <div class="vehicleConfigurationDetailPanel">
  3. <el-form ref="form" :model="form" :rules="rules" label-width="108px">
  4. <div class="inputBox flexBox">
  5. <span class="label">配置ID</span>
  6. <div>{{ form.configCode }}</div>
  7. </div>
  8. <div class="flexBox headBox">
  9. <el-form-item label="配置名称:" prop="configName">
  10. <el-input
  11. placeholder="请输入"
  12. maxlength="60"
  13. v-autoTrim="{ obj: form, key: 'configName' }"
  14. v-model="form.configName"
  15. >
  16. </el-input>
  17. </el-form-item>
  18. <el-form-item label="配置描述:" prop="configDescription">
  19. <el-input
  20. placeholder="请输入"
  21. maxlength="200"
  22. v-autoTrim="{ obj: form, key: 'configDescription' }"
  23. v-model="form.configDescription"
  24. >
  25. </el-input>
  26. </el-form-item>
  27. <el-form-item label="车辆名称:" prop="vehicleId">
  28. <el-select v-model="form.vehicleId" @change="vehicleChange">
  29. <el-option
  30. v-for="item in vehicleNameList"
  31. :label="item.vehicleName"
  32. :value="item.id"
  33. :key="item.id"
  34. ></el-option>
  35. </el-select>
  36. </el-form-item>
  37. <el-form-item label="车辆描述:" prop="vehicleDescription">
  38. <el-input
  39. placeholder="请输入"
  40. maxlength="200"
  41. v-autoTrim="{ obj: form, key: 'vehicleDescription' }"
  42. v-model="form.vehicleDescription"
  43. disabled
  44. >
  45. </el-input>
  46. </el-form-item>
  47. </div>
  48. </el-form>
  49. <div class="contentBox">
  50. <div>
  51. <handle-config-list
  52. ref="handleConfigList"
  53. @curItem="curItem"
  54. @addOne="addOne"
  55. @delOne="delOne"
  56. :configList="configList"
  57. :curOne="curOne"
  58. ></handle-config-list>
  59. </div>
  60. <div
  61. class="model"
  62. v-bind:style="{ width: width + 'px', height: width / 2 + 'px' }"
  63. >
  64. <!-- <img :src="modelImgSrc" width="100%" /> -->
  65. <canvas-sensor
  66. ref="canvasSensor"
  67. :coordinate="coordinate"
  68. :modelImgSrc="modelImgSrc"
  69. ></canvas-sensor>
  70. </div>
  71. <div class="conditions">
  72. <div class="btnBox">
  73. <el-button type="primary" @click="saveConfig"
  74. >保存设置</el-button
  75. >
  76. </div>
  77. <el-form
  78. ref="formA"
  79. :model="formA"
  80. :rules="rulesA"
  81. label-width="108px"
  82. >
  83. <div class="forms">
  84. <el-form-item label="X(m):" prop="sensorX">
  85. <el-input
  86. placeholder="请输入"
  87. maxlength="9"
  88. v-autoTrim="{ obj: formA, key: 'sensorX' }"
  89. v-model="formA.sensorX"
  90. @input="inputChange"
  91. >
  92. </el-input>
  93. </el-form-item>
  94. <el-form-item label="Y(m):" prop="sensorY">
  95. <el-input
  96. placeholder="请输入"
  97. maxlength="9"
  98. v-autoTrim="{ obj: formA, key: 'sensorY' }"
  99. v-model="formA.sensorY"
  100. @input="inputChange"
  101. >
  102. </el-input>
  103. </el-form-item>
  104. <el-form-item label="Z(m):" prop="sensorZ">
  105. <el-input
  106. placeholder="请输入"
  107. maxlength="9"
  108. v-autoTrim="{ obj: formA, key: 'sensorZ' }"
  109. v-model="formA.sensorZ"
  110. >
  111. </el-input>
  112. </el-form-item>
  113. <el-form-item label="横摆角(deg):" prop="sensorH">
  114. <el-input
  115. placeholder="请输入"
  116. maxlength="9"
  117. v-autoTrim="{ obj: formA, key: 'sensorH' }"
  118. v-model="formA.sensorH"
  119. @input="inputChange"
  120. >
  121. </el-input>
  122. </el-form-item>
  123. <el-form-item label="俯仰角(deg):" prop="sensorP">
  124. <el-input
  125. placeholder="请输入"
  126. maxlength="9"
  127. v-autoTrim="{ obj: formA, key: 'sensorP' }"
  128. v-model="formA.sensorP"
  129. >
  130. </el-input>
  131. </el-form-item>
  132. <el-form-item label="翻滚角(deg):" prop="sensorR">
  133. <el-input
  134. placeholder="请输入"
  135. maxlength="9"
  136. v-autoTrim="{ obj: formA, key: 'sensorR' }"
  137. v-model="formA.sensorR"
  138. >
  139. </el-input>
  140. </el-form-item>
  141. <el-form-item
  142. label="端口"
  143. prop="sensorPort"
  144. v-show="curOne.name === 'ogt'"
  145. >
  146. <el-input
  147. placeholder="请输入"
  148. maxlength="9"
  149. v-autoTrim="{ obj: formA, key: 'sensorPort' }"
  150. v-model="formA.sensorPort"
  151. >
  152. </el-input>
  153. </el-form-item>
  154. </div>
  155. </el-form>
  156. </div>
  157. </div>
  158. <div class="btns">
  159. <el-button
  160. v-if="form.share === '0' || form.share === ''"
  161. type="primary"
  162. @click="save(false)"
  163. >保存</el-button
  164. >
  165. <el-button
  166. v-if="form.share === '0' || form.share === '1'"
  167. type="primary"
  168. @click="save(true)"
  169. >另存为</el-button
  170. >
  171. <el-button type="primary" plain @click="cancel">取消</el-button>
  172. </div>
  173. </div>
  174. </template>
  175. <script>
  176. import handleConfigList from "./components/handleConfigList.vue";
  177. import canvasSensor from "./components/canvasVehicleConfiguration.vue";
  178. import { mapState } from "vuex";
  179. export default {
  180. name: "vehicleConfigurationDetail", // 车辆配置详情
  181. components: { handleConfigList, canvasSensor },
  182. data() {
  183. // 校验最多4位小数
  184. let validateNum = (rule, value, callback) => {
  185. !/^(-?(0|[1-9][0-9]*))(\.\d{1,4})?$/.test(value) &&
  186. callback(new Error(rule.message));
  187. callback();
  188. };
  189. // 校验不大于180且不小于-180
  190. let validateNumC = (rule, value, callback) => {
  191. if (value < -180 || value > 180) {
  192. callback(new Error(rule.message));
  193. return;
  194. }
  195. callback();
  196. };
  197. return {
  198. vehicleNameList: [],
  199. form: {
  200. id: "",
  201. configCode: "", // 配置ID
  202. configName: "", // 配置名称
  203. configDescription: "", // 配置描述
  204. vehicleName: "", // 车辆名称
  205. vehicleId: "", // 车辆名称
  206. vehicleDescription: "", // 车辆描述
  207. share: "",
  208. },
  209. formA: {
  210. sensorX: "", // 传感器横向偏移量(x轴)
  211. sensorY: "", // 传感器横向偏移量(y轴)
  212. sensorZ: "", // 传感器横向偏移量(z轴)
  213. sensorH: "", // 横摆角
  214. sensorP: "", // 俯仰角
  215. sensorR: "", // 横滚角
  216. sensorPort: "", // 端口
  217. },
  218. rules: {
  219. configName: [
  220. { required: true, message: "请输入", trigger: "blur" },
  221. ],
  222. configDescription: [
  223. { required: true, message: "请输入", trigger: "blur" },
  224. ],
  225. vehicleId: [
  226. {
  227. required: true,
  228. message: "请选择",
  229. trigger: "change",
  230. },
  231. ],
  232. vehicleDescription: [
  233. { required: true, message: "请输入", trigger: "blur" },
  234. ],
  235. },
  236. rulesA: {
  237. sensorX: [
  238. {
  239. required: true,
  240. message: "请输入",
  241. trigger: "blur",
  242. },
  243. {
  244. validator: validateNum,
  245. message: "请输入最多带有4位小数的数字",
  246. trigger: ["blur"],
  247. },
  248. ],
  249. sensorY: [
  250. {
  251. required: true,
  252. message: "请输入",
  253. trigger: "blur",
  254. },
  255. {
  256. validator: validateNum,
  257. message: "请输入最多带有4位小数的数字",
  258. trigger: ["blur"],
  259. },
  260. ],
  261. sensorZ: [
  262. {
  263. required: true,
  264. message: "请输入",
  265. trigger: "blur",
  266. },
  267. {
  268. validator: validateNum,
  269. message: "请输入最多带有4位小数的数字",
  270. trigger: ["blur"],
  271. },
  272. ],
  273. sensorH: [
  274. { required: true, message: "请输入", trigger: "blur" },
  275. {
  276. validator: validateNum,
  277. message: "请输入最多带有4位小数的数字",
  278. trigger: ["blur"],
  279. },
  280. {
  281. validator: validateNumC,
  282. message: "请输入不小于-180且不大于180的数字",
  283. trigger: ["blur"],
  284. },
  285. ],
  286. sensorP: [
  287. { required: true, message: "请输入", trigger: "blur" },
  288. {
  289. validator: validateNum,
  290. message: "请输入最多带有4位小数的数字",
  291. trigger: ["blur"],
  292. },
  293. {
  294. validator: validateNumC,
  295. message: "请输入不小于-180且不大于180的数字",
  296. trigger: ["blur"],
  297. },
  298. ],
  299. sensorR: [
  300. { required: true, message: "请输入", trigger: "blur" },
  301. {
  302. validator: validateNum,
  303. message: "请输入最多带有4位小数的数字",
  304. trigger: ["blur"],
  305. },
  306. {
  307. validator: validateNumC,
  308. message: "请输入不小于-180且不大于180的数字",
  309. trigger: ["blur"],
  310. },
  311. ],
  312. sensorPort: [
  313. { required: false, message: "请输入", trigger: "blur" },
  314. ],
  315. },
  316. // 传感器对象集合
  317. configList: {
  318. camera: [],
  319. ogt: [],
  320. lidar: [],
  321. gps: [],
  322. },
  323. // 用于当前选中项的展示
  324. curOne: {
  325. name: "",
  326. index: -1,
  327. },
  328. modelImgSrc: require("@/assets/common/image/others/carTopView.png"), // 车辆图片地址
  329. // canDraw: false,
  330. width: 300,
  331. coordinate: { x: 0, y: 0 }, // 存放传递给canvas的值
  332. };
  333. },
  334. watch: {
  335. curOne(val) {
  336. if (val.name === "ogt") {
  337. // 校验端口号
  338. let validatePort = (rule, value, callback) => {
  339. !/^(\d{5})$/.test(value) &&
  340. callback(new Error(rule.message));
  341. if (value > 65535 || value < 62000) {
  342. callback(new Error(rule.message));
  343. return;
  344. }
  345. callback();
  346. };
  347. let validatePortNoRepeat = (rule, value, callback) => {
  348. let ports = this.configList.ogt.map(
  349. (i) => i.sensorPort + ""
  350. );
  351. ports.splice(this.curOne.index, 1);
  352. if (ports.includes(value)) {
  353. callback(new Error(rule.message));
  354. return;
  355. } else {
  356. callback();
  357. }
  358. };
  359. this.rulesA.sensorPort[0].required = true;
  360. this.rulesA.sensorPort[1] = {
  361. validator: validatePort,
  362. message: "请输入62000至65535之间的5位数字",
  363. trigger: ["blur"],
  364. };
  365. this.rulesA.sensorPort[2] = {
  366. validator: validatePortNoRepeat,
  367. message: "端口号重复",
  368. trigger: ["blur"],
  369. };
  370. } else {
  371. this.rulesA.sensorPort[0].required = false;
  372. this.rulesA.sensorPort.length = 1;
  373. }
  374. },
  375. },
  376. computed: {
  377. ...mapState(["fileHost", "fileUrl"]),
  378. },
  379. methods: {
  380. // 获取车辆名称私有下拉列表
  381. async getMyVehicleList() {
  382. await this.$axios({
  383. method: "post",
  384. url: this.$api.modelLibrary.getMyVehicleList,
  385. data: {},
  386. }).then((res) => {
  387. if (res.code == 200 && res.info) {
  388. this.vehicleNameList = res.info;
  389. } else {
  390. this.$message.error(res.message || "获取信息失败");
  391. }
  392. });
  393. },
  394. getImgUrl(addr) {
  395. let url = "";
  396. if (process.env.VUE_APP_IS_DEV == "true") {
  397. url = this.fileHost + this.fileUrl;
  398. } else {
  399. url = this.fileUrl;
  400. }
  401. let token = localStorage.getItem("Authorization").split(" ")[1];
  402. let src = `${url}?objectName=${addr}&access_token=${token}`;
  403. return src;
  404. },
  405. vehicleChange(id) {
  406. let item = this.vehicleNameList.find((i) => i.id == id);
  407. this.form.vehicleDescription = item.description;
  408. this.modelImgSrc = this.getImgUrl(item.vehicleTopView);
  409. this.$refs.canvasSensor.drawBg();
  410. },
  411. // 验证各传感器数组的每一项表单数据是否齐全
  412. validateSensorsList() {
  413. // console.log(Object.keys(this.configList));
  414. // console.log(Object.values(this.configList));
  415. // console.log(Object.entries(this.configList));
  416. let lists = Object.entries(this.configList);
  417. for (let index = 0; index < lists.length; index++) {
  418. const element = lists[index];
  419. let oneIndex = element[1].findIndex(
  420. (i) => i.sensorX == null && i.sensorY == null
  421. );
  422. // console.log(oneIndex);
  423. if (oneIndex > -1) {
  424. this.$refs.handleConfigList.configHandle(
  425. element[0],
  426. oneIndex
  427. );
  428. // 如果对应项未展开 让其展开
  429. if (
  430. element[0] === "camera" &&
  431. !this.$refs.handleConfigList.isActiveA
  432. ) {
  433. this.$refs.handleConfigList.isActiveA = true;
  434. } else if (
  435. element[0] === "ogt" &&
  436. !this.$refs.handleConfigList.isActiveB
  437. ) {
  438. this.$refs.handleConfigList.isActiveB = true;
  439. } else if (
  440. element[0] === "lidar" &&
  441. !this.$refs.handleConfigList.isActiveC
  442. ) {
  443. this.$refs.handleConfigList.isActiveC = true;
  444. } else if (
  445. element[0] === "gps" &&
  446. !this.$refs.handleConfigList.isActiveE
  447. ) {
  448. this.$refs.handleConfigList.isActiveE = true;
  449. }
  450. this.$message.error("请先设置数据并保存");
  451. return false;
  452. }
  453. }
  454. return true;
  455. },
  456. save(isAdd) {
  457. this.$refs.form.validate((valid) => {
  458. if (valid) {
  459. if (isAdd) {
  460. this.form.id = "";
  461. }
  462. if (!this.validateSensorsList()) return;
  463. // console.log(this.configList);
  464. // console.log(Object.keys(this.configList));
  465. // console.log(Object.values(this.configList));
  466. // console.log(Object.entries(this.configList));
  467. // this.curOne = {
  468. // name: "gps",
  469. // index: 0,
  470. // };
  471. // return;
  472. let data = Object.assign({}, this.form, {
  473. configSensors: this.configList,
  474. });
  475. this.$axios({
  476. method: "post",
  477. url: this.$api.modelLibrary.saveConfig,
  478. data,
  479. }).then((res) => {
  480. if (res.code == 200) {
  481. this.$message.success("保存成功");
  482. this.cancel();
  483. } else {
  484. this.$message.error(res.message || "保存失败");
  485. }
  486. });
  487. }
  488. });
  489. },
  490. /**
  491. * info 新增传感器信息
  492. * type 传感器类型
  493. */
  494. addOne(info, type) {
  495. // 如果列表里没有对应类型的数组则需手动添加
  496. if (!this.configList[type]) {
  497. this.configList[type] = [];
  498. }
  499. //若直接传info即this.form,可能是由于传入了响应式,造成数据会变动
  500. this.configList[type].unshift({ ...info });
  501. },
  502. delOne(type, index) {
  503. this.configList[type].splice(index, 1);
  504. },
  505. curItem(item, isAdd) {
  506. this.$refs.formA.resetFields();
  507. this.curOne = item;
  508. if (isAdd) {
  509. this.formA.sensorX = "0";
  510. this.formA.sensorY = "0";
  511. this.formA.sensorZ = "0";
  512. this.formA.sensorH = "0";
  513. this.formA.sensorP = "0";
  514. this.formA.sensorR = "0";
  515. if (this.curOne.name === "ogt") {
  516. this.formA.sensorPort = "62001";
  517. }
  518. } else {
  519. Object.assign(
  520. this.formA,
  521. this.configList[item.name][item.index]
  522. );
  523. }
  524. this.$refs.canvasSensor.clear();
  525. this.inputChange();
  526. },
  527. saveConfig() {
  528. if (this.curOne.index < 0) {
  529. this.$message.info("请先选择传感器");
  530. return;
  531. }
  532. this.$refs.formA.validate((valid) => {
  533. if (valid) {
  534. Object.assign(
  535. this.configList[this.curOne.name][this.curOne.index],
  536. this.formA
  537. );
  538. this.$message.success("保存设置成功");
  539. }
  540. });
  541. },
  542. cancel() {
  543. this.$router.replace({ path: "/vehicleConfigurationList" });
  544. },
  545. domHandle() {
  546. $(document).ready(() => {
  547. this.width = $(
  548. ".vehicleConfigurationDetailPanel .model"
  549. ).outerWidth();
  550. // this.canDraw = true;
  551. });
  552. },
  553. inputChange() {
  554. if (this.curOne.index < 0) return;
  555. if (
  556. this.formA.sensorX === "" ||
  557. this.formA.sensorY === "" ||
  558. this.formA.sensorH === ""
  559. )
  560. return;
  561. this.coordinate = {
  562. x: this.formA.sensorX,
  563. y: this.formA.sensorY,
  564. h: this.formA.sensorH,
  565. };
  566. },
  567. },
  568. mounted() {
  569. setTimeout(() => {
  570. this.domHandle();
  571. }, 0);
  572. this.getMyVehicleList();
  573. if (this.$route.query.id) {
  574. let id = "";
  575. this.form.id = id = this.$route.query.id;
  576. this.form.share = this.$route.query.share;
  577. if (id) {
  578. this.$axios({
  579. method: "post",
  580. url: this.$api.modelLibrary.getConfigInfo,
  581. data: {
  582. id,
  583. },
  584. }).then((res) => {
  585. if (res.code == 200 && res.info) {
  586. this.form = res.info;
  587. this.configList = res.info.configSensors;
  588. this.modelImgSrc = this.getImgUrl(
  589. res.info.vehicleTopView
  590. );
  591. // this.validateSensorsList();
  592. } else {
  593. this.$message.error(res.message || "获取信息失败");
  594. }
  595. });
  596. }
  597. }
  598. },
  599. };
  600. </script>
  601. <style lang='less' scoped>
  602. .vehicleConfigurationDetailPanel {
  603. margin: 55px 50px 0;
  604. }
  605. .headBox {
  606. .el-form-item {
  607. margin-right: 20px;
  608. }
  609. }
  610. .inputBox.flexBox {
  611. margin-bottom: 22px;
  612. .label {
  613. width: 88px;
  614. }
  615. div {
  616. line-height: 32px;
  617. }
  618. }
  619. .contentBox {
  620. display: flex;
  621. justify-content: space-between;
  622. margin-top: 30px;
  623. .model {
  624. // width: 400px;
  625. flex: 1;
  626. margin: 0 10%;
  627. }
  628. .conditions {
  629. .btnBox {
  630. padding: 0 0 30px;
  631. }
  632. .forms /deep/ .el-form-item__label {
  633. width: 120px !important;
  634. }
  635. .forms /deep/ .el-form-item__content {
  636. margin-left: 120px !important;
  637. }
  638. }
  639. }
  640. .btns {
  641. padding-top: 30px;
  642. text-align: center;
  643. }
  644. </style>