style:dashBoard1数据大屏适配中英文

main
黄伟杰 4 days ago
parent 13d157fa72
commit 39bfd8a2e9

@ -99,165 +99,6 @@ export default {
messageRouteMissing: 'Preview route is not configured', messageRouteMissing: 'Preview route is not configured',
messageDevicePointRequired: 'Please configure at least one device and point group', messageDevicePointRequired: 'Please configure at least one device and point group',
messageMissingId: 'Missing record ID, unable to edit' messageMissingId: 'Missing record ID, unable to edit'
},
Dashboard1: {
header: {
title: 'Production Line Dashboard',
weather: {
cloudyToClear: 'Cloudy to clear'
},
weekDays: {
Sunday: 'Sunday',
Monday: 'Monday',
Tuesday: 'Tuesday',
Wednesday: 'Wednesday',
Thursday: 'Thursday',
Friday: 'Friday',
Saturday: 'Saturday'
}
},
deviceIdPrefix: 'ID:',
defaultDeviceName: 'Default Device',
statusOffline: 'Offline',
statusRunning: 'Running',
statusStandby: 'Standby',
statusFault: 'Fault',
deviceOverview: {
title: 'Device Overview',
device: 'Devices',
running: 'Running',
idle: 'Standby',
alarm: 'Alarms',
utilization: 'Utilization',
faultRate: 'Fault Rate'
},
alarms: {
title: 'Real-time Alarms',
tag: 'Scrolling',
levelSevere: 'Severe',
levelWarn: 'Warning',
levelInfo: 'Info'
},
productionTrend: {
title: 'Output Trend',
tagToday: 'Today',
seriesOutput: 'Output'
},
eventReminder: {
title: 'Event Reminder',
modeDevice: 'Device',
modeMold: 'Mold',
check: 'Inspection',
maintain: 'Maintenance',
repair: 'Repair'
},
taskList: {
title: 'Task List',
columns: {
code: 'Code',
name: 'Name',
type: 'Type',
finishStatus: 'Completion',
result: 'Result'
},
finishPending: 'Pending',
finishDone: 'Completed',
finishCanceled: 'Canceled',
resultPass: 'Pass',
resultFail: 'Fail'
},
energyMonitor: {
title: 'Energy Monitor',
selectPlaceholder: 'Please select',
seriesEnergy: 'Energy'
}
}
},
Dashboard8: {
Header: {
title: 'Smart Manufacturing Line Task Overview',
subTitle: 'INTELLIGENT MANUFACTURING REAL-TIME DASHBOARD'
},
TaskBoard: {
title: 'Line Task Board',
tag: 'Auto refresh · Scrolling',
statusCompleted: 'Completed',
statusLowProgress: 'Behind',
columns: {
lineName: 'Line',
planNo: 'Plan No.',
productName: 'Product',
planQty: 'Planned',
doneQty: 'Completed',
passRate: 'Pass Rate'
}
},
DayCapacity: {
title: 'Daily Capacity',
tag: 'Today',
metrics: {
orders: 'Orders',
scheduled: 'Scheduled',
produced: 'Produced',
rate: 'Quality Rate'
},
chart: {
scheduled: 'Scheduled',
produced: 'Produced'
}
},
MonthCapacity: {
title: 'Monthly Capacity',
tag: 'This month',
metrics: {
orders: 'Orders',
scheduled: 'Scheduled',
produced: 'Produced',
rate: 'Quality Rate'
},
chart: {
scheduled: 'Scheduled',
produced: 'Produced'
}
},
WeekTrend: {
title: 'Weekly Output Trend',
legendOutput: 'Output',
legendPlan: 'Plan',
seriesPlanOutput: 'Planned Output',
seriesActualOutput: 'Actual Output'
},
OpsTrend: {
title: 'Completed Output',
defaultLine: 'All lines',
yAxisName: 'Completed Output',
seriesName: 'Completed Output',
summary: '{line} · Avg {value}'
},
TodayOps: {
title: 'Today Power/Utilization',
empty: 'No data',
powerOnRate: 'Power-on Rate',
utilizationRate: 'Utilization'
},
QualityTrend: {
title: 'Product Quality Trend',
tag: 'Daily (All lines)',
seriesName: 'Pass Rate',
markLineAverage: 'Avg {value}%',
markLineAverageName: 'Average'
},
RealAlarm: {
title: 'Real-time Alarms',
tag: 'Scrolling',
levelSevere: 'Severe',
levelWarn: 'Warning',
levelInfo: 'Info'
},
EnergyTrend: {
title: 'Weekly Energy Trend',
selectPlaceholder: 'Please select',
seriesActualEnergy: 'Actual Energy (kWh)'
} }
}, },
ErpStock: { ErpStock: {
@ -3964,6 +3805,8 @@ export default {
dialogCollectionTimeLabel: 'Collection Time', dialogCollectionTimeLabel: 'Collection Time',
dialogCollectionTimeStartPlaceholder: 'Start Time', dialogCollectionTimeStartPlaceholder: 'Start Time',
dialogCollectionTimeEndPlaceholder: 'End Time', dialogCollectionTimeEndPlaceholder: 'End Time',
dialogPointFilterLabel: 'Point Filter',
dialogPointFilterPlaceholder: 'Please select points',
dialogSearchButtonText: 'Search', dialogSearchButtonText: 'Search',
dialogResetButtonText: 'Reset', dialogResetButtonText: 'Reset',
dialogRecordCollectionTimePrefix: 'Collection Time: ', dialogRecordCollectionTimePrefix: 'Collection Time: ',

@ -99,165 +99,6 @@ export default {
messageRouteMissing: '未配置预览路由', messageRouteMissing: '未配置预览路由',
messageDevicePointRequired: '请至少配置一组设备和点位', messageDevicePointRequired: '请至少配置一组设备和点位',
messageMissingId: '缺少数据编号,无法编辑' messageMissingId: '缺少数据编号,无法编辑'
},
Dashboard1: {
header: {
title: '产线运行看板',
weather: {
cloudyToClear: '多云转晴'
},
weekDays: {
Sunday: '星期日',
Monday: '星期一',
Tuesday: '星期二',
Wednesday: '星期三',
Thursday: '星期四',
Friday: '星期五',
Saturday: '星期六'
}
},
deviceIdPrefix: 'ID:',
defaultDeviceName: '默认设备',
statusOffline: '离线',
statusRunning: '运行',
statusStandby: '待机',
statusFault: '故障',
deviceOverview: {
title: '设备概况',
device: '设备数量',
running: '运行数量',
idle: '待机数量',
alarm: '报警数量',
utilization: '稼动率',
faultRate: '故障率'
},
alarms: {
title: '实时报警信息',
tag: '滚动展示',
levelSevere: '严重',
levelWarn: '警告',
levelInfo: '提示'
},
productionTrend: {
title: '产量趋势',
tagToday: '今日',
seriesOutput: '产量'
},
eventReminder: {
title: '事件提醒',
modeDevice: '设备',
modeMold: '模具',
check: '点检',
maintain: '保养',
repair: '维修'
},
taskList: {
title: '任务列表',
columns: {
code: '编号',
name: '名称',
type: '类型',
finishStatus: '完成状态',
result: '结果'
},
finishPending: '待完成',
finishDone: '已完成',
finishCanceled: '已取消',
resultPass: '通过',
resultFail: '不通过'
},
energyMonitor: {
title: '能耗监测',
selectPlaceholder: '请选择',
seriesEnergy: '能耗'
}
}
},
Dashboard8: {
Header: {
title: '智能制造产线任务总览',
subTitle: '智能制造实时看板'
},
TaskBoard: {
title: '产线任务看板',
tag: '实时刷新 · 滚动展示',
statusCompleted: '已完成',
statusLowProgress: '进度偏低',
columns: {
lineName: '产线名称',
planNo: '计划单',
productName: '产品名称',
planQty: '计划数量',
doneQty: '完工数量',
passRate: '合格率'
}
},
DayCapacity: {
title: '日产能达成情况',
tag: '当日维度',
metrics: {
orders: '排产单数量',
scheduled: '已排产数量',
produced: '已生产数量',
rate: '产能合格率'
},
chart: {
scheduled: '已排产',
produced: '已生产'
}
},
MonthCapacity: {
title: '月产能达成情况',
tag: '当月累计',
metrics: {
orders: '排产单数量',
scheduled: '已排产数量',
produced: '已生产数量',
rate: '产能合格率'
},
chart: {
scheduled: '已排产',
produced: '已生产'
}
},
WeekTrend: {
title: '周生产趋势',
legendOutput: '产量',
legendPlan: '计划',
seriesPlanOutput: '计划产量',
seriesActualOutput: '实际产量'
},
OpsTrend: {
title: '产能完成数',
defaultLine: '全部产线',
yAxisName: '产能完成数',
seriesName: '产能完成数',
summary: '{line} · 日均完成 {value}'
},
TodayOps: {
title: '今日开机率/稼动率',
empty: '暂无数据',
powerOnRate: '开机率',
utilizationRate: '稼动率'
},
QualityTrend: {
title: '成品检合格率趋势图',
tag: '按天统计(全产线)',
seriesName: '合格率',
markLineAverage: '平均 {value}%',
markLineAverageName: '平均值'
},
RealAlarm: {
title: '实时报警信息',
tag: '滚动展示',
levelSevere: '严重',
levelWarn: '警告',
levelInfo: '提示'
},
EnergyTrend: {
title: '能耗周趋势',
selectPlaceholder: '请选择',
seriesActualEnergy: '实际能耗(kWh)'
} }
}, },
ErpStock: { ErpStock: {
@ -3808,6 +3649,8 @@ export default {
dialogCollectionTimeLabel: '采集时间', dialogCollectionTimeLabel: '采集时间',
dialogCollectionTimeStartPlaceholder: '开始时间', dialogCollectionTimeStartPlaceholder: '开始时间',
dialogCollectionTimeEndPlaceholder: '结束时间', dialogCollectionTimeEndPlaceholder: '结束时间',
dialogPointFilterLabel: '点位筛选',
dialogPointFilterPlaceholder: '请选择点位',
dialogSearchButtonText: '查询', dialogSearchButtonText: '查询',
dialogResetButtonText: '重置', dialogResetButtonText: '重置',
dialogRecordCollectionTimePrefix: '采集时间:', dialogRecordCollectionTimePrefix: '采集时间:',

@ -43,7 +43,7 @@
filter="url(#frameGlow)" filter="url(#frameGlow)"
/> />
</svg> </svg>
<div class="title">{{ t('Dashboard1.header.title') }}</div> <div class="title">产线运行看板</div>
</div> </div>
</div> </div>
<div class="header-right"> <div class="header-right">
@ -64,17 +64,13 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue' import { ref, onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useI18n } from '@/hooks/web/useI18n'
import { useLocaleStore } from '@/store/modules/locale'
const router = useRouter() const router = useRouter()
const { t } = useI18n('ReportDashboard')
const localeStore = useLocaleStore()
const timeStr = ref('') const timeStr = ref('')
const dateStr = ref('') const dateStr = ref('')
const weather = ref({ temp: '27°C', desc: t('Dashboard1.header.weather.cloudyToClear') }) const weather = ref({ temp: '27°C', desc: 'Cloudy to clear' })
let timer: number | undefined let timer: number | undefined
const goBack = () => { const goBack = () => {
@ -91,9 +87,8 @@ const updateTime = () => {
const y = d.getFullYear() const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0') const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0') const day = String(d.getDate()).padStart(2, '0')
const weekKeys = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] const weekMap = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
const weekKey = weekKeys[d.getDay()] || 'Sunday' dateStr.value = `${weekMap[d.getDay()]}, ${y}-${m}-${day}`
dateStr.value = `${t(`Dashboard1.header.weekDays.${weekKey}`)}, ${y}-${m}-${day}`
} }
onMounted(() => { onMounted(() => {
@ -101,14 +96,6 @@ onMounted(() => {
timer = window.setInterval(updateTime, 1000) timer = window.setInterval(updateTime, 1000)
}) })
watch(
() => localeStore.getCurrentLocale.lang,
() => {
weather.value.desc = t('Dashboard1.header.weather.cloudyToClear')
updateTime()
}
)
onUnmounted(() => { onUnmounted(() => {
if (timer) clearInterval(timer) if (timer) clearInterval(timer)
}) })

@ -2,7 +2,7 @@
<div class="card"> <div class="card">
<div class="panel-title"> <div class="panel-title">
<span class="title-dot"></span> <span class="title-dot"></span>
<span>{{ t('Dashboard1.deviceOverview.title') }}</span> <span>设备概况</span>
</div> </div>
<div class="panel-body overview-body"> <div class="panel-body overview-body">
<div v-for="item in overviewItems" :key="item.key" class="gauge-item"> <div v-for="item in overviewItems" :key="item.key" class="gauge-item">
@ -18,12 +18,10 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, watch } from 'vue' import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { colors } from '../utils' import { colors } from '../utils'
import { DashboardApi } from '@/api/dashboard' import { DashboardApi } from '@/api/dashboard'
import { useI18n } from '@/hooks/web/useI18n'
import { useLocaleStore } from '@/store/modules/locale'
type OverviewItemKey = 'device' | 'running' | 'idle' | 'alarm' | 'utilization' | 'faultRate' type OverviewItemKey = 'device' | 'running' | 'idle' | 'alarm' | 'utilization' | 'faultRate'
@ -37,25 +35,14 @@ interface OverviewItem {
const route = useRoute() const route = useRoute()
const orgId = route.query.orgId const orgId = route.query.orgId
const { t } = useI18n('ReportDashboard')
const localeStore = useLocaleStore()
const getLabel = (key: OverviewItemKey) => {
if (key === 'device') return t('Dashboard1.deviceOverview.device')
if (key === 'running') return t('Dashboard1.deviceOverview.running')
if (key === 'idle') return t('Dashboard1.deviceOverview.idle')
if (key === 'alarm') return t('Dashboard1.deviceOverview.alarm')
if (key === 'utilization') return t('Dashboard1.deviceOverview.utilization')
return t('Dashboard1.deviceOverview.faultRate')
}
const overviewItems = ref<OverviewItem[]>([ const overviewItems = ref<OverviewItem[]>([
{ key: 'device', label: getLabel('device'), value: '0', percent: 0, color: colors.cyan }, { key: 'device', label: '设备数量', value: '0', percent: 0, color: colors.cyan },
{ key: 'running', label: getLabel('running'), value: '0', percent: 0, color: colors.blue }, { key: 'running', label: '运行数量', value: '0', percent: 0, color: colors.blue },
{ key: 'idle', label: getLabel('idle'), value: '0', percent: 0, color: colors.warn }, { key: 'idle', label: '待机数量', value: '0', percent: 0, color: colors.warn },
{ key: 'alarm', label: getLabel('alarm'), value: '0', percent: 0, color: colors.danger }, { key: 'alarm', label: '报警数量', value: '0', percent: 0, color: colors.danger },
{ key: 'utilization', label: getLabel('utilization'), value: '0%', percent: 0, color: colors.green }, { key: 'utilization', label: '稼动率', value: '0%', percent: 0, color: colors.green },
{ key: 'faultRate', label: getLabel('faultRate'), value: '0%', percent: 0, color: colors.purple } { key: 'faultRate', label: '故障率', value: '0%', percent: 0, color: colors.purple }
]) ])
const getGaugeStyle = (percent: number, color: string) => { const getGaugeStyle = (percent: number, color: string) => {
@ -68,8 +55,7 @@ const getGaugeStyle = (percent: number, color: string) => {
const formatNumber = (value: number | string | undefined | null) => { const formatNumber = (value: number | string | undefined | null) => {
const n = Number(value ?? 0) const n = Number(value ?? 0)
if (!Number.isFinite(n)) return '0' if (!Number.isFinite(n)) return '0'
const lang = localeStore.getCurrentLocale.lang return n.toLocaleString('zh-CN')
return n.toLocaleString(lang === 'zh-CN' ? 'zh-CN' : 'en-US')
} }
const calcPercent = (part: number, total: number) => { const calcPercent = (part: number, total: number) => {
@ -151,14 +137,6 @@ const loadOverview = async () => {
onMounted(() => { onMounted(() => {
loadOverview() loadOverview()
}) })
watch(
() => localeStore.getCurrentLocale.lang,
() => {
overviewItems.value = overviewItems.value.map((item) => ({ ...item, label: getLabel(item.key) }))
loadOverview()
}
)
</script> </script>
<style scoped> <style scoped>

@ -3,11 +3,11 @@
<div class="panel-title panel-title-between"> <div class="panel-title panel-title-between">
<div class="panel-title-left"> <div class="panel-title-left">
<span class="title-dot"></span> <span class="title-dot"></span>
<span>{{ t('Dashboard1.energyMonitor.title') }}</span> <span>能耗监测</span>
</div> </div>
<div class="tabs"> <div class="tabs">
<el-select <el-select
v-model="selectedEnergyTypeId" :placeholder="t('Dashboard1.energyMonitor.selectPlaceholder')" style="width: 120px" size="small" v-model="selectedEnergyTypeId" placeholder="请选择" style="width: 120px" size="small"
@change="getChartData"> @change="getChartData">
<el-option v-for="item in energyTypes" :key="item.id" :label="item.name" :value="item.id" /> <el-option v-for="item in energyTypes" :key="item.id" :label="item.name" :value="item.id" />
</el-select> </el-select>
@ -20,19 +20,15 @@ v-model="selectedEnergyTypeId" :placeholder="t('Dashboard1.energyMonitor.selectP
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, onUnmounted, ref, watch } from 'vue' import { onMounted, onUnmounted, ref } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { colors, style } from '../utils' import { colors, style } from '../utils'
import { EnergyTypeApi, EnergyTypeVO } from '@/api/mes/energytype' import { EnergyTypeApi, EnergyTypeVO } from '@/api/mes/energytype'
import { EnergyDeviceApi } from '@/api/mes/energydevice' import { EnergyDeviceApi } from '@/api/mes/energydevice'
import { useI18n } from '@/hooks/web/useI18n'
import { useLocaleStore } from '@/store/modules/locale'
const route = useRoute() const route = useRoute()
const orgId = route.query.orgId const orgId = route.query.orgId
const { t } = useI18n('ReportDashboard')
const localeStore = useLocaleStore()
const energyTypes = ref<EnergyTypeVO[]>([]) const energyTypes = ref<EnergyTypeVO[]>([])
const selectedEnergyTypeId = ref<number | undefined>(undefined) const selectedEnergyTypeId = ref<number | undefined>(undefined)
@ -66,31 +62,6 @@ const getChartData = async () => {
} }
} }
const buildOption = (x: string[], y: number[]) => {
return {
backgroundColor: 'transparent',
tooltip: { trigger: 'axis' },
grid: { top: '18%', left: '6%', right: '4%', bottom: '12%', containLabel: true },
xAxis: { type: 'category', data: x, axisLine: style.axisLine, axisLabel: { ...style.axisLabel, fontSize: 10, rotate: 40 } },
yAxis: { type: 'value', axisLine: { show: false }, axisLabel: { ...style.axisLabel, fontSize: 10 }, splitLine: style.splitLine },
series: [
{
name: t('Dashboard1.energyMonitor.seriesEnergy'),
type: 'bar',
barWidth: 12,
itemStyle: {
borderRadius: [6, 6, 0, 0],
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: colors.blue },
{ offset: 1, color: 'rgba(30,144,255,0.10)' }
])
},
data: y
}
]
}
}
const render = (data: any = []) => { const render = (data: any = []) => {
if (!chart) return if (!chart) return
@ -118,7 +89,27 @@ const render = (data: any = []) => {
y = [] y = []
} }
chart.setOption(buildOption(x, y)) chart.setOption({
backgroundColor: 'transparent',
tooltip: { trigger: 'axis' },
grid: { top: '18%', left: '6%', right: '4%', bottom: '12%', containLabel: true },
xAxis: { type: 'category', data: x, axisLine: style.axisLine, axisLabel: { ...style.axisLabel, fontSize: 10, rotate: 40 } },
yAxis: { type: 'value', axisLine: { show: false }, axisLabel: { ...style.axisLabel, fontSize: 10 }, splitLine: style.splitLine },
series: [
{
type: 'bar',
barWidth: 12,
itemStyle: {
borderRadius: [6, 6, 0, 0],
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: colors.blue },
{ offset: 1, color: 'rgba(30,144,255,0.10)' }
])
},
data: y
}
]
})
} }
const resize = () => { const resize = () => {
@ -128,19 +119,13 @@ const resize = () => {
onMounted(() => { onMounted(() => {
if (!chartRef.value) return if (!chartRef.value) return
chart = echarts.init(chartRef.value, 'dark', { renderer: 'canvas' }) chart = echarts.init(chartRef.value, 'dark', { renderer: 'canvas' })
chart.setOption(buildOption([], [])) //
render([])
// //
getEnergyTypes() getEnergyTypes()
window.addEventListener('resize', resize) window.addEventListener('resize', resize)
}) })
watch(
() => localeStore.getCurrentLocale.lang,
() => {
getChartData()
}
)
onUnmounted(() => { onUnmounted(() => {
window.removeEventListener('resize', resize) window.removeEventListener('resize', resize)
chart?.dispose() chart?.dispose()

@ -3,12 +3,12 @@
<div class="panel-title"> <div class="panel-title">
<div class="panel-title-left"> <div class="panel-title-left">
<span class="title-dot"></span> <span class="title-dot"></span>
<span>{{ t('Dashboard1.eventReminder.title') }}</span> <span>事件提醒</span>
</div> </div>
<div class="panel-title-right"> <div class="panel-title-right">
<el-radio-group v-model="mode" size="small"> <el-radio-group v-model="mode" size="small">
<el-radio-button label="device">{{ t('Dashboard1.eventReminder.modeDevice') }}</el-radio-button> <el-radio-button label="device">设备</el-radio-button>
<el-radio-button label="mold">{{ t('Dashboard1.eventReminder.modeMold') }}</el-radio-button> <el-radio-button label="mold">模具</el-radio-button>
</el-radio-group> </el-radio-group>
</div> </div>
</div> </div>
@ -37,8 +37,6 @@ import { useRoute } from 'vue-router'
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { DashboardApi, TaskStatisticsData } from '@/api/dashboard' import { DashboardApi, TaskStatisticsData } from '@/api/dashboard'
import { colors } from '../utils' import { colors } from '../utils'
import { useI18n } from '@/hooks/web/useI18n'
import { useLocaleStore } from '@/store/modules/locale'
interface EventItem { interface EventItem {
key: string key: string
@ -50,8 +48,6 @@ interface EventItem {
const route = useRoute() const route = useRoute()
const orgId = route.query.orgId const orgId = route.query.orgId
const { t } = useI18n('ReportDashboard')
const localeStore = useLocaleStore()
const chartRef = ref<HTMLElement | null>(null) const chartRef = ref<HTMLElement | null>(null)
let chart: echarts.ECharts | null = null let chart: echarts.ECharts | null = null
@ -112,21 +108,21 @@ const applyTaskStatistics = (data: TaskStatisticsData) => {
eventItems.value = [ eventItems.value = [
{ {
key: 'check', key: 'check',
name: t('Dashboard1.eventReminder.check'), name: '点检',
count: inspection, count: inspection,
percent: toPercent(inspection), percent: toPercent(inspection),
color: colors.cyan color: colors.cyan
}, },
{ {
key: 'maintain', key: 'maintain',
name: t('Dashboard1.eventReminder.maintain'), name: '保养',
count: maintenance, count: maintenance,
percent: toPercent(maintenance), percent: toPercent(maintenance),
color: colors.warn color: colors.warn
}, },
{ {
key: 'repair', key: 'repair',
name: t('Dashboard1.eventReminder.repair'), name: '维修',
count: repair, count: repair,
percent: toPercent(repair), percent: toPercent(repair),
color: colors.danger color: colors.danger
@ -153,14 +149,6 @@ watch(mode, () => {
applyTaskStatistics(rawStats.value) applyTaskStatistics(rawStats.value)
}) })
watch(
() => localeStore.getCurrentLocale.lang,
() => {
if (!rawStats.value) return
applyTaskStatistics(rawStats.value)
}
)
const resize = () => { const resize = () => {
chart?.resize() chart?.resize()
} }

@ -5,9 +5,9 @@
<span class="card-title-icon"> <span class="card-title-icon">
<Icon icon="fa-solid:bell" /> <Icon icon="fa-solid:bell" />
</span> </span>
<span>{{ t('Dashboard1.alarms.title') }}</span> <span>实时报警信息</span>
</div> </div>
<span class="tag">{{ t('Dashboard1.alarms.tag') }}</span> <span class="tag">滚动展示</span>
</div> </div>
<div class="card-body"> <div class="card-body">
<ul ref="listRef" class="alarm-list"> <ul ref="listRef" class="alarm-list">
@ -28,35 +28,17 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue' import { ref, onMounted, onUnmounted } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { DeviceWarningRecordApi, DeviceWarningRecordVO } from '@/api/iot/deviceWarningRecord' import { DeviceWarningRecordApi, DeviceWarningRecordVO } from '@/api/iot/deviceWarningRecord'
import { useI18n } from '@/hooks/web/useI18n'
import { useLocaleStore } from '@/store/modules/locale'
const route = useRoute() const route = useRoute()
const orgId = route.query.orgId const orgId = route.query.orgId
const { t } = useI18n('ReportDashboard')
const localeStore = useLocaleStore()
const alarms = ref<any[]>([]) const alarms = ref<any[]>([])
const isAnimating = ref(false) const isAnimating = ref(false)
let timer: ReturnType<typeof setInterval> | null = null let timer: ReturnType<typeof setInterval> | null = null
const mapAlarmLevel = (alarmLevel: unknown) => {
const raw = String(alarmLevel ?? '').trim()
if (raw === '2' || raw === '严重' || raw.toLowerCase() === 'severe') {
return { type: 'danger', levelText: t('Dashboard1.alarms.levelSevere') }
}
if (raw === '1' || raw === '警告' || raw.toLowerCase() === 'warning' || raw.toLowerCase() === 'warn') {
return { type: 'warn', levelText: t('Dashboard1.alarms.levelWarn') }
}
if (raw === '0' || raw === '提示' || raw.toLowerCase() === 'info' || raw.toLowerCase() === 'notice') {
return { type: 'safe', levelText: t('Dashboard1.alarms.levelInfo') }
}
return { type: 'safe', levelText: raw || t('Dashboard1.alarms.levelInfo') }
}
const getAlarms = async () => { const getAlarms = async () => {
try { try {
const data = (await DeviceWarningRecordApi.getList({ orgId })) || [] const data = (await DeviceWarningRecordApi.getList({ orgId })) || []
@ -67,12 +49,28 @@ const getAlarms = async () => {
timeStr = d.toTimeString().slice(0, 8) timeStr = d.toTimeString().slice(0, 8)
} }
const mapped = mapAlarmLevel(item.alarmLevel) let type = 'safe'
let levelText = item.alarmLevel
if (item.alarmLevel === '2') {
type = 'danger'
levelText = '严重'
} else if (item.alarmLevel === '1') {
type = 'warn'
levelText = '警告'
} else if (item.alarmLevel === '0') {
type = 'safe'
levelText = '提示'
} else {
if (item.alarmLevel === '严重') type = 'danger'
else if (item.alarmLevel === '警告') type = 'warn'
else if (item.alarmLevel === '提示') type = 'safe'
}
return { return {
time: timeStr, time: timeStr,
level: mapped.levelText, level: levelText,
type: mapped.type, type,
msg: `${item.deviceName}-${item.ruleName}` msg: `${item.deviceName}-${item.ruleName}`
} }
}) })
@ -103,13 +101,6 @@ onMounted(() => {
getAlarms() getAlarms()
}) })
watch(
() => localeStore.getCurrentLocale.lang,
() => {
getAlarms()
}
)
onUnmounted(() => { onUnmounted(() => {
if (timer) clearInterval(timer) if (timer) clearInterval(timer)
}) })

@ -2,8 +2,8 @@
<div class="card"> <div class="card">
<div class="panel-title"> <div class="panel-title">
<span class="title-dot"></span> <span class="title-dot"></span>
<span>{{ t('Dashboard1.productionTrend.title') }}</span> <span>产量趋势</span>
<span class="tag">{{ t('Dashboard1.productionTrend.tagToday') }}</span> <span class="tag">今日</span>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div ref="chartRef" class="chart"></div> <div ref="chartRef" class="chart"></div>
@ -12,19 +12,15 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, onUnmounted, ref, watch } from 'vue' import { onMounted, onUnmounted, ref } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { colors, style } from '../utils' import { colors, style } from '../utils'
import { DeviceWarningRecordApi } from '@/api/iot/deviceWarningRecord' import { DeviceWarningRecordApi } from '@/api/iot/deviceWarningRecord'
import { useI18n } from '@/hooks/web/useI18n'
import { useLocaleStore } from '@/store/modules/locale'
const route = useRoute() const route = useRoute()
const chartRef = ref<HTMLElement | null>(null) const chartRef = ref<HTMLElement | null>(null)
let chart: echarts.ECharts | null = null let chart: echarts.ECharts | null = null
const { t } = useI18n('ReportDashboard')
const localeStore = useLocaleStore()
const render = async () => { const render = async () => {
if (!chart) return if (!chart) return
@ -73,7 +69,7 @@ const render = async () => {
}, },
series: [ series: [
{ {
name: t('Dashboard1.productionTrend.seriesOutput'), name: '产量',
type: 'bar', type: 'bar',
barWidth: 12, barWidth: 12,
itemStyle: { itemStyle: {
@ -100,13 +96,6 @@ onMounted(() => {
window.addEventListener('resize', resize) window.addEventListener('resize', resize)
}) })
watch(
() => localeStore.getCurrentLocale.lang,
() => {
render()
}
)
onUnmounted(() => { onUnmounted(() => {
window.removeEventListener('resize', resize) window.removeEventListener('resize', resize)
chart?.dispose() chart?.dispose()

@ -2,7 +2,7 @@
<div class="card"> <div class="card">
<div class="panel-title"> <div class="panel-title">
<span class="title-dot"></span> <span class="title-dot"></span>
<span>{{ t('Dashboard1.taskList.title') }}</span> <span>任务列表</span>
</div> </div>
<div class="panel-body table-body"> <div class="panel-body table-body">
<el-table <el-table
@ -14,10 +14,10 @@
:border="false" :border="false"
:highlight-current-row="false" :highlight-current-row="false"
> >
<el-table-column prop="code" :label="t('Dashboard1.taskList.columns.code')" width="100" show-overflow-tooltip /> <el-table-column prop="code" label="编号" width="100" show-overflow-tooltip />
<el-table-column prop="name" :label="t('Dashboard1.taskList.columns.name')" /> <el-table-column prop="name" label="名称" />
<el-table-column prop="type" :label="t('Dashboard1.taskList.columns.type')" /> <el-table-column prop="type" label="类型" />
<el-table-column :label="t('Dashboard1.taskList.columns.finishStatus')"> <el-table-column label="完成状态">
<template #default="scope"> <template #default="scope">
<el-tag <el-tag
v-if="scope.row.finishStatusLabel" v-if="scope.row.finishStatusLabel"
@ -32,7 +32,7 @@
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="t('Dashboard1.taskList.columns.result')"> <el-table-column label="结果">
<template #default="scope"> <template #default="scope">
<div class="status-cell"> <div class="status-cell">
<el-tag <el-tag
@ -56,12 +56,10 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue' import { ref, onMounted, onUnmounted } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import type { ElTable } from 'element-plus' import type { ElTable } from 'element-plus'
import { DashboardApi, DashboardTaskItem } from '@/api/dashboard' import { DashboardApi, DashboardTaskItem } from '@/api/dashboard'
import { useI18n } from '@/hooks/web/useI18n'
import { useLocaleStore } from '@/store/modules/locale'
interface TaskRow { interface TaskRow {
id: string id: string
@ -76,32 +74,29 @@ interface TaskRow {
const route = useRoute() const route = useRoute()
const orgId = route.query.orgId const orgId = route.query.orgId
const { t } = useI18n('ReportDashboard')
const localeStore = useLocaleStore()
const taskRows = ref<TaskRow[]>([]) const taskRows = ref<TaskRow[]>([])
const rawItems = ref<DashboardTaskItem[]>([])
const tableRef = ref<InstanceType<typeof ElTable> | null>(null) const tableRef = ref<InstanceType<typeof ElTable> | null>(null)
let scrollTimer: number | undefined let scrollTimer: number | undefined
const mapItemToRow = (item: DashboardTaskItem, index: number): TaskRow => { const mapItemToRow = (item: DashboardTaskItem, index: number): TaskRow => {
const resultStatus = Number(item.resultStatus) || 0 const resultStatus = Number(item.resultStatus) || 0
const finishCode = String(item.finishStatus ?? '').trim() const finishCode = String(item.finishStatus ?? '').trim()
let finishStatusLabel = String(item.finishStatus ?? '') let finishStatusLabel = item.finishStatus
let finishStatusType: TaskRow['finishStatusType'] = '' let finishStatusType: TaskRow['finishStatusType'] = ''
if (finishCode === '0') finishStatusLabel = t('Dashboard1.taskList.finishPending') if (finishCode === '0') finishStatusLabel = '待完成'
else if (finishCode === '1') finishStatusLabel = t('Dashboard1.taskList.finishDone') else if (finishCode === '1') finishStatusLabel = '已完成'
else if (finishCode === '2') finishStatusLabel = t('Dashboard1.taskList.finishCanceled') else if (finishCode === '2') finishStatusLabel = '已取消'
if (finishCode === '0') finishStatusType = 'warning' if (finishCode === '0') finishStatusType = 'warning'
else if (finishCode === '1') finishStatusType = 'success' else if (finishCode === '1') finishStatusType = 'success'
else if (finishCode === '2') finishStatusType = 'info' else if (finishCode === '2') finishStatusType = 'info'
let resultStatusLabel = '-' let resultStatusLabel = '-'
let resultStatusType: TaskRow['resultStatusType'] = '' let resultStatusType: TaskRow['resultStatusType'] = ''
if (resultStatus === 1) { if (resultStatus === 1) {
resultStatusLabel = t('Dashboard1.taskList.resultPass') resultStatusLabel = '通过'
resultStatusType = 'success' resultStatusType = 'success'
} else if (resultStatus === 2) { } else if (resultStatus === 2) {
resultStatusLabel = t('Dashboard1.taskList.resultFail') resultStatusLabel = '不通过'
resultStatusType = 'danger' resultStatusType = 'danger'
} }
return { return {
@ -123,15 +118,12 @@ const loadTaskList = async () => {
| DashboardTaskItem[] | DashboardTaskItem[]
| null | null
if (!payload || !Array.isArray(payload)) { if (!payload || !Array.isArray(payload)) {
rawItems.value = []
taskRows.value = [] taskRows.value = []
return return
} }
rawItems.value = payload
taskRows.value = payload.map(mapItemToRow) taskRows.value = payload.map(mapItemToRow)
} catch (error) { } catch (error) {
console.error(error) console.error(error)
rawItems.value = []
taskRows.value = [] taskRows.value = []
} }
} }
@ -169,13 +161,6 @@ onMounted(async () => {
startAutoScroll() startAutoScroll()
}) })
watch(
() => localeStore.getCurrentLocale.lang,
() => {
taskRows.value = rawItems.value.map(mapItemToRow)
}
)
onUnmounted(() => { onUnmounted(() => {
if (scrollTimer) { if (scrollTimer) {
clearInterval(scrollTimer) clearInterval(scrollTimer)

@ -48,7 +48,7 @@
</el-tag> </el-tag>
</div> </div>
<div class="header-right"> <div class="header-right">
<span class="device-id">{{ t('Dashboard1.deviceIdPrefix') }}{{ item.deviceId }}</span> <span class="device-id">{{ t('ReportDashboard.Dashboard1.deviceIdPrefix') }}{{ item.deviceId }}</span>
</div> </div>
</div> </div>
<div class="device-body"> <div class="device-body">
@ -80,7 +80,7 @@
</el-tag> </el-tag>
</div> </div>
<div class="header-right"> <div class="header-right">
<span class="device-id">{{ t('Dashboard1.deviceIdPrefix') }}{{ item.deviceId }}</span> <span class="device-id">{{ t('ReportDashboard.Dashboard1.deviceIdPrefix') }}{{ item.deviceId }}</span>
</div> </div>
</div> </div>
<div class="device-body"> <div class="device-body">
@ -128,7 +128,7 @@ import ProductionTrend from './components/ProductionTrend.vue'
const route = useRoute() const route = useRoute()
const goviewId = route.query.goviewId as string const goviewId = route.query.goviewId as string
const orgId = route.query.orgId const orgId = route.query.orgId
const { t } = useI18n('ReportDashboard') const { t } = useI18n()
interface DeviceAttribute { interface DeviceAttribute {
attributeName: string attributeName: string
@ -165,7 +165,7 @@ const loadDeviceAttributes = async () => {
const cards: DeviceCardData[] = list.map((d: any) => { const cards: DeviceCardData[] = list.map((d: any) => {
return { return {
deviceName: d.deviceName || t('Dashboard1.defaultDeviceName'), deviceName: d.deviceName || t('ReportDashboard.Dashboard1.defaultDeviceName'),
deviceId: d.deviceId, deviceId: d.deviceId,
operatingStatus: d.operatingStatus, operatingStatus: d.operatingStatus,
attributes: (d.attributes || []).map((attr: any) => ({ attributes: (d.attributes || []).map((attr: any) => ({
@ -194,14 +194,8 @@ const getDeviceStatusType = (status?: string) => {
} }
const getDeviceStatusText = (status?: string) => { const getDeviceStatusText = (status?: string) => {
if (!status) return t('Dashboard1.statusOffline') if (!status) return t('ReportDashboard.Dashboard1.statusOffline')
const raw = String(status).trim() return status
const s = raw.toLowerCase()
if (s.includes('故障') || s === 'fault') return t('Dashboard1.statusFault')
if (s.includes('待机') || s === 'standby') return t('Dashboard1.statusStandby')
if (s.includes('运行') || s === 'run' || s === 'running') return t('Dashboard1.statusRunning')
if (s.includes('离线') || s === 'offline') return t('Dashboard1.statusOffline')
return raw
} }
onMounted(() => { onMounted(() => {

@ -6,8 +6,8 @@
<Icon icon="fa-solid:microchip" class="title-mark-icon" /> <Icon icon="fa-solid:microchip" class="title-mark-icon" />
</div> </div>
<div> <div>
<div class="title">{{ t('Header.title') }}</div> <div class="title">智能制造产线任务总览</div>
<div class="sub-title">{{ t('Header.subTitle') }}</div> <div class="sub-title">INTELLIGENT MANUFACTURING REAL-TIME DASHBOARD</div>
</div> </div>
</div> </div>
<div class="header-right"> <div class="header-right">
@ -31,10 +31,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue' import { ref, onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useI18n } from '@/hooks/web/useI18n'
const router = useRouter() const router = useRouter()
const { t } = useI18n('Dashboard8')
const timeStr = ref('') const timeStr = ref('')
let timer: number | undefined let timer: number | undefined

@ -5,9 +5,9 @@
<span class="card-title-icon"> <span class="card-title-icon">
<Icon icon="fa-solid:sun" /> <Icon icon="fa-solid:sun" />
</span> </span>
<span>{{ t('DayCapacity.title') }}</span> <span>日产能达成情况</span>
</div> </div>
<span class="tag">{{ t('DayCapacity.tag') }}</span> <span class="tag">当日维度</span>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="card-body-row"> <div class="card-body-row">
@ -17,19 +17,19 @@
<div class="card-body-col"> <div class="card-body-col">
<div class="metrics-grid"> <div class="metrics-grid">
<div class="metric-card"> <div class="metric-card">
<div class="metric-label">{{ t('DayCapacity.metrics.orders') }}</div> <div class="metric-label">排产单数量</div>
<div class="metric-value" ref="dayOrderEl"></div> <div class="metric-value" ref="dayOrderEl"></div>
</div> </div>
<div class="metric-card"> <div class="metric-card">
<div class="metric-label">{{ t('DayCapacity.metrics.scheduled') }}</div> <div class="metric-label">已排产数量</div>
<div class="metric-value" ref="dayPlanEl"></div> <div class="metric-value" ref="dayPlanEl"></div>
</div> </div>
<div class="metric-card"> <div class="metric-card">
<div class="metric-label">{{ t('DayCapacity.metrics.produced') }}</div> <div class="metric-label">已生产数量</div>
<div class="metric-value ok" ref="dayPendingEl"></div> <div class="metric-value ok" ref="dayPendingEl"></div>
</div> </div>
<div class="metric-card"> <div class="metric-card">
<div class="metric-label">{{ t('DayCapacity.metrics.rate') }}</div> <div class="metric-label">产能合格率</div>
<div class="metric-value accent" ref="dayRateEl"></div> <div class="metric-value accent" ref="dayRateEl"></div>
</div> </div>
</div> </div>
@ -40,18 +40,14 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue' import { ref, onMounted, onUnmounted } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { colors, animateCount, style } from '../utils' import { colors, animateCount, style } from '../utils'
import { PlanApi } from '@/api/mes/plan' import { PlanApi } from '@/api/mes/plan'
import { useI18n } from '@/hooks/web/useI18n'
import { useLocaleStore } from '@/store/modules/locale'
const route = useRoute() const route = useRoute()
const orgId = route.query.orgId const orgId = route.query.orgId
const { t } = useI18n('Dashboard8')
const localeStore = useLocaleStore()
type CapacityData = { type CapacityData = {
orders: number orders: number
@ -75,27 +71,6 @@ const dayRateEl = ref<HTMLElement | null>(null)
let chart: echarts.ECharts | null = null let chart: echarts.ECharts | null = null
const buildOption = () => {
return {
backgroundColor: 'transparent',
tooltip: { trigger: 'item' },
legend: { bottom: '0%', left: 'center', textStyle: style.legendText },
series: [
{
type: 'pie',
radius: ['60%', '82%'],
center: ['50%', '55%'],
label: { show: false },
emphasis: { scale: false },
data: [
{ value: day.scheduled, name: t('DayCapacity.chart.scheduled'), itemStyle: { color: colors.cyan } },
{ value: day.produced, name: t('DayCapacity.chart.produced'), itemStyle: { color: colors.green } }
]
}
]
}
}
const mapCapacity = (raw: any): CapacityData => { const mapCapacity = (raw: any): CapacityData => {
const orderCount = Number(raw?.orders ?? raw?.order ?? 0) const orderCount = Number(raw?.orders ?? raw?.order ?? 0)
const scheduled = Number(raw?.plan ?? 0) const scheduled = Number(raw?.plan ?? 0)
@ -119,7 +94,24 @@ const loadDayCapacity = async () => {
const initChart = () => { const initChart = () => {
if (!chartRef.value) return if (!chartRef.value) return
chart = echarts.init(chartRef.value, 'dark', { renderer: 'canvas' }) chart = echarts.init(chartRef.value, 'dark', { renderer: 'canvas' })
chart.setOption(buildOption()) chart.setOption({
backgroundColor: 'transparent',
tooltip: { trigger: 'item' },
legend: { bottom: '0%', left: 'center', textStyle: style.legendText },
series: [
{
type: 'pie',
radius: ['60%', '82%'],
center: ['50%', '55%'],
label: { show: false },
emphasis: { scale: false },
data: [
{ value: day.scheduled, name: '已排产', itemStyle: { color: colors.cyan } },
{ value: day.produced, name: '已生产', itemStyle: { color: colors.green } }
]
}
]
})
} }
const resizeHandler = () => { const resizeHandler = () => {
@ -129,7 +121,6 @@ const resizeHandler = () => {
onMounted(async () => { onMounted(async () => {
await loadDayCapacity() await loadDayCapacity()
initChart() initChart()
chart?.setOption(buildOption(), true)
animateCount(dayOrderEl.value, day.orders, '', 900) animateCount(dayOrderEl.value, day.orders, '', 900)
animateCount(dayPlanEl.value, day.scheduled, '', 900) animateCount(dayPlanEl.value, day.scheduled, '', 900)
animateCount(dayPendingEl.value, day.produced, '', 900) animateCount(dayPendingEl.value, day.produced, '', 900)
@ -137,13 +128,6 @@ onMounted(async () => {
window.addEventListener('resize', resizeHandler) window.addEventListener('resize', resizeHandler)
}) })
watch(
() => localeStore.getCurrentLocale.lang,
() => {
chart?.setOption(buildOption(), true)
}
)
onUnmounted(() => { onUnmounted(() => {
window.removeEventListener('resize', resizeHandler) window.removeEventListener('resize', resizeHandler)
chart?.dispose() chart?.dispose()

@ -5,11 +5,11 @@
<span class="card-title-icon"> <span class="card-title-icon">
<Icon icon="fa-solid:bolt" /> <Icon icon="fa-solid:bolt" />
</span> </span>
<span>{{ t('EnergyTrend.title') }}</span> <span>能耗周趋势</span>
</div> </div>
<div class="card-toolbar"> <div class="card-toolbar">
<el-select <el-select
v-model="selectedEnergyTypeId" :placeholder="t('EnergyTrend.selectPlaceholder')" class="energy-type-select" size="small" v-model="selectedEnergyTypeId" placeholder="请选择" class="energy-type-select" size="small"
@change="handleEnergyTypeChange"> @change="handleEnergyTypeChange">
<el-option v-for="item in energyTypes" :key="item.id" :label="item.name" :value="item.id" /> <el-option v-for="item in energyTypes" :key="item.id" :label="item.name" :value="item.id" />
</el-select> </el-select>
@ -22,19 +22,15 @@ v-model="selectedEnergyTypeId" :placeholder="t('EnergyTrend.selectPlaceholder')"
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, onUnmounted, ref, watch } from 'vue' import { onMounted, onUnmounted, ref } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { colors, style } from '../utils' import { colors, style } from '../utils'
import { EnergyTypeApi, EnergyTypeVO } from '@/api/mes/energytype' import { EnergyTypeApi, EnergyTypeVO } from '@/api/mes/energytype'
import { EnergyDeviceApi } from '@/api/mes/energydevice' import { EnergyDeviceApi } from '@/api/mes/energydevice'
import { useI18n } from '@/hooks/web/useI18n'
import { useLocaleStore } from '@/store/modules/locale'
const route = useRoute() const route = useRoute()
const orgId = route.query.orgId const orgId = route.query.orgId
const { t } = useI18n('Dashboard8')
const localeStore = useLocaleStore()
const energyTypes = ref<EnergyTypeVO[]>([]) const energyTypes = ref<EnergyTypeVO[]>([])
const selectedEnergyTypeId = ref<number | undefined>(undefined) const selectedEnergyTypeId = ref<number | undefined>(undefined)
@ -72,8 +68,24 @@ const handleEnergyTypeChange = () => {
getChartData() getChartData()
} }
const buildOption = (x: string[], actual: number[]) => { const render = (data: any = []) => {
return { if (!chart) return
const list = (data as any).data || (Array.isArray(data) ? data : [])
const x: string[] = []
const actual: number[] = []
const baseline: number[] = []
if (list && list.length > 0) {
list.forEach((item: any) => {
const label = item.hour || item.day || ''
x.push(label)
const v = Number(item.value ?? item.energy ?? item.consumption ?? 0)
actual.push(Number.isNaN(v) ? 0 : v)
})
}
chart.setOption({
backgroundColor: 'transparent', backgroundColor: 'transparent',
tooltip: { trigger: 'axis' }, tooltip: { trigger: 'axis' },
legend: { top: 0, right: 0, textStyle: style.legendText }, legend: { top: 0, right: 0, textStyle: style.legendText },
@ -87,7 +99,7 @@ const buildOption = (x: string[], actual: number[]) => {
yAxis: { type: 'value', axisLine: { show: false }, axisLabel: style.axisLabel, splitLine: style.splitLine }, yAxis: { type: 'value', axisLine: { show: false }, axisLabel: style.axisLabel, splitLine: style.splitLine },
series: [ series: [
{ {
name: t('EnergyTrend.seriesActualEnergy'), name: '实际能耗(kWh)',
type: 'bar', type: 'bar',
barWidth: 16, barWidth: 16,
itemStyle: { itemStyle: {
@ -100,26 +112,7 @@ const buildOption = (x: string[], actual: number[]) => {
data: actual data: actual
} }
] ]
} })
}
const render = (data: any = []) => {
if (!chart) return
const list = (data as any).data || (Array.isArray(data) ? data : [])
const x: string[] = []
const actual: number[] = []
if (list && list.length > 0) {
list.forEach((item: any) => {
const label = item.hour || item.day || ''
x.push(label)
const v = Number(item.value ?? item.energy ?? item.consumption ?? 0)
actual.push(Number.isNaN(v) ? 0 : v)
})
}
chart.setOption(buildOption(x, actual))
} }
const resize = () => { const resize = () => {
@ -129,18 +122,11 @@ const resize = () => {
onMounted(async () => { onMounted(async () => {
if (!chartRef.value) return if (!chartRef.value) return
chart = echarts.init(chartRef.value, 'dark', { renderer: 'canvas' }) chart = echarts.init(chartRef.value, 'dark', { renderer: 'canvas' })
chart.setOption(buildOption([], [])) render([])
await getEnergyTypes() await getEnergyTypes()
window.addEventListener('resize', resize) window.addEventListener('resize', resize)
}) })
watch(
() => localeStore.getCurrentLocale.lang,
() => {
getChartData()
}
)
onUnmounted(() => { onUnmounted(() => {
window.removeEventListener('resize', resize) window.removeEventListener('resize', resize)
chart?.dispose() chart?.dispose()

@ -5,9 +5,9 @@
<span class="card-title-icon"> <span class="card-title-icon">
<Icon icon="fa-solid:moon" /> <Icon icon="fa-solid:moon" />
</span> </span>
<span>{{ t('MonthCapacity.title') }}</span> <span>月产能达成情况</span>
</div> </div>
<span class="tag">{{ t('MonthCapacity.tag') }}</span> <span class="tag">当月累计</span>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="card-body-row"> <div class="card-body-row">
@ -17,19 +17,19 @@
<div class="card-body-col"> <div class="card-body-col">
<div class="metrics-grid"> <div class="metrics-grid">
<div class="metric-card"> <div class="metric-card">
<div class="metric-label">{{ t('MonthCapacity.metrics.orders') }}</div> <div class="metric-label">排产单数量</div>
<div class="metric-value" ref="monthOrderEl"></div> <div class="metric-value" ref="monthOrderEl"></div>
</div> </div>
<div class="metric-card"> <div class="metric-card">
<div class="metric-label">{{ t('MonthCapacity.metrics.scheduled') }}</div> <div class="metric-label">已排产数量</div>
<div class="metric-value" ref="monthPlanEl"></div> <div class="metric-value" ref="monthPlanEl"></div>
</div> </div>
<div class="metric-card"> <div class="metric-card">
<div class="metric-label">{{ t('MonthCapacity.metrics.produced') }}</div> <div class="metric-label">已生产数量</div>
<div class="metric-value ok" ref="monthPendingEl"></div> <div class="metric-value ok" ref="monthPendingEl"></div>
</div> </div>
<div class="metric-card"> <div class="metric-card">
<div class="metric-label">{{ t('MonthCapacity.metrics.rate') }}</div> <div class="metric-label">产能合格率</div>
<div class="metric-value accent" ref="monthRateEl"></div> <div class="metric-value accent" ref="monthRateEl"></div>
</div> </div>
</div> </div>
@ -40,18 +40,14 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue' import { ref, onMounted, onUnmounted } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { colors, animateCount, style } from '../utils' import { colors, animateCount, style } from '../utils'
import { PlanApi } from '@/api/mes/plan' import { PlanApi } from '@/api/mes/plan'
import { useI18n } from '@/hooks/web/useI18n'
import { useLocaleStore } from '@/store/modules/locale'
const route = useRoute() const route = useRoute()
const orgId = route.query.orgId const orgId = route.query.orgId
const { t } = useI18n('Dashboard8')
const localeStore = useLocaleStore()
type CapacityData = { type CapacityData = {
orders: number orders: number
@ -75,27 +71,6 @@ const monthRateEl = ref<HTMLElement | null>(null)
let chart: echarts.ECharts | null = null let chart: echarts.ECharts | null = null
const buildOption = () => {
return {
backgroundColor: 'transparent',
tooltip: { trigger: 'item' },
legend: { bottom: '0%', left: 'center', textStyle: style.legendText },
series: [
{
type: 'pie',
radius: ['60%', '82%'],
center: ['50%', '55%'],
label: { show: false },
emphasis: { scale: false },
data: [
{ value: month.scheduled, name: t('MonthCapacity.chart.scheduled'), itemStyle: { color: colors.cyan } },
{ value: month.produced, name: t('MonthCapacity.chart.produced'), itemStyle: { color: colors.green } }
]
}
]
}
}
const mapCapacity = (raw: any): CapacityData => { const mapCapacity = (raw: any): CapacityData => {
const orderCount = Number(raw?.orders ?? raw?.order ?? 0) const orderCount = Number(raw?.orders ?? raw?.order ?? 0)
const scheduled = Number(raw?.plan ?? 0) const scheduled = Number(raw?.plan ?? 0)
@ -119,7 +94,24 @@ const loadMonthCapacity = async () => {
const initChart = () => { const initChart = () => {
if (!chartRef.value) return if (!chartRef.value) return
chart = echarts.init(chartRef.value, 'dark', { renderer: 'canvas' }) chart = echarts.init(chartRef.value, 'dark', { renderer: 'canvas' })
chart.setOption(buildOption()) chart.setOption({
backgroundColor: 'transparent',
tooltip: { trigger: 'item' },
legend: { bottom: '0%', left: 'center', textStyle: style.legendText },
series: [
{
type: 'pie',
radius: ['60%', '82%'],
center: ['50%', '55%'],
label: { show: false },
emphasis: { scale: false },
data: [
{ value: month.scheduled, name: '已排产', itemStyle: { color: colors.cyan } },
{ value: month.produced, name: '已生产', itemStyle: { color: colors.green } }
]
}
]
})
} }
const resizeHandler = () => { const resizeHandler = () => {
@ -129,7 +121,6 @@ const resizeHandler = () => {
onMounted(async () => { onMounted(async () => {
await loadMonthCapacity() await loadMonthCapacity()
initChart() initChart()
chart?.setOption(buildOption(), true)
animateCount(monthOrderEl.value, month.orders, '', 900) animateCount(monthOrderEl.value, month.orders, '', 900)
animateCount(monthPlanEl.value, month.scheduled, '', 900) animateCount(monthPlanEl.value, month.scheduled, '', 900)
animateCount(monthPendingEl.value, month.produced, '', 900) animateCount(monthPendingEl.value, month.produced, '', 900)
@ -137,13 +128,6 @@ onMounted(async () => {
window.addEventListener('resize', resizeHandler) window.addEventListener('resize', resizeHandler)
}) })
watch(
() => localeStore.getCurrentLocale.lang,
() => {
chart?.setOption(buildOption(), true)
}
)
onUnmounted(() => { onUnmounted(() => {
window.removeEventListener('resize', resizeHandler) window.removeEventListener('resize', resizeHandler)
chart?.dispose() chart?.dispose()

@ -5,7 +5,7 @@
<span class="card-title-icon"> <span class="card-title-icon">
<Icon icon="fa-solid:wave-square" /> <Icon icon="fa-solid:wave-square" />
</span> </span>
<span>{{ t('OpsTrend.title') }}</span> <span>产能完成数</span>
</div> </div>
<div class="ops-header-right"> <div class="ops-header-right">
<span class="tag">{{ summary }}</span> <span class="tag">{{ summary }}</span>
@ -18,21 +18,17 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue' import { ref, onMounted, onUnmounted } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { colors, style } from '../utils' import { colors, style } from '../utils'
import { PlanApi } from '@/api/mes/plan' import { PlanApi } from '@/api/mes/plan'
import { useI18n } from '@/hooks/web/useI18n'
import { useLocaleStore } from '@/store/modules/locale'
const route = useRoute() const route = useRoute()
const { t } = useI18n('Dashboard8')
const localeStore = useLocaleStore()
const opsDays: string[] = [] const opsDays: string[] = []
const opsLines: { name: string; value: number[] }[] = [ const opsLines: { name: string; value: number[] }[] = [
{ name: t('OpsTrend.defaultLine'), value: [] } { name: '全部产线', value: [] }
] ]
const currentLine = ref(opsLines[0].name) const currentLine = ref(opsLines[0].name)
@ -47,7 +43,7 @@ const avg = (arr: number[]) => {
const updateOps = (lineName: string) => { const updateOps = (lineName: string) => {
currentLine.value = lineName currentLine.value = lineName
const item = opsLines.find((x) => x.name === lineName) || opsLines[0] const item = opsLines.find((x) => x.name === lineName) || opsLines[0]
summary.value = t('OpsTrend.summary', { line: item.name, value: avg(item.value) }) summary.value = `${item.name} · 日均完成 ${avg(item.value)}`
if (!chart) return if (!chart) return
chart.setOption({ chart.setOption({
@ -78,7 +74,7 @@ const loadOpsData = async () => {
opsDays.length = 0 opsDays.length = 0
opsDays.push(...days) opsDays.push(...days)
opsLines.length = 0 opsLines.length = 0
opsLines.push({ name: t('OpsTrend.defaultLine'), value: values }) opsLines.push({ name: '全部产线', value: values })
if (opsLines[0]) { if (opsLines[0]) {
currentLine.value = opsLines[0].name currentLine.value = opsLines[0].name
updateOps(currentLine.value) updateOps(currentLine.value)
@ -99,14 +95,14 @@ const initChart = async () => {
xAxis: { type: 'category', data: opsDays, axisLine: style.axisLine, axisLabel: style.axisLabel }, xAxis: { type: 'category', data: opsDays, axisLine: style.axisLine, axisLabel: style.axisLabel },
yAxis: { yAxis: {
type: 'value', type: 'value',
name: t('OpsTrend.yAxisName'), name: '产能完成数',
nameTextStyle: { color: '#a8b7d8', fontSize: 12 }, nameTextStyle: { color: '#a8b7d8', fontSize: 12 },
axisLabel: style.axisLabel, axisLabel: style.axisLabel,
splitLine: style.splitLine splitLine: style.splitLine
}, },
series: [ series: [
{ {
name: t('OpsTrend.seriesName'), name: '产能完成数',
type: 'line', type: 'line',
smooth: true, smooth: true,
showSymbol: false, showSymbol: false,
@ -128,20 +124,6 @@ onMounted(() => {
window.addEventListener('resize', resizeHandler) window.addEventListener('resize', resizeHandler)
}) })
watch(
() => localeStore.getCurrentLocale.lang,
() => {
chart?.setOption(
{
yAxis: { name: t('OpsTrend.yAxisName') },
series: [{ name: t('OpsTrend.seriesName') }]
},
false
)
updateOps(currentLine.value)
}
)
onUnmounted(() => { onUnmounted(() => {
window.removeEventListener('resize', resizeHandler) window.removeEventListener('resize', resizeHandler)
chart?.dispose() chart?.dispose()

@ -5,9 +5,9 @@
<span class="card-title-icon"> <span class="card-title-icon">
<Icon icon="fa-solid:check-double" /> <Icon icon="fa-solid:check-double" />
</span> </span>
<span>{{ t('QualityTrend.title') }}</span> <span>成品检合格率趋势图</span>
</div> </div>
<span class="tag">{{ t('QualityTrend.tag') }}</span> <span class="tag">按天统计全产线</span>
</div> </div>
<div class="card-body"> <div class="card-body">
<div id="chart-quality" class="chart"></div> <div id="chart-quality" class="chart"></div>
@ -16,20 +16,16 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref, watch } from 'vue' import { onMounted } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { useChart, colors, style } from '../utils' import { useChart, colors, style } from '../utils'
import { PlanApi } from '@/api/mes/plan' import { PlanApi } from '@/api/mes/plan'
import { useI18n } from '@/hooks/web/useI18n'
import { useLocaleStore } from '@/store/modules/locale'
const route = useRoute() const route = useRoute()
const orgId = route.query.orgId const orgId = route.query.orgId
const { t } = useI18n('Dashboard8')
const localeStore = useLocaleStore()
const { init, instance } = useChart('chart-quality') const { init } = useChart('chart-quality')
const last7Days: string[] = [] const last7Days: string[] = []
for (let i = 6; i >= 0; i--) { for (let i = 6; i >= 0; i--) {
@ -39,8 +35,6 @@ for (let i = 6; i >= 0; i--) {
} }
const passRate = [98.5, 99.2, 97.8, 98.9, 99.0, 98.2, 99.5] const passRate = [98.5, 99.2, 97.8, 98.9, 99.0, 98.2, 99.5]
const xAxisDataRef = ref<string[]>(last7Days.slice())
const seriesDataRef = ref<number[]>(passRate.slice())
type QualityPoint = { type QualityPoint = {
label: string label: string
@ -77,12 +71,15 @@ const normalizeQualityData = (raw: any): QualityPoint[] => {
} }
onMounted(async () => { onMounted(async () => {
let xAxisData = last7Days.slice()
let seriesData = passRate.slice()
try { try {
const data = await PlanApi.getLastDaysRate({ orgId }) const data = await PlanApi.getLastDaysRate({ orgId })
const list = normalizeQualityData(data) const list = normalizeQualityData(data)
if (list.length > 0) { if (list.length > 0) {
xAxisDataRef.value = list.map((item) => item.label) xAxisData = list.map((item) => item.label)
seriesDataRef.value = list.map((item) => item.rate) seriesData = list.map((item) => item.rate)
} }
} catch { } catch {
} }
@ -94,10 +91,10 @@ onMounted(async () => {
backgroundColor: 'transparent', backgroundColor: 'transparent',
tooltip: { trigger: 'axis' }, tooltip: { trigger: 'axis' },
grid: { top: '18%', left: '6%', right: '6%', bottom: '10%', containLabel: true }, grid: { top: '18%', left: '6%', right: '6%', bottom: '10%', containLabel: true },
xAxis: { type: 'category', data: xAxisDataRef.value, axisLine: style.axisLine, axisLabel: style.axisLabel }, xAxis: { type: 'category', data: xAxisData, axisLine: style.axisLine, axisLabel: style.axisLabel },
yAxis: { type: 'value', min: 0, max: 100, axisLine: { show: false }, axisLabel: style.axisLabel, splitLine: style.splitLine }, yAxis: { type: 'value', min: 0, max: 100, axisLine: { show: false }, axisLabel: style.axisLabel, splitLine: style.splitLine },
series: [{ series: [{
name: t('QualityTrend.seriesName'), name: '合格率',
type: 'bar', type: 'bar',
barWidth: '45%', barWidth: '45%',
itemStyle: { itemStyle: {
@ -107,52 +104,16 @@ onMounted(async () => {
{ offset: 1, color: 'rgba(139,92,246,0.10)' } { offset: 1, color: 'rgba(139,92,246,0.10)' }
]) ])
}, },
data: seriesDataRef.value, data: seriesData,
markLine: { markLine: {
symbol: ['none', 'none'], symbol: ['none', 'none'],
label: { label: { show: true, color: '#fff', fontSize: 12, formatter: '平均 {c}%' },
show: true,
color: '#fff',
fontSize: 12,
formatter: (p: any) => t('QualityTrend.markLineAverage', { value: p?.value ?? 0 })
},
lineStyle: { color: colors.cyan, width: 2, type: 'dashed' }, lineStyle: { color: colors.cyan, width: 2, type: 'dashed' },
data: [{ type: 'average', name: t('QualityTrend.markLineAverageName') }] data: [{ type: 'average', name: '平均值' }]
} }
}] }]
}) })
}) })
watch(
() => localeStore.getCurrentLocale.lang,
() => {
const chart = instance()
if (!chart) return
chart.setOption(
{
xAxis: { data: xAxisDataRef.value },
series: [
{
name: t('QualityTrend.seriesName'),
data: seriesDataRef.value,
markLine: {
symbol: ['none', 'none'],
label: {
show: true,
color: '#fff',
fontSize: 12,
formatter: (p: any) => t('QualityTrend.markLineAverage', { value: p?.value ?? 0 })
},
lineStyle: { color: colors.cyan, width: 2, type: 'dashed' },
data: [{ type: 'average', name: t('QualityTrend.markLineAverageName') }]
}
}
]
},
true
)
}
)
</script> </script>
<style scoped> <style scoped>

@ -5,9 +5,9 @@
<span class="card-title-icon"> <span class="card-title-icon">
<Icon icon="fa-solid:bell" /> <Icon icon="fa-solid:bell" />
</span> </span>
<span>{{ t('RealAlarm.title') }}</span> <span>实时报警信息</span>
</div> </div>
<span class="tag">{{ t('RealAlarm.tag') }}</span> <span class="tag">滚动展示</span>
</div> </div>
<div class="card-body"> <div class="card-body">
<ul ref="listRef" class="alarm-list"> <ul ref="listRef" class="alarm-list">
@ -28,39 +28,22 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue' import { ref, onMounted, onUnmounted } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { DeviceWarningRecordApi, DeviceWarningRecordVO } from '@/api/iot/deviceWarningRecord' import { DeviceWarningRecordApi, DeviceWarningRecordVO } from '@/api/iot/deviceWarningRecord'
import { useI18n } from '@/hooks/web/useI18n'
import { useLocaleStore } from '@/store/modules/locale'
const route = useRoute() const route = useRoute()
const orgId = route.query.orgId const orgId = route.query.orgId
const { t } = useI18n('Dashboard8')
const localeStore = useLocaleStore()
const alarms = ref<any[]>([]) const alarms = ref<any[]>([])
const isAnimating = ref(false) const isAnimating = ref(false)
let timer: ReturnType<typeof setInterval> | null = null let timer: ReturnType<typeof setInterval> | null = null
const mapAlarmLevel = (alarmLevel: unknown) => {
const raw = String(alarmLevel ?? '').trim()
if (raw === '2' || raw === '严重' || raw.toLowerCase() === 'severe') {
return { type: 'danger', levelText: t('RealAlarm.levelSevere') }
}
if (raw === '1' || raw === '警告' || raw.toLowerCase() === 'warning' || raw.toLowerCase() === 'warn') {
return { type: 'warn', levelText: t('RealAlarm.levelWarn') }
}
if (raw === '0' || raw === '提示' || raw.toLowerCase() === 'info' || raw.toLowerCase() === 'notice') {
return { type: 'safe', levelText: t('RealAlarm.levelInfo') }
}
return { type: 'safe', levelText: raw || t('RealAlarm.levelInfo') }
}
const getAlarms = async () => { const getAlarms = async () => {
try { try {
const data = await DeviceWarningRecordApi.getList({ orgId }) || [] const data = await DeviceWarningRecordApi.getList({ orgId }) || []
console.log('data',data)
alarms.value = data.map((item: DeviceWarningRecordVO) => { alarms.value = data.map((item: DeviceWarningRecordVO) => {
// //
@ -71,12 +54,29 @@ const getAlarms = async () => {
} }
// //
const mapped = mapAlarmLevel(item.alarmLevel) let type = 'safe'
let levelText = item.alarmLevel
if (item.alarmLevel === '2') {
type = 'danger'
levelText = '严重'
} else if (item.alarmLevel === '1') {
type = 'warn'
levelText = '警告'
} else if (item.alarmLevel === '0') {
type = 'safe'
levelText = '提示'
} else {
//
if (item.alarmLevel === '严重') type = 'danger'
else if (item.alarmLevel === '警告') type = 'warn'
else if (item.alarmLevel === '提示') type = 'safe'
}
return { return {
time: timeStr, time: timeStr,
level: mapped.levelText, level: levelText,
type: mapped.type, type: type,
msg: `${item.deviceName}-${item.ruleName}` msg: `${item.deviceName}-${item.ruleName}`
} }
}) })
@ -107,13 +107,6 @@ onMounted(() => {
getAlarms() getAlarms()
}) })
watch(
() => localeStore.getCurrentLocale.lang,
() => {
getAlarms()
}
)
onUnmounted(() => { onUnmounted(() => {
if (timer) clearInterval(timer) if (timer) clearInterval(timer)
}) })

@ -5,12 +5,12 @@
<span class="card-title-icon"> <span class="card-title-icon">
<Icon icon="fa-solid:table-list" /> <Icon icon="fa-solid:table-list" />
</span> </span>
<span>{{ t('TaskBoard.title') }}</span> <span>产线任务看板</span>
</div> </div>
<div class="legend-inline"> <div class="legend-inline">
<span class="tag">{{ t('TaskBoard.tag') }}</span> <span class="tag">实时刷新 · 滚动展示</span>
<span class="dot" style="background: var(--green);"></span> {{ t('TaskBoard.statusCompleted') }} <span class="dot" style="background: var(--green);"></span> 已完成
<span class="dot" style="background: var(--warn);"></span> {{ t('TaskBoard.statusLowProgress') }} <span class="dot" style="background: var(--warn);"></span> 进度偏低
</div> </div>
</div> </div>
<div class="card-body"> <div class="card-body">
@ -18,12 +18,12 @@
<table class="task-table"> <table class="task-table">
<thead> <thead>
<tr> <tr>
<th>{{ t('TaskBoard.columns.lineName') }}</th> <th>产线名称</th>
<th>{{ t('TaskBoard.columns.planNo') }}</th> <th>计划单</th>
<th>{{ t('TaskBoard.columns.productName') }}</th> <th>产品名称</th>
<th>{{ t('TaskBoard.columns.planQty') }}</th> <th>计划数量</th>
<th>{{ t('TaskBoard.columns.doneQty') }}</th> <th>完工数量</th>
<th>{{ t('TaskBoard.columns.passRate') }}</th> <th>合格率</th>
</tr> </tr>
</thead> </thead>
<tbody ref="tbodyRef"> <tbody ref="tbodyRef">
@ -53,11 +53,9 @@
import { ref, onMounted, onUnmounted } from 'vue' import { ref, onMounted, onUnmounted } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { PlanApi, PlanVO } from '@/api/mes/plan' import { PlanApi, PlanVO } from '@/api/mes/plan'
import { useI18n } from '@/hooks/web/useI18n'
const route = useRoute() const route = useRoute()
const orgId = route.query.orgId const orgId = route.query.orgId
const { t } = useI18n('Dashboard8')
const colors = { const colors = {
blue: '#1e90ff', blue: '#1e90ff',

@ -5,7 +5,7 @@
<span class="card-title-icon"> <span class="card-title-icon">
<Icon icon="fa-solid:gauge-high" /> <Icon icon="fa-solid:gauge-high" />
</span> </span>
<span>{{ t('TodayOps.title') }}</span> <span>今日开机率/稼动率</span>
</div> </div>
<span class="chip">{{ currentLineName }}</span> <span class="chip">{{ currentLineName }}</span>
</div> </div>
@ -16,15 +16,11 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue' import { ref, onMounted, onUnmounted } from 'vue'
import { useChart, colors } from '../utils' import { useChart, colors } from '../utils'
import { DeviceOperationRecordApi, type DeviceOperationRecordVO } from '@/api/iot/deviceOperationRecord' import { DeviceOperationRecordApi, type DeviceOperationRecordVO } from '@/api/iot/deviceOperationRecord'
import { useI18n } from '@/hooks/web/useI18n'
import { useLocaleStore } from '@/store/modules/locale'
const { init, instance } = useChart('chart-today') const { init, instance } = useChart('chart-today')
const { t } = useI18n('Dashboard8')
const localeStore = useLocaleStore()
type LineMetric = { name: string; run: number; avail: number } type LineMetric = { name: string; run: number; avail: number }
const lineMetrics = ref<LineMetric[]>([]) const lineMetrics = ref<LineMetric[]>([])
@ -98,7 +94,7 @@ const gaugeOption = (run: number, avail: number) => {
progress: { show: true, width: 8, itemStyle: { color: colors.blue } }, progress: { show: true, width: 8, itemStyle: { color: colors.blue } },
detail: { formatter: '{value}%', color: '#fff', fontSize: 26, offsetCenter: ['0%', '-5%'] }, detail: { formatter: '{value}%', color: '#fff', fontSize: 26, offsetCenter: ['0%', '-5%'] },
title: { show: true, color: '#a8b7d8', fontSize: 12, offsetCenter: ['0%', '-25%'] }, title: { show: true, color: '#a8b7d8', fontSize: 12, offsetCenter: ['0%', '-25%'] },
data: [{ value: run, name: t('TodayOps.powerOnRate') }] data: [{ value: run, name: '开机率' }]
}, },
{ {
type: 'gauge', type: 'gauge',
@ -116,7 +112,7 @@ const gaugeOption = (run: number, avail: number) => {
progress: { show: true, width: 8, itemStyle: { color: colors.green } }, progress: { show: true, width: 8, itemStyle: { color: colors.green } },
detail: { formatter: '{value}%', color: '#fff', fontSize: 20, offsetCenter: ['0%', '45%'] }, detail: { formatter: '{value}%', color: '#fff', fontSize: 20, offsetCenter: ['0%', '45%'] },
title: { show: true, color: '#a8b7d8', fontSize: 12, offsetCenter: ['0%', '25%'] }, title: { show: true, color: '#a8b7d8', fontSize: 12, offsetCenter: ['0%', '25%'] },
data: [{ value: avail, name: t('TodayOps.utilizationRate') }] data: [{ value: avail, name: '稼动率' }]
} }
] ]
} }
@ -125,7 +121,7 @@ const gaugeOption = (run: number, avail: number) => {
const renderCurrent = () => { const renderCurrent = () => {
const list = lineMetrics.value const list = lineMetrics.value
if (!list.length) { if (!list.length) {
currentLineName.value = t('TodayOps.empty') currentLineName.value = '暂无数据'
const c = instance() const c = instance()
if (c) c.setOption(gaugeOption(0, 0)) if (c) c.setOption(gaugeOption(0, 0))
return return
@ -174,13 +170,6 @@ onMounted(async () => {
startRotate() startRotate()
}) })
watch(
() => localeStore.getCurrentLocale.lang,
() => {
renderCurrent()
}
)
onUnmounted(() => { onUnmounted(() => {
if (timer) clearInterval(timer) if (timer) clearInterval(timer)
}) })

@ -5,11 +5,11 @@
<span class="card-title-icon"> <span class="card-title-icon">
<Icon icon="fa-solid:chart-line" /> <Icon icon="fa-solid:chart-line" />
</span> </span>
<span>{{ t('WeekTrend.title') }}</span> <span>周生产趋势</span>
</div> </div>
<div class="legend-inline"> <div class="legend-inline">
<span class="dot" style="background: var(--accent);"></span> {{ t('WeekTrend.legendOutput') }} <span class="dot" style="background: var(--accent);"></span> 产量
<span class="dot" style="background: var(--purple);"></span> {{ t('WeekTrend.legendPlan') }} <span class="dot" style="background: var(--purple);"></span> 计划
</div> </div>
</div> </div>
<div class="card-body"> <div class="card-body">
@ -19,18 +19,14 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue' import { ref, onMounted, onUnmounted } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { colors, style } from '../utils' import { colors, style } from '../utils'
import { PlanApi } from '@/api/mes/plan' import { PlanApi } from '@/api/mes/plan'
import { useI18n } from '@/hooks/web/useI18n'
import { useLocaleStore } from '@/store/modules/locale'
const route = useRoute() const route = useRoute()
const orgId = route.query.orgId const orgId = route.query.orgId
const { t } = useI18n('Dashboard8')
const localeStore = useLocaleStore()
const weekDays = ref() const weekDays = ref()
const weekPlan = ref() const weekPlan = ref()
@ -39,8 +35,10 @@ const weekReal = ref()
const chartRef = ref<HTMLElement | null>(null) const chartRef = ref<HTMLElement | null>(null)
let chart: echarts.ECharts | null = null let chart: echarts.ECharts | null = null
const buildOption = () => { const initChart = () => {
return { if (!chartRef.value) return
chart = echarts.init(chartRef.value, 'dark', { renderer: 'canvas' })
chart.setOption({
backgroundColor: 'transparent', backgroundColor: 'transparent',
tooltip: { trigger: 'axis' }, tooltip: { trigger: 'axis' },
legend: { top: 0, right: 0, textStyle: style.legendText }, legend: { top: 0, right: 0, textStyle: style.legendText },
@ -49,7 +47,7 @@ const buildOption = () => {
yAxis: { type: 'value', axisLine: style.axisLine, axisLabel: style.axisLabel, splitLine: style.splitLine }, yAxis: { type: 'value', axisLine: style.axisLine, axisLabel: style.axisLabel, splitLine: style.splitLine },
series: [ series: [
{ {
name: t('WeekTrend.seriesPlanOutput'), name: '计划产量',
type: 'line', type: 'line',
smooth: true, smooth: true,
showSymbol: false, showSymbol: false,
@ -57,7 +55,7 @@ const buildOption = () => {
data: weekPlan.value data: weekPlan.value
}, },
{ {
name: t('WeekTrend.seriesActualOutput'), name: '实际产量',
type: 'line', type: 'line',
smooth: true, smooth: true,
showSymbol: true, showSymbol: true,
@ -73,13 +71,7 @@ const buildOption = () => {
data: weekReal.value data: weekReal.value
} }
] ]
} })
}
const initChart = () => {
if (!chartRef.value) return
chart = echarts.init(chartRef.value, 'dark', { renderer: 'canvas' })
chart.setOption(buildOption())
} }
const resizeHandler = () => { const resizeHandler = () => {
@ -93,15 +85,9 @@ onMounted( async() => {
weekPlan.value = data.weekPlan weekPlan.value = data.weekPlan
weekReal.value = data.weekReal weekReal.value = data.weekReal
initChart() initChart()
// console.log(data)
}) })
watch(
() => localeStore.getCurrentLocale.lang,
() => {
chart?.setOption(buildOption(), true)
}
)
onUnmounted(() => { onUnmounted(() => {
window.removeEventListener('resize', resizeHandler) window.removeEventListener('resize', resizeHandler)
chart?.dispose() chart?.dispose()

Loading…
Cancel
Save