detail.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  1. <!-- 物联网卡-详情 -->
  2. <template>
  3. <div>
  4. <el-card shadow="nover">
  5. <el-descriptions class="margin-top" title="基本信息" :column="3" :size="size" border>
  6. <!-- 卡号 -->
  7. <el-descriptions-item>
  8. <template #label>
  9. <div class="cell-item">
  10. <el-icon :style="iconStyle">
  11. <user />
  12. </el-icon>
  13. 卡号
  14. </div>
  15. </template>
  16. {{sim.accNumber}}
  17. </el-descriptions-item>
  18. <!-- ICCID -->
  19. <el-descriptions-item>
  20. <template #label>
  21. <div class="cell-item">
  22. <el-icon :style="iconStyle">
  23. <iphone />
  24. </el-icon>
  25. ICCID
  26. </div>
  27. </template>
  28. {{sim.iccid}}
  29. </el-descriptions-item>
  30. <!-- 绑定设备 -->
  31. <el-descriptions-item>
  32. <template #label>
  33. <div class="cell-item">
  34. <el-icon :style="iconStyle">
  35. <iphone />
  36. </el-icon>
  37. 绑定设备
  38. </div>
  39. </template>
  40. {{sim.bindDeviceName}}
  41. </el-descriptions-item>
  42. <!-- 平台类型 -->
  43. <el-descriptions-item>
  44. <template #label>
  45. <div class="cell-item">
  46. <el-icon :style="iconStyle">
  47. <iphone />
  48. </el-icon>
  49. 平台类型
  50. </div>
  51. </template>
  52. {{sim.platTypes}}
  53. </el-descriptions-item>
  54. <!-- 平台名称 -->
  55. <el-descriptions-item>
  56. <template #label>
  57. <div class="cell-item">
  58. <el-icon :style="iconStyle">
  59. <location />
  60. </el-icon>
  61. 平台名称
  62. </div>
  63. </template>
  64. {{sim.platName}}
  65. </el-descriptions-item>
  66. <!-- 运营商 -->
  67. <el-descriptions-item>
  68. <template #label>
  69. <div class="cell-item">
  70. <el-icon :style="iconStyle">
  71. <location />
  72. </el-icon>
  73. 运营商
  74. </div>
  75. </template>
  76. {{formatOperator(sim.types)}}
  77. </el-descriptions-item>
  78. <!-- 类型 -->
  79. <el-descriptions-item>
  80. <template #label>
  81. <div class="cell-item">
  82. <el-icon :style="iconStyle">
  83. <location />
  84. </el-icon>
  85. 类型
  86. </div>
  87. </template>
  88. {{formatType(sim.simTypes)}}
  89. </el-descriptions-item>
  90. <!-- 激活日期 -->
  91. <el-descriptions-item>
  92. <template #label>
  93. <div class="cell-item">
  94. <el-icon :style="iconStyle">
  95. <location />
  96. </el-icon>
  97. 激活日期
  98. </div>
  99. </template>
  100. {{sim.activationTime}}
  101. </el-descriptions-item>
  102. <!-- 更新时间 -->
  103. <el-descriptions-item>
  104. <template #label>
  105. <div class="cell-item">
  106. <el-icon :style="iconStyle">
  107. <location />
  108. </el-icon>
  109. 更新时间
  110. </div>
  111. </template>
  112. {{sim.updatedAt}}
  113. </el-descriptions-item>
  114. <!-- 总流量 -->
  115. <el-descriptions-item>
  116. <template #label>
  117. <div class="cell-item">
  118. <el-icon :style="iconStyle">
  119. <location />
  120. </el-icon>
  121. 总流量
  122. </div>
  123. </template>
  124. {{sim.totalFlow}}
  125. </el-descriptions-item>
  126. <!-- 使用流量 -->
  127. <el-descriptions-item>
  128. <template #label>
  129. <div class="cell-item">
  130. <el-icon :style="iconStyle">
  131. <location />
  132. </el-icon>
  133. 使用流量
  134. </div>
  135. </template>
  136. {{sim.usedFlow}}
  137. </el-descriptions-item>
  138. <!-- 剩余流量 -->
  139. <el-descriptions-item>
  140. <template #label>
  141. <div class="cell-item">
  142. <el-icon :style="iconStyle">
  143. <location />
  144. </el-icon>
  145. 剩余流量
  146. </div>
  147. </template>
  148. {{sim.leaveFlow}}
  149. </el-descriptions-item>
  150. <!-- 状态 -->
  151. <el-descriptions-item>
  152. <template #label>
  153. <div class="cell-item">
  154. <el-icon :style="iconStyle">
  155. <tickets />
  156. </el-icon>
  157. 状态
  158. </div>
  159. </template>
  160. <el-tag size="small">{{formatStatus(sim.simStatus)}}</el-tag>
  161. </el-descriptions-item>
  162. <!-- 说明 -->
  163. <el-descriptions-item>
  164. <template #label>
  165. <div class="cell-item">
  166. <el-icon :style="iconStyle">
  167. <office-building />
  168. </el-icon>
  169. 说明
  170. </div>
  171. </template>
  172. {{sim.iccid}}
  173. </el-descriptions-item>
  174. </el-descriptions>
  175. </el-card>
  176. <div class="statistics-wrap gap-3">
  177. <el-card shadow="nover" class="left-wrap">
  178. <div class="top-title-wrap">
  179. <div class="title">流量统计</div>
  180. <div class="operate-wrap">
  181. <el-button-group>
  182. <el-button @click="changeDate(1)" :type="activeIndex == 1 ? 'primary' : ''">昨日</el-button>
  183. <el-button @click="changeDate(2)" :type="activeIndex == 2 ? 'primary' : ''">近一周</el-button>
  184. <el-button @click="changeDate(3)" :type="activeIndex == 3 ? 'primary' : ''">近一月</el-button>
  185. <el-button @click="changeDate(4)" :type="activeIndex == 4 ? 'primary' : ''">近一年</el-button>
  186. </el-button-group>
  187. <el-date-picker
  188. class="date-picker-wrap"
  189. v-model="dateRange"
  190. type="datetimerange"
  191. range-separator="至"
  192. start-placeholder="开始时间"
  193. end-placeholder="结束时间"
  194. format="YYYY-MM-DD HH:mm:ss"
  195. date-format="YYYY/MM/DD"
  196. time-format="hh:mm:ss"
  197. />
  198. </div>
  199. </div>
  200. <div style="height: 460px;" ref="flowLine"></div>
  201. </el-card>
  202. <el-card shadow="nover" class="right-wrap">
  203. <div class="title">数据统计</div>
  204. <div class="line-wrap flow-line-wrap">
  205. <div class="text-wrap">
  206. <div class="text">昨日流量消耗</div>
  207. <div>{{formatSize(statisticsData.yesterdayTotal * 1024 * 1024)}}</div>
  208. </div>
  209. <div class="line-inner-wrap" ref="yesterdayLine"></div>
  210. </div>
  211. <div class="line-wrap flow-line-wrap">
  212. <div class="text-wrap">
  213. <div class="text">当月流量消耗</div>
  214. <div>{{formatSize(statisticsData.monthTotal * 1024 * 1024)}}</div>
  215. </div>
  216. <div class="line-inner-wrap" ref="monthLine"></div>
  217. </div>
  218. <div class="line-wrap flow-line-wrap">
  219. <div class="text-wrap">
  220. <div class="text">本年流量消耗</div>
  221. <div>{{formatSize(statisticsData.yearTotal * 1024 * 1024)}}</div>
  222. </div>
  223. <div class="line-inner-wrap" ref="yearLine"></div>
  224. </div>
  225. </el-card>
  226. </div>
  227. </div>
  228. </template>
  229. <script lang="ts" setup>
  230. import { ref, reactive, nextTick, watch, markRaw } from "vue";
  231. import { formatSize } from "/@/utils/common";
  232. import api from '/@/api/iotCard';
  233. import { useStore } from '/@/store/index';
  234. import { useRoute } from 'vue-router';
  235. import * as echarts from 'echarts';
  236. import dayjs from 'dayjs';
  237. const store = useStore();
  238. const route = useRoute();
  239. const sim = ref({
  240. accNumber: "",// 卡号
  241. iccid: "",// ICCID
  242. bindDeviceName: "",// 绑定设备
  243. platName: "",// 平台对接
  244. types: "",// 运营商
  245. simTypes: "",// 类型
  246. totalFlow: "",// 总流量
  247. usedFlow: "",// 使用流量
  248. leaveFlow: "",// 剩余流量
  249. activationTime: "",// 激活日期
  250. updatedAt: "",// 更新时间
  251. simStatus: "",// 状态
  252. remark: ""// 说明
  253. })
  254. const flowLine = ref();
  255. const yesterdayLine = ref();
  256. const monthLine = ref();
  257. const yearLine = ref();
  258. const dateRange = ref<any>([
  259. dayjs(new Date()).subtract(6, 'day'),
  260. dayjs(new Date()),
  261. ])
  262. const activeIndex= ref(2);
  263. const flowLineXAxisData = ref<any>([]);
  264. const flowLineData = ref<any>([]);
  265. const yearLineXAxisData = ref<any>([]);
  266. const yearLineData = ref<any>([]);
  267. const monthLineXAxisData = ref<any>([]);
  268. const monthLineData = ref<any>([]);
  269. const yesterdayLineXAxisData = ref<any>([dayjs(new Date()).subtract(1, 'day').format('YYYY-MM-DD')]);
  270. const yesterdayLineData = ref<any>([]);
  271. const statisticsData = ref({
  272. monthTotal: 0,
  273. yearTotal: 0,
  274. yesterdayTotal: 0
  275. })
  276. const state = reactive({
  277. global: {
  278. yesterdayLine: null,
  279. monthLine: null,
  280. yearLine: null,
  281. dispose: [null, '', undefined],
  282. } as any,
  283. myCharts: [],
  284. charts: {
  285. theme: '',
  286. bgColor: '',
  287. color: '#303133',
  288. },
  289. });
  290. const getDetailInfo = async () => {
  291. const res = await api.simCard.detailItem({ id: route.params.id });
  292. sim.value = res.sim;
  293. statisticsData.value = {
  294. monthTotal: res.monthFlow,
  295. yearTotal: res.yearFlow,
  296. yesterdayTotal: res.yesterdayFlow
  297. }
  298. await getFlowDataByDateRange();
  299. res.yearDataList.reverse().forEach((item:any) => {
  300. yearLineXAxisData.value.push(item.date);
  301. yearLineData.value.push(item.value);
  302. })
  303. res.monthDataList.reverse().forEach((item:any) => {
  304. monthLineXAxisData.value.push(item.date);
  305. monthLineData.value.push(item.value);
  306. })
  307. yesterdayLineData.value = [res.yearFlow];
  308. iniFlowLineChart();
  309. initYesterdayLineChart();
  310. initMonthLineChart();
  311. initYearLineChart();
  312. }
  313. getDetailInfo();
  314. const getFlowDataByDateRange = async () => {
  315. const simFlowRes = await api.simCard.getFlowDataByDateRange({
  316. sdate: activeIndex.value !== 1 ? dateRange.value[0].format('YYYY-MM-DD HH:mm:ss') : dateRange.value[0],
  317. edate: activeIndex.value !== 1 ? dateRange.value[1].format('YYYY-MM-DD HH:mm:ss') : dateRange.value[1],
  318. accNumber: sim.value.accNumber,
  319. types: sim.value.types
  320. })
  321. simFlowRes.data.reverse().forEach((item:any) => {
  322. flowLineXAxisData.value.push(item.date);
  323. flowLineData.value.push(item.value);
  324. })
  325. iniFlowLineChart();
  326. }
  327. const changeDate = (key:number) => {
  328. // 1 昨天 2近一周 3近一月 4近一年
  329. activeIndex.value = key;
  330. if(key === 1) {
  331. // 昨天
  332. const yesterday = dayjs(new Date()).subtract(1, 'day').format('YYYY-MM-DD')
  333. dateRange.value = [
  334. yesterday + " 00:00:00",
  335. yesterday + " 23:59:59"
  336. ]
  337. }else if(key === 2) {
  338. // 近一周
  339. dateRange.value = [
  340. dayjs(new Date()).subtract(6, 'day'),
  341. dayjs(new Date()),
  342. ]
  343. }else if(key === 3) {
  344. // 近一月
  345. dateRange.value = [
  346. dayjs(new Date()).subtract(1, 'month'),
  347. dayjs(new Date()),
  348. ]
  349. }else if(key === 4) {
  350. // 近一年
  351. dateRange.value = [
  352. dayjs(new Date()).subtract(1, 'year'),
  353. dayjs(new Date()),
  354. ]
  355. }
  356. flowLineXAxisData.value = [];
  357. flowLineData.value = [];
  358. getFlowDataByDateRange();
  359. }
  360. const formatOperator = (val:number) => {
  361. // 1电信,2联通,3移动
  362. return ['', '电信', '联通', '移动'][val];
  363. }
  364. const formatType = (val:number) => {
  365. // 1月卡,2季卡,3年卡,4其他
  366. return ['', '月卡', '季卡', '年卡', '其他'][val];
  367. }
  368. const formatStatus = (val:any) => {
  369. // 1:可激活 2:测试激活 3:测试去激活 4:在用 5:停机 6:运营商管理状态
  370. return ['', '可激活', '测试激活', '测试去激活', '在用', '停机', '运营商管理状态'][val];
  371. }
  372. // 折线图 - 昨日流量消耗
  373. const initYesterdayLineChart = () => {
  374. if (!state.global.dispose.some((b: any) => b === state.global.yesterdayLine)) state.global.yesterdayLine.dispose();
  375. state.global.yesterdayLine = markRaw(echarts.init(yesterdayLine.value, state.charts.theme));
  376. const option = {
  377. backgroundColor: state.charts.bgColor,
  378. xAxis: {
  379. data: yesterdayLineXAxisData.value,
  380. show: false,
  381. },
  382. yAxis: [
  383. {
  384. type: 'value',
  385. name: '',
  386. show: false,
  387. splitLine: { show: false, lineStyle: { type: 'dashed', color: '#f5f5f5' } }
  388. },
  389. ],
  390. tooltip: {
  391. trigger: 'axis',
  392. formatter: function (params:any) {
  393. var relVal = params[0].name
  394. let circle = `<i style="margin-right:4px;display: inline-block;width: 10px;height: 10px;border-radius: 50%;background-color:${params[0].color}"></i>`
  395. relVal += '<br/>' + circle + ' 流量: ' + formatSize(params[0].value*1024*1024)
  396. return relVal;
  397. }
  398. },
  399. grid: { top: 10, right: 10, bottom: 10, left: 10 },
  400. series: [
  401. {
  402. name: '流量',
  403. type: 'line',
  404. smooth: true,
  405. data: yesterdayLineData.value,
  406. lineStyle: { color: '#fe9a8b' },
  407. itemStyle: { color: '#fe9a8b', borderColor: '#fe9a8b' }
  408. }
  409. ],
  410. };
  411. (<any>state.global.yesterdayLine).setOption(option);
  412. (<any>state.myCharts).push(state.global.yesterdayLine);
  413. };
  414. // 折线图 - 当月流量消耗
  415. const initMonthLineChart = () => {
  416. if (!state.global.dispose.some((b: any) => b === state.global.monthLine)) state.global.monthLine.dispose();
  417. state.global.monthLine = markRaw(echarts.init(monthLine.value, state.charts.theme));
  418. const option = {
  419. backgroundColor: state.charts.bgColor,
  420. xAxis: {
  421. data: monthLineXAxisData.value,
  422. show: false,
  423. },
  424. yAxis: [
  425. {
  426. type: 'value',
  427. name: '',
  428. show: false,
  429. splitLine: { show: false, lineStyle: { type: 'dashed', color: '#f5f5f5' } }
  430. },
  431. ],
  432. tooltip: {
  433. trigger: 'axis',
  434. formatter: function (params:any) {
  435. var relVal = params[0].name
  436. let circle = `<i style="margin-right:4px;display: inline-block;width: 10px;height: 10px;border-radius: 50%;background-color:${params[0].color}"></i>`
  437. relVal += '<br/>' + circle + ' 流量: ' + formatSize(params[0].value*1024*1024)
  438. return relVal;
  439. }
  440. },
  441. grid: { top: 10, right: 10, bottom: 10, left: 10 },
  442. series: [
  443. {
  444. name: '流量',
  445. type: 'line',
  446. smooth: true,
  447. data: monthLineData.value,
  448. lineStyle: { color: '#9E87FF' },
  449. itemStyle: { color: '#9E87FF', borderColor: '#9E87FF' },
  450. }
  451. ],
  452. };
  453. (<any>state.global.monthLine).setOption(option);
  454. (<any>state.myCharts).push(state.global.monthLine);
  455. };
  456. // 折线图 - 本年流量消耗
  457. const initYearLineChart = () => {
  458. if (!state.global.dispose.some((b: any) => b === state.global.yearLine)) state.global.yearLine.dispose();
  459. state.global.yearLine = markRaw(echarts.init(yearLine.value, state.charts.theme));
  460. const option = {
  461. backgroundColor: state.charts.bgColor,
  462. xAxis: {
  463. data: yearLineXAxisData.value,
  464. show: false,
  465. },
  466. yAxis: [
  467. {
  468. type: 'value',
  469. name: '',
  470. show: false,
  471. splitLine: { show: false, lineStyle: { type: 'dashed', color: '#f5f5f5' } }
  472. },
  473. ],
  474. tooltip: {
  475. trigger: 'axis',
  476. formatter: function (params:any) {
  477. var relVal = params[0].name
  478. let circle = `<i style="margin-right:4px;display: inline-block;width: 10px;height: 10px;border-radius: 50%;background-color:${params[0].color}"></i>`
  479. relVal += '<br/>' + circle + ' 流量: ' + formatSize(params[0].value*1024*1024)
  480. return relVal;
  481. }
  482. },
  483. grid: { top: 10, right: 10, bottom: 10, left: 10 },
  484. series: [
  485. {
  486. name: '流量',
  487. type: 'line',
  488. smooth: true,
  489. data: yearLineData.value,
  490. lineStyle: { color: '#fe9a8b' },
  491. itemStyle: { color: '#fe9a8b', borderColor: '#fe9a8b' }
  492. }
  493. ],
  494. };
  495. (<any>state.global.yearLine).setOption(option);
  496. (<any>state.myCharts).push(state.global.yearLine);
  497. };
  498. // 折线图 - 流量统计
  499. const iniFlowLineChart = async () => {
  500. if (!state.global.dispose.some((b: any) => b === state.global.flowLine)) state.global.flowLine.dispose();
  501. state.global.flowLine = markRaw(echarts.init(flowLine.value, state.charts.theme));
  502. const option = {
  503. backgroundColor: state.charts.bgColor,
  504. grid: { top: 70, right: 20, bottom: 30, left: 30 },
  505. tooltip: {
  506. trigger: 'axis',
  507. formatter: function (params:any) {
  508. var relVal = params[0].name
  509. let circle = `<i style="margin-right:4px;display: inline-block;width: 10px;height: 10px;border-radius: 50%;background-color:${params[0].color}"></i>`
  510. relVal += '<br/>' + circle + ' 流量: ' + params[0].value + 'MB'
  511. return relVal;
  512. }
  513. },
  514. xAxis: {
  515. data: flowLineXAxisData.value,
  516. },
  517. yAxis: [
  518. {
  519. type: 'value',
  520. name: '',
  521. splitLine: { show: true, lineStyle: { type: 'dashed', color: '#f5f5f5' } },
  522. axisLabel: {
  523. margin: 2,
  524. formatter: function (value:any) {
  525. if (value >= 10000 && value < 10000000) {
  526. value = value / 10000 + "W";
  527. } else if (value >= 10000000) {
  528. value = value / 10000000 + "KW";
  529. }
  530. return value;
  531. }
  532. },
  533. },
  534. ],
  535. series: [
  536. {
  537. name: '流量',
  538. type: 'line',
  539. symbolSize: 6,
  540. symbol: 'circle',
  541. smooth: true,
  542. data: flowLineData.value,
  543. lineStyle: { color: '#9E87FF' },
  544. itemStyle: { color: '#9E87FF', borderColor: '#9E87FF' },
  545. areaStyle: {
  546. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  547. { offset: 0, color: '#9E87FFb3' },
  548. { offset: 1, color: '#9E87FF03' },
  549. ]),
  550. },
  551. emphasis: {
  552. itemStyle: {
  553. color: {
  554. type: 'radial',
  555. x: 0.5,
  556. y: 0.5,
  557. r: 0.5,
  558. colorStops: [
  559. { offset: 0, color: '#9E87FF' },
  560. { offset: 0.4, color: '#9E87FF' },
  561. { offset: 0.5, color: '#fff' },
  562. { offset: 0.7, color: '#fff' },
  563. { offset: 0.8, color: '#fff' },
  564. { offset: 1, color: '#fff' },
  565. ],
  566. },
  567. borderColor: '#9E87FF',
  568. borderWidth: 2,
  569. },
  570. },
  571. },
  572. ],
  573. };
  574. (<any>state.global.flowLine).setOption(option);
  575. (<any>state.myCharts).push(state.global.flowLine);
  576. };
  577. // 监听 vuex 中是否开启深色主题
  578. watch(
  579. () => store.state.themeConfig.themeConfig.isIsDark,
  580. (isIsDark) => {
  581. nextTick(() => {
  582. state.charts.theme = isIsDark ? 'dark' : '';
  583. state.charts.bgColor = isIsDark ? 'transparent' : '';
  584. state.charts.color = isIsDark ? '#dadada' : '#303133';
  585. setTimeout(() => {
  586. iniFlowLineChart();
  587. initYesterdayLineChart();
  588. initMonthLineChart();
  589. initYearLineChart();
  590. }, 500);
  591. });
  592. },
  593. {
  594. deep: true,
  595. immediate: true,
  596. }
  597. );
  598. </script>
  599. <style lang="scss" scoped>
  600. .statistics-wrap {
  601. display: flex;
  602. justify-content: space-between;
  603. align-items: normal;
  604. margin-top: 20px;
  605. .title {
  606. color: var(--el-text-color-primary);
  607. font-size: 16px;
  608. font-weight: 700;
  609. }
  610. .left-wrap {
  611. width: 66%;
  612. .top-title-wrap {
  613. display: flex;
  614. justify-content: space-between;
  615. align-items: center;
  616. margin-bottom: 16px;
  617. ::v-deep .el-date-editor.el-input__wrapper {
  618. width: 360px!important;
  619. margin-left: 12px;
  620. }
  621. .operate-wrap {
  622. display: flex;
  623. justify-content: center;
  624. align-items: center;
  625. }
  626. }
  627. }
  628. .right-wrap {
  629. width: 36%;
  630. .line-wrap {
  631. width: 100%;
  632. background-color: #fff;
  633. background: #fcfcfc;
  634. border: 1px solid #e0e4e8;
  635. display: flex;
  636. justify-content: space-between;
  637. align-items: center;
  638. padding: 20px;
  639. position: relative;
  640. .text-wrap {
  641. position: absolute;
  642. left: 20px;
  643. top: 40px;
  644. .text {
  645. font-size: 14px;
  646. color: #000000a3;
  647. }
  648. div:nth-child(2) {
  649. font-size: 32px;
  650. font-weight: 700;
  651. overflow: hidden;
  652. white-space: nowrap;
  653. text-overflow: ellipsis;
  654. }
  655. }
  656. .line-inner-wrap {
  657. height: 100px;
  658. width: calc(100% - 120px);
  659. margin-left: 120px;
  660. }
  661. }
  662. .line-wrap:not(:nth-child(1)) {
  663. margin-top: 20px;
  664. }
  665. }
  666. }
  667. </style>