renewableResourcesDashboard.vue 63 KB

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