style:Dashboard8数据大屏页面中英文适配

main
黄伟杰 5 days ago
parent 50f112c28a
commit cf117ea396

@ -37,6 +37,7 @@ export default {
toolDes: 'Used to set up custom systems', toolDes: 'Used to set up custom systems',
query: 'Query', query: 'Query',
reset: 'Reset', reset: 'Reset',
noData: 'No data',
shrink: 'Put away', shrink: 'Put away',
expand: 'Expand', expand: 'Expand',
confirmTitle: 'System Hint', confirmTitle: 'System Hint',
@ -59,6 +60,134 @@ export default {
copyError: 'Copy Error', copyError: 'Copy Error',
code:'Auto-generate on Save' code:'Auto-generate on Save'
}, },
ReportDashboard: {
DashboardList: {
searchNameLabel: 'Name',
searchNamePlaceholder: 'Please enter name',
searchRemarkLabel: 'Remark',
searchRemarkPlaceholder: 'Please enter remark',
searchStateLabel: 'Status',
searchStatePlaceholder: 'Please select status',
coverAlt: 'Cover image',
stateEnabled: 'Enabled',
stateDisabled: 'Disabled',
noRemark: 'No description',
dialogCreateTitle: 'Create Dashboard',
dialogEditTitle: 'Edit Dashboard',
dialogNameLabel: 'Name',
dialogNamePlaceholder: 'Please enter name',
dialogTypeLabel: 'Type',
dialogTypePlaceholder: 'Please select type',
dialogOrgLabel: 'Line',
dialogOrgPlaceholder: 'Please select line',
dialogDeviceLabel: 'Device',
dialogDevicePlaceholder: 'Please select device',
dialogPointPlaceholder: 'Please select points',
dialogAddDeviceButton: 'Add device',
dialogContentLabel: 'Content',
dialogContentPlaceholder: 'Please enter content',
dialogRemarkLabel: 'Remark',
dialogRemarkPlaceholder: 'Please enter remark',
dialogStateLabel: 'Status',
validatorNameRequired: 'Name is required',
validatorTypeRequired: 'Dashboard type is required',
validatorOrgRequired: 'Line is required',
messageRouteMissing: 'Preview route is not configured',
messageDevicePointRequired: 'Please configure at least one device and point group',
messageMissingId: 'Missing record ID, unable to edit'
}
},
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: {
Warehouse: { Warehouse: {
name: 'Warehouse Name', name: 'Warehouse Name',

@ -37,6 +37,7 @@ export default {
toolDes: '用于设置定制系统', toolDes: '用于设置定制系统',
query: '查询', query: '查询',
reset: '重置', reset: '重置',
noData: '暂无数据',
shrink: '收起', shrink: '收起',
expand: '展开', expand: '展开',
confirmTitle: '系统提示', confirmTitle: '系统提示',
@ -59,6 +60,134 @@ export default {
copyError: '复制失败', copyError: '复制失败',
code: '编码保存后自动生成' code: '编码保存后自动生成'
}, },
ReportDashboard: {
DashboardList: {
searchNameLabel: '名称',
searchNamePlaceholder: '请输入名称',
searchRemarkLabel: '备注',
searchRemarkPlaceholder: '请输入备注',
searchStateLabel: '启用状态',
searchStatePlaceholder: '请选择启用状态',
coverAlt: '封面图',
stateEnabled: '启用',
stateDisabled: '禁用',
noRemark: '暂无描述',
dialogCreateTitle: '新增数据大屏',
dialogEditTitle: '编辑数据大屏',
dialogNameLabel: '名称',
dialogNamePlaceholder: '请输入名称',
dialogTypeLabel: '大屏类型',
dialogTypePlaceholder: '请选择大屏类型',
dialogOrgLabel: '产线',
dialogOrgPlaceholder: '请选择产线',
dialogDeviceLabel: '设备',
dialogDevicePlaceholder: '请选择设备',
dialogPointPlaceholder: '请选择点位',
dialogAddDeviceButton: '添加设备',
dialogContentLabel: '内容',
dialogContentPlaceholder: '请输入内容',
dialogRemarkLabel: '备注',
dialogRemarkPlaceholder: '请输入备注',
dialogStateLabel: '启用状态',
validatorNameRequired: '名称不能为空',
validatorTypeRequired: '大屏类型不能为空',
validatorOrgRequired: '产线不能为空',
messageRouteMissing: '未配置预览路由',
messageDevicePointRequired: '请至少配置一组设备和点位',
messageMissingId: '缺少数据编号,无法编辑'
}
},
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: {
Warehouse: { Warehouse: {
name: '仓库名称', name: '仓库名称',

@ -48,7 +48,7 @@
</el-tag> </el-tag>
</div> </div>
<div class="header-right"> <div class="header-right">
<span class="device-id">ID: {{ 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">ID: {{ 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,6 +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()
interface DeviceAttribute { interface DeviceAttribute {
attributeName: string attributeName: string
@ -164,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 || 'Device', 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) => ({
@ -193,7 +194,7 @@ const getDeviceStatusType = (status?: string) => {
} }
const getDeviceStatusText = (status?: string) => { const getDeviceStatusText = (status?: string) => {
if (!status) return '离线' if (!status) return t('ReportDashboard.Dashboard1.statusOffline')
return status return status
} }

@ -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">智能制造产线任务总览</div> <div class="title">{{ t('Header.title') }}</div>
<div class="sub-title">INTELLIGENT MANUFACTURING REAL-TIME DASHBOARD</div> <div class="sub-title">{{ t('Header.subTitle') }}</div>
</div> </div>
</div> </div>
<div class="header-right"> <div class="header-right">
@ -31,8 +31,10 @@
<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>日产能达成情况</span> <span>{{ t('DayCapacity.title') }}</span>
</div> </div>
<span class="tag">当日维度</span> <span class="tag">{{ t('DayCapacity.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">排产单数量</div> <div class="metric-label">{{ t('DayCapacity.metrics.orders') }}</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">已排产数量</div> <div class="metric-label">{{ t('DayCapacity.metrics.scheduled') }}</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">已生产数量</div> <div class="metric-label">{{ t('DayCapacity.metrics.produced') }}</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">产能合格率</div> <div class="metric-label">{{ t('DayCapacity.metrics.rate') }}</div>
<div class="metric-value accent" ref="dayRateEl"></div> <div class="metric-value accent" ref="dayRateEl"></div>
</div> </div>
</div> </div>
@ -40,14 +40,18 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue' import { ref, onMounted, onUnmounted, watch } 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
@ -71,6 +75,27 @@ 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)
@ -94,24 +119,7 @@ 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({ chart.setOption(buildOption())
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 = () => {
@ -121,6 +129,7 @@ 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)
@ -128,6 +137,13 @@ 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>能耗周趋势</span> <span>{{ t('EnergyTrend.title') }}</span>
</div> </div>
<div class="card-toolbar"> <div class="card-toolbar">
<el-select <el-select
v-model="selectedEnergyTypeId" placeholder="请选择" class="energy-type-select" size="small" v-model="selectedEnergyTypeId" :placeholder="t('EnergyTrend.selectPlaceholder')" 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,15 +22,19 @@ v-model="selectedEnergyTypeId" placeholder="请选择" class="energy-type-select
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue' import { onMounted, onUnmounted, ref, watch } 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)
@ -68,24 +72,8 @@ const handleEnergyTypeChange = () => {
getChartData() getChartData()
} }
const render = (data: any = []) => { const buildOption = (x: string[], actual: number[]) => {
if (!chart) return 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 },
@ -99,7 +87,7 @@ const render = (data: any = []) => {
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: '实际能耗(kWh)', name: t('EnergyTrend.seriesActualEnergy'),
type: 'bar', type: 'bar',
barWidth: 16, barWidth: 16,
itemStyle: { itemStyle: {
@ -112,7 +100,26 @@ const render = (data: any = []) => {
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 = () => {
@ -122,11 +129,18 @@ 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' })
render([]) chart.setOption(buildOption([], []))
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>月产能达成情况</span> <span>{{ t('MonthCapacity.title') }}</span>
</div> </div>
<span class="tag">当月累计</span> <span class="tag">{{ t('MonthCapacity.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">排产单数量</div> <div class="metric-label">{{ t('MonthCapacity.metrics.orders') }}</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">已排产数量</div> <div class="metric-label">{{ t('MonthCapacity.metrics.scheduled') }}</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">已生产数量</div> <div class="metric-label">{{ t('MonthCapacity.metrics.produced') }}</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">产能合格率</div> <div class="metric-label">{{ t('MonthCapacity.metrics.rate') }}</div>
<div class="metric-value accent" ref="monthRateEl"></div> <div class="metric-value accent" ref="monthRateEl"></div>
</div> </div>
</div> </div>
@ -40,14 +40,18 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue' import { ref, onMounted, onUnmounted, watch } 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
@ -71,6 +75,27 @@ 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)
@ -94,24 +119,7 @@ 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({ chart.setOption(buildOption())
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 = () => {
@ -121,6 +129,7 @@ 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)
@ -128,6 +137,13 @@ 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>产能完成数</span> <span>{{ t('OpsTrend.title') }}</span>
</div> </div>
<div class="ops-header-right"> <div class="ops-header-right">
<span class="tag">{{ summary }}</span> <span class="tag">{{ summary }}</span>
@ -18,17 +18,21 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue' import { ref, onMounted, onUnmounted, watch } 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: '全部产线', value: [] } { name: t('OpsTrend.defaultLine'), value: [] }
] ]
const currentLine = ref(opsLines[0].name) const currentLine = ref(opsLines[0].name)
@ -43,7 +47,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 = `${item.name} · 日均完成 ${avg(item.value)}` summary.value = t('OpsTrend.summary', { line: item.name, value: avg(item.value) })
if (!chart) return if (!chart) return
chart.setOption({ chart.setOption({
@ -74,7 +78,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: '全部产线', value: values }) opsLines.push({ name: t('OpsTrend.defaultLine'), value: values })
if (opsLines[0]) { if (opsLines[0]) {
currentLine.value = opsLines[0].name currentLine.value = opsLines[0].name
updateOps(currentLine.value) updateOps(currentLine.value)
@ -95,14 +99,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: '产能完成数', name: t('OpsTrend.yAxisName'),
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: '产能完成数', name: t('OpsTrend.seriesName'),
type: 'line', type: 'line',
smooth: true, smooth: true,
showSymbol: false, showSymbol: false,
@ -124,6 +128,20 @@ 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>成品检合格率趋势图</span> <span>{{ t('QualityTrend.title') }}</span>
</div> </div>
<span class="tag">按天统计全产线</span> <span class="tag">{{ t('QualityTrend.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,16 +16,20 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted } from 'vue' import { onMounted, ref, watch } 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 } = useChart('chart-quality') const { init, instance } = useChart('chart-quality')
const last7Days: string[] = [] const last7Days: string[] = []
for (let i = 6; i >= 0; i--) { for (let i = 6; i >= 0; i--) {
@ -35,6 +39,8 @@ 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
@ -71,15 +77,12 @@ 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) {
xAxisData = list.map((item) => item.label) xAxisDataRef.value = list.map((item) => item.label)
seriesData = list.map((item) => item.rate) seriesDataRef.value = list.map((item) => item.rate)
} }
} catch { } catch {
} }
@ -91,10 +94,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: xAxisData, axisLine: style.axisLine, axisLabel: style.axisLabel }, xAxis: { type: 'category', data: xAxisDataRef.value, 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: '合格率', name: t('QualityTrend.seriesName'),
type: 'bar', type: 'bar',
barWidth: '45%', barWidth: '45%',
itemStyle: { itemStyle: {
@ -104,16 +107,52 @@ onMounted(async () => {
{ offset: 1, color: 'rgba(139,92,246,0.10)' } { offset: 1, color: 'rgba(139,92,246,0.10)' }
]) ])
}, },
data: seriesData, data: seriesDataRef.value,
markLine: { markLine: {
symbol: ['none', 'none'], symbol: ['none', 'none'],
label: { show: true, color: '#fff', fontSize: 12, formatter: '平均 {c}%' }, 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' }, lineStyle: { color: colors.cyan, width: 2, type: 'dashed' },
data: [{ type: 'average', name: '平均值' }] data: [{ type: 'average', name: t('QualityTrend.markLineAverageName') }]
} }
}] }]
}) })
}) })
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>实时报警信息</span> <span>{{ t('RealAlarm.title') }}</span>
</div> </div>
<span class="tag">滚动展示</span> <span class="tag">{{ t('RealAlarm.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,22 +28,39 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue' import { ref, onMounted, onUnmounted, watch } 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) => {
// //
@ -54,29 +71,12 @@ const getAlarms = async () => {
} }
// //
let type = 'safe' const mapped = mapAlarmLevel(item.alarmLevel)
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: levelText, level: mapped.levelText,
type: type, type: mapped.type,
msg: `${item.deviceName}-${item.ruleName}` msg: `${item.deviceName}-${item.ruleName}`
} }
}) })
@ -107,6 +107,13 @@ 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>产线任务看板</span> <span>{{ t('TaskBoard.title') }}</span>
</div> </div>
<div class="legend-inline"> <div class="legend-inline">
<span class="tag">实时刷新 · 滚动展示</span> <span class="tag">{{ t('TaskBoard.tag') }}</span>
<span class="dot" style="background: var(--green);"></span> 已完成 <span class="dot" style="background: var(--green);"></span> {{ t('TaskBoard.statusCompleted') }}
<span class="dot" style="background: var(--warn);"></span> 进度偏低 <span class="dot" style="background: var(--warn);"></span> {{ t('TaskBoard.statusLowProgress') }}
</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>产线名称</th> <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>
</tr> </tr>
</thead> </thead>
<tbody ref="tbodyRef"> <tbody ref="tbodyRef">
@ -53,9 +53,11 @@
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>今日开机率/稼动率</span> <span>{{ t('TodayOps.title') }}</span>
</div> </div>
<span class="chip">{{ currentLineName }}</span> <span class="chip">{{ currentLineName }}</span>
</div> </div>
@ -16,11 +16,15 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue' import { ref, onMounted, onUnmounted, watch } 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[]>([])
@ -94,7 +98,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: '开机率' }] data: [{ value: run, name: t('TodayOps.powerOnRate') }]
}, },
{ {
type: 'gauge', type: 'gauge',
@ -112,7 +116,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: '稼动率' }] data: [{ value: avail, name: t('TodayOps.utilizationRate') }]
} }
] ]
} }
@ -121,7 +125,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 = '暂无数据' currentLineName.value = t('TodayOps.empty')
const c = instance() const c = instance()
if (c) c.setOption(gaugeOption(0, 0)) if (c) c.setOption(gaugeOption(0, 0))
return return
@ -170,6 +174,13 @@ 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>周生产趋势</span> <span>{{ t('WeekTrend.title') }}</span>
</div> </div>
<div class="legend-inline"> <div class="legend-inline">
<span class="dot" style="background: var(--accent);"></span> 产量 <span class="dot" style="background: var(--accent);"></span> {{ t('WeekTrend.legendOutput') }}
<span class="dot" style="background: var(--purple);"></span> 计划 <span class="dot" style="background: var(--purple);"></span> {{ t('WeekTrend.legendPlan') }}
</div> </div>
</div> </div>
<div class="card-body"> <div class="card-body">
@ -19,14 +19,18 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue' import { ref, onMounted, onUnmounted, watch } 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()
@ -35,10 +39,8 @@ 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 initChart = () => { const buildOption = () => {
if (!chartRef.value) return 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 },
@ -47,7 +49,7 @@ const initChart = () => {
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: '计划产量', name: t('WeekTrend.seriesPlanOutput'),
type: 'line', type: 'line',
smooth: true, smooth: true,
showSymbol: false, showSymbol: false,
@ -55,7 +57,7 @@ const initChart = () => {
data: weekPlan.value data: weekPlan.value
}, },
{ {
name: '实际产量', name: t('WeekTrend.seriesActualOutput'),
type: 'line', type: 'line',
smooth: true, smooth: true,
showSymbol: true, showSymbol: true,
@ -71,7 +73,13 @@ const initChart = () => {
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 = () => {
@ -85,9 +93,15 @@ 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