|
|
@@ -1,1070 +1,27 @@
|
|
|
<template>
|
|
|
- <div class="s5-dashboard">
|
|
|
- <!-- 顶部标题栏 -->
|
|
|
- <div class="top-header">
|
|
|
- <div class="header-left">
|
|
|
- <div class="breadcrumb">
|
|
|
- <el-icon class="back-icon" @click="$router.push('/')"><ArrowLeft /></el-icon>
|
|
|
- <span>企业数字化运营看板 V5.0</span>
|
|
|
- <el-tag size="small" class="gold-tag">正式版</el-tag>
|
|
|
- </div>
|
|
|
- <h1 class="page-title">
|
|
|
- S5 物料仓储(仓储)全流程详情
|
|
|
- <span class="subtitle">实时监控仓储五大环节核心指标与异常状态</span>
|
|
|
- </h1>
|
|
|
- </div>
|
|
|
- <div class="header-right">
|
|
|
- <div class="system-time">{{ currentTime }}</div>
|
|
|
- <el-button size="small" class="btn-icon"><el-icon><Search /></el-icon></el-button>
|
|
|
- <el-button size="small" class="btn-icon"><el-icon><Bell /></el-icon></el-button>
|
|
|
- <el-button size="small" class="btn-icon"><el-icon><Setting /></el-icon></el-button>
|
|
|
- <el-button size="small" class="btn-export">
|
|
|
- <el-icon><Download /></el-icon>
|
|
|
- 导出数据集
|
|
|
- </el-button>
|
|
|
- <el-button size="small" type="primary" class="btn-sync">
|
|
|
- <el-icon><Refresh /></el-icon>
|
|
|
- 立即同步
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 仓储作业:日期、仓库、物料、工单(齐套/发运关联) -->
|
|
|
- <DetailQueryBar
|
|
|
- dark
|
|
|
- band-title="基础查询:日期、产品、订单号、产线"
|
|
|
- @query="onDetailQuery"
|
|
|
- @reset="onDetailQueryReset"
|
|
|
- >
|
|
|
- <SmartOpsBaseQueryFields v-model="detailQuery" compact />
|
|
|
+ <ModuleDashboardPage
|
|
|
+ module-code="S5"
|
|
|
+ title="S5 物料仓储详情"
|
|
|
+ left-title="物料仓储执行"
|
|
|
+ left-subtitle="收货 / 检验 / 上架 / 备货 / 发货 — 周期与人效"
|
|
|
+ right-title="物料仓储结果"
|
|
|
+ right-subtitle="各环节满足率与周转"
|
|
|
+ :extra-query-init="{ warehouse: '', material: '', workOrder: '' }"
|
|
|
+ >
|
|
|
+ <template #extra-fields="{ query }">
|
|
|
<el-form-item label="仓库">
|
|
|
- <el-input v-model="detailQuery.warehouse" placeholder="仓库/库区编码" clearable style="width: 140px" />
|
|
|
+ <el-input v-model="query.warehouse" placeholder="仓库编码/名称" clearable style="width: 150px" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="物料">
|
|
|
- <el-input v-model="detailQuery.material" placeholder="物料编码" clearable style="width: 140px" />
|
|
|
+ <el-input v-model="query.material" placeholder="物料编码(SKU)" clearable style="width: 150px" />
|
|
|
</el-form-item>
|
|
|
- <el-form-item label="工单号">
|
|
|
- <el-input v-model="detailQuery.workOrder" placeholder="生产/配送工单" clearable style="width: 160px" />
|
|
|
+ <el-form-item label="工单">
|
|
|
+ <el-input v-model="query.workOrder" placeholder="工单号" clearable style="width: 140px" />
|
|
|
</el-form-item>
|
|
|
- </DetailQueryBar>
|
|
|
-
|
|
|
- <!-- 第一行:4 个 KPI 卡片 -->
|
|
|
- <div class="row-1">
|
|
|
- <div class="kpi-card">
|
|
|
- <div class="kpi-header">
|
|
|
- <span class="kpi-label">物料上线周期</span>
|
|
|
- <el-icon :size="24"><Timer /></el-icon>
|
|
|
- </div>
|
|
|
- <div class="kpi-value">
|
|
|
- <span class="value">{{ homeS5.matchLeadTimeActualHrs }}</span>
|
|
|
- <span class="unit">Hrs</span>
|
|
|
- </div>
|
|
|
- <div class="kpi-trend down">
|
|
|
- <el-icon><ArrowDown /></el-icon>
|
|
|
- <span>{{ d(0, 12.5, 1) }}%</span>
|
|
|
- </div>
|
|
|
- <div class="kpi-bar warning">
|
|
|
- <div
|
|
|
- class="bar-fill"
|
|
|
- :style="{
|
|
|
- width: `${Math.min(100, (homeS5.matchLeadTimeTargetHrs / homeS5.matchLeadTimeActualHrs) * 100)}%`
|
|
|
- }"
|
|
|
- />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="kpi-card success">
|
|
|
- <div class="kpi-header">
|
|
|
- <span class="kpi-label">物料上线满足率</span>
|
|
|
- <el-icon :size="24"><CircleCheck /></el-icon>
|
|
|
- </div>
|
|
|
- <div class="kpi-value">
|
|
|
- <span class="value success">{{ homeS5.matchOnTimeActualPct }}</span>
|
|
|
- <span class="unit">%</span>
|
|
|
- </div>
|
|
|
- <div class="kpi-trend up">
|
|
|
- <el-icon><ArrowUp /></el-icon>
|
|
|
- <span>{{ d(1, 0.34, 2) }}%</span>
|
|
|
- </div>
|
|
|
- <div class="kpi-bar success">
|
|
|
- <div class="bar-fill" :style="{ width: `${homeS5.matchOnTimeActualPct}%` }"></div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="kpi-card">
|
|
|
- <div class="kpi-header">
|
|
|
- <span class="kpi-label">物料仓储人效</span>
|
|
|
- <el-icon :size="24"><User /></el-icon>
|
|
|
- </div>
|
|
|
- <div class="kpi-value">
|
|
|
- <span class="value">{{ homeS5.rawWarehouseHeadcount }}</span>
|
|
|
- <span class="unit subtle">人</span>
|
|
|
- </div>
|
|
|
- <div class="kpi-status">
|
|
|
- <el-icon><UserFilled /></el-icon>
|
|
|
- <span>Active</span>
|
|
|
- </div>
|
|
|
- <div class="kpi-bar danger">
|
|
|
- <div
|
|
|
- class="bar-fill"
|
|
|
- :style="{
|
|
|
- width: `${Math.min(100, (homeS5.rawWarehouseHeadcount / homeS5.rawWarehouseHeadcountTarget) * 100)}%`
|
|
|
- }"
|
|
|
- />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="kpi-card warning">
|
|
|
- <div class="kpi-header">
|
|
|
- <span class="kpi-label">物料库存周转</span>
|
|
|
- <el-icon :size="24"><Refresh /></el-icon>
|
|
|
- </div>
|
|
|
- <div class="kpi-value">
|
|
|
- <span class="value">{{ homeS5.materialInventoryTurnoverDays }}</span>
|
|
|
- <span class="unit">Days</span>
|
|
|
- </div>
|
|
|
- <div class="kpi-trend up">
|
|
|
- <el-icon><ArrowUp /></el-icon>
|
|
|
- <span>{{ d(2, 1.2, 1) }}d</span>
|
|
|
- </div>
|
|
|
- <div class="kpi-bar"><div class="bar-fill" :style="{ width: `${Math.min(100, (homeS5.materialInventoryTurnoverDays / 30) * 100)}%` }"></div></div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 第二行:两个图表 -->
|
|
|
- <div class="row-2">
|
|
|
- <div class="chart-card">
|
|
|
- <div class="card-header">
|
|
|
- <span class="card-title">
|
|
|
- <span class="title-line"></span>
|
|
|
- 7 日环节周期变化趋势
|
|
|
- </span>
|
|
|
- <div class="chart-legend">
|
|
|
- <span class="legend-item"><span class="legend-dot blue"></span>收货</span>
|
|
|
- <span class="legend-item"><span class="legend-dot red"></span>发货</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div id="trend-chart" class="chart-container"></div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="chart-card">
|
|
|
- <div class="card-header">
|
|
|
- <span class="card-title">
|
|
|
- <span class="title-line"></span>
|
|
|
- 子流程满足率对比分析
|
|
|
- </span>
|
|
|
- </div>
|
|
|
- <div id="radar-chart" class="radar-container"></div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 第三行:5 个流程卡片 -->
|
|
|
- <div class="row-3">
|
|
|
- <!-- 收货 -->
|
|
|
- <div class="process-card">
|
|
|
- <div class="process-header">
|
|
|
- <span class="process-title">
|
|
|
- <el-icon><Folder /></el-icon>
|
|
|
- 物料仓储(收货)
|
|
|
- </span>
|
|
|
- <el-tag size="small" :type="statusTypeByRate(Number(d(7, 94.5, 1)))">{{ statusTextByRate(Number(d(7, 94.5, 1))) }}</el-tag>
|
|
|
- </div>
|
|
|
- <div class="process-metrics">
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">1. 物料收货周期</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value">{{ d(3, 2.4, 1) }}</span>
|
|
|
- <span class="unit">h</span>
|
|
|
- <span class="trend down"><el-icon><ArrowDown /></el-icon>{{ t(0, '0.2h') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">2. 物料收货满足率</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value success">{{ homeS5.matchOnTimeActualPct }}</span>
|
|
|
- <span class="unit">%</span>
|
|
|
- <span class="trend">目标 {{ homeS5.matchOnTimeTargetPct }}%</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">3. 收货人效</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value">{{ d(4, 158, 0) }}</span>
|
|
|
- <span class="unit">P/H</span>
|
|
|
- <span class="trend up"><el-icon><ArrowUp /></el-icon>{{ t(1, '5%') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">4. 收货物料周转</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value">{{ d(5, 12.2, 1) }}</span>
|
|
|
- <span class="unit">x</span>
|
|
|
- <span class="trend stable">{{ t(2, '平稳') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- IQC -->
|
|
|
- <div class="process-card" :class="statusTypeByRate(Number(d(7, 94.5, 1))) === 'danger' ? 'danger-border' : statusTypeByRate(Number(d(7, 94.5, 1))) === 'warning' ? 'warning-border' : ''">
|
|
|
- <div class="process-header">
|
|
|
- <span class="process-title">
|
|
|
- <el-icon><Checked /></el-icon>
|
|
|
- 来料检验 (IQC)
|
|
|
- </span>
|
|
|
- <el-tag size="small" :type="statusTypeByRate(Number(d(7, 94.5, 1)))">{{ statusTextByRate(Number(d(7, 94.5, 1))) }}</el-tag>
|
|
|
- </div>
|
|
|
- <div class="process-metrics">
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">1. 物料检验周期</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value warning">{{ d(6, 4.8, 1) }}</span>
|
|
|
- <span class="unit">h</span>
|
|
|
- <span class="trend up"><el-icon><ArrowUp /></el-icon>{{ t(3, '1.2h') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">2. 物料检验合格率</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value">{{ d(7, 94.5, 1) }}</span>
|
|
|
- <span class="unit">%</span>
|
|
|
- <span class="trend down"><el-icon><ArrowDown /></el-icon>{{ t(4, '2.1%') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">3. 物料检验人效</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value">{{ d(8, 92, 0) }}</span>
|
|
|
- <span class="unit">P/H</span>
|
|
|
- <span class="trend up"><el-icon><ArrowUp /></el-icon>{{ t(5, '2%') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">4. 检验物料周转</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value">{{ d(9, 8.4, 1) }}</span>
|
|
|
- <span class="unit">x</span>
|
|
|
- <span class="trend down"><el-icon><ArrowDown /></el-icon>{{ t(6, '0.5') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 上架 -->
|
|
|
- <div class="process-card">
|
|
|
- <div class="process-header">
|
|
|
- <span class="process-title">
|
|
|
- <el-icon><Top /></el-icon>
|
|
|
- 物料仓储(上架)
|
|
|
- </span>
|
|
|
- <el-tag size="small" :type="statusTypeByRate(Number(d(11, 99.1, 1)))">{{ statusTextByRate(Number(d(11, 99.1, 1))) }}</el-tag>
|
|
|
- </div>
|
|
|
- <div class="process-metrics">
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">1. 物料上架周期</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value">{{ d(10, 1.2, 1) }}</span>
|
|
|
- <span class="unit">h</span>
|
|
|
- <span class="trend down"><el-icon><ArrowDown /></el-icon>{{ t(7, '0.4h') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">2. 物料上架满足率</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value success">{{ d(11, 99.1, 1) }}</span>
|
|
|
- <span class="unit">%</span>
|
|
|
- <span class="trend up"><el-icon><ArrowUp /></el-icon>{{ t(8, '0.4%') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">3. 物料上架人效</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value">{{ d(12, 210, 0) }}</span>
|
|
|
- <span class="unit">P/H</span>
|
|
|
- <span class="trend up"><el-icon><ArrowUp /></el-icon>{{ t(9, '8%') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">4. 上架物料周转</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value">{{ d(13, 15.4, 1) }}</span>
|
|
|
- <span class="unit">x</span>
|
|
|
- <span class="trend up"><el-icon><ArrowUp /></el-icon>{{ t(10, '2.1') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 备货 -->
|
|
|
- <div class="process-card">
|
|
|
- <div class="process-header">
|
|
|
- <span class="process-title">
|
|
|
- <el-icon><ShoppingBag /></el-icon>
|
|
|
- 物料仓储(备货)
|
|
|
- </span>
|
|
|
- <el-tag size="small" :type="statusTypeByRate(Number(d(15, 97.8, 1)))">{{ statusTextByRate(Number(d(15, 97.8, 1))) }}</el-tag>
|
|
|
- </div>
|
|
|
- <div class="process-metrics">
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">1. 物料备货周期</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value">{{ d(14, 5.2, 1) }}</span>
|
|
|
- <span class="unit">h</span>
|
|
|
- <span class="trend down"><el-icon><ArrowDown /></el-icon>{{ t(11, '0.5h') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">2. 物料备货满足率</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value success">{{ d(15, 97.8, 1) }}</span>
|
|
|
- <span class="unit">%</span>
|
|
|
- <span class="trend up"><el-icon><ArrowUp /></el-icon>{{ t(12, '0.7%') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">3. 物料备货人效</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value">{{ d(16, 114, 0) }}</span>
|
|
|
- <span class="unit">P/H</span>
|
|
|
- <span class="trend stable">{{ t(13, '持平') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">4. 备货物料周转</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value">{{ d(17, 9.6, 1) }}</span>
|
|
|
- <span class="unit">x</span>
|
|
|
- <span class="trend up"><el-icon><ArrowUp /></el-icon>{{ t(14, '0.3') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 发货 -->
|
|
|
- <div class="process-card" :class="statusTypeByRate(Number(d(19, 88.5, 1))) === 'danger' ? 'danger-border' : statusTypeByRate(Number(d(19, 88.5, 1))) === 'warning' ? 'warning-border' : ''">
|
|
|
- <div class="process-header">
|
|
|
- <span class="process-title">
|
|
|
- <el-icon><Van /></el-icon>
|
|
|
- 物料仓储(发货)
|
|
|
- </span>
|
|
|
- <el-tag size="small" :type="statusTypeByRate(Number(d(19, 88.5, 1)))">{{ statusTextByRate(Number(d(19, 88.5, 1))) }}</el-tag>
|
|
|
- </div>
|
|
|
- <div class="process-metrics">
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">1. 物料发货周期</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value danger">{{ d(18, 2.8, 1) }}</span>
|
|
|
- <span class="unit">d</span>
|
|
|
- <span class="trend up"><el-icon><ArrowUp /></el-icon>{{ t(15, '0.4d') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">2. 物料发货满足率</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value danger">{{ d(19, 88.5, 1) }}</span>
|
|
|
- <span class="unit">%</span>
|
|
|
- <span class="trend down"><el-icon><ArrowDown /></el-icon>{{ t(16, '4.2%') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">3. 物料发货人效</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value">{{ d(20, 2197, 0) }}</span>
|
|
|
- <span class="unit">人</span>
|
|
|
- <span class="trend up"><el-icon><ArrowUp /></el-icon>{{ t(17, '7%') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="metric-item">
|
|
|
- <span class="metric-label">4. 发货物料周转</span>
|
|
|
- <div class="metric-value">
|
|
|
- <span class="value">{{ d(21, 8.2, 1) }}</span>
|
|
|
- <span class="unit">x</span>
|
|
|
- <span class="trend down"><el-icon><ArrowDown /></el-icon>{{ t(18, '0.3') }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 右下角:辅助工具 -->
|
|
|
- <div class="tools-section">
|
|
|
- <div class="tools-header">
|
|
|
- <el-icon><Tools /></el-icon>
|
|
|
- <span>辅助工具</span>
|
|
|
- </div>
|
|
|
- <div class="tools-grid">
|
|
|
- <div class="tool-item">
|
|
|
- <el-icon><Document /></el-icon>
|
|
|
- <span>历史报告</span>
|
|
|
- </div>
|
|
|
- <div class="tool-item">
|
|
|
- <el-icon><Location /></el-icon>
|
|
|
- <span>库位导航</span>
|
|
|
- </div>
|
|
|
- <div class="tool-item">
|
|
|
- <el-icon><User /></el-icon>
|
|
|
- <span>人员调度</span>
|
|
|
- </div>
|
|
|
- <div class="tool-item warning">
|
|
|
- <el-icon><Warning /></el-icon>
|
|
|
- <span>风险预警</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ </template>
|
|
|
+ </ModuleDashboardPage>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { ref, onMounted, nextTick } from 'vue'
|
|
|
-import { useRouter } from 'vue-router'
|
|
|
-import { ElMessage } from 'element-plus'
|
|
|
-import DetailQueryBar from './components/DetailQueryBar.vue'
|
|
|
-import SmartOpsBaseQueryFields from './components/SmartOpsBaseQueryFields.vue'
|
|
|
-import { emptySmartOpsBaseQuery, summarizeSmartOpsBaseQuery } from './utils/smartOpsBaseQuery'
|
|
|
-import {
|
|
|
- ArrowLeft, Search, Bell, Setting, Download, Refresh,
|
|
|
- Timer, CircleCheck, User, UserFilled, Folder, Checked,
|
|
|
- Top, ShoppingBag, Van, Tools, Document, Location, Warning
|
|
|
-} from '@element-plus/icons-vue'
|
|
|
-import * as echarts from 'echarts'
|
|
|
-import { homeS5 } from './data/homeModulesSync'
|
|
|
-import { loadHomeModuleMetrics } from './data/homeModulesSync'
|
|
|
-import { fetchModuleDetail } from '../api/kanbanData'
|
|
|
-
|
|
|
-const router = useRouter()
|
|
|
-const currentTime = ref('')
|
|
|
-const trendXAxis = ref(['D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7'])
|
|
|
-const inboundTrend = ref([2.8, 2.6, 2.7, 2.5, 2.4, 2.4, 2.4])
|
|
|
-const outboundTrend = ref([1.8, 2.0, 2.2, 2.5, 2.6, 2.7, 2.8])
|
|
|
-const radarValues = ref([98.2, 88.5, 97.8, 99.1, 94.5])
|
|
|
-const detailNums = ref([12.5, 0.34, 1.2, 2.4, 158, 12.2, 4.8, 94.5, 92, 8.4, 1.2, 99.1, 210, 15.4, 5.2, 97.8, 114, 9.6, 2.8, 88.5, 2197, 8.2])
|
|
|
-const trendTexts = ref(['0.2h', '5%', '平稳', '1.2h', '2.1%', '2%', '0.5', '0.4h', '0.4%', '8%', '2.1', '0.5h', '0.7%', '持平', '0.3', '0.4d', '4.2%', '7%', '0.3'])
|
|
|
-
|
|
|
-const detailQuery = ref({
|
|
|
- ...emptySmartOpsBaseQuery(),
|
|
|
- warehouse: '',
|
|
|
- material: '',
|
|
|
- workOrder: '',
|
|
|
-})
|
|
|
-
|
|
|
-function onDetailQuery() {
|
|
|
- ElMessage.success(`已应用仓储筛选(${summarizeSmartOpsBaseQuery(detailQuery.value)})`)
|
|
|
-}
|
|
|
-
|
|
|
-function onDetailQueryReset() {
|
|
|
- detailQuery.value = { ...emptySmartOpsBaseQuery(), warehouse: '', material: '', workOrder: '' }
|
|
|
- ElMessage.info('已重置')
|
|
|
-}
|
|
|
-
|
|
|
-let trendChart = null
|
|
|
-let radarChart = null
|
|
|
-
|
|
|
-const updateTime = () => {
|
|
|
- currentTime.value = new Date().toLocaleString('zh-CN', {
|
|
|
- year: 'numeric',
|
|
|
- month: '2-digit',
|
|
|
- day: '2-digit',
|
|
|
- hour: '2-digit',
|
|
|
- minute: '2-digit',
|
|
|
- second: '2-digit',
|
|
|
- hour12: false
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-const d = (idx, fallback = 0, digits = 1) => {
|
|
|
- const n = Number(detailNums.value[idx] ?? fallback)
|
|
|
- return Number.isFinite(n) ? n.toFixed(digits) : Number(fallback).toFixed(digits)
|
|
|
-}
|
|
|
-const t = (idx, fallback = '-') => trendTexts.value[idx] ?? fallback
|
|
|
-const statusTypeByRate = (val, target = 95) => {
|
|
|
- if (val >= target) return 'success'
|
|
|
- if (val >= target - 5) return 'warning'
|
|
|
- return 'danger'
|
|
|
-}
|
|
|
-const statusTextByRate = (val, target = 95) => {
|
|
|
- if (val >= target) return '优秀'
|
|
|
- if (val >= target - 5) return '警告'
|
|
|
- return '严重'
|
|
|
-}
|
|
|
-
|
|
|
-const initTrendChart = () => {
|
|
|
- const chartDom = document.getElementById('trend-chart')
|
|
|
- if (!chartDom) return
|
|
|
-
|
|
|
- trendChart = echarts.init(chartDom)
|
|
|
- const option = {
|
|
|
- tooltip: {
|
|
|
- trigger: 'axis',
|
|
|
- backgroundColor: 'rgba(15, 23, 42, 0.95)',
|
|
|
- borderColor: '#334155',
|
|
|
- textStyle: { color: '#e2e8f0' }
|
|
|
- },
|
|
|
- legend: { show: false },
|
|
|
- grid: { left: '3%', right: '4%', bottom: '10%', top: '15%' },
|
|
|
- xAxis: {
|
|
|
- type: 'category',
|
|
|
- data: trendXAxis.value,
|
|
|
- axisLine: { lineStyle: { color: '#334155' } },
|
|
|
- axisLabel: { color: '#64748b' }
|
|
|
- },
|
|
|
- yAxis: {
|
|
|
- type: 'value',
|
|
|
- min: 0,
|
|
|
- max: 3,
|
|
|
- splitLine: { lineStyle: { color: '#1e293b' } },
|
|
|
- axisLabel: { color: '#64748b' }
|
|
|
- },
|
|
|
- series: [
|
|
|
- {
|
|
|
- name: '收货',
|
|
|
- type: 'line',
|
|
|
- smooth: true,
|
|
|
- symbol: 'circle',
|
|
|
- symbolSize: 6,
|
|
|
- itemStyle: { color: '#60a5fa' },
|
|
|
- lineStyle: { color: '#60a5fa', width: 2 },
|
|
|
- data: inboundTrend.value
|
|
|
- },
|
|
|
- {
|
|
|
- name: '发货',
|
|
|
- type: 'line',
|
|
|
- smooth: true,
|
|
|
- symbol: 'circle',
|
|
|
- symbolSize: 6,
|
|
|
- itemStyle: { color: '#f87171' },
|
|
|
- lineStyle: { color: '#f87171', width: 2 },
|
|
|
- data: outboundTrend.value
|
|
|
- }
|
|
|
- ]
|
|
|
- }
|
|
|
- trendChart.setOption(option)
|
|
|
-}
|
|
|
-
|
|
|
-const initRadarChart = () => {
|
|
|
- const chartDom = document.getElementById('radar-chart')
|
|
|
- if (!chartDom) return
|
|
|
-
|
|
|
- radarChart = echarts.init(chartDom)
|
|
|
- const option = {
|
|
|
- tooltip: {},
|
|
|
- radar: {
|
|
|
- indicator: [
|
|
|
- { name: '收货满足率', max: 100 },
|
|
|
- { name: '发货满足率', max: 100 },
|
|
|
- { name: '备货满足率', max: 100 },
|
|
|
- { name: '上架满足率', max: 100 },
|
|
|
- { name: '检验合格率', max: 100 }
|
|
|
- ],
|
|
|
- axisName: {
|
|
|
- color: '#94a3b8',
|
|
|
- fontSize: 11
|
|
|
- },
|
|
|
- splitLine: {
|
|
|
- lineStyle: { color: '#334155' }
|
|
|
- },
|
|
|
- splitArea: {
|
|
|
- areaStyle: { color: ['rgba(30, 41, 59, 0.5)', 'rgba(15, 23, 42, 0.5)'] }
|
|
|
- }
|
|
|
- },
|
|
|
- series: [{
|
|
|
- type: 'radar',
|
|
|
- data: [
|
|
|
- {
|
|
|
- value: radarValues.value,
|
|
|
- name: '子流程满足率',
|
|
|
- areaStyle: {
|
|
|
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
- { offset: 0, color: 'rgba(96, 165, 250, 0.5)' },
|
|
|
- { offset: 1, color: 'rgba(96, 165, 250, 0.1)' }
|
|
|
- ])
|
|
|
- },
|
|
|
- lineStyle: { color: '#60a5fa', width: 2 },
|
|
|
- itemStyle: { color: '#60a5fa' }
|
|
|
- }
|
|
|
- ]
|
|
|
- }]
|
|
|
- }
|
|
|
- radarChart.setOption(option)
|
|
|
-}
|
|
|
-
|
|
|
-const initCharts = () => {
|
|
|
- nextTick(() => {
|
|
|
- initTrendChart()
|
|
|
- initRadarChart()
|
|
|
-
|
|
|
- window.addEventListener('resize', () => {
|
|
|
- trendChart?.resize()
|
|
|
- radarChart?.resize()
|
|
|
- })
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-onMounted(async () => {
|
|
|
- await loadHomeModuleMetrics()
|
|
|
- const detail = await fetchModuleDetail('S5')
|
|
|
- const l2 = detail.l2 ?? []
|
|
|
- const l3 = detail.l3 ?? []
|
|
|
- const merged = [...l2, ...l3]
|
|
|
- if (l2.length > 0) {
|
|
|
- const vals = l2.slice(0, 7).map((x) => Number(x.metricValue ?? 0))
|
|
|
- trendXAxis.value = l2.slice(0, 7).map((x, i) => (x.statDate ? String(x.statDate).slice(5, 10) : `D${i + 1}`))
|
|
|
- inboundTrend.value = vals.map((v) => Number((v / 10).toFixed(1)))
|
|
|
- outboundTrend.value = [...inboundTrend.value].reverse()
|
|
|
- radarValues.value = l2.slice(0, 5).map((x) => Math.max(0, Math.min(100, Number(x.metricValue ?? 0))))
|
|
|
- }
|
|
|
- if (merged.length > 0) {
|
|
|
- detailNums.value = merged.slice(0, 22).map((x, i) => Number(x.metricValue ?? detailNums.value[i] ?? 0))
|
|
|
- }
|
|
|
- updateTime()
|
|
|
- setInterval(updateTime, 1000)
|
|
|
- initCharts()
|
|
|
-})
|
|
|
+import ModuleDashboardPage from './components/ModuleDashboardPage.vue'
|
|
|
</script>
|
|
|
-
|
|
|
-<style scoped>
|
|
|
-.s5-dashboard {
|
|
|
- box-sizing: border-box;
|
|
|
- flex: 1;
|
|
|
- min-height: 0;
|
|
|
- max-height: 100%;
|
|
|
- overflow-x: hidden;
|
|
|
- overflow-y: auto;
|
|
|
- -webkit-overflow-scrolling: touch;
|
|
|
- background: #0b0f19;
|
|
|
- padding: 20px;
|
|
|
- padding-bottom: 24px;
|
|
|
- color: #e2e8f0;
|
|
|
-}
|
|
|
-
|
|
|
-/* 顶部标题栏 */
|
|
|
-.top-header {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: flex-start;
|
|
|
- margin-bottom: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.header-left {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 8px;
|
|
|
-}
|
|
|
-
|
|
|
-.breadcrumb {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 10px;
|
|
|
- font-size: 12px;
|
|
|
- color: #64748b;
|
|
|
-}
|
|
|
-
|
|
|
-.back-icon {
|
|
|
- cursor: pointer;
|
|
|
- color: #60a5fa;
|
|
|
-}
|
|
|
-
|
|
|
-.back-icon:hover {
|
|
|
- color: #93c5fd;
|
|
|
-}
|
|
|
-
|
|
|
-.gold-tag {
|
|
|
- background: linear-gradient(135deg, #fbbf24, #f59e0b);
|
|
|
- border: none;
|
|
|
- color: white;
|
|
|
- font-size: 10px;
|
|
|
- padding: 2px 8px;
|
|
|
-}
|
|
|
-
|
|
|
-.page-title {
|
|
|
- margin: 0;
|
|
|
- font-size: 20px;
|
|
|
- font-weight: 700;
|
|
|
- color: #e2e8f0;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 4px;
|
|
|
-}
|
|
|
-
|
|
|
-.page-title .subtitle {
|
|
|
- font-size: 12px;
|
|
|
- font-weight: 400;
|
|
|
- color: #64748b;
|
|
|
-}
|
|
|
-
|
|
|
-.header-right {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.system-time {
|
|
|
- font-size: 12px;
|
|
|
- color: #64748b;
|
|
|
- margin-right: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.btn-icon {
|
|
|
- padding: 8px;
|
|
|
- background: rgba(51, 65, 85, 0.6);
|
|
|
- border: 1px solid #334155;
|
|
|
- color: #94a3b8;
|
|
|
-}
|
|
|
-
|
|
|
-.btn-export {
|
|
|
- background: rgba(51, 65, 85, 0.6);
|
|
|
- border: 1px solid #334155;
|
|
|
- color: #94a3b8;
|
|
|
-}
|
|
|
-
|
|
|
-.btn-sync {
|
|
|
- background: linear-gradient(135deg, #3b82f6, #2563eb);
|
|
|
- border: none;
|
|
|
-}
|
|
|
-
|
|
|
-/* 第一行 KPI */
|
|
|
-.row-1 {
|
|
|
- display: grid;
|
|
|
- grid-template-columns: repeat(4, 1fr);
|
|
|
- gap: 15px;
|
|
|
- margin-bottom: 15px;
|
|
|
-}
|
|
|
-
|
|
|
-.kpi-card {
|
|
|
- background: rgba(30, 41, 59, 0.4);
|
|
|
- border-radius: 8px;
|
|
|
- padding: 15px;
|
|
|
- border: 1px solid #1e293b;
|
|
|
-}
|
|
|
-
|
|
|
-.kpi-card.success {
|
|
|
- border-color: rgba(52, 211, 153, 0.5);
|
|
|
-}
|
|
|
-
|
|
|
-.kpi-card.warning {
|
|
|
- border-color: rgba(251, 191, 36, 0.5);
|
|
|
-}
|
|
|
-
|
|
|
-.kpi-header {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- margin-bottom: 12px;
|
|
|
- color: #94a3b8;
|
|
|
- font-size: 12px;
|
|
|
-}
|
|
|
-
|
|
|
-.kpi-value {
|
|
|
- display: flex;
|
|
|
- align-items: baseline;
|
|
|
- gap: 6px;
|
|
|
- margin-bottom: 8px;
|
|
|
-}
|
|
|
-
|
|
|
-.kpi-value .value {
|
|
|
- font-size: 32px;
|
|
|
- font-weight: 700;
|
|
|
- color: #e2e8f0;
|
|
|
-}
|
|
|
-
|
|
|
-.kpi-value .value.success { color: #34d399; }
|
|
|
-.kpi-value .value.warning { color: #fbbf24; }
|
|
|
-
|
|
|
-.kpi-value .unit {
|
|
|
- font-size: 12px;
|
|
|
- color: #64748b;
|
|
|
-}
|
|
|
-
|
|
|
-.kpi-trend {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 4px;
|
|
|
- font-size: 11px;
|
|
|
- font-weight: 600;
|
|
|
- margin-bottom: 8px;
|
|
|
-}
|
|
|
-
|
|
|
-.kpi-trend.up { color: #34d399; }
|
|
|
-.kpi-trend.down { color: #34d399; }
|
|
|
-
|
|
|
-.kpi-status {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 6px;
|
|
|
- font-size: 11px;
|
|
|
- color: #60a5fa;
|
|
|
- margin-bottom: 8px;
|
|
|
-}
|
|
|
-
|
|
|
-.kpi-bar {
|
|
|
- height: 3px;
|
|
|
- background: #1e293b;
|
|
|
- border-radius: 2px;
|
|
|
- overflow: hidden;
|
|
|
-}
|
|
|
-
|
|
|
-.kpi-bar .bar-fill {
|
|
|
- height: 100%;
|
|
|
- background: linear-gradient(90deg, #60a5fa, #3b82f6);
|
|
|
- border-radius: 2px;
|
|
|
-}
|
|
|
-
|
|
|
-.kpi-bar.success .bar-fill { background: linear-gradient(90deg, #34d399, #10b981); }
|
|
|
-.kpi-bar.warning .bar-fill { background: linear-gradient(90deg, #fbbf24, #f59e0b); }
|
|
|
-.kpi-bar.danger .bar-fill { background: linear-gradient(90deg, #ef4444, #dc2626); }
|
|
|
-
|
|
|
-/* 第二行图表 */
|
|
|
-.row-2 {
|
|
|
- display: grid;
|
|
|
- grid-template-columns: 1fr 1fr;
|
|
|
- gap: 15px;
|
|
|
- margin-bottom: 15px;
|
|
|
-}
|
|
|
-
|
|
|
-.chart-card {
|
|
|
- background: rgba(30, 41, 59, 0.4);
|
|
|
- border-radius: 8px;
|
|
|
- padding: 15px;
|
|
|
- border: 1px solid #1e293b;
|
|
|
-}
|
|
|
-
|
|
|
-.card-header {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- margin-bottom: 15px;
|
|
|
-}
|
|
|
-
|
|
|
-.card-title {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 8px;
|
|
|
- font-size: 13px;
|
|
|
- font-weight: 700;
|
|
|
- color: #e2e8f0;
|
|
|
-}
|
|
|
-
|
|
|
-.title-line {
|
|
|
- width: 4px;
|
|
|
- height: 16px;
|
|
|
- background: #60a5fa;
|
|
|
- border-radius: 2px;
|
|
|
-}
|
|
|
-
|
|
|
-.chart-legend {
|
|
|
- display: flex;
|
|
|
- gap: 15px;
|
|
|
- font-size: 12px;
|
|
|
- color: #94a3b8;
|
|
|
-}
|
|
|
-
|
|
|
-.legend-item {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 6px;
|
|
|
-}
|
|
|
-
|
|
|
-.legend-dot {
|
|
|
- width: 8px;
|
|
|
- height: 8px;
|
|
|
- border-radius: 50%;
|
|
|
-}
|
|
|
-
|
|
|
-.legend-dot.blue { background: #60a5fa; }
|
|
|
-.legend-dot.red { background: #f87171; }
|
|
|
-
|
|
|
-.chart-container {
|
|
|
- width: 100%;
|
|
|
- height: 280px;
|
|
|
-}
|
|
|
-
|
|
|
-.radar-container {
|
|
|
- width: 100%;
|
|
|
- height: 280px;
|
|
|
-}
|
|
|
-
|
|
|
-/* 第三行流程卡片 */
|
|
|
-.row-3 {
|
|
|
- display: grid;
|
|
|
- grid-template-columns: repeat(5, 1fr);
|
|
|
- gap: 12px;
|
|
|
- margin-bottom: 15px;
|
|
|
-}
|
|
|
-
|
|
|
-.process-card {
|
|
|
- background: rgba(30, 41, 59, 0.4);
|
|
|
- border-radius: 8px;
|
|
|
- padding: 12px;
|
|
|
- border: 1px solid #1e293b;
|
|
|
-}
|
|
|
-
|
|
|
-.process-card.warning-border {
|
|
|
- border-color: rgba(251, 191, 36, 0.5);
|
|
|
-}
|
|
|
-
|
|
|
-.process-card.danger-border {
|
|
|
- border-color: rgba(239, 68, 68, 0.5);
|
|
|
-}
|
|
|
-
|
|
|
-.process-header {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- margin-bottom: 12px;
|
|
|
- padding-bottom: 10px;
|
|
|
- border-bottom: 1px solid #1e293b;
|
|
|
-}
|
|
|
-
|
|
|
-.process-title {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 6px;
|
|
|
- font-size: 12px;
|
|
|
- font-weight: 700;
|
|
|
- color: #e2e8f0;
|
|
|
-}
|
|
|
-
|
|
|
-.process-metrics {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.metric-item {
|
|
|
- padding: 8px;
|
|
|
- background: rgba(15, 23, 42, 0.5);
|
|
|
- border-radius: 4px;
|
|
|
-}
|
|
|
-
|
|
|
-.metric-label {
|
|
|
- display: block;
|
|
|
- font-size: 11px;
|
|
|
- color: #64748b;
|
|
|
- margin-bottom: 6px;
|
|
|
-}
|
|
|
-
|
|
|
-.metric-value {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 6px;
|
|
|
-}
|
|
|
-
|
|
|
-.metric-value .value {
|
|
|
- font-size: 16px;
|
|
|
- font-weight: 700;
|
|
|
- color: #e2e8f0;
|
|
|
-}
|
|
|
-
|
|
|
-.metric-value .value.success { color: #34d399; }
|
|
|
-.metric-value .value.warning { color: #fbbf24; }
|
|
|
-.metric-value .value.danger { color: #ef4444; }
|
|
|
-
|
|
|
-.metric-value .unit {
|
|
|
- font-size: 10px;
|
|
|
- color: #64748b;
|
|
|
-}
|
|
|
-
|
|
|
-.metric-value .trend {
|
|
|
- font-size: 10px;
|
|
|
- font-weight: 600;
|
|
|
- margin-left: auto;
|
|
|
-}
|
|
|
-
|
|
|
-.metric-value .trend.up { color: #34d399; }
|
|
|
-.metric-value .trend.down { color: #ef4444; }
|
|
|
-.metric-value .trend.stable { color: #64748b; }
|
|
|
-
|
|
|
-/* 辅助工具 */
|
|
|
-.tools-section {
|
|
|
- position: fixed;
|
|
|
- bottom: 20px;
|
|
|
- right: 20px;
|
|
|
- background: rgba(30, 41, 59, 0.8);
|
|
|
- border-radius: 8px;
|
|
|
- padding: 15px;
|
|
|
- border: 1px solid #1e293b;
|
|
|
- min-width: 280px;
|
|
|
-}
|
|
|
-
|
|
|
-.tools-header {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 8px;
|
|
|
- font-size: 13px;
|
|
|
- font-weight: 700;
|
|
|
- color: #e2e8f0;
|
|
|
- margin-bottom: 12px;
|
|
|
- padding-bottom: 10px;
|
|
|
- border-bottom: 1px solid #1e293b;
|
|
|
-}
|
|
|
-
|
|
|
-.tools-grid {
|
|
|
- display: grid;
|
|
|
- grid-template-columns: repeat(2, 1fr);
|
|
|
- gap: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.tool-item {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- gap: 6px;
|
|
|
- padding: 12px;
|
|
|
- background: rgba(15, 23, 42, 0.5);
|
|
|
- border-radius: 6px;
|
|
|
- cursor: pointer;
|
|
|
- transition: all 0.3s;
|
|
|
- border: 1px solid transparent;
|
|
|
-}
|
|
|
-
|
|
|
-.tool-item:hover {
|
|
|
- background: rgba(96, 165, 250, 0.1);
|
|
|
- border-color: #60a5fa;
|
|
|
-}
|
|
|
-
|
|
|
-.tool-item.warning {
|
|
|
- color: #fbbf24;
|
|
|
-}
|
|
|
-
|
|
|
-.tool-item.warning:hover {
|
|
|
- background: rgba(251, 191, 36, 0.1);
|
|
|
- border-color: #fbbf24;
|
|
|
-}
|
|
|
-
|
|
|
-.tool-item .el-icon {
|
|
|
- font-size: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.tool-item span {
|
|
|
- font-size: 11px;
|
|
|
-}
|
|
|
-
|
|
|
-/* Element Plus 覆盖 */
|
|
|
-:deep(.el-button--small) {
|
|
|
- padding: 8px 16px;
|
|
|
- font-size: 12px;
|
|
|
-}
|
|
|
-
|
|
|
-:deep(.el-tag) {
|
|
|
- font-size: 10px;
|
|
|
- padding: 2px 8px;
|
|
|
- border-radius: 4px;
|
|
|
-}
|
|
|
-
|
|
|
-:deep(.el-tag--success) {
|
|
|
- background: rgba(52, 211, 153, 0.2);
|
|
|
- border-color: rgba(52, 211, 153, 0.3);
|
|
|
- color: #34d399;
|
|
|
-}
|
|
|
-
|
|
|
-:deep(.el-tag--warning) {
|
|
|
- background: rgba(251, 191, 36, 0.2);
|
|
|
- border-color: rgba(251, 191, 36, 0.3);
|
|
|
- color: #fbbf24;
|
|
|
-}
|
|
|
-
|
|
|
-:deep(.el-tag--danger) {
|
|
|
- background: rgba(239, 68, 68, 0.2);
|
|
|
- border-color: rgba(239, 68, 68, 0.3);
|
|
|
- color: #ef4444;
|
|
|
-}
|
|
|
-</style>
|