hsafe.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. <script lang="ts" setup>
  2. import CountTo from '@/components/count-to1.vue'
  3. import { IotStatApi } from '@/api/pms/stat'
  4. const safeCount = ref(0)
  5. const loading = ref(false)
  6. function toNumber(value: unknown) {
  7. const num = Number(value)
  8. return Number.isFinite(num) ? num : 0
  9. }
  10. async function loadSafeCount() {
  11. loading.value = true
  12. try {
  13. const res = await IotStatApi.getSafeCount()
  14. safeCount.value = toNumber(res)
  15. } catch (error) {
  16. console.error('获取库存预警数量失败:', error)
  17. safeCount.value = 0
  18. } finally {
  19. loading.value = false
  20. }
  21. }
  22. onMounted(() => {
  23. loadSafeCount()
  24. })
  25. </script>
  26. <template>
  27. <div class="panel flex flex-col">
  28. <div class="panel-title h-12">
  29. <div class="icon-decorator">
  30. <span></span>
  31. <span></span>
  32. </div>
  33. 库存预警物料数量
  34. </div>
  35. <div
  36. class="metric-panel flex-1 min-h-0"
  37. style="
  38. /* stylelint-disable-next-line custom-property-empty-line-before */
  39. --metric-accent: #ef6b6f;
  40. --metric-glow: rgb(239 107 111 / 18%);
  41. --metric-border: rgb(239 107 111 / 14%);
  42. --metric-tag-bg: rgb(239 107 111 / 10%);
  43. "
  44. >
  45. <div class="metric-panel__orbit metric-panel__orbit--outer"></div>
  46. <div class="metric-panel__orbit metric-panel__orbit--inner"></div>
  47. <div class="metric-panel__top">
  48. <span class="metric-panel__tag">ALERT</span>
  49. </div>
  50. <div class="metric-panel__body">
  51. <div class="metric-panel__center">
  52. <div class="metric-panel__headline">当前预警物料</div>
  53. <div class="metric-panel__value-row">
  54. <CountTo
  55. class="metric-panel__value"
  56. :start-val="0"
  57. :end-val="safeCount"
  58. :duration="1200"
  59. />
  60. </div>
  61. </div>
  62. </div>
  63. </div>
  64. </div>
  65. </template>
  66. <style lang="scss" scoped>
  67. @import url('@/styles/kb.scss');
  68. .metric-panel {
  69. position: relative;
  70. display: grid;
  71. padding: 16px 14px 20px;
  72. overflow: hidden;
  73. grid-template-rows: auto minmax(0, 1fr);
  74. gap: 16px;
  75. }
  76. .metric-panel::before {
  77. position: absolute;
  78. inset: 54px 18px 16px;
  79. pointer-events: none;
  80. background: radial-gradient(
  81. circle at center,
  82. rgb(255 255 255 / 20%) 0%,
  83. rgb(255 255 255 / 0%) 72%
  84. );
  85. content: '';
  86. }
  87. .metric-panel__orbit {
  88. position: absolute;
  89. top: 56%;
  90. left: 50%;
  91. border: 1px solid var(--metric-border);
  92. border-radius: 999px;
  93. transform: translate(-50%, -50%);
  94. }
  95. .metric-panel__orbit--outer {
  96. width: 240px;
  97. height: 240px;
  98. }
  99. .metric-panel__orbit--inner {
  100. width: 188px;
  101. height: 188px;
  102. border-color: rgb(255 255 255 / 42%);
  103. opacity: 0.55;
  104. }
  105. .metric-panel__top,
  106. .metric-panel__body,
  107. .metric-panel__center {
  108. position: relative;
  109. z-index: 1;
  110. }
  111. .metric-panel__body {
  112. display: flex;
  113. min-height: 0;
  114. align-items: center;
  115. justify-content: center;
  116. }
  117. .metric-panel__tag {
  118. display: inline-flex;
  119. padding: 5px 12px;
  120. font-family: YouSheBiaoTiHei, sans-serif;
  121. font-size: 16px;
  122. line-height: 1;
  123. letter-spacing: 2px;
  124. color: var(--metric-accent);
  125. background: var(--metric-tag-bg);
  126. border: 1px solid rgb(255 255 255 / 72%);
  127. border-radius: 999px;
  128. box-shadow: inset 0 1px 0 rgb(255 255 255 / 78%);
  129. }
  130. .metric-panel__center {
  131. display: flex;
  132. width: 100%;
  133. flex-direction: column;
  134. align-items: center;
  135. justify-content: center;
  136. text-align: center;
  137. }
  138. .metric-panel__headline {
  139. font-size: 22px;
  140. font-weight: 600;
  141. letter-spacing: 2px;
  142. color: #4f678a;
  143. text-shadow: 0 4px 12px rgb(255 255 255 / 35%);
  144. }
  145. .metric-panel__value-row {
  146. display: flex;
  147. margin-top: 18px;
  148. align-items: flex-end;
  149. justify-content: center;
  150. }
  151. .metric-panel__value {
  152. font-family: YouSheBiaoTiHei, sans-serif;
  153. font-size: 90px;
  154. line-height: 0.88;
  155. letter-spacing: 2px;
  156. color: var(--metric-accent);
  157. text-shadow: 0 10px 18px var(--metric-glow);
  158. }
  159. </style>