index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818
  1. <template>
  2. <div class="table-box">
  3. <div class="card table-search" style="overflow: hidden;">
  4. <el-form ref="formRef" :model="pageable" :inline="true" label-width="auto">
  5. <el-form-item label="所属基地:" prop="base">
  6. <el-select v-model="pageable.base" placeholder="请选择" style="width: 200px" @change="changeBase">
  7. <el-option v-for="item in baseList" :key="item.value" :label="item.label" :value="item.value" />
  8. </el-select>
  9. </el-form-item>
  10. <el-form-item>
  11. <div>
  12. <el-button type="primary" @click="handleSearch">查询</el-button>
  13. <el-button plain @click="resetQuery">重置</el-button>
  14. </div>
  15. </el-form-item>
  16. </el-form>
  17. </div>
  18. <div class="main_list ">
  19. <el-row :gutter="15">
  20. <el-col :xs="24" :sm="12" :md="8" :lg="8">
  21. <div class="chart_item zhuti">
  22. <div style="font-weight: bold;" class="item_title">
  23. <span>设备工况(单位:台)</span>
  24. </div>
  25. <div class="mt5">
  26. <div ref="device" class="ve-ring" style="height: 200px" v-if="stateList"></div>
  27. <div v-else
  28. style="height: 200px; display: flex; justify-content: center; align-items: center; font-size: 20px;">
  29. 暂无数据</div>
  30. </div>
  31. </div>
  32. </el-col>
  33. <el-col :xs="24" :sm="12" :md="8" :lg="8">
  34. <div class="chart_item zhuti">
  35. <div style="font-weight: bold;" class="item_title">
  36. <span>检定周期(单位:台)</span>
  37. </div>
  38. <div class="mt5">
  39. <div ref="period" class="ve-ring" style="height: 200px"></div>
  40. </div>
  41. </div>
  42. </el-col>
  43. <el-col :xs="24" :sm="12" :md="8" :lg="8">
  44. <div class="chart_item zhuti">
  45. <div style="font-weight: bold;" class="item_title">
  46. <span>FTP链路</span>
  47. </div>
  48. <div class="mt5">
  49. <div class="FTP_box" style="height: 200px">
  50. <div class="FTP_item">
  51. <img src="@/assets/images/centerStation.png" alt="">
  52. <div>正常FTP({{ FTPList && FTPList.true ? FTPList?.true.length : 0 }})</div>
  53. </div>
  54. <div class="FTP_item" @click="gotoFTP">
  55. <img src="@/assets/images/areaStation.png" alt="">
  56. <div>异常FTP({{ FTPList && FTPList.false ? FTPList?.false.length : 0 }})</div>
  57. </div>
  58. </div>
  59. </div>
  60. </div>
  61. </el-col>
  62. </el-row>
  63. <el-row :gutter="15">
  64. <el-col :span="24">
  65. <div class="chart_item zhuti">
  66. <div style="font-weight: bold;" class="item_title">
  67. <span>危险天气</span>
  68. </div>
  69. <el-row :gutter="15">
  70. <el-col :span="8">
  71. <div class="mt5">
  72. <div ref="weather" class="ve-ring" style="height: 300px"></div>
  73. </div>
  74. </el-col>
  75. <el-col :span="16" style="margin-bottom: 0;">
  76. <div>
  77. <div ref="element" class="ve-ring" style="height: 300px"></div>
  78. </div>
  79. </el-col>
  80. </el-row>
  81. </div>
  82. </el-col>
  83. </el-row>
  84. <el-row :gutter="15">
  85. <el-col :span="24">
  86. <div class="chart_item zhuti">
  87. <div style="font-weight: bold;" class="item_title">
  88. <span>到报监控</span>
  89. </div>
  90. <div class="mt5">
  91. <div ref="control" class="ve-ring" style="height: 300px"></div>
  92. </div>
  93. </div>
  94. </el-col>
  95. </el-row>
  96. </div>
  97. </div>
  98. </template>
  99. <script setup lang="ts" name="allDevice">
  100. import * as echarts from 'echarts';
  101. import { getStamp, groupByType, getNextDayMidnight } from "@/utils/dateTime";
  102. import { ElMessage } from "element-plus";
  103. import { useGlobalStore } from "@/stores/modules/global";
  104. import { ref, computed, onMounted, reactive, watch, onDeactivated, onActivated, nextTick } from "vue";
  105. import { getTacRecordList, getFTPList, getCertificateList, getStaitemList, getArriveList } from "@/api/modules/allData";
  106. import { Platform } from "@/api/interface";
  107. import { parseTime } from '@/utils/index';
  108. import { useRouter } from "vue-router";
  109. import { useUserStore } from "@/stores/modules/user";
  110. const router = useRouter();
  111. const gotoFTP = () => {
  112. router.push({
  113. path: '/system/disposition',
  114. query: {
  115. status: 'distributionAutomatic',
  116. }
  117. })
  118. }
  119. // 查询自动站列表
  120. const queryas = ref<Platform>({
  121. pageSize: 5000,
  122. pageNum: 1,
  123. currentpage: 1
  124. })
  125. const pageable = ref({
  126. data_type: true,
  127. time_order: 1,
  128. time_space: 1,
  129. base: undefined,
  130. as_code_list: [],
  131. data_items: [
  132. {
  133. data_r_table: "SHI_SHI_LIU_YAO_SU_SHU_JU",
  134. data_id: 101,
  135. data_type: "温湿度",
  136. data_item: "QI_WEN",
  137. data_name: "气温",
  138. data_unit: "℃",
  139. data_h_table: "LI_SHI_LIU_YAO_SU_SHU_JU",
  140. data_value: "",
  141. data_order: 1,
  142. data_condition: 0
  143. }
  144. ],
  145. });
  146. const userStore = useUserStore();
  147. const platformList = ref<any>(computed(() => userStore.stations))
  148. const baseList = ref<any>([])
  149. const selectPlatform = ref()
  150. const getPlatforms = async () => {
  151. baseList.value = groupByType(platformList.value)
  152. pageable.value.base = baseList.value[0].value
  153. pageable.value.as_code_list = baseList.value[0].children
  154. selectPlatform.value = baseList.value[0]
  155. // getDeviceStatus()
  156. // getArrive()
  157. // getHistoryList()
  158. };
  159. const resetQuery = () => {
  160. pageable.value.base = baseList.value[0].value
  161. pageable.value.as_code_list = baseList.value[0].children
  162. handleSearch()
  163. };
  164. const changeBase = (e) => {
  165. const item = baseList.value.find(item => item.value === e);
  166. pageable.value.as_code_list = item.children
  167. // getCertificate()
  168. // getFTP()
  169. // getDeviceStatus()
  170. // getArrive()
  171. // getHistoryList()
  172. }
  173. watch(() => pageable.value.as_code_list, (newValue, oldValue) => {
  174. if (newValue) {
  175. weatherInfo();
  176. getCertificate();
  177. getFTP();
  178. getDeviceStatus();
  179. getArrive();
  180. // getHistoryList();
  181. }
  182. });
  183. const formRef = ref()
  184. const device = ref()
  185. const period = ref()
  186. const weather = ref()
  187. const element = ref()
  188. const control = ref()
  189. // 获取到报监控
  190. const arriveList = ref<any>({ aa: [], bb: [], cc: [] })
  191. const arriveTime = ref<any>()
  192. const getArrive = async () => {
  193. const { data } = await getArriveList({ ...pageable.value, time_space: 60, data_type: false, end_time: getStamp(parseTime(new Date(), '{y}-{m}-{d} {h}') + ':01'), begin_time: getStamp(parseTime(new Date(), '{y}-{m}-{d}') + ' 01:00') })
  194. // 提取键并排序
  195. const sortedKeys = Object.keys(data).sort((a, b) => {
  196. const [timeA] = a.split(':').map(Number);
  197. const [timeB] = b.split(':').map(Number);
  198. return timeA - timeB;
  199. });
  200. // 根据排序后的键构建新对象
  201. const sortedObj = {};
  202. sortedKeys.forEach(key => {
  203. sortedObj[key] = data[key];
  204. });
  205. arriveTime.value = Object.keys(sortedObj)
  206. const arr = <any>{ aa: [], bb: [], cc: [] }
  207. arriveTime.value?.forEach((item, index) => {
  208. arr.aa.push(pageable.value.as_code_list.length)
  209. arr.bb.push(data[item].length)
  210. arr.cc.push(pageable.value.as_code_list.length - data[item].length)
  211. });
  212. arriveList.value = arr
  213. nextTick(() => {
  214. showControl()
  215. })
  216. };
  217. const wertherColumns = ref<any>({
  218. tact_state_on: true,
  219. tact_data_on: false,
  220. tact_state: 0,
  221. // tact_state: 0,
  222. // tact_data: 0,
  223. pageNum: 1,
  224. pageSize: 999,
  225. });
  226. const weatherInfoArr = ref()
  227. const dangetWeatherNum = ref(0)
  228. const weatherNormal = ref()
  229. const weatherWarning = ref()
  230. const weatherInfo = async () => {
  231. const { data } = await getTacRecordList({ ...wertherColumns.value, as_code_list: pageable.value.as_code_list });
  232. dangetWeatherNum.value = [...new Set(data.list?.map(obj => obj.as_code))].length
  233. weatherInfoArr.value = data.list
  234. let arr2 = new Array(8).fill(0);
  235. let arr1 = new Array(8).fill(pageable.value.as_code_list.length);
  236. data.list?.forEach((item, index) => {
  237. arr1[item.data_type]--
  238. arr2[item.data_type]++
  239. })
  240. weatherNormal.value = arr1
  241. weatherWarning.value = arr2
  242. nextTick(() => {
  243. showWeather()
  244. showElement()
  245. })
  246. };
  247. // 获取自动站定检证书
  248. // 返回两个数组中相同的个数
  249. function findCommonCount(arr1, arr2) {
  250. const common = arr1.filter(item => arr2.includes(item));
  251. return common.length;
  252. }
  253. const certificateList = ref<any>({})
  254. const getCertificate = async () => {
  255. const { data } = await getCertificateList()
  256. // certificateList.value.a = data[0]?.length || 0
  257. certificateList.value.a = findCommonCount(pageable.value.as_code_list, data[0]?.length ? data[0] : [])
  258. certificateList.value.b = findCommonCount(pageable.value.as_code_list, data[1]?.length ? data[1] : [])
  259. certificateList.value.c = findCommonCount(pageable.value.as_code_list, data[2]?.length ? data[2] : [])
  260. nextTick(() => {
  261. showPeriod()
  262. })
  263. // certificateList.value=data.list
  264. };
  265. // 获取FTP链路
  266. const FTPList = ref<any>({})
  267. const getFTP = async () => {
  268. const { data } = await getFTPList()
  269. FTPList.value = data
  270. };
  271. // 获取设备工况 stateList(用于存储设备状态)、getDeviceStatus(存储设备状态)
  272. const stateList = ref<any>()
  273. const getDeviceStatus = async () => {
  274. const { data } = await getStaitemList(pageable.value);
  275. const state = { normal: [], warning: [], error: [] }
  276. data?.list?.forEach(item => {
  277. const staList = item.sta_list;
  278. staList.forEach(sta => {
  279. if (sta.state === 0) {
  280. if (!state.normal.includes(item.as_code)) {
  281. state.normal.push(item.as_code);
  282. }
  283. // state.normal++;
  284. } else if (sta.state === 2) { // 注意:你的要求中提到了state为2的个数,但原始数据中并没有state为2的例子,这里我假设你需要统计它
  285. if (!state.warning.includes(item.as_code)) {
  286. state.warning.push(item.as_code);
  287. }
  288. // state.warning++;
  289. } else if (sta.state === 3) {
  290. if (!state.error.includes(item.as_code)) {
  291. state.error.push(item.as_code);
  292. }
  293. // state.error++;
  294. }
  295. });
  296. });
  297. state.normal=state.normal?.filter(item => !state.error?.includes(item)); //过滤正常状态设备,删除掉异常状态的设备代码
  298. stateList.value = state
  299. nextTick(() => {
  300. showDevice()
  301. })
  302. };
  303. const handleSearch = () => {
  304. getArrive()
  305. weatherInfo()
  306. getCertificate()
  307. getFTP()
  308. getDeviceStatus()
  309. }
  310. const globalStore = useGlobalStore();
  311. const isDark = computed(() => globalStore.isDark);
  312. const showDevice = () => {
  313. let mychart = echarts.init(device.value);
  314. let option = {
  315. tooltip: {
  316. trigger: 'item',
  317. formatter:function(params) {
  318. return `<div>${params.name}:${params.value}台</div>`;
  319. }
  320. },
  321. legend: {
  322. bottom: '0%',
  323. left: 'center',
  324. textStyle: {//图例文字的样式
  325. color: isDark.value ? '#fff' : "#000",
  326. }
  327. },
  328. series: [
  329. {
  330. name: '设备工况',
  331. type: 'pie',
  332. radius: ['50%', '68%'],
  333. center: ['50%', '45%'],
  334. hoverAnimation: false,
  335. itemStyle: {
  336. borderRadius: 3,
  337. borderColor: '#fff',
  338. borderWidth: 1
  339. },
  340. label: {
  341. normal: {
  342. show: true,
  343. position: 'outer',
  344. formatter: '{b}:{c}',
  345. overflow: 'none',
  346. fontSize: 15,
  347. },
  348. },
  349. emphasis: {
  350. label: {
  351. show: true,
  352. fontSize: 20,
  353. fontWeight: 'bold'
  354. }
  355. },
  356. //设置提示线
  357. labelLine: {
  358. normal: {
  359. show: true,//开启提示线展示
  360. length: 10,//设置第一条提示线长度
  361. length2: 30,//设置第二条提示线长度
  362. }
  363. },
  364. data: [
  365. {
  366. value: stateList.value ? stateList.value.normal.length : 0,
  367. name: '正常',
  368. list: stateList.value ? stateList.value.normal : [],
  369. itemStyle: { color: '#00C4B3' },
  370. label: { color: '#00C4B3' }
  371. },
  372. {
  373. value: stateList.value ? stateList.value.warning.length : 0,
  374. name: '告警',
  375. list: stateList.value ? stateList.value.warning : [],
  376. itemStyle: { color: '#EF6666' },
  377. label: { color: '#EF6666' }
  378. },
  379. {
  380. value: stateList.value ? stateList.value.error.length : 0,
  381. name: '故障',
  382. list: stateList.value ? stateList.value.error : [],
  383. itemStyle: { color: '#FAC858' },
  384. label: { color: '#FAC858' }
  385. }
  386. ]
  387. }
  388. ]
  389. };
  390. mychart.setOption(option)
  391. window.addEventListener("resize", function () {
  392. mychart.resize();
  393. });
  394. }
  395. const showPeriod = () => {
  396. let mychart = echarts.init(period.value);
  397. let option = {
  398. tooltip: {
  399. trigger: 'item',
  400. formatter: "{a} <br/>{b}: {c}台"
  401. },
  402. legend: {
  403. bottom: 0,
  404. left: 'center',
  405. textStyle: {//图例文字的样式
  406. color: isDark.value ? '#fff' : "#000",
  407. }
  408. },
  409. series: [
  410. {
  411. name: '检定周期',
  412. type: 'pie',
  413. radius: '65%',
  414. center: ['50%', '45%'],
  415. label: {
  416. normal: {
  417. show: true,
  418. position: 'outer',
  419. formatter: '{b}:{c}',
  420. fontSize: 14,
  421. },
  422. },
  423. data: [
  424. { value: certificateList.value.c ? certificateList.value.c : 0, name: '剩余31-60天', itemStyle: { color: '#5470C6' } },
  425. { value: certificateList.value.b ? certificateList.value.b : 0, name: '剩余1-30天', itemStyle: { color: '#FAC858' } },
  426. { value: certificateList.value.a ? certificateList.value.a : 0, name: '已过检', itemStyle: { color: '#EF6666' } }
  427. ],
  428. emphasis: {
  429. itemStyle: {
  430. shadowBlur: 10,
  431. shadowOffsetX: 0,
  432. shadowColor: 'rgba(0, 0, 0, 0.5)'
  433. }
  434. }
  435. }
  436. ]
  437. };
  438. mychart.setOption(option)
  439. window.addEventListener("resize", function () {
  440. mychart.resize();
  441. });
  442. }
  443. const allSataion = ref(5)
  444. const showWeather = () => {
  445. let mychart = echarts.init(weather.value);
  446. let option = {
  447. title: {
  448. text: `${pageable.value.as_code_list.length} \n 总站数 `,
  449. left: "center",
  450. top: "38%",
  451. textStyle: {
  452. fontSize: 20,
  453. color: '#000',
  454. },
  455. },
  456. tooltip: {
  457. trigger: 'item',
  458. formatter: "{a} <br/>{b}: {c}"
  459. },
  460. legend: {
  461. bottom: '1%',
  462. left: 'center',
  463. textStyle: {//图例文字的样式
  464. color: isDark.value ? '#fff' : "#000",
  465. }
  466. },
  467. series: [
  468. {
  469. name: '天气状况',
  470. type: 'pie',
  471. radius: ['50%', '70%'],
  472. center: ['50%', '45%'],
  473. hoverAnimation: false,
  474. itemStyle: {
  475. borderRadius: 3,
  476. borderColor: '#fff',
  477. borderWidth: 1
  478. },
  479. label: {
  480. normal: {
  481. show: true,
  482. position: 'outer',
  483. formatter: '{b}:{c}',
  484. overflow: 'none',
  485. fontSize: 15,
  486. },
  487. },
  488. emphasis: {
  489. label: {
  490. show: true,
  491. fontSize: 20,
  492. fontWeight: 'bold'
  493. }
  494. },
  495. //设置提示线
  496. labelLine: {
  497. normal: {
  498. show: true,//开启提示线展示
  499. length: 15,//设置第一条提示线长度
  500. length2: 30,//设置第二条提示线长度
  501. }
  502. },
  503. data: [
  504. {
  505. value: pageable.value.as_code_list.length - dangetWeatherNum.value,
  506. name: '正常',
  507. itemStyle: { color: '#5470C6' },
  508. label: { color: '#5470C6' }
  509. },
  510. {
  511. value: dangetWeatherNum.value,
  512. name: '告警',
  513. itemStyle: { color: '#EF6666' },
  514. label: { color: '#EF6666' }
  515. }
  516. ]
  517. }
  518. ]
  519. };
  520. mychart.setOption(option)
  521. window.addEventListener("resize", function () {
  522. mychart.resize();
  523. });
  524. }
  525. const showElement = () => {
  526. let mychart = echarts.init(element.value);
  527. let option = {
  528. tooltip: {
  529. trigger: 'axis',
  530. axisPointer: {
  531. type: 'shadow'
  532. }
  533. },
  534. grid: {
  535. top: '3%',
  536. left: '3%',
  537. right: '4%',
  538. bottom: '0%',
  539. containLabel: true
  540. },
  541. xAxis: [
  542. {
  543. type: 'category',
  544. data: [
  545. '能见度',
  546. '风速',
  547. '大气电场',
  548. '云量',
  549. '云高',
  550. '温度',
  551. '湿度',
  552. '小时雨量'
  553. ]
  554. }
  555. ],
  556. yAxis: [
  557. {
  558. type: 'value'
  559. }
  560. ],
  561. series: [
  562. {
  563. name: '正常',
  564. barWidth: '50%',
  565. type: 'bar',
  566. stack: 'Ad',
  567. emphasis: {
  568. focus: 'series'
  569. },
  570. itemStyle: {
  571. color: '#5470C6'
  572. },
  573. data: weatherNormal.value
  574. },
  575. {
  576. name: '告警',
  577. barWidth: '50%',
  578. type: 'bar',
  579. stack: 'Ad',
  580. emphasis: {
  581. focus: 'series'
  582. },
  583. itemStyle: {
  584. color: '#EF6666'
  585. },
  586. data: weatherWarning.value
  587. }
  588. ]
  589. };
  590. mychart.setOption(option)
  591. window.addEventListener("resize", function () {
  592. mychart.resize();
  593. });
  594. }
  595. const showControl = () => {
  596. let mychart = echarts.init(control.value);
  597. let option = {
  598. tooltip: {
  599. trigger: 'axis',
  600. axisPointer: {
  601. type: 'shadow'
  602. }
  603. },
  604. legend: {
  605. textStyle: {//图例文字的样式
  606. color: isDark.value ? '#fff' : "#000",
  607. }
  608. },
  609. grid: {
  610. left: '15',
  611. right: '15',
  612. bottom: '3%',
  613. containLabel: true
  614. },
  615. xAxis: [
  616. {
  617. type: 'category',
  618. data: arriveTime.value
  619. }
  620. ],
  621. yAxis: [
  622. {
  623. type: 'value'
  624. }
  625. ],
  626. series: [
  627. {
  628. name: '应报情况',
  629. type: 'bar',
  630. stack: 'Ad',
  631. emphasis: {
  632. focus: 'series'
  633. },
  634. itemStyle: {
  635. color: '#3BA272' // 蓝色
  636. },
  637. data: arriveList.value.aa.length ? arriveList.value.aa : [],
  638. },
  639. {
  640. name: '实报情况',
  641. type: 'bar',
  642. stack: 'Ad',
  643. emphasis: {
  644. focus: 'series'
  645. },
  646. itemStyle: {
  647. color: '#5470C6' // 绿色
  648. },
  649. data: arriveList.value.bb.length ? arriveList.value.bb : [],
  650. },
  651. {
  652. name: '未报情况',
  653. type: 'bar',
  654. stack: 'Ad',
  655. emphasis: {
  656. focus: 'series'
  657. },
  658. itemStyle: {
  659. color: '#EF6666' // 红色
  660. },
  661. data: arriveList.value.cc.length ? arriveList.value.cc : [],
  662. },
  663. ]
  664. };
  665. mychart.setOption(option)
  666. window.addEventListener("resize", function () {
  667. mychart.resize();
  668. });
  669. }
  670. watch(isDark, () => { showDevice(), showPeriod(), showWeather(), showElement(), showControl() });
  671. onMounted(() => {
  672. // getFTP()
  673. // getCertificate()
  674. getPlatforms()
  675. // showDevice()
  676. // showPeriod()
  677. // showWeather()
  678. // showElement()
  679. // showControl()
  680. })
  681. let intervalId;
  682. onActivated(() => {
  683. intervalId = setInterval(() => {
  684. // getList();
  685. weatherInfo()
  686. getCertificate();
  687. getFTP();
  688. getDeviceStatus();
  689. getArrive();
  690. }, 60 * 1000);
  691. });
  692. onDeactivated(() => {
  693. clearInterval(intervalId);
  694. });
  695. </script>
  696. <style scoped lang="scss">
  697. .el-row .el-col {
  698. margin-bottom: 15px;
  699. }
  700. .main_list {
  701. background: transparent !important;
  702. box-shadow: none !important;
  703. padding: 0 !important;
  704. height: calc(100vh - 150px);
  705. margin-bottom: 10px;
  706. overflow-y: scroll;
  707. overflow-x: hidden;
  708. .chart_item {
  709. border-radius: 10px;
  710. padding: 10px;
  711. background-color: #fff;
  712. // height: 100%;
  713. // margin-bottom: 15px;
  714. .item_title {
  715. display: flex;
  716. justify-content: space-between;
  717. align-items: center;
  718. }
  719. .FTP_box {
  720. padding: 0 50px;
  721. display: flex;
  722. align-items: center;
  723. justify-content: space-between;
  724. .FTP_item {
  725. flex: 1;
  726. flex-shrink: 0;
  727. display: flex;
  728. flex-direction: column;
  729. justify-content: center;
  730. align-items: center;
  731. img {
  732. width: 56px;
  733. margin-bottom: 20px;
  734. }
  735. }
  736. }
  737. }
  738. .info_box {
  739. .info_title {
  740. color: #999999;
  741. font-size: 16px;
  742. }
  743. .info_content {
  744. height: 40px;
  745. font-weight: bold;
  746. color: #000;
  747. font-size: 26px;
  748. }
  749. }
  750. }
  751. </style>