PersonStatistics.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  1. <template>
  2. <div class="page_container">
  3. <base-title title="门禁管理" />
  4. <div class="page_content">
  5. <!-- 都匀人员不统计 -->
  6. <div class="person_title">人员信息</div>
  7. <div class="person_num_box">
  8. <vue-seamless
  9. :data="personList"
  10. class="seamless-warp"
  11. :class-option="scrollOption"
  12. ref="seamlessScroll"
  13. :key="seamLessTimeKey"
  14. >
  15. <div v-if="personList.length">
  16. <div class="item" v-for="item of personList" :key="item.id">
  17. <div class="left">
  18. <img :src="item.imgUrl" @click="delInfo(item)" />
  19. </div>
  20. <div class="divider"></div>
  21. <div class="right">
  22. <div class="position">{{ item.type }}</div>
  23. <div class="rymain">
  24. <div class="row">
  25. <div style="width: 40%">
  26. <span>姓名:</span>
  27. <span class="val">{{ item.name }}</span>
  28. </div>
  29. <div v-show="item.phone">
  30. <span>电话号码:</span>
  31. <span class="val" style="color: #00e0ff">{{
  32. item.phone
  33. }}</span>
  34. </div>
  35. </div>
  36. <div class="row">
  37. <div>
  38. <span>人员类型:</span>
  39. <span class="val">{{ item.personType }}</span>
  40. </div>
  41. </div>
  42. <div class="row">
  43. <div>
  44. <span>岗位名称:</span>
  45. <span class="val">{{ item.posi }}</span>
  46. </div>
  47. </div>
  48. <div class="row">
  49. <span>所属单位:</span>
  50. </div>
  51. <div class="row" v-if="item.comp">
  52. <span class="val">{{ item.comp }}</span>
  53. </div>
  54. </div>
  55. </div>
  56. </div>
  57. </div>
  58. <div v-else>暂无数据</div>
  59. </vue-seamless>
  60. </div>
  61. <!-- <div class="person_type_box">
  62. <div class="person_title">出入设备</div>
  63. <div class="type_content">
  64. <div class="left_part">
  65. <img
  66. :src="require('@/assets/imgs/panels/img_personnel_02@2x.png')"
  67. alt=""
  68. @click="openPersonList()"
  69. />
  70. <span class="totle">{{ count }}</span>
  71. <span class="text">总数</span>
  72. </div>
  73. <div class="right_part">
  74. <div
  75. class="row_item"
  76. v-for="(item, index) in devicesTypeCount"
  77. :key="index"
  78. >
  79. <img
  80. v-if="item.name === '员工'"
  81. :src="require('@/assets/imgs/panels/icon_staff@2x.png')"
  82. alt=""
  83. />
  84. <img
  85. v-if="item.name === '访客'"
  86. :src="require('@/assets/imgs/panels/icon_visitor@2x.png')"
  87. alt=""
  88. />
  89. <img
  90. v-if="item.name === '施工'"
  91. :src="require('@/assets/imgs/panels/icon_construction@2x.png')"
  92. alt=""
  93. />
  94. <div class="row_main">
  95. <img
  96. :src="require('@/assets/imgs/panels/icon_arrow@2x.png')"
  97. alt=""
  98. />
  99. <span class="name">{{ item.name }}</span>
  100. <div class="line"></div>
  101. <span class="num">{{ item.value }}</span>
  102. <span class="unit">个</span>
  103. </div>
  104. </div>
  105. </div>
  106. </div>
  107. </div> -->
  108. <!-- <div class="person_events_box">
  109. <div class="person_title">出入信息</div>
  110. <div class="person_event_box">
  111. <vue-seamless
  112. :data="eventsList"
  113. class="seamless-warp-event"
  114. :class-option="scrollOptionEvent"
  115. ref="seamlessScroll"
  116. :key="seamLessTimeKeyEvent"
  117. >
  118. <div v-if="eventsList.length">
  119. <div class="event_item" v-for="item of eventsList" :key="item.id">
  120. <div class="person_event_title">
  121. <span class="person_event_name">{{
  122. item.accessControlName
  123. }}</span>
  124. <span class="split"></span>
  125. <span class="person_event_time">{{ item.eventTime }}</span>
  126. </div>
  127. <div class="person_event_content">{{ item.content }}</div>
  128. </div>
  129. </div>
  130. <div v-else>暂无数据</div>
  131. </vue-seamless>
  132. </div>
  133. </div> -->
  134. <div class="person_type_box">
  135. <div class="person_title">类型统计</div>
  136. <div class="type_content">
  137. <div class="left_part">
  138. <img
  139. :src="require('@/assets/imgs/panels/img_personnel_01@2x.png')"
  140. alt=""
  141. @click="openPersonList()"
  142. />
  143. <span class="totle">{{ total }}</span>
  144. <span class="text">总数</span>
  145. </div>
  146. <div class="right_part">
  147. <div
  148. class="row_item"
  149. v-for="(item, index) in personTypeCount"
  150. :key="index"
  151. >
  152. <img
  153. v-if="item.name === '站内员工'"
  154. :src="require('@/assets/imgs/panels/icon_staff@2x.png')"
  155. alt=""
  156. />
  157. <img
  158. v-if="item.name === '访客人员'"
  159. :src="require('@/assets/imgs/panels/icon_visitor@2x.png')"
  160. alt=""
  161. />
  162. <img
  163. v-if="item.name === '施工人员'"
  164. :src="require('@/assets/imgs/panels/icon_construction@2x.png')"
  165. alt=""
  166. />
  167. <div class="row_main">
  168. <img
  169. :src="require('@/assets/imgs/panels/icon_arrow@2x.png')"
  170. alt=""
  171. />
  172. <span class="name">{{ item.name }}</span>
  173. <div class="line"></div>
  174. <span class="num">{{ item.value }}</span>
  175. <span class="unit">人</span>
  176. </div>
  177. </div>
  178. </div>
  179. </div>
  180. </div>
  181. </div>
  182. </div>
  183. </template>
  184. <script>
  185. import BaseTitle from "./BaseTitle.vue";
  186. import VueSeamless from "vue-seamless-scroll";
  187. import { getPersonTypeList, getAccessInfo } from "@/API/positioning";
  188. import {
  189. setAreaPersonOut,
  190. getAreaPersonList,
  191. getAccessLogList,
  192. } from "@/API/accessControl";
  193. import Dayjs from "dayjs";
  194. import { openDialog } from "@/utils/mapUtil.js";
  195. export default {
  196. name: "PersonStatistics",
  197. components: { BaseTitle, VueSeamless },
  198. data() {
  199. return {
  200. total: 4,
  201. count: 6,
  202. seamLessTimeKey: new Date().getTime(),
  203. seamLessTimeKeyEvent: new Date().getTime(),
  204. personTypeCount: [
  205. {
  206. name: "站内员工",
  207. value: 0,
  208. },
  209. {
  210. name: "访客人员",
  211. value: 0,
  212. },
  213. {
  214. name: "施工人员",
  215. value: 0,
  216. },
  217. ],
  218. devicesTypeCount: [
  219. {
  220. name: "都匀末站",
  221. value: 3,
  222. },
  223. {
  224. name: "凯口清管站",
  225. value: 1,
  226. },
  227. {
  228. name: "独山首站",
  229. value: 2,
  230. },
  231. ],
  232. personRiskCount: [
  233. {
  234. code: "306001",
  235. name: "3万方汽油罐区",
  236. value: 0,
  237. },
  238. {
  239. code: "306002",
  240. name: "8万方汽油罐区",
  241. value: 0,
  242. },
  243. {
  244. code: "306003",
  245. name: "20万方柴油油罐区",
  246. value: 0,
  247. },
  248. {
  249. code: "306004",
  250. name: "500方泄压罐",
  251. value: 0,
  252. },
  253. ],
  254. scrollOption: {
  255. limitMoveNum: 2,
  256. singleHeight: 173,
  257. waitTime: 5000,
  258. openWatch: true,
  259. },
  260. scrollOptionEvent: {
  261. limitMoveNum: 1,
  262. singleHeight: 66.5,
  263. waitTime: 5000,
  264. openWatch: true,
  265. },
  266. defaultPhoto: "~@/assets/imgs/stationMap/img_无照片.png",
  267. personList: [
  268. {
  269. id: "1",
  270. name: "",
  271. pic: "",
  272. type: "值班干部",
  273. posi: "主任",
  274. personType: "员工",
  275. comp: "XXXXX公司",
  276. phone: 15500001111,
  277. imgUrl: "~@/assets/imgs/stationMap/img_无照片.png",
  278. },
  279. ],
  280. eventsList: [
  281. {
  282. id: "1",
  283. accessControlName: "门口人脸识别",
  284. eventTime: "2025-01-16 15:51:46",
  285. content: "【张华亚】在门禁【门口人脸识别】人脸认证通过",
  286. },
  287. // {
  288. // id: "3",
  289. // name: "306004",
  290. // startTime: "2022-11-16 15:51:46",
  291. // content: "周界入侵触发,事件等级较低",
  292. // },
  293. // {
  294. // id: "4",
  295. // name: "306003",
  296. // startTime: "2022-11-16 15:51:46",
  297. // content: "激光云台触发气体泄漏,事件等级中",
  298. // },
  299. ],
  300. };
  301. },
  302. created() {
  303. // this.openPersonInfo();
  304. // this.initAccessLogList();
  305. },
  306. computed: {
  307. VUE_APP_BASE_API() {
  308. return process.env.VUE_APP_BASE_API;
  309. },
  310. },
  311. mounted() {
  312. this.startMqtt();
  313. let timer = null;
  314. if (!timer) {
  315. timer = setInterval(() => {
  316. this.getMessage();
  317. }, 3000);
  318. }
  319. this.$once("hook:beforeDestroy", () => {
  320. clearInterval(timer);
  321. timer = null;
  322. });
  323. // this.getPersonTypeList();
  324. },
  325. methods: {
  326. openDialog,
  327. async initAccessLogList() {
  328. try {
  329. const params = {
  330. pageSize: 100,
  331. pageIndex: 1,
  332. startTime: Dayjs(new Date())
  333. .subtract(1, "day")
  334. .format("YYYY-MM-DD HH:mm:ss"),
  335. endTime: Dayjs(new Date()).format("YYYY-MM-DD HH:mm:ss"),
  336. };
  337. const res = await getAccessLogList(params);
  338. this.eventsList = res.data.content;
  339. console.log("门禁事件列表", params, this.eventsList);
  340. } catch (err) {
  341. console.log(err);
  342. }
  343. },
  344. async openPersonInfo() {
  345. try {
  346. const res = await getAccessInfo({ id: "789185626355277824" });
  347. const data = res.data;
  348. console.log("门禁信息", data);
  349. if (data.remark) {
  350. const c = data.remark.split(":");
  351. if (c.length == 3) {
  352. this.personTypeCount[0].value = c[0]; //员工
  353. this.personTypeCount[1].value = c[2]; //访客
  354. this.personTypeCount[2].value = c[1]; //施工
  355. this.total = Number(c[0]) + Number(c[1]) + Number(c[2]);
  356. }
  357. }
  358. } catch (err) {
  359. console.log(err);
  360. }
  361. },
  362. openPersonList() {
  363. // this.openDialog(
  364. // "进站跟踪",
  365. // "https://10.0.0.201:8082/#/main?nolayout=1&token={token}",
  366. // 1500,
  367. // 760
  368. // );
  369. // this.$store.dispatch("globalConfig/setPersonListDialog", {
  370. // show: true,
  371. // dialogMsg: this.personList,
  372. // type: "All",
  373. // });
  374. },
  375. async getPersonTypeList() {
  376. try {
  377. const p = {};
  378. const res = await getPersonTypeList(p);
  379. // console.log(res.data);
  380. } catch (err) {
  381. console.log(err);
  382. }
  383. },
  384. startMqtt() {
  385. const topics = [
  386. // "CountArea/AllCount/All",
  387. // "CountArea/RiskCount/All",
  388. // "CountArea/PersonTypeCount/All",
  389. "AccessControl/Log",
  390. ];
  391. const _this = this;
  392. this.$store.dispatch("mqtt/subscribe", {
  393. topic: topics,
  394. onMessage: (topic, message, packet) => {
  395. const content = message.toString();
  396. // if (topic === "CountArea/AllCount/All") {
  397. // this.total = content;
  398. // } else if (topic === "CountArea/RiskCount/All") {
  399. // const data = JSON.parse(content);
  400. // this.personRiskCount.forEach((item) => {
  401. // item.value = data[item.code];
  402. // });
  403. // } else if (topic === "CountArea/PersonTypeCountDic/All") {
  404. // const data = JSON.parse(content);
  405. // } else
  406. console.log("门禁内容调整", content);
  407. if (topic === "AccessControl/Log") {
  408. //站内人员变动,重新查询数据
  409. // if (
  410. // JSON.parse(content).AreaId == "791707314364096512" &&
  411. // JSON.parse(content).PersonId != null
  412. // ) {
  413. this.getMessage();
  414. // }
  415. }
  416. },
  417. });
  418. this.$once("hook:beforeDestroy", () => {
  419. this.$store.dispatch("mqtt/unsubscribe", topics);
  420. });
  421. },
  422. async getMessage() {
  423. try {
  424. let res = await getAreaPersonList({ id: "791707314364096512" });
  425. if (res.code === 20000) {
  426. // console.log(res);
  427. if (res.data.content != null && res.data.content != undefined) {
  428. let localList = [];
  429. let workList = [];
  430. let visitList = [];
  431. let personInfoList = [];
  432. res.data.content.forEach((i) => {
  433. if (i.typeBelong == 1) {
  434. personInfoList.push({
  435. id: i.workNo,
  436. name: i.name,
  437. pic: "",
  438. type: i.positionName,
  439. posi: i.positionName,
  440. personType: i.typeName,
  441. comp: i.departmentName == null ? "" : i.departmentName,
  442. phone: i.telephone,
  443. imgUrl:
  444. i.photoPath == null
  445. ? this.defaultPhoto
  446. : "/yapi" + i.photoPath,
  447. });
  448. } else {
  449. personInfoList.push({
  450. id: i.workNo,
  451. name: i.name,
  452. pic: "",
  453. type: i.positionName,
  454. posi: i.positionName,
  455. personType: i.typeName,
  456. comp: i.companyName == null ? "" : i.companyName,
  457. phone: i.telephone,
  458. imgUrl:
  459. i.photoPath == null
  460. ? this.defaultPhoto
  461. : "/yapi" + i.photoPath,
  462. });
  463. }
  464. switch (i.type) {
  465. //访客
  466. case "546093319541760000":
  467. visitList.push({
  468. id: i.id,
  469. workNo: i.workNo,
  470. name: i.name,
  471. });
  472. break;
  473. //施工
  474. case "403245878963347456":
  475. workList.push({
  476. id: i.id,
  477. workNo: i.workNo,
  478. name: i.name,
  479. });
  480. break;
  481. //员工
  482. case "255022541838691649":
  483. localList.push({
  484. id: i.id,
  485. workNo: i.workNo,
  486. name: i.name,
  487. });
  488. break;
  489. }
  490. });
  491. this.personList = personInfoList.sort(function (a, b) {
  492. return a.id - b.id;
  493. });
  494. this.personTypeCount[0].value = localList.length; //员工
  495. this.personTypeCount[1].value = visitList.length; //访客
  496. this.personTypeCount[2].value = workList.length; //施工
  497. this.total = localList.length + workList.length + visitList.length;
  498. // console.log(
  499. // "数据数组:",
  500. // personInfoList,
  501. // localList,
  502. // visitList,
  503. // workList
  504. // );
  505. }
  506. } else {
  507. }
  508. } catch (error) {
  509. console.log(error);
  510. }
  511. },
  512. async delPersonMessage(item) {
  513. try {
  514. let res = await setAreaPersonOut({
  515. areaId: "791707314364096512",
  516. personId: item.id,
  517. });
  518. } catch (error) {
  519. console.log(error);
  520. }
  521. },
  522. delInfo(item) {
  523. this.$confirm("是否将" + item.name + "从入场列表中删除,?", "提示", {
  524. confirmButtonText: "确定",
  525. cancelButtonText: "取消",
  526. type: "warning",
  527. })
  528. .then(() => {
  529. console.log("删除" + item.name + "人员已入场信息!");
  530. this.delPersonMessage(item); //删除接口
  531. this.$message({
  532. type: "success",
  533. message: "删除成功!",
  534. });
  535. setTimeout(() => {
  536. this.getMessage();
  537. }, 500);
  538. })
  539. .catch(() => {
  540. this.$message({
  541. type: "info",
  542. message: "已取消删除",
  543. });
  544. });
  545. },
  546. },
  547. beforeDestroy() {},
  548. };
  549. </script>
  550. <style lang="less" scoped>
  551. .page_container {
  552. width: 410px;
  553. z-index: 2;
  554. .page_content {
  555. width: 100%;
  556. height: 62%;
  557. .person_title {
  558. margin-top: 4px;
  559. padding-left: 20px;
  560. height: 24px;
  561. line-height: 24px;
  562. background: url(~@/assets/imgs/panels/title_bg_01@2x.png) no-repeat;
  563. background-size: 100% 100%;
  564. font-family: MicrosoftYaHei-Bold;
  565. font-size: 14px;
  566. color: #e0f3ff;
  567. letter-spacing: 0.88px;
  568. text-shadow: 0 0 10px #1162ff;
  569. font-weight: 700;
  570. }
  571. .person_type_box {
  572. width: 100%;
  573. height: 154px;
  574. .person_title {
  575. margin-top: 10px;
  576. }
  577. .type_content {
  578. margin-top: 4px;
  579. width: 100%;
  580. height: 126px;
  581. display: flex;
  582. justify-content: space-between;
  583. align-items: center;
  584. .left_part {
  585. width: 110px;
  586. height: 100%;
  587. display: flex;
  588. flex-direction: column;
  589. justify-content: center;
  590. align-items: center;
  591. img {
  592. width: 64px;
  593. height: 64px;
  594. }
  595. .totle {
  596. font-size: 30px;
  597. color: #ffffff;
  598. letter-spacing: 1.26px;
  599. text-shadow: 0 0 10px rgba(0, 180, 255, 0.5);
  600. font-weight: 700;
  601. }
  602. .text {
  603. font-size: 14px;
  604. color: #ffffff;
  605. letter-spacing: 0;
  606. text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
  607. font-weight: 400;
  608. }
  609. }
  610. }
  611. }
  612. .person_num_box {
  613. width: 100%;
  614. height: 342px;
  615. overflow: hidden;
  616. .num_content {
  617. width: 100%;
  618. height: 168px;
  619. display: flex;
  620. justify-content: space-between;
  621. align-items: center;
  622. .left_part {
  623. width: 110px;
  624. height: 100%;
  625. display: flex;
  626. flex-direction: column;
  627. justify-content: center;
  628. align-items: center;
  629. img {
  630. width: 80px;
  631. height: 80px;
  632. }
  633. }
  634. }
  635. .seamless-warp {
  636. .item {
  637. margin-top: 9px;
  638. height: 164px;
  639. display: flex;
  640. position: relative;
  641. .left {
  642. width: 25%;
  643. height: 100%;
  644. text-align: center;
  645. margin-right: 8px;
  646. img {
  647. width: 120px;
  648. height: 160px;
  649. }
  650. }
  651. .divider {
  652. width: 5%;
  653. }
  654. .right {
  655. width: 70%;
  656. min-height: 163px;
  657. position: relative;
  658. .position {
  659. font-family: 优设标题黑;
  660. font-size: 18px;
  661. color: #ffffff;
  662. letter-spacing: 1.29px;
  663. position: absolute;
  664. z-index: 99;
  665. background-image: linear-gradient(180deg, #eeeeee, #5cd5ff);
  666. -webkit-background-clip: text;
  667. background-clip: text;
  668. color: transparent;
  669. font-weight: 400;
  670. padding-left: 10px;
  671. }
  672. .rymain {
  673. width: 100%;
  674. height: calc(100% - 14px);
  675. position: absolute;
  676. bottom: 0;
  677. opacity: 0.9;
  678. background-image: linear-gradient(
  679. 270deg,
  680. rgba(0, 24, 46, 0.1) 0%,
  681. #00487b 98%
  682. );
  683. display: flex;
  684. flex-direction: column;
  685. justify-content: space-around;
  686. font-size: 12px;
  687. color: #b3c0d4;
  688. // padding-top: 12px;
  689. .row {
  690. display: flex;
  691. padding-left: 5px;
  692. font-family: MicrosoftYaHei;
  693. .val {
  694. color: #ffffff;
  695. white-space: nowrap; /*强制单行显示*/
  696. text-overflow: ellipsis; /*超出部分省略号表示*/
  697. overflow: hidden; /*超出部分隐藏*/
  698. width: 256px; /*设置显示的最大宽度*/
  699. }
  700. }
  701. .row:nth-child(2) {
  702. margin-top: -8px;
  703. }
  704. }
  705. }
  706. }
  707. }
  708. }
  709. .person_events_box {
  710. .person_event_box {
  711. height: 66px;
  712. overflow: hidden;
  713. .seamless-warp-event {
  714. max-height: 66px;
  715. .event_item {
  716. height: 14%;
  717. position: relative;
  718. .person_event_title {
  719. margin-top: 2px;
  720. height: 27px;
  721. background-image: linear-gradient(
  722. 90deg,
  723. #53a3ff 2%,
  724. rgba(249, 40, 40, 0) 100%
  725. );
  726. display: flex;
  727. align-items: center;
  728. color: #fff;
  729. position: relative;
  730. img {
  731. width: 14px;
  732. height: 14px;
  733. }
  734. .person_event_name {
  735. margin-left: 19px;
  736. }
  737. .split {
  738. width: 2px;
  739. height: 20px;
  740. border-left: 2px solid #fff;
  741. margin: 0 8px;
  742. }
  743. }
  744. .person_event_content {
  745. margin-left: 14px;
  746. padding: 10px 0;
  747. font-size: 13px;
  748. color: #ffffff;
  749. letter-spacing: 1px;
  750. font-weight: 400;
  751. }
  752. }
  753. }
  754. }
  755. }
  756. .right_part {
  757. width: 300px;
  758. display: flex;
  759. flex-direction: column;
  760. justify-content: space-between;
  761. align-items: center;
  762. .row_item {
  763. width: 300px;
  764. height: 30px;
  765. display: flex;
  766. justify-content: space-between;
  767. align-items: center;
  768. margin-bottom: 8px;
  769. &:last-child {
  770. margin-bottom: 0;
  771. }
  772. img {
  773. width: 30px;
  774. height: 30px;
  775. }
  776. .row_main {
  777. width: 260px;
  778. height: 30px;
  779. display: flex;
  780. justify-content: space-between;
  781. align-items: center;
  782. background-color: rgba(51, 125, 206, 0.27);
  783. padding-right: 10px;
  784. .name {
  785. flex-shrink: 0;
  786. text-align: center;
  787. font-size: 13px;
  788. color: #ffffff;
  789. letter-spacing: 0;
  790. font-weight: 400;
  791. }
  792. .line {
  793. margin: 0 10px;
  794. width: 100%;
  795. height: 1px;
  796. border-top: 1px dashed #fff;
  797. opacity: 0.4;
  798. }
  799. .num {
  800. flex-shrink: 0;
  801. font-size: 18px;
  802. color: #ffffff;
  803. letter-spacing: 0;
  804. font-weight: 700;
  805. }
  806. .unit {
  807. opacity: 0.4;
  808. font-family: MicrosoftYaHei;
  809. font-size: 12px;
  810. color: #ffffff;
  811. letter-spacing: 0;
  812. font-weight: 400;
  813. }
  814. }
  815. }
  816. }
  817. }
  818. }
  819. </style>