renewableResourcesDashboard.vue 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187
  1. <template>
  2. <vue-fullscreen
  3. class="rr-container"
  4. v-cloak
  5. v-model="isFullscreen"
  6. fullscreenClass="rr-container"
  7. :exit-on-click-wrapper="false"
  8. >
  9. <div class="rr-container" v-cloak>
  10. <div class="rr-header">
  11. <div class="rr-header-side rr-header-left">
  12. <!-- <div class="rr-header-chip">黑屏看板</div> -->
  13. <el-date-picker
  14. v-model="dateRange"
  15. class="rr-date-picker"
  16. size="mini"
  17. type="daterange"
  18. range-separator="-"
  19. start-placeholder="开始日期"
  20. end-placeholder="结束日期"
  21. value-format="yyyy-MM-dd"
  22. />
  23. </div>
  24. <div class="rr-title">越隆达再生资源集团公司</div>
  25. <div class="rr-header-side rr-header-right">
  26. <div class="rr-time-box">
  27. <span class="rr-date">{{ date }}</span>
  28. <span class="rr-week">{{ week }}</span>
  29. <span class="rr-time">{{ time }}</span>
  30. </div>
  31. <span class="rr-weather">晴 27-19°C</span>
  32. <span class="rr-fullscreen" @click="onFullscreen">
  33. <i
  34. v-if="isFullscreen"
  35. class="el-icon-_screen-restore"
  36. title="退出全屏"
  37. ></i>
  38. <i v-else class="el-icon-_screen-full" title="全屏"></i>
  39. </span>
  40. </div>
  41. </div>
  42. <div class="rr-body">
  43. <div class="rr-side-column">
  44. <section class="rr-panel rr-panel-sales">
  45. <div class="rr-panel-title">营销总览</div>
  46. <div class="rr-summary-strip">
  47. <div
  48. v-for="item in salesCards"
  49. :key="item.key"
  50. class="rr-summary-item"
  51. >
  52. <div class="rr-summary-icon-box">
  53. <div class="rr-summary-icon-wrap">
  54. <div class="rr-summary-icon-ring"></div>
  55. <div class="rr-summary-icon">
  56. <img
  57. class="rr-summary-icon-img"
  58. :src="item.iconSrc"
  59. :alt="item.label"
  60. />
  61. </div>
  62. </div>
  63. </div>
  64. <div class="rr-summary-content">
  65. <div class="rr-summary-label">{{ item.label }}</div>
  66. <div class="rr-summary-main">
  67. <span class="rr-summary-value">{{ item.value }}</span>
  68. <span class="rr-summary-unit">{{ item.unit }}</span>
  69. <div class="rr-summary-trend" :class="item.trendType">
  70. <span class="rr-summary-trend-label">{{
  71. item.trendLabel
  72. }}</span>
  73. <span class="rr-summary-trend-value"
  74. >{{ item.trendType === 'up' ? '↗' : '↘'
  75. }}{{ item.trend }}%</span
  76. >
  77. </div>
  78. </div>
  79. </div>
  80. <div
  81. v-if="item.key !== salesCards[salesCards.length - 1].key"
  82. class="rr-summary-divider"
  83. ></div>
  84. </div>
  85. </div>
  86. </section>
  87. <section class="rr-panel rr-panel-procurement">
  88. <div class="rr-panel-title">采购总览</div>
  89. <div class="rr-procurement-body">
  90. <div class="rr-procurement-pane rr-procurement-pane-area">
  91. <div class="rr-pane-caption">
  92. <span>单位:件</span>
  93. <div class="rr-pane-legend">
  94. <span class="rr-legend-item rr-legend-item-blue"
  95. >采购量</span
  96. >
  97. <span class="rr-legend-item rr-legend-item-gold"
  98. >到货量</span
  99. >
  100. </div>
  101. </div>
  102. <div class="rr-chart-panel rr-chart-panel-compact">
  103. <area-line-chart
  104. v-if="isChartReady"
  105. :categories="monthCategories"
  106. :series="procurementSeries"
  107. :colors="['#3c87ff', '#e5b15d']"
  108. :show-legend="false"
  109. class="rr-fill-chart"
  110. />
  111. </div>
  112. </div>
  113. <div class="rr-procurement-pane rr-procurement-pane-bar">
  114. <div class="rr-pane-caption rr-pane-caption-right">
  115. <span>准时交付率</span>
  116. </div>
  117. <div class="rr-mini-bar-panel rr-mini-bar-panel-fill">
  118. <div ref="procurementBarRef" class="rr-native-chart"></div>
  119. </div>
  120. </div>
  121. </div>
  122. </section>
  123. <section class="rr-panel rr-panel-inventory">
  124. <div class="rr-panel-title">仓储总览</div>
  125. <div class="rr-inventory-body">
  126. <div class="rr-inv-left">
  127. <div class="rr-inv-chart-wrap">
  128. <div ref="inventoryDonutRef" class="rr-native-chart"></div>
  129. <div class="rr-inv-center">
  130. <span class="rr-inv-center-value">{{
  131. inventoryOverview.total
  132. }}</span>
  133. <span class="rr-inv-center-label">库存总量</span>
  134. </div>
  135. </div>
  136. </div>
  137. <div class="rr-inv-right">
  138. <div class="rr-inv-trend-caption">周转率</div>
  139. <div class="rr-inv-trend-chart">
  140. <div ref="inventoryTrendRef" class="rr-native-chart"></div>
  141. </div>
  142. </div>
  143. </div>
  144. </section>
  145. </div>
  146. <section class="rr-map-panel">
  147. <div class="rr-map-head">
  148. <div class="rr-map-tabs">
  149. <span
  150. class="rr-tab"
  151. :class="{ active: mapTab === 'nation' }"
  152. @click="mapTab = 'nation'"
  153. >
  154. 全国
  155. </span>
  156. <span
  157. class="rr-tab"
  158. :class="{ active: mapTab === 'factory' }"
  159. @click="mapTab = 'factory'"
  160. >
  161. 工厂分布
  162. </span>
  163. </div>
  164. <div class="rr-map-summary">
  165. <div
  166. v-for="item in mapHeaderStats"
  167. :key="item.label"
  168. class="rr-map-summary-item"
  169. >
  170. <span>{{ item.label }}</span>
  171. <strong>{{ item.value }}</strong>
  172. </div>
  173. </div>
  174. </div>
  175. <div class="rr-map-body">
  176. <china-map-chart
  177. v-if="isChartReady"
  178. :scatter-data="currentMapScatterData"
  179. :legend-categories="currentMapLegendCategories"
  180. class="rr-map-chart"
  181. />
  182. </div>
  183. </section>
  184. <div class="rr-side-column">
  185. <section class="rr-panel rr-panel-quality">
  186. <div class="rr-panel-title">质量总览</div>
  187. <div class="rr-quality-grid">
  188. <div
  189. v-for="item in qualityCards"
  190. :key="item.title"
  191. class="rr-quality-card"
  192. >
  193. <div class="rr-quality-header">
  194. <span class="rr-quality-dot"></span>
  195. <span>{{ item.title }}</span>
  196. </div>
  197. <div class="rr-quality-rate">{{ item.passRate }}%</div>
  198. <div class="rr-quality-bars">
  199. <div class="rr-progress-row">
  200. <span>合格率</span>
  201. <strong>{{ item.passRate }}%</strong>
  202. </div>
  203. <div class="rr-progress-track">
  204. <span
  205. class="rr-progress-fill rr-progress-fill-good"
  206. :style="{ width: item.passRate + '%' }"
  207. ></span>
  208. </div>
  209. <div class="rr-progress-row">
  210. <span>不合格率</span>
  211. <strong>{{ item.failRate }}%</strong>
  212. </div>
  213. <div class="rr-progress-track">
  214. <span
  215. class="rr-progress-fill rr-progress-fill-bad"
  216. :style="{ width: item.failRate + '%' }"
  217. ></span>
  218. </div>
  219. </div>
  220. </div>
  221. </div>
  222. </section>
  223. <section class="rr-panel rr-panel-production">
  224. <div class="rr-panel-title">生产总览</div>
  225. <div class="rr-procurement-body">
  226. <div class="rr-procurement-pane rr-procurement-pane-area">
  227. <div class="rr-pane-caption">
  228. <span>单位:件</span>
  229. <div class="rr-pane-legend">
  230. <span class="rr-legend-item rr-legend-item-blue"
  231. >采购量</span
  232. >
  233. <span class="rr-legend-item rr-legend-item-gold"
  234. >到货量</span
  235. >
  236. </div>
  237. </div>
  238. <div class="rr-chart-panel rr-chart-panel-compact">
  239. <area-line-chart
  240. v-if="isChartReady"
  241. :categories="monthCategories"
  242. :series="procurementSeries"
  243. :colors="['#3c87ff', '#e5b15d']"
  244. :show-legend="false"
  245. class="rr-fill-chart"
  246. />
  247. </div>
  248. </div>
  249. <div class="rr-procurement-pane rr-procurement-pane-bar">
  250. <div class="rr-pane-caption rr-pane-caption-right">
  251. <span>准时交付率</span>
  252. </div>
  253. <div class="rr-mini-bar-panel rr-mini-bar-panel-fill">
  254. <div ref="productionBarRef" class="rr-native-chart"></div>
  255. </div>
  256. </div>
  257. </div>
  258. </section>
  259. <section class="rr-panel rr-panel-equipment">
  260. <div class="rr-panel-title">设备总览</div>
  261. <div class="rr-equipment-body">
  262. <div class="rr-equipment-gauge">
  263. <div class="rr-gauge-wrap">
  264. <div ref="utilDonutRef" class="rr-native-chart"></div>
  265. </div>
  266. <ul class="rr-equipment-list">
  267. <li v-for="item in leftEquipmentList" :key="item.label">
  268. <span>{{ item.label }}</span>
  269. <strong>{{ item.value }}</strong>
  270. </li>
  271. </ul>
  272. </div>
  273. <div class="rr-equipment-gauge">
  274. <div class="rr-gauge-wrap">
  275. <div ref="faultDonutRef" class="rr-native-chart"></div>
  276. </div>
  277. <ul class="rr-equipment-list">
  278. <li v-for="item in rightEquipmentList" :key="item.label">
  279. <span>{{ item.label }}</span>
  280. <strong>{{ item.value }}</strong>
  281. </li>
  282. </ul>
  283. </div>
  284. </div>
  285. </section>
  286. </div>
  287. </div>
  288. </div>
  289. </vue-fullscreen>
  290. </template>
  291. <script>
  292. import { component as VueFullscreen } from 'vue-fullscreen';
  293. import * as echarts from 'echarts';
  294. import AreaLineChart from './components/charts/AreaLineChart';
  295. import ChinaMapChart from './components/charts/ChinaMapChart';
  296. export default {
  297. name: 'RenewableResourcesDashboard',
  298. components: {
  299. VueFullscreen,
  300. AreaLineChart,
  301. ChinaMapChart
  302. },
  303. data() {
  304. return {
  305. isFullscreen: false,
  306. isChartReady: false,
  307. resizeTimer: null,
  308. clockTimer: null,
  309. date: '',
  310. time: '',
  311. week: '',
  312. dateRange: [],
  313. mapTab: 'nation',
  314. monthCategories: [
  315. '1月',
  316. '2月',
  317. '3月',
  318. '4月',
  319. '5月',
  320. '6月',
  321. '7月',
  322. '8月',
  323. '9月',
  324. '10月',
  325. '11月',
  326. '12月'
  327. ],
  328. salesCards: [
  329. {
  330. key: 'order',
  331. iconSrc: require('@/assets/renewable_icon_2.svg'),
  332. label: '订单量',
  333. value: '1024',
  334. unit: '万',
  335. trend: 25,
  336. trendType: 'up',
  337. trendLabel: '同比上升'
  338. },
  339. {
  340. key: 'ship',
  341. iconSrc: require('@/assets/renewable_icon_3.svg'),
  342. label: '出货量',
  343. value: '2048',
  344. unit: '万',
  345. trend: 25,
  346. trendType: 'warn',
  347. trendLabel: '同比上升'
  348. },
  349. {
  350. key: 'delivery',
  351. iconSrc: require('@/assets/renewable_icon_4.svg'),
  352. label: '准时交货率',
  353. value: '89',
  354. unit: '%',
  355. trend: 25,
  356. trendType: 'up',
  357. trendLabel: '同比下降'
  358. }
  359. ],
  360. qualityCards: [
  361. { title: '成品质检', passRate: 98, failRate: 2 },
  362. { title: '原料质检', passRate: 91, failRate: 9 }
  363. ],
  364. inventoryOverview: {
  365. total: 6247
  366. },
  367. inventoryStats: [
  368. { label: '成品数', value: 2533 },
  369. { label: '半成品数', value: 1050 },
  370. { label: '原材料数', value: 2523 },
  371. { label: '备品备件数', value: 58 },
  372. { label: '呆滞品数', value: 83 }
  373. ],
  374. // mapHeaderStats: [
  375. // { label: '覆盖省份', value: 24 },
  376. // { label: '合作基地', value: 16 },
  377. // { label: '实时车辆', value: 37 }
  378. // ],
  379. nationMapScatterData: [
  380. { name: '新疆', value: [87.6168, 43.8256], category: 0 },
  381. { name: '甘肃', value: [103.8236, 36.0581], category: 1 },
  382. { name: '河南', value: [113.6254, 34.7466], category: 2 },
  383. { name: '山东', value: [117.0208, 36.6683], category: 3 },
  384. { name: '江苏', value: [118.7969, 32.0603], category: 0 },
  385. { name: '浙江', value: [120.1536, 30.2875], category: 1 },
  386. { name: '福建', value: [119.2965, 26.1006], category: 2 },
  387. { name: '广东', value: [113.2644, 23.1291], category: 3 }
  388. ],
  389. factoryMapScatterData: [
  390. { name: '乌鲁木齐工厂', value: [87.6168, 43.8256], category: 0 },
  391. { name: '兰州工厂', value: [103.8236, 36.0581], category: 1 },
  392. { name: '郑州工厂', value: [113.6254, 34.7466], category: 2 },
  393. { name: '青岛工厂', value: [120.3826, 36.0671], category: 3 },
  394. { name: '南京工厂', value: [118.7969, 32.0603], category: 0 },
  395. { name: '广州工厂', value: [113.2644, 23.1291], category: 2 }
  396. ],
  397. nationMapLegendCategories: [
  398. { name: '危废回收', count: 15 },
  399. { name: '金属分拣', count: 12 },
  400. { name: '塑料再生', count: 10 },
  401. { name: '纸类回收', count: 13 }
  402. ],
  403. factoryMapLegendCategories: [
  404. { name: '总装厂', count: 3 },
  405. { name: '分拣厂', count: 5 },
  406. { name: '再生厂', count: 4 },
  407. { name: '仓储站', count: 4 }
  408. ],
  409. procurementSeries: [
  410. {
  411. name: '采购量',
  412. data: [
  413. 2100, 3200, 2800, 4200, 4673, 2600, 1800, 2200, 1500, 2800, 4800,
  414. 1900
  415. ]
  416. },
  417. {
  418. name: '到货量',
  419. data: [
  420. 1400, 2100, 1800, 2600, 2895, 1700, 1300, 1600, 1100, 1700, 2500,
  421. 1200
  422. ]
  423. }
  424. ],
  425. productionSeries: [
  426. {
  427. name: '生产量',
  428. data: [240, 286, 332, 365, 398, 430, 412, 448, 470, 502, 534, 561]
  429. },
  430. {
  431. name: '达成量',
  432. data: [205, 240, 285, 318, 345, 380, 366, 398, 420, 446, 478, 505]
  433. }
  434. ],
  435. equipmentOverview: {
  436. utilRate: 92,
  437. faultRate: 23,
  438. online: 1247,
  439. waiting: 523,
  440. maintenance: 80,
  441. scrapped: 23,
  442. deviceCount: 533,
  443. productCount: 1247,
  444. spareCount: 523,
  445. toolCount: 80
  446. },
  447. chartInstances: {
  448. procurementBar: null,
  449. productionBar: null,
  450. inventoryDonut: null,
  451. inventoryTrend: null,
  452. utilDonut: null,
  453. faultDonut: null
  454. }
  455. };
  456. },
  457. computed: {
  458. currentMapScatterData() {
  459. return this.mapTab === 'factory'
  460. ? this.factoryMapScatterData
  461. : this.nationMapScatterData;
  462. },
  463. currentMapLegendCategories() {
  464. return this.mapTab === 'factory'
  465. ? this.factoryMapLegendCategories
  466. : this.nationMapLegendCategories;
  467. },
  468. leftEquipmentList() {
  469. return [
  470. { label: '在线设备', value: this.equipmentOverview.online },
  471. { label: '待机设备', value: this.equipmentOverview.waiting },
  472. { label: '维修设备', value: this.equipmentOverview.maintenance }
  473. ];
  474. },
  475. rightEquipmentList() {
  476. return [
  477. { label: '生产设备', value: this.equipmentOverview.deviceCount },
  478. { label: '产品设备', value: this.equipmentOverview.productCount },
  479. { label: '备件库存', value: this.equipmentOverview.spareCount }
  480. ];
  481. }
  482. },
  483. created() {
  484. this.updateTime();
  485. this.clockTimer = setInterval(this.updateTime, 1000);
  486. const now = new Date();
  487. const start = new Date(now.getTime() - 1000 * 60 * 60 * 24 * 30);
  488. this.dateRange = [this.formatDate(start), this.formatDate(now)];
  489. },
  490. mounted() {
  491. this.applyScreenSize();
  492. window.addEventListener('resize', this.handleResize);
  493. document.addEventListener(
  494. 'fullscreenchange',
  495. this.handleFullscreenChange
  496. );
  497. document.addEventListener(
  498. 'webkitfullscreenchange',
  499. this.handleFullscreenChange
  500. );
  501. this.$nextTick(() => {
  502. this.isChartReady = true;
  503. this.$nextTick(() => {
  504. this.initNativeCharts();
  505. });
  506. });
  507. },
  508. beforeDestroy() {
  509. clearInterval(this.clockTimer);
  510. clearTimeout(this.resizeTimer);
  511. window.removeEventListener('resize', this.handleResize);
  512. document.removeEventListener(
  513. 'fullscreenchange',
  514. this.handleFullscreenChange
  515. );
  516. document.removeEventListener(
  517. 'webkitfullscreenchange',
  518. this.handleFullscreenChange
  519. );
  520. Object.values(this.chartInstances).forEach((chart) => chart?.dispose());
  521. },
  522. methods: {
  523. formatDate(date) {
  524. const pad = (n) => String(n).padStart(2, '0');
  525. return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(
  526. date.getDate()
  527. )}`;
  528. },
  529. onFullscreen() {
  530. this.isFullscreen = !this.isFullscreen;
  531. },
  532. updateTime() {
  533. const now = new Date();
  534. const pad = (n) => String(n).padStart(2, '0');
  535. this.time = `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(
  536. now.getSeconds()
  537. )}`;
  538. this.date = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(
  539. now.getDate()
  540. )}`;
  541. const weeks = [
  542. '星期日',
  543. '星期一',
  544. '星期二',
  545. '星期三',
  546. '星期四',
  547. '星期五',
  548. '星期六'
  549. ];
  550. this.week = weeks[now.getDay()];
  551. },
  552. handleResize() {
  553. clearTimeout(this.resizeTimer);
  554. this.resizeTimer = setTimeout(() => {
  555. this.applyScreenSize();
  556. Object.values(this.chartInstances).forEach((chart) =>
  557. chart?.resize()
  558. );
  559. window.dispatchEvent(new Event('resize'));
  560. }, 120);
  561. },
  562. handleFullscreenChange() {
  563. this.$nextTick(() => {
  564. setTimeout(() => {
  565. this.applyScreenSize();
  566. Object.values(this.chartInstances).forEach((chart) =>
  567. chart?.resize()
  568. );
  569. window.dispatchEvent(new Event('resize'));
  570. }, 160);
  571. });
  572. },
  573. applyScreenSize() {
  574. const isFs = !!(
  575. document.fullscreenElement || document.webkitFullscreenElement
  576. );
  577. const deviceWidth = isFs
  578. ? window.innerWidth || document.documentElement.clientWidth
  579. : document.documentElement.clientWidth;
  580. const deviceHeight = isFs
  581. ? window.innerHeight || document.documentElement.clientHeight
  582. : document.documentElement.clientHeight;
  583. const headerH =
  584. (!isFs &&
  585. document.querySelector('.ele-admin-header')?.offsetHeight) ||
  586. 0;
  587. const tabsH =
  588. (!isFs && document.querySelector('.ele-admin-tabs')?.offsetHeight) ||
  589. 0;
  590. const sidebarW =
  591. (!isFs &&
  592. document.querySelector('.ele-admin-sidebar')?.offsetWidth) ||
  593. 0;
  594. const h = isFs ? deviceHeight : deviceHeight - headerH - tabsH;
  595. const w = isFs ? deviceWidth : deviceWidth - sidebarW;
  596. document.querySelectorAll('.rr-container').forEach((el) => {
  597. el.style.height = `${h}px`;
  598. el.style.width = `${w}px`;
  599. });
  600. const designWidth = 1920;
  601. const designHeight = 1080;
  602. const scale = Math.min(w / designWidth, h / designHeight);
  603. const baseFontSize = isFs ? 16 * scale : 16;
  604. document.documentElement.style.fontSize = `${baseFontSize}px`;
  605. },
  606. initNativeCharts() {
  607. this.initBarChart(
  608. 'procurementBar',
  609. this.$refs.procurementBarRef,
  610. [68, 58, 62, 78, 55, 81, 90, 88, 75, 55, 82, 88],
  611. '#1089BB'
  612. );
  613. this.initBarChart(
  614. 'productionBar',
  615. this.$refs.productionBarRef,
  616. [18, 22, 26, 29, 35, 37, 36, 40, 42, 45, 49, 51],
  617. '#22d4b8'
  618. );
  619. this.initInventoryDonutChart();
  620. this.initInventoryTrendChart();
  621. this.initGaugeChart(
  622. 'utilDonut',
  623. this.$refs.utilDonutRef,
  624. 92,
  625. '#27dfd3'
  626. );
  627. this.initGaugeChart(
  628. 'faultDonut',
  629. this.$refs.faultDonutRef,
  630. 23,
  631. '#ff834d'
  632. );
  633. },
  634. initBarChart(key, el, data, color) {
  635. if (!el) return;
  636. this.chartInstances[key]?.dispose();
  637. const chart = echarts.init(el);
  638. if (key === 'procurementBar' || key === 'productionBar') {
  639. const topColor = '#0DF1FF';
  640. const barW = 22;
  641. const diamondW = barW;
  642. const diamondH = Math.round(diamondW * 0.42);
  643. chart.setOption({
  644. backgroundColor: 'transparent',
  645. tooltip: {
  646. trigger: 'axis',
  647. axisPointer: {
  648. type: 'shadow',
  649. shadowStyle: { color: 'rgba(13,241,255,0.06)' }
  650. },
  651. backgroundColor: 'rgba(255,255,255,0.96)',
  652. borderColor: '#ddd',
  653. textStyle: { color: '#333', fontSize: 13 },
  654. formatter: (params) => {
  655. const p = params.find((s) => s.seriesIndex === 1);
  656. return p
  657. ? `<b>${p.name}</b><br/>准时到货率 <b>${p.value}%</b>`
  658. : '';
  659. }
  660. },
  661. grid: {
  662. left: '6%',
  663. right: '4%',
  664. top: '12%',
  665. bottom: '8%',
  666. containLabel: true
  667. },
  668. xAxis: {
  669. type: 'category',
  670. data: this.monthCategories,
  671. axisLine: { lineStyle: { color: 'rgba(32, 105, 168, 0.45)' } },
  672. axisTick: { show: false },
  673. axisLabel: {
  674. color: '#d4ebff',
  675. fontSize: 11,
  676. margin: 8
  677. }
  678. },
  679. yAxis: {
  680. type: 'value',
  681. min: 0,
  682. max: 100,
  683. interval: 20,
  684. axisLine: { show: false },
  685. axisTick: { show: false },
  686. axisLabel: {
  687. color: '#b8d4ef',
  688. fontSize: 11,
  689. formatter: '{value}%'
  690. },
  691. splitLine: {
  692. lineStyle: { color: 'rgba(21, 77, 123, 0.22)' }
  693. }
  694. },
  695. series: [
  696. {
  697. name: 'bg',
  698. type: 'bar',
  699. data: new Array(data.length).fill(100),
  700. barWidth: barW,
  701. barGap: '-100%',
  702. silent: true,
  703. z: 1,
  704. itemStyle: {
  705. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  706. { offset: 0, color: 'rgba(16, 137, 187, 0.1)' },
  707. { offset: 1, color: 'rgba(16, 137, 187, 0.02)' }
  708. ])
  709. }
  710. },
  711. {
  712. name: 'value',
  713. type: 'bar',
  714. data,
  715. barWidth: barW,
  716. z: 3,
  717. itemStyle: {
  718. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  719. { offset: 0, color: 'rgba(13, 241, 255, 0.92)' },
  720. { offset: 0.4, color: 'rgba(16, 137, 187, 0.82)' },
  721. { offset: 1, color: 'rgba(10, 68, 122, 0.72)' }
  722. ])
  723. }
  724. },
  725. {
  726. name: 'topCap',
  727. type: 'pictorialBar',
  728. data,
  729. symbol: 'diamond',
  730. symbolSize: [diamondW, diamondH],
  731. symbolOffset: [0, -(diamondH / 2)],
  732. symbolPosition: 'end',
  733. z: 5,
  734. tooltip: { show: false },
  735. itemStyle: {
  736. color: topColor,
  737. shadowBlur: 8,
  738. shadowColor: 'rgba(13, 241, 255, 0.55)'
  739. }
  740. }
  741. ]
  742. });
  743. this.chartInstances[key] = chart;
  744. return;
  745. }
  746. chart.setOption({
  747. backgroundColor: 'transparent',
  748. grid: {
  749. left: '8%',
  750. right: '4%',
  751. top: '10%',
  752. bottom: '12%',
  753. containLabel: true
  754. },
  755. xAxis: {
  756. type: 'category',
  757. data: this.monthCategories,
  758. axisLine: { lineStyle: { color: '#154d7b' } },
  759. axisTick: { show: false },
  760. axisLabel: { color: '#b8d4ef', fontSize: 10 }
  761. },
  762. yAxis: {
  763. type: 'value',
  764. axisLine: { show: false },
  765. axisTick: { show: false },
  766. axisLabel: { color: '#b8d4ef', fontSize: 10 },
  767. splitLine: { lineStyle: { color: 'rgba(21, 77, 123, 0.28)' } }
  768. },
  769. series: [
  770. {
  771. type: 'bar',
  772. data,
  773. barWidth: '42%',
  774. itemStyle: {
  775. borderRadius: [6, 6, 0, 0],
  776. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  777. { offset: 0, color },
  778. { offset: 1, color: color + '2b' }
  779. ])
  780. }
  781. }
  782. ]
  783. });
  784. this.chartInstances[key] = chart;
  785. },
  786. initInventoryDonutChart() {
  787. if (!this.$refs.inventoryDonutRef) return;
  788. this.chartInstances.inventoryDonut?.dispose();
  789. const chart = echarts.init(this.$refs.inventoryDonutRef);
  790. const pieColors = [
  791. '#2d5dbe',
  792. '#ffb648',
  793. '#3cd8c8',
  794. '#7b69ff',
  795. '#1fa4df'
  796. ];
  797. const pieData = [
  798. { name: '成品数', value: 2533 },
  799. { name: '半成品数', value: 1050 },
  800. { name: '原材料数', value: 2523 },
  801. { name: '备品备件数', value: 58 },
  802. { name: '呆滞品数', value: 83 }
  803. ];
  804. const cw = chart.getWidth();
  805. const ch = chart.getHeight();
  806. const isSmall = cw < 240 || ch < 160;
  807. const valFs = isSmall ? 12 : 14;
  808. const nameFs = isSmall ? 10 : 11;
  809. chart.setOption({
  810. backgroundColor: 'transparent',
  811. color: pieColors,
  812. tooltip: {
  813. trigger: 'item',
  814. backgroundColor: 'rgba(8,29,65,0.92)',
  815. borderColor: '#124c77',
  816. textStyle: { color: '#fff', fontSize: 13 }
  817. },
  818. series: [
  819. {
  820. type: 'pie',
  821. radius: ['36%', '58%'],
  822. center: ['50%', '50%'],
  823. padAngle: 2,
  824. itemStyle: { borderRadius: 4 },
  825. minShowLabelAngle: 2,
  826. label: {
  827. show: true,
  828. position: 'outside',
  829. formatter: (p) => `{val|${p.data.value}}\n{name|${p.name}}`,
  830. rich: {
  831. val: {
  832. color: '#fff',
  833. fontSize: valFs,
  834. fontWeight: 700,
  835. lineHeight: valFs + 6
  836. },
  837. name: {
  838. color: '#c3dfff',
  839. fontSize: nameFs,
  840. lineHeight: nameFs + 5
  841. }
  842. },
  843. distanceToLabelLine: 2
  844. },
  845. labelLine: {
  846. show: true,
  847. length: 10,
  848. length2: 20,
  849. smooth: false,
  850. lineStyle: { color: '#4da6d8', width: 1.2 }
  851. },
  852. labelLayout: (params) => {
  853. const isLeft = params.labelRect.x < cw / 2;
  854. return {
  855. align: isLeft ? 'right' : 'left',
  856. hideOverlap: true
  857. };
  858. },
  859. data: pieData
  860. },
  861. {
  862. type: 'pie',
  863. radius: ['30%', '32%'],
  864. center: ['50%', '50%'],
  865. silent: true,
  866. label: { show: false },
  867. labelLine: { show: false },
  868. data: [
  869. { value: 1, itemStyle: { color: 'rgba(60, 135, 255, 0.18)' } }
  870. ]
  871. }
  872. ]
  873. });
  874. this.chartInstances.inventoryDonut = chart;
  875. },
  876. initInventoryTrendChart() {
  877. if (!this.$refs.inventoryTrendRef) return;
  878. this.chartInstances.inventoryTrend?.dispose();
  879. const chart = echarts.init(this.$refs.inventoryTrendRef);
  880. chart.setOption({
  881. backgroundColor: 'transparent',
  882. tooltip: {
  883. trigger: 'axis',
  884. backgroundColor: 'rgba(8,29,65,0.92)',
  885. borderColor: '#124c77',
  886. textStyle: { color: '#fff', fontSize: 12 },
  887. formatter: (params) => {
  888. const p = params[0];
  889. return p ? `${p.name}&emsp;周转率: <b>${p.value}%</b>` : '';
  890. }
  891. },
  892. grid: {
  893. left: '2%',
  894. right: '4%',
  895. top: '16%',
  896. bottom: '10%',
  897. containLabel: true
  898. },
  899. xAxis: {
  900. type: 'category',
  901. data: [
  902. '数据一',
  903. '数据二',
  904. '数据三',
  905. '数据四',
  906. '数据五',
  907. '数据六',
  908. '数据七'
  909. ],
  910. axisLine: { lineStyle: { color: 'rgba(21, 77, 123, 0.6)' } },
  911. axisTick: { show: false },
  912. axisLabel: { color: '#b8d4ef', fontSize: 10 }
  913. },
  914. yAxis: {
  915. type: 'value',
  916. min: 50,
  917. max: 100,
  918. interval: 10,
  919. axisLine: { show: false },
  920. axisTick: { show: false },
  921. axisLabel: {
  922. color: '#b8d4ef',
  923. fontSize: 10,
  924. formatter: '{value}%'
  925. },
  926. splitLine: { lineStyle: { color: 'rgba(21, 77, 123, 0.24)' } }
  927. },
  928. series: [
  929. {
  930. type: 'line',
  931. smooth: 0.3,
  932. data: [78, 82, 72, 80, 85, 79, 88],
  933. symbol: 'circle',
  934. symbolSize: 8,
  935. showSymbol: true,
  936. lineStyle: { color: '#3c87ff', width: 2.5 },
  937. itemStyle: {
  938. color: '#3c87ff',
  939. borderColor: '#fff',
  940. borderWidth: 2
  941. },
  942. areaStyle: {
  943. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  944. { offset: 0, color: 'rgba(60, 135, 255, 0.3)' },
  945. { offset: 1, color: 'rgba(60, 135, 255, 0.02)' }
  946. ])
  947. }
  948. }
  949. ]
  950. });
  951. this.chartInstances.inventoryTrend = chart;
  952. },
  953. initGaugeChart(key, el, value, color) {
  954. if (!el) return;
  955. this.chartInstances[key]?.dispose();
  956. const chart = echarts.init(el);
  957. const label = key === 'utilDonut' ? '设备利用率' : '设备故障率';
  958. chart.setOption({
  959. backgroundColor: 'transparent',
  960. series: [
  961. {
  962. type: 'gauge',
  963. center: ['50%', '62%'],
  964. radius: '90%',
  965. startAngle: 200,
  966. endAngle: -20,
  967. min: 0,
  968. max: 100,
  969. pointer: { show: false },
  970. progress: {
  971. show: true,
  972. width: 16,
  973. roundCap: true,
  974. itemStyle: { color }
  975. },
  976. axisLine: {
  977. lineStyle: {
  978. width: 16,
  979. color: [[1, 'rgba(18, 76, 119, 0.32)']]
  980. }
  981. },
  982. axisTick: { show: false },
  983. splitLine: { show: false },
  984. axisLabel: {
  985. show: true,
  986. distance: -32,
  987. color: 'rgba(180, 220, 255, 0.6)',
  988. fontSize: 10,
  989. formatter: (v) => {
  990. if (v === 0 || v === 100) return v + '%';
  991. return '';
  992. }
  993. },
  994. title: {
  995. show: true,
  996. offsetCenter: [0, '38%'],
  997. color: '#c3dfff',
  998. fontSize: 14,
  999. fontWeight: 400
  1000. },
  1001. detail: {
  1002. valueAnimation: true,
  1003. offsetCenter: [0, '4%'],
  1004. color: '#fff',
  1005. fontSize: 30,
  1006. fontWeight: 700,
  1007. formatter: (v) => {
  1008. return `{val|${v}}{unit|%}`;
  1009. },
  1010. rich: {
  1011. val: {
  1012. color: '#fff',
  1013. fontSize: 30,
  1014. fontWeight: 700
  1015. },
  1016. unit: {
  1017. color: 'rgba(255,255,255,0.68)',
  1018. fontSize: 14,
  1019. fontWeight: 400,
  1020. padding: [0, 0, 2, 2]
  1021. }
  1022. }
  1023. },
  1024. data: [{ value, name: label }]
  1025. },
  1026. {
  1027. type: 'gauge',
  1028. center: ['50%', '62%'],
  1029. radius: '80%',
  1030. startAngle: 200,
  1031. endAngle: -20,
  1032. min: 0,
  1033. max: 100,
  1034. pointer: { show: false },
  1035. progress: { show: false },
  1036. axisLine: {
  1037. lineStyle: {
  1038. width: 1,
  1039. color: [[1, 'rgba(18, 76, 119, 0.18)']]
  1040. }
  1041. },
  1042. axisTick: { show: false },
  1043. splitLine: { show: false },
  1044. axisLabel: { show: false },
  1045. title: { show: false },
  1046. detail: { show: false }
  1047. }
  1048. ]
  1049. });
  1050. this.chartInstances[key] = chart;
  1051. }
  1052. }
  1053. };
  1054. </script>
  1055. <style lang="scss" scoped>
  1056. .rr-container {
  1057. color: #fff;
  1058. display: flex;
  1059. flex-direction: column;
  1060. overflow: hidden;
  1061. background: radial-gradient(
  1062. circle at top center,
  1063. rgba(30, 113, 255, 0.18),
  1064. transparent 26%
  1065. ),
  1066. radial-gradient(
  1067. circle at center,
  1068. rgba(0, 148, 255, 0.08),
  1069. transparent 40%
  1070. ),
  1071. linear-gradient(180deg, #04132e 0%, #051d47 48%, #031229 100%);
  1072. }
  1073. .rr-header {
  1074. position: relative;
  1075. display: grid;
  1076. grid-template-columns: 1fr auto 1fr;
  1077. align-items: center;
  1078. gap: 1rem;
  1079. min-height: 4.6rem;
  1080. padding: 0 0.9rem;
  1081. background: radial-gradient(
  1082. circle at center top,
  1083. rgba(37, 118, 255, 0.18),
  1084. transparent 45%
  1085. ),
  1086. linear-gradient(180deg, rgba(8, 33, 78, 0.96), rgba(4, 19, 46, 0.78));
  1087. border-bottom: 1px solid rgba(59, 132, 255, 0.3);
  1088. }
  1089. .rr-header::before,
  1090. .rr-header::after {
  1091. content: '';
  1092. position: absolute;
  1093. left: 50%;
  1094. transform: translateX(-50%);
  1095. width: 24rem;
  1096. height: 0.2rem;
  1097. border-radius: 999px;
  1098. background: linear-gradient(
  1099. 90deg,
  1100. transparent,
  1101. rgba(95, 182, 255, 0.85),
  1102. transparent
  1103. );
  1104. }
  1105. .rr-header::before {
  1106. top: 0.25rem;
  1107. }
  1108. .rr-header::after {
  1109. bottom: 0.25rem;
  1110. }
  1111. .rr-header-side {
  1112. display: flex;
  1113. align-items: center;
  1114. gap: 0.75rem;
  1115. z-index: 1;
  1116. }
  1117. .rr-header-right {
  1118. justify-content: flex-end;
  1119. }
  1120. .rr-header-chip {
  1121. padding: 0.28rem 0.72rem;
  1122. font-size: 0.78rem;
  1123. color: #d8efff;
  1124. border: 1px solid rgba(79, 168, 255, 0.45);
  1125. background: linear-gradient(
  1126. 180deg,
  1127. rgba(12, 74, 160, 0.78),
  1128. rgba(4, 37, 93, 0.72)
  1129. );
  1130. box-shadow: inset 0 0 0.75rem rgba(79, 168, 255, 0.18);
  1131. }
  1132. .rr-date-picker {
  1133. width: 16rem;
  1134. }
  1135. ::v-deep .rr-date-picker.el-date-editor,
  1136. ::v-deep .rr-date-picker .el-input__inner,
  1137. ::v-deep .rr-date-picker.el-range-editor.el-input__inner {
  1138. background-color: #011944;
  1139. border: 1px solid #0b6fd5;
  1140. color: #e9f3ff;
  1141. box-shadow: 0 0 4px rgba(11, 109, 213, 0.28);
  1142. }
  1143. ::v-deep .rr-date-picker .el-range-input,
  1144. ::v-deep .rr-date-picker .el-range-separator,
  1145. ::v-deep .rr-date-picker .el-range__icon {
  1146. background: transparent;
  1147. color: #9fc5ff;
  1148. }
  1149. .rr-title {
  1150. position: relative;
  1151. z-index: 1;
  1152. display: flex;
  1153. align-items: center;
  1154. justify-content: center;
  1155. min-width: 33rem;
  1156. height: 1.88rem;
  1157. padding: 0 4.4rem 0.02rem;
  1158. font-family: '优设标题黑';
  1159. font-size: clamp(1.3rem, 1.7vw, 1.76rem);
  1160. font-style: italic;
  1161. letter-spacing: 0.01rem;
  1162. color: #f3fbff;
  1163. text-align: center;
  1164. text-shadow: 0 0 0.14rem rgba(255, 255, 255, 0.22),
  1165. 0 0 0.42rem rgba(80, 184, 255, 0.14);
  1166. background: radial-gradient(
  1167. ellipse at 50% 2%,
  1168. rgba(209, 244, 255, 0.28),
  1169. rgba(209, 244, 255, 0) 48%
  1170. ),
  1171. linear-gradient(
  1172. 90deg,
  1173. rgba(14, 76, 194, 0.14) 0%,
  1174. rgba(54, 148, 255, 0.24) 14%,
  1175. rgba(118, 213, 255, 0.3) 50%,
  1176. rgba(54, 148, 255, 0.24) 86%,
  1177. rgba(14, 76, 194, 0.14) 100%
  1178. ),
  1179. linear-gradient(
  1180. 180deg,
  1181. rgba(55, 142, 255, 0.92) 0%,
  1182. rgba(33, 114, 235, 0.92) 36%,
  1183. rgba(11, 69, 182, 0.96) 74%,
  1184. rgba(7, 44, 122, 0.98) 100%
  1185. );
  1186. border: 1px solid rgba(102, 188, 255, 0.28);
  1187. border-top-color: rgba(177, 232, 255, 0.42);
  1188. border-bottom-color: rgba(80, 155, 255, 0.4);
  1189. clip-path: polygon(
  1190. 0 0,
  1191. 100% 0,
  1192. 100% 68%,
  1193. 98.8% 80%,
  1194. 93% 100%,
  1195. 7% 100%,
  1196. 1.2% 80%,
  1197. 0 68%
  1198. );
  1199. box-shadow: inset 0 0.05rem 0.16rem rgba(223, 248, 255, 0.14),
  1200. inset 0 -0.16rem 0.34rem rgba(4, 22, 74, 0.34),
  1201. 0 0.05rem 0.18rem rgba(0, 0, 0, 0.12);
  1202. overflow: visible;
  1203. }
  1204. .rr-title::before {
  1205. content: '';
  1206. position: absolute;
  1207. left: 50%;
  1208. top: 0.08rem;
  1209. width: calc(100% + 3.2rem);
  1210. height: 0.82rem;
  1211. transform: translateX(-50%);
  1212. background: radial-gradient(
  1213. ellipse at 50% 10%,
  1214. rgba(196, 241, 255, 0.22),
  1215. rgba(196, 241, 255, 0) 34%
  1216. ),
  1217. linear-gradient(
  1218. 90deg,
  1219. rgba(20, 83, 210, 0) 0%,
  1220. rgba(31, 111, 233, 0.03) 14%,
  1221. rgba(52, 151, 255, 0.08) 24%,
  1222. rgba(128, 221, 255, 0.18) 50%,
  1223. rgba(52, 151, 255, 0.08) 76%,
  1224. rgba(31, 111, 233, 0.03) 86%,
  1225. rgba(20, 83, 210, 0) 100%
  1226. );
  1227. clip-path: polygon(
  1228. 0 82%,
  1229. 10% 58%,
  1230. 22% 28%,
  1231. 78% 28%,
  1232. 90% 58%,
  1233. 100% 82%,
  1234. 88% 100%,
  1235. 12% 100%
  1236. );
  1237. opacity: 0.52;
  1238. z-index: -1;
  1239. filter: drop-shadow(0 0 0.12rem rgba(59, 162, 255, 0.14));
  1240. }
  1241. .rr-title::after {
  1242. content: '';
  1243. position: absolute;
  1244. left: 50%;
  1245. bottom: 0.06rem;
  1246. width: calc(100% - 4.2rem);
  1247. height: 0.06rem;
  1248. transform: translateX(-50%);
  1249. border-radius: 999px;
  1250. background: linear-gradient(
  1251. 90deg,
  1252. rgba(137, 222, 255, 0) 0%,
  1253. rgba(137, 222, 255, 0.2) 18%,
  1254. rgba(212, 246, 255, 0.72) 50%,
  1255. rgba(137, 222, 255, 0.2) 82%,
  1256. rgba(137, 222, 255, 0) 100%
  1257. );
  1258. box-shadow: 0 0 0.14rem rgba(113, 214, 255, 0.12);
  1259. }
  1260. .rr-time-box {
  1261. display: flex;
  1262. align-items: center;
  1263. gap: 0.6rem;
  1264. color: #a9d0ff;
  1265. font-size: 0.82rem;
  1266. }
  1267. .rr-time {
  1268. color: #fff;
  1269. font-size: 1rem;
  1270. font-weight: 600;
  1271. }
  1272. .rr-weather {
  1273. color: #f6d067;
  1274. font-size: 0.82rem;
  1275. }
  1276. .rr-fullscreen {
  1277. color: #7fa7ce;
  1278. cursor: pointer;
  1279. }
  1280. .rr-body {
  1281. flex: 1;
  1282. min-height: 0;
  1283. display: grid;
  1284. grid-template-columns: 1fr 1fr 1fr;
  1285. gap: 0.6rem;
  1286. padding: 0.55rem 0.75rem 0.75rem;
  1287. }
  1288. .rr-side-column {
  1289. min-height: 0;
  1290. display: grid;
  1291. grid-template-rows: 1fr 1fr 1fr;
  1292. gap: 0.6rem;
  1293. }
  1294. .rr-panel,
  1295. .rr-map-panel {
  1296. position: relative;
  1297. min-height: 0;
  1298. overflow: hidden;
  1299. border: 1px solid rgba(50, 116, 193, 0.55);
  1300. background: linear-gradient(
  1301. 180deg,
  1302. rgba(7, 31, 70, 0.82),
  1303. rgba(3, 18, 41, 0.92)
  1304. ),
  1305. linear-gradient(90deg, rgba(39, 127, 255, 0.1), transparent);
  1306. box-shadow: inset 0 0 1rem rgba(0, 133, 255, 0.08),
  1307. 0 0 1rem rgba(0, 0, 0, 0.18);
  1308. }
  1309. .rr-panel::before,
  1310. .rr-map-panel::before {
  1311. content: '';
  1312. position: absolute;
  1313. inset: 0.25rem;
  1314. border: 1px solid rgba(98, 190, 255, 0.08);
  1315. pointer-events: none;
  1316. }
  1317. .rr-panel {
  1318. display: flex;
  1319. flex-direction: column;
  1320. padding: 0;
  1321. }
  1322. .rr-panel-title {
  1323. margin-bottom: 0;
  1324. min-height: 2rem;
  1325. display: flex;
  1326. align-items: center;
  1327. padding: 0.2rem 0.6rem 0.2rem 1.75rem;
  1328. font-family: '优设标题黑';
  1329. font-size: 1rem;
  1330. color: #d6ebff;
  1331. letter-spacing: 0.06rem;
  1332. position: relative;
  1333. background: linear-gradient(180deg, #004085, #003568);
  1334. border-bottom: 1px solid rgba(18, 76, 119, 0.9);
  1335. flex-shrink: 0;
  1336. }
  1337. .rr-panel-title::before {
  1338. content: '';
  1339. position: absolute;
  1340. left: 0.6rem;
  1341. top: 50%;
  1342. width: 0.72rem;
  1343. height: 0.96rem;
  1344. transform: translateY(-50%);
  1345. background-image: url('@/assets/renewable_icon_1.svg');
  1346. background-repeat: no-repeat;
  1347. background-size: 100% 100%;
  1348. background-position: center;
  1349. }
  1350. .rr-panel-sales {
  1351. display: flex;
  1352. flex-direction: column;
  1353. }
  1354. .rr-summary-strip {
  1355. position: relative;
  1356. display: flex;
  1357. flex: 1 1 auto;
  1358. align-items: center;
  1359. justify-content: center;
  1360. min-height: 0;
  1361. padding: 0.5rem 0.55rem;
  1362. overflow: hidden;
  1363. background: radial-gradient(
  1364. circle at center,
  1365. rgba(57, 137, 255, 0.06),
  1366. transparent 55%
  1367. ),
  1368. linear-gradient(180deg, rgba(5, 24, 66, 0.18), rgba(5, 24, 66, 0));
  1369. }
  1370. .rr-summary-item {
  1371. position: relative;
  1372. display: grid;
  1373. grid-template-columns: clamp(2rem, 2.6vw, 2.6rem) minmax(0, 1fr);
  1374. align-items: center;
  1375. flex: 1 1 0;
  1376. max-width: none;
  1377. min-width: 0;
  1378. gap: clamp(0.24rem, 0.35vw, 0.4rem);
  1379. padding: 0 0.15rem;
  1380. }
  1381. .rr-summary-divider {
  1382. position: absolute;
  1383. right: 0;
  1384. top: 14%;
  1385. width: 1px;
  1386. height: 72%;
  1387. background: linear-gradient(
  1388. 180deg,
  1389. rgba(58, 126, 209, 0),
  1390. rgba(58, 126, 209, 0.45),
  1391. rgba(58, 126, 209, 0)
  1392. );
  1393. }
  1394. .rr-summary-icon-box {
  1395. width: clamp(2rem, 2.6vw, 2.6rem);
  1396. flex: 0 0 clamp(2rem, 2.6vw, 2.6rem);
  1397. display: flex;
  1398. justify-content: center;
  1399. }
  1400. .rr-summary-icon-wrap {
  1401. position: relative;
  1402. width: clamp(2rem, 2.6vw, 2.6rem);
  1403. height: clamp(2rem, 2.6vw, 2.6rem);
  1404. flex-shrink: 0;
  1405. }
  1406. .rr-summary-icon-ring {
  1407. position: absolute;
  1408. inset: 0;
  1409. border-radius: 50%;
  1410. border: 1px solid rgba(125, 194, 255, 0.45);
  1411. box-shadow: 0 0 0 0.15rem rgba(41, 118, 255, 0.18),
  1412. inset 0 0 0.7rem rgba(91, 176, 255, 0.22);
  1413. }
  1414. .rr-summary-icon {
  1415. position: absolute;
  1416. left: 50%;
  1417. top: 50%;
  1418. width: clamp(1.4rem, 1.8vw, 1.9rem);
  1419. height: clamp(1.4rem, 1.8vw, 1.9rem);
  1420. border-radius: 50%;
  1421. transform: translate(-50%, -50%);
  1422. display: flex;
  1423. align-items: center;
  1424. justify-content: center;
  1425. font-size: 1.5rem;
  1426. font-weight: 700;
  1427. color: #f3fbff;
  1428. background: radial-gradient(
  1429. circle at 35% 30%,
  1430. rgba(124, 198, 255, 0.95),
  1431. rgba(43, 112, 232, 0.96) 70%
  1432. );
  1433. box-shadow: 0 0 1rem rgba(69, 153, 255, 0.42),
  1434. inset 0 -0.35rem 0.75rem rgba(9, 34, 86, 0.4);
  1435. }
  1436. .rr-summary-icon-img {
  1437. width: 60%;
  1438. height: 60%;
  1439. object-fit: contain;
  1440. filter: drop-shadow(0 0 0.35rem rgba(255, 255, 255, 0.16));
  1441. }
  1442. .rr-summary-content {
  1443. min-width: 0;
  1444. display: flex;
  1445. flex-direction: column;
  1446. align-items: flex-start;
  1447. justify-content: center;
  1448. overflow: hidden;
  1449. text-align: left;
  1450. z-index: 1;
  1451. }
  1452. .rr-summary-label {
  1453. color: #d9ebff;
  1454. font-size: clamp(0.48rem, 0.58vw, 0.64rem);
  1455. letter-spacing: 0.02rem;
  1456. line-height: 1.2;
  1457. white-space: nowrap;
  1458. overflow: hidden;
  1459. text-overflow: ellipsis;
  1460. text-shadow: 0 0 0.35rem rgba(79, 171, 255, 0.18);
  1461. }
  1462. .rr-summary-main {
  1463. display: flex;
  1464. align-items: flex-end;
  1465. justify-content: flex-start;
  1466. gap: 0.06rem;
  1467. margin-top: 0.08rem;
  1468. width: 100%;
  1469. min-width: 0;
  1470. flex-wrap: nowrap;
  1471. overflow: hidden;
  1472. }
  1473. .rr-summary-value {
  1474. color: #fff;
  1475. font-size: clamp(0.8rem, 1vw, 1.1rem);
  1476. line-height: 1;
  1477. font-weight: 700;
  1478. letter-spacing: 0.01rem;
  1479. white-space: nowrap;
  1480. text-shadow: 0 0 0.55rem rgba(255, 255, 255, 0.12);
  1481. }
  1482. .rr-summary-unit {
  1483. color: rgba(255, 255, 255, 0.72);
  1484. font-size: clamp(0.36rem, 0.42vw, 0.48rem);
  1485. line-height: 1;
  1486. margin-bottom: 0.02rem;
  1487. white-space: nowrap;
  1488. }
  1489. .rr-summary-trend {
  1490. display: flex;
  1491. flex-direction: column;
  1492. align-items: flex-start;
  1493. justify-content: center;
  1494. gap: 0.02rem;
  1495. min-width: 0;
  1496. margin-left: 0.1rem;
  1497. font-size: clamp(0.3rem, 0.36vw, 0.4rem);
  1498. white-space: nowrap;
  1499. flex-shrink: 0;
  1500. align-self: stretch;
  1501. }
  1502. .rr-summary-trend-label {
  1503. color: #8db2db;
  1504. line-height: 1.2;
  1505. }
  1506. .rr-summary-trend-value {
  1507. font-size: clamp(0.32rem, 0.38vw, 0.42rem);
  1508. font-weight: 600;
  1509. line-height: 1.2;
  1510. }
  1511. .rr-summary-trend.up .rr-summary-trend-value {
  1512. color: #2bd38e;
  1513. }
  1514. .rr-summary-trend.warn .rr-summary-trend-value {
  1515. color: #ff8a65;
  1516. }
  1517. .rr-chart-panel,
  1518. .rr-mini-bar-panel,
  1519. .rr-fill-chart,
  1520. .rr-native-chart,
  1521. .rr-map-body {
  1522. width: 100%;
  1523. height: 100%;
  1524. min-height: 0;
  1525. }
  1526. .rr-chart-panel {
  1527. flex: 1;
  1528. min-height: 9rem;
  1529. padding: 0.55rem 0.7rem 0;
  1530. }
  1531. .rr-mini-bar-panel {
  1532. height: 6.2rem;
  1533. margin-top: 0.2rem;
  1534. padding: 0 0.7rem 0.55rem;
  1535. }
  1536. .rr-procurement-body {
  1537. display: flex;
  1538. flex: 1;
  1539. min-height: 0;
  1540. padding: 0.7rem 0.75rem 0.75rem;
  1541. gap: 0.75rem;
  1542. }
  1543. .rr-procurement-pane {
  1544. min-width: 0;
  1545. min-height: 0;
  1546. display: flex;
  1547. flex-direction: column;
  1548. }
  1549. .rr-procurement-pane-area {
  1550. flex: 1.1;
  1551. }
  1552. .rr-procurement-pane-bar {
  1553. flex: 0.9;
  1554. }
  1555. .rr-pane-caption {
  1556. display: flex;
  1557. align-items: center;
  1558. justify-content: space-between;
  1559. gap: 0.5rem;
  1560. min-height: 1.2rem;
  1561. padding: 0 0.15rem;
  1562. color: #cfe6ff;
  1563. font-size: 0.72rem;
  1564. }
  1565. .rr-pane-caption-right {
  1566. justify-content: flex-start;
  1567. }
  1568. .rr-pane-legend {
  1569. display: flex;
  1570. align-items: center;
  1571. gap: 0.8rem;
  1572. color: #d6ebff;
  1573. }
  1574. .rr-legend-item {
  1575. position: relative;
  1576. padding-left: 0.9rem;
  1577. white-space: nowrap;
  1578. }
  1579. .rr-legend-item::before {
  1580. content: '';
  1581. position: absolute;
  1582. left: 0;
  1583. top: 50%;
  1584. width: 0.5rem;
  1585. height: 0.12rem;
  1586. transform: translateY(-50%);
  1587. border-radius: 999px;
  1588. }
  1589. .rr-legend-item-blue::before {
  1590. background: #3c87ff;
  1591. box-shadow: 0 0 0.35rem rgba(60, 135, 255, 0.7);
  1592. }
  1593. .rr-legend-item-gold::before {
  1594. background: #e5b15d;
  1595. box-shadow: 0 0 0.35rem rgba(229, 177, 93, 0.7);
  1596. }
  1597. .rr-chart-panel-compact {
  1598. padding: 0.15rem 0 0;
  1599. }
  1600. .rr-mini-bar-panel-fill {
  1601. flex: 1;
  1602. height: auto;
  1603. min-height: 0;
  1604. margin-top: 0;
  1605. padding: 0.15rem 0 0;
  1606. }
  1607. .rr-inventory-body {
  1608. flex: 1;
  1609. min-height: 0;
  1610. display: flex;
  1611. gap: 0.4rem;
  1612. padding: 0.5rem 0.6rem;
  1613. }
  1614. .rr-inv-left {
  1615. flex: 0 0 48%;
  1616. position: relative;
  1617. min-height: 0;
  1618. display: flex;
  1619. align-items: center;
  1620. justify-content: center;
  1621. }
  1622. .rr-inv-right {
  1623. flex: 1;
  1624. min-width: 0;
  1625. min-height: 0;
  1626. display: flex;
  1627. flex-direction: column;
  1628. }
  1629. .rr-inv-chart-wrap {
  1630. position: relative;
  1631. width: 100%;
  1632. height: 100%;
  1633. min-height: 8rem;
  1634. }
  1635. .rr-inv-center {
  1636. position: absolute;
  1637. left: 50%;
  1638. top: 50%;
  1639. transform: translate(-50%, -50%);
  1640. text-align: center;
  1641. pointer-events: none;
  1642. }
  1643. .rr-inv-center-value {
  1644. display: block;
  1645. color: #fff;
  1646. font-size: clamp(1.1rem, 1.5vw, 1.7rem);
  1647. font-weight: 700;
  1648. line-height: 1;
  1649. text-shadow: 0 0 0.6rem rgba(60, 135, 255, 0.3);
  1650. }
  1651. .rr-inv-center-label {
  1652. display: block;
  1653. margin-top: 0.15rem;
  1654. color: #b4d4f2;
  1655. font-size: clamp(0.58rem, 0.7vw, 0.78rem);
  1656. }
  1657. .rr-inv-trend-caption {
  1658. flex-shrink: 0;
  1659. color: #d4ebff;
  1660. font-size: clamp(0.68rem, 0.8vw, 0.88rem);
  1661. padding: 0.15rem 0.3rem 0;
  1662. line-height: 1.4;
  1663. }
  1664. .rr-inv-trend-chart {
  1665. position: relative;
  1666. flex: 1;
  1667. min-height: 0;
  1668. }
  1669. .rr-map-panel {
  1670. display: flex;
  1671. flex-direction: column;
  1672. padding: 0;
  1673. }
  1674. .rr-map-head {
  1675. display: flex;
  1676. justify-content: center;
  1677. align-items: center;
  1678. gap: 0.75rem;
  1679. min-height: 2.2rem;
  1680. padding: 0.35rem 0.75rem 0.2rem;
  1681. }
  1682. .rr-map-tabs {
  1683. display: flex;
  1684. gap: 0.5rem;
  1685. }
  1686. .rr-tab {
  1687. min-width: 3.6rem;
  1688. padding: 0.28rem 0.9rem;
  1689. text-align: center;
  1690. font-size: 0.76rem;
  1691. color: #8fc0ff;
  1692. border: 1px solid rgba(61, 128, 206, 0.45);
  1693. background: rgba(5, 28, 62, 0.78);
  1694. cursor: pointer;
  1695. }
  1696. .rr-tab.active {
  1697. color: #fff;
  1698. background: linear-gradient(180deg, #2d84ff, #1163fb);
  1699. box-shadow: 0 0 0.75rem rgba(17, 99, 251, 0.3);
  1700. }
  1701. .rr-map-summary {
  1702. display: flex;
  1703. gap: 0.45rem;
  1704. }
  1705. .rr-map-summary-item {
  1706. min-width: 4.8rem;
  1707. padding: 0.3rem 0.55rem;
  1708. text-align: center;
  1709. font-size: 0.72rem;
  1710. color: #a9d0ff;
  1711. background: rgba(6, 34, 82, 0.68);
  1712. border: 1px solid rgba(55, 120, 196, 0.4);
  1713. }
  1714. .rr-map-summary-item strong {
  1715. display: block;
  1716. margin-top: 0.15rem;
  1717. color: #fff;
  1718. font-size: 1rem;
  1719. }
  1720. .rr-map-body {
  1721. flex: 1;
  1722. padding: 0.2rem 0.35rem 0.35rem;
  1723. }
  1724. .rr-quality-grid {
  1725. flex: 1;
  1726. min-height: 0;
  1727. display: grid;
  1728. grid-template-columns: repeat(2, minmax(0, 1fr));
  1729. gap: 0.65rem;
  1730. padding: 0.75rem;
  1731. }
  1732. .rr-quality-card {
  1733. padding: 0.75rem;
  1734. border: 1px solid rgba(55, 120, 196, 0.4);
  1735. background: rgba(6, 34, 82, 0.6);
  1736. }
  1737. .rr-quality-header {
  1738. display: flex;
  1739. align-items: center;
  1740. gap: 0.4rem;
  1741. color: #cfe6ff;
  1742. font-size: 0.82rem;
  1743. }
  1744. .rr-quality-dot {
  1745. width: 0.5rem;
  1746. height: 0.5rem;
  1747. border-radius: 50%;
  1748. background: #49b2ff;
  1749. box-shadow: 0 0 0.4rem rgba(73, 178, 255, 0.9);
  1750. }
  1751. .rr-quality-rate {
  1752. margin: 0.55rem 0 0.75rem;
  1753. font-size: 2rem;
  1754. font-weight: 700;
  1755. color: #fff;
  1756. }
  1757. .rr-progress-row {
  1758. display: flex;
  1759. justify-content: space-between;
  1760. margin-top: 0.3rem;
  1761. font-size: 0.72rem;
  1762. color: #9fc5ff;
  1763. }
  1764. .rr-progress-row strong {
  1765. color: #fff;
  1766. }
  1767. .rr-progress-track {
  1768. height: 0.42rem;
  1769. margin-top: 0.22rem;
  1770. border-radius: 999px;
  1771. background: rgba(17, 54, 115, 0.85);
  1772. overflow: hidden;
  1773. }
  1774. .rr-progress-fill {
  1775. display: block;
  1776. height: 100%;
  1777. border-radius: inherit;
  1778. }
  1779. .rr-progress-fill-good {
  1780. background: linear-gradient(90deg, #21d07a, rgba(33, 208, 122, 0.2));
  1781. }
  1782. .rr-progress-fill-bad {
  1783. background: linear-gradient(90deg, #ff8a65, rgba(255, 138, 101, 0.2));
  1784. }
  1785. .rr-equipment-body {
  1786. flex: 1;
  1787. min-height: 0;
  1788. display: grid;
  1789. grid-template-columns: repeat(2, minmax(0, 1fr));
  1790. gap: 0.65rem;
  1791. padding: 0.75rem;
  1792. }
  1793. .rr-equipment-gauge {
  1794. display: flex;
  1795. flex-direction: column;
  1796. gap: 0.45rem;
  1797. min-height: 0;
  1798. }
  1799. .rr-gauge-wrap {
  1800. position: relative;
  1801. flex: 1;
  1802. min-height: 7rem;
  1803. }
  1804. .rr-equipment-list {
  1805. list-style: none;
  1806. margin: 0;
  1807. padding: 0;
  1808. }
  1809. .rr-equipment-list li {
  1810. display: flex;
  1811. justify-content: space-between;
  1812. gap: 0.6rem;
  1813. padding: 0.38rem 0.48rem;
  1814. margin-top: 0.28rem;
  1815. font-size: 0.74rem;
  1816. color: #b9d7ef;
  1817. background: rgba(8, 35, 79, 0.66);
  1818. border: 1px solid rgba(39, 99, 170, 0.4);
  1819. }
  1820. .rr-equipment-list strong {
  1821. color: #fff;
  1822. }
  1823. @media (max-width: 1600px) {
  1824. .rr-side-column {
  1825. grid-template-rows: 1fr 1fr 1fr;
  1826. }
  1827. .rr-summary-strip {
  1828. padding: 0.4rem 0.35rem;
  1829. }
  1830. .rr-summary-item {
  1831. gap: 0.2rem;
  1832. padding: 0 0.1rem;
  1833. grid-template-columns: 1.9rem minmax(0, 1fr);
  1834. }
  1835. .rr-summary-icon-box {
  1836. width: 1.9rem;
  1837. flex: 0 0 1.9rem;
  1838. }
  1839. .rr-summary-icon-wrap {
  1840. width: 1.9rem;
  1841. height: 1.9rem;
  1842. }
  1843. .rr-summary-icon {
  1844. width: 1.35rem;
  1845. height: 1.35rem;
  1846. }
  1847. .rr-summary-label {
  1848. font-size: 0.42rem;
  1849. }
  1850. .rr-summary-value {
  1851. font-size: 0.72rem;
  1852. }
  1853. .rr-summary-unit {
  1854. font-size: 0.32rem;
  1855. }
  1856. .rr-summary-trend {
  1857. font-size: 0.28rem;
  1858. margin-left: 0.06rem;
  1859. }
  1860. .rr-summary-trend-value {
  1861. font-size: 0.3rem;
  1862. }
  1863. }
  1864. @media (min-width: 1800px) {
  1865. .rr-summary-strip {
  1866. padding: 0.55rem 0.6rem;
  1867. }
  1868. }
  1869. @media (max-width: 1280px) {
  1870. .rr-summary-strip {
  1871. padding: 0.35rem 0.3rem;
  1872. }
  1873. .rr-summary-item {
  1874. gap: 0.16rem;
  1875. padding: 0 0.06rem;
  1876. grid-template-columns: 1.75rem minmax(0, 1fr);
  1877. }
  1878. .rr-summary-icon-box {
  1879. width: 1.75rem;
  1880. flex: 0 0 1.75rem;
  1881. }
  1882. .rr-summary-icon-wrap {
  1883. width: 1.75rem;
  1884. height: 1.75rem;
  1885. }
  1886. .rr-summary-icon {
  1887. width: 1.2rem;
  1888. height: 1.2rem;
  1889. }
  1890. .rr-summary-label {
  1891. font-size: 0.38rem;
  1892. }
  1893. .rr-summary-value {
  1894. font-size: 0.65rem;
  1895. }
  1896. .rr-summary-unit {
  1897. font-size: 0.28rem;
  1898. }
  1899. .rr-summary-trend {
  1900. font-size: 0.26rem;
  1901. margin-left: 0.05rem;
  1902. }
  1903. .rr-summary-trend-value {
  1904. font-size: 0.28rem;
  1905. }
  1906. }
  1907. @media (max-width: 1366px) {
  1908. .rr-title {
  1909. min-width: 27rem;
  1910. height: 1.7rem;
  1911. padding: 0 3.6rem 0.02rem;
  1912. letter-spacing: 0;
  1913. }
  1914. .rr-title::before {
  1915. width: calc(100% + 2.2rem);
  1916. height: 0.72rem;
  1917. }
  1918. .rr-title::after {
  1919. width: calc(100% - 3.4rem);
  1920. }
  1921. .rr-body {
  1922. grid-template-columns: 1fr;
  1923. grid-template-rows: auto auto auto;
  1924. overflow: auto;
  1925. }
  1926. .rr-side-column {
  1927. grid-template-columns: 1fr;
  1928. grid-template-rows: repeat(3, minmax(12rem, auto));
  1929. }
  1930. .rr-map-panel {
  1931. min-height: 28rem;
  1932. }
  1933. .rr-map-head {
  1934. flex-wrap: wrap;
  1935. }
  1936. .rr-procurement-body,
  1937. .rr-inventory-body {
  1938. padding: 0.4rem;
  1939. }
  1940. .rr-inventory-body {
  1941. flex-direction: column;
  1942. }
  1943. .rr-inv-left {
  1944. flex: 0 0 auto;
  1945. width: 100%;
  1946. min-height: 12rem;
  1947. }
  1948. .rr-inv-right {
  1949. min-height: 10rem;
  1950. }
  1951. }
  1952. @media (max-width: 520px) {
  1953. .rr-title {
  1954. min-width: 15.8rem;
  1955. height: 1.46rem;
  1956. padding: 0 1.8rem 0;
  1957. letter-spacing: 0;
  1958. }
  1959. .rr-title::before {
  1960. width: calc(100% + 1.2rem);
  1961. height: 0.56rem;
  1962. }
  1963. .rr-title::after {
  1964. width: calc(100% - 2.6rem);
  1965. bottom: 0.04rem;
  1966. }
  1967. .rr-summary-strip {
  1968. justify-content: flex-start;
  1969. flex-direction: column;
  1970. gap: 0.6rem;
  1971. }
  1972. .rr-summary-item {
  1973. padding: 0;
  1974. max-width: none;
  1975. grid-template-columns: 1.75rem minmax(0, 1fr);
  1976. }
  1977. .rr-summary-icon-box {
  1978. width: 1.75rem;
  1979. flex: 0 0 1.75rem;
  1980. }
  1981. .rr-summary-icon-wrap {
  1982. width: 1.75rem;
  1983. height: 1.75rem;
  1984. }
  1985. .rr-summary-icon {
  1986. width: 1.2rem;
  1987. height: 1.2rem;
  1988. }
  1989. .rr-summary-label {
  1990. font-size: 0.42rem;
  1991. }
  1992. .rr-summary-value {
  1993. font-size: 0.7rem;
  1994. }
  1995. .rr-summary-unit {
  1996. font-size: 0.3rem;
  1997. }
  1998. .rr-summary-divider {
  1999. display: none;
  2000. }
  2001. .rr-summary-trend {
  2002. margin-left: 0.06rem;
  2003. font-size: 0.28rem;
  2004. }
  2005. .rr-summary-trend-value {
  2006. font-size: 0.3rem;
  2007. }
  2008. .rr-procurement-body {
  2009. padding: 0.6rem;
  2010. }
  2011. .rr-inventory-body {
  2012. padding: 0.4rem;
  2013. }
  2014. }
  2015. </style>
  2016. <style>
  2017. .el-icon-_screen-full,
  2018. .el-icon-_screen-restore {
  2019. font-size: 1.2rem;
  2020. cursor: pointer;
  2021. transition: all 0.3s;
  2022. color: #7fa7ce;
  2023. }
  2024. .el-icon-_screen-full:hover,
  2025. .el-icon-_screen-restore:hover {
  2026. color: #fff;
  2027. transform: scale(1.1);
  2028. }
  2029. </style>