xsh_1997 1 week ago
parent
commit
c3f8ce4d6a

+ 6 - 2
ruoyi-screen/src/api/tradeSales.js

@@ -1,10 +1,14 @@
1 1
 import request from '@/utils/request'
2 2
 
3 3
 /** 看板主数据 GET /bigScreen/tradeSales/dashboard */
4
-export function getTradeSalesDashboard(statYear) {
4
+export function getTradeSalesDashboard(statYear, forceRefresh = false) {
5
+  const params = { statYear }
6
+  if (forceRefresh) {
7
+    params.forceRefresh = true
8
+  }
5 9
   return request({
6 10
     url: '/bigScreen/tradeSales/dashboard',
7 11
     method: 'get',
8
-    params: { statYear }
12
+    params
9 13
   })
10 14
 }

+ 70 - 23
ruoyi-screen/src/views/tradeSales/chartOptions.js

@@ -43,27 +43,39 @@ function formatQuoteDate(quoteDate) {
43 43
   return quoteDate
44 44
 }
45 45
 
46
-/** 产地行情 — 近 7 日均价面积图 */
46
+/** 产地行情 — 近 7 日最低/最高/均价三曲线 */
47 47
 export function buildOriginQuoteOption(originQuote) {
48 48
   if (!originQuote?.hasQuoteData || !originQuote.dailyTrend?.length) {
49 49
     return emptyOption('暂无行情数据')
50 50
   }
51 51
   const dates = originQuote.dailyTrend.map((d) => formatQuoteDate(d.quoteDate))
52
+  const minPrices = originQuote.dailyTrend.map((d) => Number(d.minPrice ?? 0))
53
+  const maxPrices = originQuote.dailyTrend.map((d) => Number(d.maxPrice ?? 0))
52 54
   const avgPrices = originQuote.dailyTrend.map((d) => Number(d.avgPrice ?? 0))
53
-  if (!avgPrices.some((v) => v > 0)) {
55
+  if (![...minPrices, ...maxPrices, ...avgPrices].some((v) => v > 0)) {
54 56
     return emptyOption('暂无行情数据')
55 57
   }
56 58
   const unit = originQuote.priceUnitLabel || ''
57 59
   return {
58
-    color: ['#5ef0c8'],
60
+    color: ['#6eb5ff', '#ecd27b', '#5ef0c8'],
59 61
     tooltip: {
60 62
       trigger: 'axis',
61 63
       formatter: (params) => {
62
-        const p = params[0]
63
-        return `${p.name}<br/>均价 ${p.value}${unit}`
64
+        const lines = [params[0]?.name || '']
65
+        params.forEach((p) => {
66
+          lines.push(`${p.marker}${p.seriesName} ${p.value}${unit}`)
67
+        })
68
+        return lines.join('<br/>')
64 69
       }
65 70
     },
66
-    grid: { ...GRID, top: 8, bottom: 24 },
71
+    legend: {
72
+      bottom: 0,
73
+      left: 'center',
74
+      textStyle: { color: '#a8d4c8', fontSize: 9 },
75
+      itemWidth: 12,
76
+      itemHeight: 6
77
+    },
78
+    grid: { ...GRID, top: 8, bottom: 30 },
67 79
     xAxis: {
68 80
       type: 'category',
69 81
       data: dates,
@@ -77,13 +89,29 @@ export function buildOriginQuoteOption(originQuote) {
77 89
       splitLine: SPLIT_LINE
78 90
     },
79 91
     series: [
92
+      {
93
+        name: '最低价',
94
+        type: 'line',
95
+        smooth: true,
96
+        symbol: 'circle',
97
+        symbolSize: 3,
98
+        data: minPrices
99
+      },
100
+      {
101
+        name: '最高价',
102
+        type: 'line',
103
+        smooth: true,
104
+        symbol: 'circle',
105
+        symbolSize: 3,
106
+        data: maxPrices
107
+      },
80 108
       {
81 109
         name: '均价',
82 110
         type: 'line',
83 111
         smooth: true,
84 112
         symbol: 'circle',
85
-        symbolSize: 4,
86
-        areaStyle: { color: 'rgba(94, 240, 200, 0.25)' },
113
+        symbolSize: 3,
114
+        areaStyle: { color: 'rgba(94, 240, 200, 0.18)' },
87 115
         data: avgPrices
88 116
       }
89 117
     ]
@@ -170,9 +198,6 @@ export function buildSalesDestinationBarOption(salesDestination) {
170 198
   const sorted = [...salesDestination].sort((a, b) => a.salesDestination - b.salesDestination)
171 199
   const names = sorted.map((r) => r.salesDestinationName || '')
172 200
   const values = sorted.map((r) => r.tradeHeads ?? 0)
173
-  if (!values.some((v) => v > 0)) {
174
-    return emptyOption('暂无去向数据')
175
-  }
176 201
   return {
177 202
     color: DESTINATION_COLOR,
178 203
     tooltip: {
@@ -219,13 +244,12 @@ export function buildQualityGradePieOption(qualityGrade) {
219 244
     return emptyOption('暂无等级数据')
220 245
   }
221 246
   const data = qualityGrade.items
222
-    .filter((item) => (item.tradeHeads ?? 0) > 0)
223 247
     .map((item, i) => ({
224 248
       name: item.gradeName || item.gradeCode,
225 249
       value: item.tradeHeads ?? 0,
226 250
       itemStyle: { color: GRADE_COLOR[i % GRADE_COLOR.length] }
227 251
     }))
228
-  if (!data.length) {
252
+  if (!data.length || !data.some((item) => item.value > 0)) {
229 253
     return emptyOption('暂无等级数据')
230 254
   }
231 255
   return {
@@ -265,11 +289,22 @@ export function buildQualityGradePieOption(qualityGrade) {
265 289
 const MALL_PIE_COLOR = ['#5ef0c8', '#ecd27b', '#6eb5ff', '#0f8f72', '#c9a227', '#8b7cf6']
266 290
 const MALL_BAR_COLOR = ['#5ef0c8', '#6eb5ff', '#ecd27b', '#0f8f72', '#c9a227']
267 291
 const WORD_COLORS = ['#5ef0c8', '#ecd27b', '#6eb5ff', '#98e9aa', '#0f8f72', '#c9a227']
292
+const MALL_UNAVAILABLE_TEXT = '商城统计未接入'
293
+
294
+function resolveMallEmptyText(mallStatsAvailable, defaultText = '暂无数据') {
295
+  if (mallStatsAvailable === false) {
296
+    return MALL_UNAVAILABLE_TEXT
297
+  }
298
+  return defaultText
299
+}
268 300
 
269 301
 /** 农资品类销售占比 — 饼图 */
270
-export function buildCategorySalesPieOption(categorySales) {
302
+export function buildCategorySalesPieOption(categorySales, mallStatsAvailable = true) {
303
+  if (mallStatsAvailable === false) {
304
+    return emptyOption(MALL_UNAVAILABLE_TEXT)
305
+  }
271 306
   if (!categorySales?.items?.length || !(categorySales.totalQty > 0)) {
272
-    return emptyOption('暂无品类数据')
307
+    return emptyOption(resolveMallEmptyText(mallStatsAvailable, '暂无品类数据'))
273 308
   }
274 309
   const data = categorySales.items
275 310
     .filter((item) => (item.qty ?? 0) > 0)
@@ -312,9 +347,12 @@ export function buildCategorySalesPieOption(categorySales) {
312 347
 }
313 348
 
314 349
 /** 商城订单趋势 — 曲线 */
315
-export function buildMallOrderTrendOption(mallOrderTrend) {
350
+export function buildMallOrderTrendOption(mallOrderTrend, mallStatsAvailable = true) {
351
+  if (mallStatsAvailable === false) {
352
+    return emptyOption(MALL_UNAVAILABLE_TEXT)
353
+  }
316 354
   if (!mallOrderTrend?.items?.length) {
317
-    return emptyOption('暂无订单数据')
355
+    return emptyOption(resolveMallEmptyText(mallStatsAvailable, '暂无订单数据'))
318 356
   }
319 357
   const counts = monthSeries(mallOrderTrend.items, 'orderCount')
320 358
   if (!counts.some((v) => v > 0)) {
@@ -352,9 +390,12 @@ export function buildMallOrderTrendOption(mallOrderTrend) {
352 390
 }
353 391
 
354 392
 /** 店铺入驻 — 饼图(按月占比) */
355
-export function buildShopEntryPieOption(shopEntry) {
393
+export function buildShopEntryPieOption(shopEntry, mallStatsAvailable = true) {
394
+  if (mallStatsAvailable === false) {
395
+    return emptyOption(MALL_UNAVAILABLE_TEXT)
396
+  }
356 397
   if (!shopEntry?.items?.length || !(shopEntry.yearTotal > 0)) {
357
-    return emptyOption('暂无入驻数据')
398
+    return emptyOption(resolveMallEmptyText(mallStatsAvailable, '暂无入驻数据'))
358 399
   }
359 400
   const data = shopEntry.items
360 401
     .filter((item) => (item.shopCount ?? 0) > 0)
@@ -393,9 +434,12 @@ export function buildShopEntryPieOption(shopEntry) {
393 434
 }
394 435
 
395 436
 /** 消费区域排名 Top5 — 柱图(万元) */
396
-export function buildRegionRankBarOption(regionRank) {
437
+export function buildRegionRankBarOption(regionRank, mallStatsAvailable = true) {
438
+  if (mallStatsAvailable === false) {
439
+    return emptyOption(MALL_UNAVAILABLE_TEXT)
440
+  }
397 441
   if (!regionRank?.items?.length) {
398
-    return emptyOption('暂无区域数据')
442
+    return emptyOption(resolveMallEmptyText(mallStatsAvailable, '暂无区域数据'))
399 443
   }
400 444
   const sorted = [...regionRank.items].sort((a, b) => a.rank - b.rank)
401 445
   const names = sorted.map((r) => r.city || '')
@@ -441,10 +485,13 @@ export function buildRegionRankBarOption(regionRank) {
441 485
 }
442 486
 
443 487
 /** 消费者评价词云 */
444
-export function buildReviewWordCloudOption(reviewWordCloud) {
488
+export function buildReviewWordCloudOption(reviewWordCloud, mallStatsAvailable = true) {
489
+  if (mallStatsAvailable === false) {
490
+    return emptyOption(MALL_UNAVAILABLE_TEXT)
491
+  }
445 492
   const list = reviewWordCloud?.items || []
446 493
   if (!list.length) {
447
-    return emptyOption('暂无评价数据')
494
+    return emptyOption(resolveMallEmptyText(mallStatsAvailable, '暂无评价数据'))
448 495
   }
449 496
   const data = list
450 497
     .filter((item) => item.word)

+ 140 - 34
ruoyi-screen/src/views/tradeSales/index.vue

@@ -1,8 +1,10 @@
1 1
 <template>
2 2
   <div class="screen-page ts-page" :class="{ 'is-loading': loading }">
3
-    <div v-if="loadError" class="ts-error">{{ loadError }}</div>
4
-
5
-    <!-- <div class="ts-year-bar">
3
+    <div v-if="loadError" class="ts-error" @click="onRetry">
4
+      {{ loadError }}(点击重试)
5
+    </div>
6
+<!-- 
7
+    <div class="ts-year-bar">
6 8
       <label class="ts-year-bar__label">统计年份</label>
7 9
       <select
8 10
         v-model="statYear"
@@ -13,9 +15,17 @@
13 15
         <option v-for="y in availableYears" :key="y" :value="String(y)">{{ y }}年</option>
14 16
       </select>
15 17
       <span v-if="statDate" class="ts-year-bar__date">统计日 {{ statDate }}</span>
18
+      <button
19
+        type="button"
20
+        class="ts-year-bar__refresh"
21
+        :disabled="loading || refreshing"
22
+        @click="onManualRefresh"
23
+      >
24
+        {{ refreshing ? '刷新中…' : '刷新' }}
25
+      </button>
16 26
     </div> -->
17 27
 
18
-    <!-- 左栏:牦牛交易(对接 §3.1) -->
28
+    <!-- 左栏:牦牛交易 -->
19 29
     <div class="screen-page--home-column">
20 30
       <div class="screen-page--home-column-top">
21 31
         <div class="top_title">交易总览 ཚོང་འདོན་ཀྱི་རྒྱུན་བསྡུས།</div>
@@ -59,6 +69,12 @@
59 69
                   <strong>{{ formatPrice(originQuote?.maxPrice7d) }}</strong>
60 70
                 </div>
61 71
               </div>
72
+              <div class="quote-summary__item">
73
+                <div class="quote-summary__label">最近行情日</div>
74
+                <div class="quote-summary__val quote-summary__val--date">
75
+                  <strong>{{ originQuote?.lastQuoteDate || '—' }}</strong>
76
+                </div>
77
+              </div>
62 78
             </div>
63 79
             <div class="quote-chart">
64 80
               <ScreenChart :option="originQuoteChartOption" />
@@ -89,10 +105,13 @@
89 105
       </div>
90 106
     </div>
91 107
 
92
-    <!-- 右栏:农资商城(对接 §8~13) -->
93
-    <div class="screen-page--home-column">
108
+    <!-- 右栏:农资商城 -->
109
+    <div class="screen-page--home-column" :class="{ 'ts-mall-unavailable': !mallStatsAvailable }">
94 110
       <div class="screen-page--home-column-right ts-mall-panel">
95
-        <div class="top_title">农资品类销售 ཞིང་ལས་རྒྱུ་ཆ་རིགས་ཀྱི་ཚོང་འདོན།</div>
111
+        <div class="top_title">
112
+          农资品类销售 ཞིང་ལས་རྒྱུ་ཆ་རིགས་ཀྱི་ཚོང་འདོན།
113
+          <span v-if="categoryStatDate" class="ts-mall-stat-date">({{ categoryStatDate }})</span>
114
+        </div>
96 115
         <div class="ts-mall-top">
97 116
           <div class="ts-mall-top__pie">
98 117
             <ScreenChart :option="categorySalesChartOption" />
@@ -103,7 +122,7 @@
103 122
               <li v-for="item in hotCategoryItems" :key="item.rank" class="ts-mall-hot-list__row">
104 123
                 <span class="ts-mall-hot-list__rank">{{ item.rank }}</span>
105 124
                 <span class="ts-mall-hot-list__name" :title="item.categoryName">{{ item.categoryName }}</span>
106
-                <span class="ts-mall-hot-list__qty">{{ formatNum(item.qty) }}</span>
125
+                <span class="ts-mall-hot-list__qty">{{ formatNum(item.qty) }}</span>
107 126
               </li>
108 127
             </ul>
109 128
             <span v-else class="ts-placeholder ts-placeholder--sm">{{ mallEmptyHint }}</span>
@@ -143,7 +162,7 @@
143 162
 </template>
144 163
 
145 164
 <script setup>
146
-import { computed, onMounted, ref } from 'vue'
165
+import { computed, onMounted, onUnmounted, ref } from 'vue'
147 166
 import ScreenChart from '@/components/ScreenChart.vue'
148 167
 import { getTradeSalesDashboard } from '@/api/tradeSales'
149 168
 import {
@@ -158,11 +177,15 @@ import {
158 177
   buildTradeMonthlyOption
159 178
 } from './chartOptions'
160 179
 
180
+/** 自动轮播刷新周期(对齐功能需求 §7.3,默认 3 分钟) */
181
+const DASHBOARD_REFRESH_MS = 3 * 60 * 1000
182
+
161 183
 const loading = ref(false)
184
+const refreshing = ref(false)
162 185
 const loadError = ref('')
163 186
 const statYear = ref(String(new Date().getFullYear()))
164 187
 const statDate = ref('')
165
-const availableYears = ref([])
188
+const availableYears = ref([new Date().getFullYear()])
166 189
 
167 190
 const tradeOverview = ref(null)
168 191
 const originQuote = ref(null)
@@ -177,15 +200,25 @@ const shopEntry = ref(null)
177 200
 const regionRank = ref(null)
178 201
 const reviewWordCloud = ref(null)
179 202
 
203
+let dashboardTimer = null
204
+
205
+const mallAvailable = computed(() => mallStatsAvailable.value)
206
+
180 207
 const originQuoteChartOption = computed(() => buildOriginQuoteOption(originQuote.value))
181 208
 const monthlyTrendChartOption = computed(() => buildTradeMonthlyOption(tradeMonthlyTrend.value))
182 209
 const destinationChartOption = computed(() => buildSalesDestinationBarOption(salesDestination.value))
183 210
 const qualityGradeChartOption = computed(() => buildQualityGradePieOption(qualityGrade.value))
184
-const categorySalesChartOption = computed(() => buildCategorySalesPieOption(categorySales.value))
185
-const mallOrderTrendChartOption = computed(() => buildMallOrderTrendOption(mallOrderTrend.value))
186
-const shopEntryChartOption = computed(() => buildShopEntryPieOption(shopEntry.value))
187
-const regionRankChartOption = computed(() => buildRegionRankBarOption(regionRank.value))
188
-const reviewWordCloudChartOption = computed(() => buildReviewWordCloudOption(reviewWordCloud.value))
211
+const categorySalesChartOption = computed(() =>
212
+  buildCategorySalesPieOption(categorySales.value, mallAvailable.value)
213
+)
214
+const mallOrderTrendChartOption = computed(() =>
215
+  buildMallOrderTrendOption(mallOrderTrend.value, mallAvailable.value)
216
+)
217
+const shopEntryChartOption = computed(() => buildShopEntryPieOption(shopEntry.value, mallAvailable.value))
218
+const regionRankChartOption = computed(() => buildRegionRankBarOption(regionRank.value, mallAvailable.value))
219
+const reviewWordCloudChartOption = computed(() =>
220
+  buildReviewWordCloudOption(reviewWordCloud.value, mallAvailable.value)
221
+)
189 222
 
190 223
 const hotCategoryItems = computed(() => {
191 224
   const items = hotCategoryRank.value?.items || []
@@ -194,13 +227,17 @@ const hotCategoryItems = computed(() => {
194 227
 
195 228
 const mallEmptyHint = computed(() => (mallStatsAvailable.value ? '暂无热销数据' : '商城统计未接入'))
196 229
 
230
+const categoryStatDate = computed(
231
+  () => categorySales.value?.statDate || hotCategoryRank.value?.statDate || ''
232
+)
233
+
197 234
 const tradeOverviewItems = computed(() => {
198 235
   const o = tradeOverview.value
199 236
   return [
200 237
     {
201 238
       key: 'orderCount',
202 239
       label: '牦牛交易订单数',
203
-      unit: '',
240
+      unit: '',
204 241
       value: display(o?.orderCount),
205 242
       placeholder: false
206 243
     },
@@ -293,6 +330,21 @@ function formatPrice(val) {
293 330
   return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
294 331
 }
295 332
 
333
+function resetDashboard() {
334
+  tradeOverview.value = null
335
+  originQuote.value = null
336
+  tradeMonthlyTrend.value = []
337
+  salesDestination.value = []
338
+  qualityGrade.value = null
339
+  mallStatsAvailable.value = false
340
+  categorySales.value = null
341
+  hotCategoryRank.value = null
342
+  mallOrderTrend.value = null
343
+  shopEntry.value = null
344
+  regionRank.value = null
345
+  reviewWordCloud.value = null
346
+}
347
+
296 348
 function applyDashboard(data) {
297 349
   if (!data) {
298 350
     return
@@ -309,7 +361,7 @@ function applyDashboard(data) {
309 361
   tradeMonthlyTrend.value = data.tradeMonthlyTrend || []
310 362
   salesDestination.value = data.salesDestination || []
311 363
   qualityGrade.value = data.qualityGrade || null
312
-  mallStatsAvailable.value = !!data.mallStatsAvailable
364
+  mallStatsAvailable.value = data.mallStatsAvailable || false
313 365
   categorySales.value = data.categorySales || null
314 366
   hotCategoryRank.value = data.hotCategoryRank || null
315 367
   mallOrderTrend.value = data.mallOrderTrend || null
@@ -318,16 +370,25 @@ function applyDashboard(data) {
318 370
   reviewWordCloud.value = data.reviewWordCloud || null
319 371
 }
320 372
 
321
-async function fetchDashboard() {
322
-  loading.value = true
373
+async function fetchDashboard(forceRefresh = false) {
374
+  if (forceRefresh) {
375
+    if (refreshing.value) {
376
+      return
377
+    }
378
+    refreshing.value = true
379
+  } else {
380
+    loading.value = true
381
+    resetDashboard()
382
+  }
323 383
   loadError.value = ''
324 384
   try {
325
-    const res = await getTradeSalesDashboard(statYear.value)
385
+    const res = await getTradeSalesDashboard(statYear.value, forceRefresh)
326 386
     applyDashboard(res.data)
327 387
   } catch (e) {
328 388
     loadError.value = e?.message || '看板数据加载失败'
329 389
   } finally {
330 390
     loading.value = false
391
+    refreshing.value = false
331 392
   }
332 393
 }
333 394
 
@@ -335,8 +396,30 @@ function onYearChange() {
335 396
   fetchDashboard()
336 397
 }
337 398
 
399
+function onManualRefresh() {
400
+  fetchDashboard(true)
401
+}
402
+
403
+function onRetry() {
404
+  fetchDashboard()
405
+}
406
+
407
+function startDashboardTimer() {
408
+  dashboardTimer = setInterval(() => {
409
+    fetchDashboard(true)
410
+  }, DASHBOARD_REFRESH_MS)
411
+}
412
+
338 413
 onMounted(() => {
339 414
   fetchDashboard()
415
+  startDashboardTimer()
416
+})
417
+
418
+onUnmounted(() => {
419
+  if (dashboardTimer) {
420
+    clearInterval(dashboardTimer)
421
+    dashboardTimer = null
422
+  }
340 423
 })
341 424
 </script>
342 425
 
@@ -367,6 +450,7 @@ onMounted(() => {
367 450
   color: #ffb4b4;
368 451
   background: rgba(80, 20, 20, 0.75);
369 452
   border-radius: 4px;
453
+  cursor: pointer;
370 454
 }
371 455
 
372 456
 .ts-year-bar {
@@ -401,6 +485,22 @@ onMounted(() => {
401 485
   color: rgba(168, 212, 200, 0.75);
402 486
 }
403 487
 
488
+.ts-year-bar__refresh {
489
+  height: 28px;
490
+  padding: 0 10px;
491
+  font-size: 12px;
492
+  color: #e8eef5;
493
+  background: rgba(4, 48, 40, 0.85);
494
+  border: 1px solid var(--screen-line-dim, rgba(61, 217, 176, 0.42));
495
+  border-radius: 4px;
496
+  cursor: pointer;
497
+}
498
+
499
+.ts-year-bar__refresh:disabled {
500
+  opacity: 0.6;
501
+  cursor: not-allowed;
502
+}
503
+
404 504
 .screen-page--home-column {
405 505
   width: 617px;
406 506
   height: 100%;
@@ -431,6 +531,12 @@ onMounted(() => {
431 531
   flex-direction: column;
432 532
 }
433 533
 
534
+.ts-mall-stat-date {
535
+  font-size: 12px;
536
+  color: rgba(168, 212, 200, 0.8);
537
+  margin-left: 4px;
538
+}
539
+
434 540
 .ts-mall-top {
435 541
   flex: 1;
436 542
   min-height: 0;
@@ -613,7 +719,6 @@ onMounted(() => {
613 719
 }
614 720
 
615 721
 .content_title {
616
-
617 722
   font-size: 11px;
618 723
   color: #a8d4c8;
619 724
   line-height: 1.3;
@@ -646,13 +751,15 @@ onMounted(() => {
646 751
 .quote-summary {
647 752
   display: flex;
648 753
   flex-direction: row;
649
-  gap: 6px;
650
-  height: 42px;
754
+  flex-wrap: wrap;
755
+  gap: 4px;
756
+  min-height: 42px;
651 757
   flex-shrink: 0;
652 758
 }
653 759
 
654 760
 .quote-summary__item {
655
-  flex: 1;
761
+  flex: 1 1 calc(50% - 4px);
762
+  min-width: 0;
656 763
   display: flex;
657 764
   flex-direction: column;
658 765
   align-items: center;
@@ -660,28 +767,33 @@ onMounted(() => {
660 767
   background: rgba(4, 48, 40, 0.45);
661 768
   border-radius: 4px;
662 769
   border: 1px solid rgba(61, 217, 176, 0.2);
770
+  padding: 2px 0;
663 771
 }
664 772
 
665 773
 .quote-summary__label {
666
-  font-size: 10px;
774
+  font-size: 9px;
667 775
   color: #a8d4c8;
668 776
 }
669 777
 
670 778
 .quote-summary__val {
671
-  font-size: 11px;
779
+  font-size: 10px;
672 780
   color: #fff;
673 781
 }
674 782
 
675 783
 .quote-summary__val strong {
676
-  font-size: 14px;
784
+  font-size: 12px;
677 785
   background: linear-gradient(to bottom, #98e9aa, #ecd27b);
678 786
   -webkit-background-clip: text;
679 787
   background-clip: text;
680 788
   color: transparent;
681 789
 }
682 790
 
683
-.quote-summary__unit {
791
+.quote-summary__val--date strong {
684 792
   font-size: 10px;
793
+}
794
+
795
+.quote-summary__unit {
796
+  font-size: 9px;
685 797
   color: #a8d4c8;
686 798
   margin-left: 2px;
687 799
 }
@@ -690,10 +802,4 @@ onMounted(() => {
690 802
   flex: 1;
691 803
   min-height: 0;
692 804
 }
693
-
694
-.flex_content--placeholder {
695
-  display: flex;
696
-  align-items: center;
697
-  justify-content: center;
698
-}
699 805
 </style>