autodoor.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. <template>
  2. <view style="overflow: auto; height: 100%">
  3. <!-- 建议放在外层 -->
  4. <u-navbar
  5. :title="name"
  6. @leftClick="backPage"
  7. :bgImage="backPic"
  8. :bgStatusImage="backPic0"
  9. >
  10. <view class="u-nav-slot" slot="left">
  11. <u-icon name="arrow-left" size="20"> </u-icon>
  12. </view>
  13. </u-navbar>
  14. <view class="main">
  15. <view class="u-page container">
  16. <div class="button-grid flcard" v-if="this.TabCur == 'gate'">
  17. <u-button
  18. type="primary"
  19. text="打开前门"
  20. @click="showPasswordDialog('frontGateOpen_S')"
  21. ></u-button>
  22. <u-button
  23. type="primary"
  24. text="关闭前门"
  25. @click="showPasswordDialog('frontGateClose_S')"
  26. ></u-button>
  27. <u-button
  28. type="primary"
  29. text="打开后门"
  30. @click="showPasswordDialog('rearGateOpen_S')"
  31. ></u-button>
  32. <u-button
  33. type="primary"
  34. text="关闭后门"
  35. @click="showPasswordDialog('rearGateClose_S')"
  36. ></u-button>
  37. <u-button
  38. type="primary"
  39. text="打开前后门"
  40. @click="showPasswordDialog('sameTimeOpen')"
  41. ></u-button>
  42. <u-button
  43. type="primary"
  44. text="关闭前后门"
  45. @click="showPasswordDialog('sameTimeClose')"
  46. ></u-button>
  47. </div>
  48. <div
  49. class="button-grid flcard"
  50. v-if="this.TabCur == 'window' && this.nwindownum == 1"
  51. >
  52. <u-button
  53. type="primary"
  54. text="设定面积"
  55. @click="showPasswordDialog('frontSetValue')"
  56. ></u-button>
  57. </div>
  58. <div
  59. class="button-grid flcard"
  60. v-if="this.TabCur == 'window' && this.nwindownum == 2"
  61. >
  62. <u-button
  63. type="primary"
  64. text="设定前窗面积"
  65. @click="showPasswordDialog('frontSetValue')"
  66. ></u-button>
  67. <u-button
  68. type="primary"
  69. text="设定后窗面积"
  70. @click="showPasswordDialog('rearSetValue')"
  71. ></u-button>
  72. </div>
  73. <div class="flcard" v-if="this.TabCur == 'gate'">
  74. <doorAnimate
  75. :gatestate1="frontGateStatus"
  76. :gatestate2="midGateStatus"
  77. :gatestate3="rearGateStatus"
  78. :cameralist="cameralist"
  79. :height="height"
  80. :doorcount="ndoorcount"
  81. ></doorAnimate>
  82. </div>
  83. <div class="flcard" v-if="this.TabCur == 'windrect'">
  84. <windrectAnimate
  85. :state="state"
  86. :title="title"
  87. :videoURL="viedeoUrl"
  88. :height="height"
  89. :type="deviceType"
  90. ></windrectAnimate>
  91. </div>
  92. <div class="flcard" v-if="this.TabCur == 'fanlocal'">
  93. <fanlocalAnimate
  94. :fan1State="fan1State"
  95. :fan2State="fan2State"
  96. :title="title"
  97. :videoURL="viedeoUrl"
  98. :height="height"
  99. ></fanlocalAnimate>
  100. </div>
  101. <div
  102. class="flcard"
  103. v-if="this.TabCur == 'window' && this.nwindownum == 1"
  104. >
  105. <windowAnimate
  106. :windowAngle="windowAngle"
  107. :height="height"
  108. :windowcount="nwindownum"
  109. ></windowAnimate>
  110. </div>
  111. <div
  112. class="flcard"
  113. v-if="this.TabCur == 'window' && this.nwindownum == 2"
  114. >
  115. <windowAnimate
  116. :windowAngle="windowAngle"
  117. :windowAngle1="windowAngle1"
  118. :height="height"
  119. :windowcount="nwindownum"
  120. ></windowAnimate>
  121. </div>
  122. <div class="flcard">
  123. <div class="flex-container">
  124. <div
  125. class="itemback"
  126. v-for="(item, index) in typeList"
  127. :key="index"
  128. v-show="item.appShow == 1"
  129. >
  130. <div class="datacardtime" v-if="item.monitorcode == 'readTime'">
  131. <view
  132. class="demo-layout bg-purple-light"
  133. style="padding: 20rpx; color: #3787fe"
  134. >
  135. {{ readTime }}
  136. </view>
  137. </div>
  138. <div class="datacard" v-if="item.monitorcode !== 'readTime'">
  139. <div class="left-content">
  140. <view
  141. v-if="item.monitorcode == 'ndoortype'"
  142. class="demo-layout bg-purple-light"
  143. style="margin-top: 10rpx; color: #3787fe"
  144. >
  145. {{
  146. tableData[item.monitorcode] == "1"
  147. ? "行人"
  148. : tableData[item.monitorcode] == "2"
  149. ? "行车"
  150. : "-"
  151. }}
  152. </view>
  153. <view
  154. v-else-if="item.monitorcode == 'netStatus'"
  155. class="demo-layout bg-purple-light"
  156. style="margin-top: 10rpx; color: #3787fe"
  157. >
  158. {{ doorNetStatus == "1" ? "正常" : "异常" }}
  159. </view>
  160. <view
  161. v-else-if="item.monitorcode == 'warnFlag'"
  162. class="demo-layout bg-purple-light"
  163. style="margin-top: 10rpx; color: #3787fe"
  164. >
  165. {{ warnFlag == "1" ? "正常" : "异常" }}
  166. </view>
  167. <view
  168. v-else
  169. class="demo-layout bg-purple-light"
  170. style="margin-top: 10rpx; color: #3787fe"
  171. >
  172. {{
  173. tableData[item.monitorcode] == null ||
  174. tableData[item.monitorcode] == ""
  175. ? "-"
  176. : tableData[item.monitorcode]
  177. }}
  178. </view>
  179. <div class="spacer"></div>
  180. <!-- 间距 -->
  181. <view
  182. class="demo-layout bg-purple-light"
  183. style="color: #677799"
  184. >
  185. {{ item.des }}
  186. </view>
  187. </div>
  188. <div
  189. class="right-content"
  190. :style="{
  191. backgroundImage:
  192. item.monitorcode === 'frontRearDP' ||
  193. item.monitorcode === 'frontRearDifference'
  194. ? 'url(\'../../../../static/model/Pa.png\')'
  195. : item.monitorcode === 'sourcePressure'
  196. ? 'url(\'../../../../static/model/MPa.png\')'
  197. : item.monitorcode === 'frontGateOpen'
  198. ? 'url(\'../../../../static/model/doorNet.png\')'
  199. : item.monitorcode === 'rearGateOpen'
  200. ? 'url(\'../../../../static/model/doorNet.png\')'
  201. : item.monitorcode === 'midGateOpen'
  202. ? 'url(\'../../../../static/model/doorNet.png\')'
  203. : item.monitorcode === 'warnFlag'
  204. ? 'url(\'../../../../static/model/9432.png\')'
  205. : item.monitorcode === 'netStatus'
  206. ? 'url(\'../../../../static/model/9431.png\')'
  207. : item.monitorcode === 'm3'
  208. ? 'url(\'../../../../static/model/windM3.png\')'
  209. : item.monitorcode === 'fsectarea'
  210. ? 'url(\'../../../../static/model/duanArea.png\')'
  211. : item.monitorcode === 'incipientWindSpeed1' ||
  212. item.monitorcode === 'incipientWindSpeed2' ||
  213. item.monitorcode === 'incipientWindSpeed3' ||
  214. item.monitorcode === 'va'
  215. ? 'url(\'../../../../static/model/fengsu.png\')'
  216. : 'url(\'\')',
  217. backgroundSize: '100% 100%',
  218. }"
  219. ></div>
  220. </div>
  221. </div>
  222. </div>
  223. </div>
  224. </view>
  225. </view>
  226. <u-popup :show="show" mode="bottom" :safeAreaInsetBottom="false">
  227. <div class="containers">
  228. <view class="passWordName">
  229. <view
  230. class="title"
  231. style="margin-top: 15px"
  232. v-if="this.TabCur == 'window'"
  233. >风窗面积</view
  234. >
  235. <u-input
  236. class="passArea"
  237. style="margin-top: 15px; border-color: #2a94ff"
  238. v-model="windowArea"
  239. type="text"
  240. v-if="this.TabCur == 'window'"
  241. ></u-input>
  242. </view>
  243. <view class="passWordInput">
  244. <view style="margin-top: 15px" class="title">输入密码</view>
  245. <u-input
  246. style="margin-top: 15px; border-color: #2a94ff"
  247. v-model="password"
  248. type="password"
  249. ></u-input
  250. ></view>
  251. </div>
  252. <view class="btns">
  253. <u-button
  254. style="margin: 20px"
  255. type="primary"
  256. @click="confirmPassword()"
  257. color="linear-gradient(to right, rgb(53, 138, 254), rgb(38, 171, 244))"
  258. >确认</u-button
  259. >
  260. <u-button
  261. style="margin: 20px"
  262. type="primary"
  263. :plain="true"
  264. @click="cancelPassword()"
  265. >取消</u-button
  266. >
  267. </view>
  268. </u-popup>
  269. </view>
  270. </template>
  271. <script>
  272. import api from "@/api/api";
  273. import initDictOptions from "@/common/util/dictUtil.js";
  274. import doorAnimate from "../doorAnimate/doorAnimate.vue";
  275. import windowAnimate from "../windowAnimate/windowAnimate.vue";
  276. import windrectAnimate from "../windrectAnimate/windrectAnimate.vue";
  277. import fanlocalAnimate from "../fanlocalAnimate/fanlocalAnimate2.vue";
  278. export default {
  279. data() {
  280. return {
  281. tableData: [], //监测数据
  282. typeList: [], //展示字段
  283. itemId: "", // 初始化 itemId
  284. name: "", // 初始化 name
  285. deviceid: "", //初始化设备id
  286. TabCur: "",
  287. checked: [],
  288. backPic0: "url(/static/topnavbar0.png)",
  289. backPic: "url(/static/topnavbar.png)",
  290. frontAngle: "", //风窗打开角度
  291. nwindownum: "", //风窗道数
  292. ndoorcount: "", //风门道数
  293. deviceType: "", //设备类型
  294. show: false, //密码弹窗是否显示
  295. password: "", //控制设备密码
  296. paramcode: "", //控制字段
  297. height: "200px",
  298. popupStyle: {
  299. // 弹窗样式
  300. "background-color": "#fff",
  301. padding: "20px",
  302. "box-shadow": "0 2px 4px rgba(0, 0, 0, 0.1)",
  303. },
  304. frontGateStatus: "", //前门状态
  305. rearGateStatus: "", //后门状态
  306. midGateStatus: "", //状态
  307. doorNetStatus: "", //风门通信状态
  308. warnFlag: "", //风门报警
  309. readTime: "", //时间
  310. windowAngle: 0, //前窗打开角度
  311. windowAngle1: 0, //后窗打开角度
  312. windowArea: "", //风窗面积设定值
  313. viedeoUrl: "", //监控url
  314. sign: "",
  315. title: "测风设备",
  316. fan1State: "",
  317. fan2State: "",
  318. deviceid: "", //ID
  319. cameralist: [], //摄像数据
  320. };
  321. },
  322. onLoad(query) {
  323. //保存id到 data 中 可以在整个页面中使用
  324. this.itemId = query.id;
  325. this.name = query.name;
  326. this.TabCur = query.type;
  327. this.ndoorcount = 2;
  328. },
  329. components: { doorAnimate, windowAnimate, windrectAnimate, fanlocalAnimate },
  330. created() {
  331. this.getShowList(this.TabCur);
  332. this.getDeviceInfo(this.itemId);
  333. this.getVideoUrlById(this.itemId);
  334. },
  335. mounted() {
  336. this.startTimer();
  337. },
  338. methods: {
  339. startTimer() {
  340. this.timer = setInterval(() => {
  341. // 执行定时任务
  342. this.getDeviceInfo(this.itemId);
  343. }, 5000);
  344. },
  345. stopTimer() {
  346. // 停止定时器
  347. clearInterval(this.timer);
  348. },
  349. // 返回上一个页面
  350. backPage() {
  351. this.$destroy();
  352. uni.navigateBack({
  353. delta: 1,
  354. });
  355. },
  356. //获取app展示字段数据
  357. getShowList(type) {
  358. const params = {
  359. devicekind: type,
  360. pagetype: "detail",
  361. pageNo: 1,
  362. pageSize: 100,
  363. };
  364. new Promise((resolve, reject) => {
  365. api
  366. .getShowColumList(params)
  367. .then((response) => {
  368. if (response.data.code == 200) {
  369. this.typeList = response.data.result.records;
  370. } else {
  371. resolve(response);
  372. }
  373. })
  374. .catch((error) => {
  375. reject(error);
  376. });
  377. });
  378. },
  379. //获取详情数据
  380. getDeviceInfo(ID) {
  381. let IDString = String(ID); // 将 ID 转换为字符串
  382. new Promise((resolve, reject) => {
  383. api
  384. .getDeviceMonitor({ devicetype: this.TabCur, ids: IDString })
  385. .then((response) => {
  386. if (
  387. response.data.code == 200 &&
  388. response.data.result.msgTxt[0].datalist.length > 0
  389. ) {
  390. var result = response.data.result.msgTxt[0].datalist[0];
  391. this.tableData = result.readData;
  392. if (this.tableData.frontGateOpen == "1") {
  393. this.tableData.frontGateOpen = "打开";
  394. } else {
  395. this.tableData.frontGateOpen = "关闭";
  396. }
  397. if (this.tableData.midGateOpen == "1") {
  398. this.tableData.midGateOpen = "打开";
  399. } else {
  400. this.tableData.midGateOpen = "关闭";
  401. }
  402. if (this.tableData.rearGateOpen == "1") {
  403. this.tableData.rearGateOpen = "打开";
  404. } else {
  405. this.tableData.rearGateOpen = "关闭";
  406. }
  407. this.fan1State = result.readData.Fan1StartStatus;
  408. this.fan2State = result.readData.Fan2StartStatus;
  409. this.nwindownum = result.nwindownum;
  410. this.ndoorcount = result.ndoorcount;
  411. this.deviceType = result.deviceType;
  412. this.state = result.readData.sign;
  413. this.frontGateStatus = this.tableData.frontGateOpen;
  414. this.midGateStatus = this.tableData.midGateOpen;
  415. this.rearGateStatus = this.tableData.rearGateOpen;
  416. this.doorNetStatus = result.netStatus;
  417. this.warnFlag = result.warnLevel_str;
  418. this.readTime = result.readTime;
  419. var maxarea = result.maxarea;
  420. this.windowAngle =
  421. (this.tableData.forntArea / maxarea) * 100 * 0.9;
  422. this.windowAngle1 =
  423. (this.tableData.rearArea / maxarea) * 100 * 0.9;
  424. this.deviceid = result.deviceID;
  425. this.$forceUpdate();
  426. } else {
  427. resolve(response);
  428. }
  429. })
  430. .catch((error) => {
  431. reject(error);
  432. });
  433. });
  434. },
  435. //获取监控URL 通过ID获取
  436. getVideoUrlById(ID) {
  437. let IDString = String(ID); // 将 ID 转换为字符串
  438. new Promise((resolve, reject) => {
  439. api
  440. .getCameraById({ deviceid: IDString })
  441. .then((response) => {
  442. if (response.data.code == 200) {
  443. if (response.data.result.records.length > 0) {
  444. this.cameralist = response.data.result.records[0];
  445. }
  446. } else {
  447. resolve(response);
  448. }
  449. })
  450. .catch((error) => {
  451. reject(error);
  452. });
  453. });
  454. },
  455. //设备控制
  456. ctrlDevice(pass) {
  457. let IDString = String(this.itemId); // 将 ID 转换为字符串
  458. const params = {
  459. deviceid: IDString,
  460. devicetype: this.deviceType,
  461. paramcode: this.paramcode,
  462. password: pass,
  463. value: this.windowArea,
  464. };
  465. new Promise((resolve, reject) => {
  466. api
  467. .controlDevice(params)
  468. .then((response) => {
  469. if (response.data.code == 200) {
  470. this.getDeviceInfo(IDString);
  471. // console.log("操作成功");
  472. } else {
  473. resolve(response);
  474. }
  475. })
  476. .catch((error) => {
  477. reject(error);
  478. });
  479. });
  480. },
  481. // 显示密码输入弹窗
  482. showPasswordDialog(controlCode) {
  483. this.paramcode = controlCode;
  484. this.show = true;
  485. },
  486. // 取消密码输入
  487. cancelPassword() {
  488. this.show = false;
  489. },
  490. confirmPassword() {
  491. this.ctrlDevice(this.password);
  492. // 发起请求后关闭密码输入弹窗
  493. this.show = false;
  494. },
  495. },
  496. destroyed() {
  497. // 停止定时器
  498. this.stopTimer();
  499. },
  500. };
  501. </script>
  502. <style lang="scss" scoped>
  503. .top-nav {
  504. background-image: url(../../../../static/topnavbar.png);
  505. background-size: cover; /* 背景图片大小适应 */
  506. height: 100%;
  507. }
  508. .top-nav2 {
  509. background-color: #ffffff;
  510. }
  511. .main {
  512. margin-top: 80px;
  513. }
  514. .container {
  515. display: flex;
  516. flex-direction: column;
  517. }
  518. .button-grid {
  519. display: grid;
  520. grid-template-columns: repeat(4, 1fr);
  521. gap: 5px; /* 可以根据需要调整行列之间的间距 */
  522. }
  523. .flcard {
  524. padding: 20rpx;
  525. background-color: #ffffff;
  526. margin-bottom: 5rpx;
  527. }
  528. .additional-div {
  529. grid-column: span 2; /* 让附加内容跨越三列 */
  530. display: flex;
  531. align-items: center;
  532. }
  533. .checkbox-group {
  534. margin-left: 10px; /* 可以根据需要调整间距 */
  535. }
  536. .card {
  537. background-color: #ffffff;
  538. margin: auto;
  539. margin-top: 20rpx;
  540. width: 90%;
  541. height: 280rpx;
  542. border: 1rpx solid #000000;
  543. border-radius: 20rpx;
  544. }
  545. .flex-containe {
  546. display: flex;
  547. flex-direction: row;
  548. flex-wrap: wrap;
  549. }
  550. .itemback {
  551. flex: 0 0 calc(33.33% - 10px); /* 使用calc函数计算每个项目的宽度,减去间距 */
  552. margin: 5px; /* 间距设置为5px */
  553. }
  554. .datacardtime {
  555. display: flex;
  556. width: 100%;
  557. flex: 1;
  558. margin: 1%;
  559. float: left;
  560. height: 50rpx;
  561. text-align: center;
  562. background: linear-gradient(
  563. to right,
  564. rgba(55, 135, 254, 0.08),
  565. rgba(4, 184, 255, 0.08),
  566. rgba(60, 161, 237, 0.08)
  567. );
  568. }
  569. .datacard {
  570. display: flex;
  571. width: 48%;
  572. flex: 1;
  573. margin: 1%;
  574. float: left;
  575. height: 100rpx;
  576. text-align: center;
  577. background: linear-gradient(
  578. to right,
  579. rgba(55, 135, 254, 0.08),
  580. rgba(4, 184, 255, 0.08),
  581. rgba(60, 161, 237, 0.08)
  582. );
  583. }
  584. .left-content {
  585. width: 50%;
  586. display: flex;
  587. flex-direction: column;
  588. }
  589. .spacer {
  590. height: 10rpx;
  591. }
  592. .right-content {
  593. width: 50%; /* 右侧内容占据50%宽度 */
  594. background-image: url(../../../../static/model/Pa.png);
  595. background-size: 100% 125%;
  596. }
  597. /*风窗样式*/
  598. div.autowindow_new {
  599. width: 200px;
  600. height: 200px;
  601. background-image: url(../../../../static/window/window-bk.png);
  602. background-size: 100% 100%;
  603. perspective: 800px;
  604. }
  605. /*风窗1 2 3 4*/
  606. div.window_new_1 {
  607. margin-top: 12px;
  608. margin-left: 15px;
  609. width: 170px;
  610. height: 30px;
  611. background-color: crimson;
  612. box-sizing: border-box;
  613. float: left;
  614. z-index: 1;
  615. /* transition: all 2s; */
  616. background-image: url(../../../../static/window/window_new1.png);
  617. background-size: 100% 100%;
  618. }
  619. div.window_new_2 {
  620. margin-top: 2px;
  621. margin-left: 15px;
  622. width: 170px;
  623. height: 29px;
  624. background-color: crimson;
  625. box-sizing: border-box;
  626. float: left;
  627. z-index: 1;
  628. /* transition: all 2s; */
  629. background-image: url(../../../../static/window/window_new1.png);
  630. background-size: 100% 100%;
  631. }
  632. div.window_new_3 {
  633. margin-top: 2px;
  634. margin-left: 15px;
  635. width: 170px;
  636. height: 29px;
  637. background-color: crimson;
  638. box-sizing: border-box;
  639. float: left;
  640. z-index: 1;
  641. /* transition: all 2s; */
  642. background-image: url(../../../../static/window/window_new1.png);
  643. background-size: 100% 100%;
  644. }
  645. div.window_new_4 {
  646. margin-top: 2px;
  647. margin-left: 15px;
  648. width: 170px;
  649. height: 29px;
  650. background-color: crimson;
  651. box-sizing: border-box;
  652. float: left;
  653. z-index: 1;
  654. /* transition: all 2s; */
  655. background-image: url(../../../../static/window/window_new1.png);
  656. background-size: 100% 100%;
  657. }
  658. div.window_new_5 {
  659. margin-top: 2px;
  660. margin-left: 15px;
  661. width: 170px;
  662. height: 29px;
  663. background-color: crimson;
  664. box-sizing: border-box;
  665. float: left;
  666. z-index: 1;
  667. /* transition: all 2s; */
  668. background-image: url(../../../../static/window/window_new1.png);
  669. background-size: 100% 100%;
  670. }
  671. div.window_new_1 {
  672. transition: all 2s ease;
  673. transform-origin: center center;
  674. }
  675. div.window_new_2 {
  676. transition: all 2s ease;
  677. transform-origin: center center;
  678. }
  679. div.window_new_3 {
  680. transition: all 2s ease;
  681. transform-origin: center center;
  682. }
  683. div.window_new_4 {
  684. transition: all 2s ease;
  685. transform-origin: center center;
  686. }
  687. div.window_new_5 {
  688. transition: all 2s ease;
  689. transform-origin: center center;
  690. }
  691. .btns {
  692. display: flex;
  693. }
  694. .containers {
  695. background-color: #fff;
  696. }
  697. .passWordName {
  698. margin: 20px;
  699. display: flex;
  700. flex-direction: row;
  701. justify-content: space-around;
  702. }
  703. .title {
  704. margin-right: 20px;
  705. line-height: 40px;
  706. }
  707. .passWordInput {
  708. margin: 20px;
  709. display: flex;
  710. flex-direction: row;
  711. justify-content: space-around;
  712. }
  713. .passArea {
  714. border-color: red;
  715. }
  716. </style>