迁移电池曲线模块
Some checks failed
Release pipeline / publish (push) Has been cancelled
Release pipeline / Always run job (push) Has been cancelled

This commit is contained in:
sheng
2026-06-22 17:29:23 +08:00
parent fe45390997
commit 264474eced
9 changed files with 410 additions and 3 deletions

View File

@@ -0,0 +1,35 @@
import { request } from '@/api/_service'
const BASE = 'planning_production/produce/traceability/'
function apiParams (method, data = {}) {
return {
method,
platform: 'background',
...data
}
}
export function getBatteryCurveRecords (data) {
return request({
url: BASE + 'batterytraceability',
method: 'get',
params: apiParams('planning_production_produce_traceability_batterytraceability', data)
})
}
export function getBatteryCurveData (data) {
return request({
url: BASE + 'curveread',
method: 'get',
params: apiParams('planning_production_produce_traceability_batterycurveread', data)
})
}
export function exportBatteryCurveData (data) {
return request({
url: BASE + 'export',
method: 'get',
params: apiParams('planning_production_produce_traceability_export', data)
})
}

View File

@@ -1250,6 +1250,24 @@
"cancel": "Cancel",
"please_select_filter_condition": "Select at least one filter condition",
"create_download_task_success": "Download task created successfully"
},
"battery_curve": {
"query": "Search",
"reset": "Reset",
"battery_code": "Battery Barcode",
"enter_battery_code": "Enter battery barcode",
"data_empty": "No curve records",
"batch_name": "Batch",
"process_name": "Process",
"upload_time": "Upload Time",
"device_code": "Device Code",
"battery_no": "Battery Channel",
"export_all_data": "Export All Data",
"view_full_tray_curve": "View Full Tray Curve",
"data_chart": "Data Chart",
"current": "Current",
"voltage": "Voltage",
"capacity": "Capacity"
}
}
}

View File

@@ -1250,6 +1250,24 @@
"cancel": "取消",
"please_select_filter_condition": "请选择筛选条件",
"create_download_task_success": "创建下载任务成功"
},
"battery_curve": {
"query": "查询",
"reset": "重置",
"battery_code": "电池条码",
"enter_battery_code": "请输入电池条码",
"data_empty": "暂无曲线记录",
"batch_name": "批次",
"process_name": "工序",
"upload_time": "上传时间",
"device_code": "设备编码",
"battery_no": "电池通道",
"export_all_data": "导出所有数据",
"view_full_tray_curve": "查看整盘曲线",
"data_chart": "数据图表",
"current": "电流",
"voltage": "电压",
"capacity": "容量"
}
}
}

View File

@@ -25,6 +25,12 @@ export default {
name: `${pre}basic_traceability-positive_direction_traceability`,
meta: { ...meta, cache: true, title: '正向追溯' },
component: _import('data-platform/traceability/forward')
},
{
path: 'produce/traceability/curve',
name: `${pre}traceability-curve`,
meta: { ...meta, cache: true, title: '电池曲线' },
component: _import('data-platform/traceability/battery-curve')
}
])('data_middleground-')
}

View File

@@ -0,0 +1,275 @@
<template>
<d2-container>
<template #header>
<div class="search-bar">
<el-form ref="searchForm" :inline="true" :model="search" size="mini">
<el-form-item :label="$t(key('battery_code'))" prop="battery_id">
<el-input
v-model.trim="search.battery_id"
:placeholder="$t(key('enter_battery_code'))"
clearable
style="width:240px"
@keyup.enter.native="fetchRecords"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" :disabled="loading" @click="fetchRecords">
{{ $t(key('query')) }}
</el-button>
<el-button icon="el-icon-refresh" :disabled="loading" @click="resetSearch">
{{ $t(key('reset')) }}
</el-button>
</el-form-item>
</el-form>
</div>
</template>
<div v-loading="loading" class="curve-page">
<aside class="curve-list">
<el-empty v-if="records.length === 0" :description="$t(key('data_empty'))" :image-size="80" />
<el-menu v-else :default-active="String(activeIndex)" @select="selectRecord">
<el-menu-item v-for="(row, index) in records" :key="row.id || index" :index="String(index)">
<div class="curve-list__item">
<div>{{ $t(key('batch_name')) }}: {{ row.batch || '-' }}</div>
<div>{{ $t(key('process_name')) }}: {{ row.process_name || '-' }}</div>
<div>{{ $t(key('upload_time')) }}: {{ row.end_time || '-' }}</div>
</div>
</el-menu-item>
</el-menu>
</aside>
<main class="curve-content">
<div class="curve-toolbar">
<el-form :inline="true" size="mini" label-width="80px">
<el-form-item :label="$t(key('device_code'))">
<el-input :value="activeRecord.device_code || ''" disabled style="width:180px" />
</el-form-item>
<el-form-item :label="$t(key('battery_no'))">
<el-input :value="activeRecord.channel || ''" disabled style="width:180px" />
</el-form-item>
<el-form-item>
<el-button type="danger" icon="el-icon-download" :disabled="!activeRecord.id" @click="exportAllData">
{{ $t(key('export_all_data')) }}
</el-button>
<el-button type="warning" icon="el-icon-view" :disabled="!activeRecord.url" @click="viewFullTrayCurve">
{{ $t(key('view_full_tray_curve')) }}
</el-button>
</el-form-item>
</el-form>
</div>
<div ref="chart" class="curve-chart" />
</main>
</div>
</d2-container>
</template>
<script>
import * as echarts from 'echarts'
import { i18nMixin } from '@/composables/useI18n'
import {
exportBatteryCurveData,
getBatteryCurveData,
getBatteryCurveRecords
} from '@/api/data-platform/traceability/battery-curve'
export default {
name: 'data-platform-traceability-battery-curve',
mixins: [i18nMixin('page.data_platform.traceability.battery_curve')],
data () {
return {
loading: false,
chartLoading: false,
search: {
battery_id: ''
},
records: [],
activeIndex: -1,
chart: null,
xAxis: [],
seriesData: []
}
},
computed: {
activeRecord () {
return this.records[this.activeIndex] || {}
}
},
mounted () {
this.initChart()
window.addEventListener('resize', this.resizeChart)
},
beforeDestroy () {
window.removeEventListener('resize', this.resizeChart)
if (this.chart) this.chart.dispose()
},
methods: {
responseData (res) {
return res && res.data !== undefined ? res.data : res
},
initChart () {
this.chart = echarts.init(this.$refs.chart)
this.drawChart()
},
resizeChart () {
if (this.chart) this.chart.resize()
},
async fetchRecords () {
this.loading = true
try {
const res = await getBatteryCurveRecords({
...this.search,
action: 'battery_traceability_search'
})
const data = this.responseData(res)
this.records = Array.isArray(data) ? data : []
this.activeIndex = this.records.length ? 0 : -1
if (this.activeIndex > -1) {
await this.loadCurve(this.activeRecord.id)
} else {
this.xAxis = []
this.seriesData = []
this.drawChart()
}
} finally {
this.loading = false
}
},
resetSearch () {
this.search.battery_id = ''
this.records = []
this.activeIndex = -1
this.xAxis = []
this.seriesData = []
this.drawChart()
},
selectRecord (index) {
this.activeIndex = Number(index)
this.loadCurve(this.activeRecord.id)
},
async loadCurve (id) {
if (!id) return
this.chartLoading = true
if (this.chart) this.chart.showLoading()
try {
const res = await getBatteryCurveData({ id, action: 'batterycurveread' })
const data = this.responseData(res) || {}
if (Array.isArray(data)) {
this.xAxis = []
this.seriesData = []
} else {
this.xAxis = data.tm || []
this.seriesData = [
{ lineStyle: { normal: { width: 1 } }, name: this.$t(this.key('current')), type: 'line', symbolSize: 0, data: data.A || [] },
{ lineStyle: { normal: { width: 1 } }, yAxisIndex: 1, name: this.$t(this.key('voltage')), type: 'line', symbolSize: 0, data: data.V || [] },
{ lineStyle: { normal: { width: 1 } }, yAxisIndex: 2, name: this.$t(this.key('capacity')), type: 'bar', symbolSize: 0, data: data.C || [] }
]
}
this.drawChart()
} finally {
this.chartLoading = false
if (this.chart) this.chart.hideLoading()
}
},
drawChart () {
if (!this.chart) return
const option = {
title: { text: this.$t(this.key('data_chart')) },
tooltip: { trigger: 'axis' },
legend: {
data: [this.$t(this.key('current')), this.$t(this.key('voltage')), this.$t(this.key('capacity'))],
selected: {
[this.$t(this.key('current'))]: true,
[this.$t(this.key('voltage'))]: true,
[this.$t(this.key('capacity'))]: false
}
},
toolbox: { feature: { saveAsImage: {} } },
dataZoom: [
{ type: 'inside', xAxisIndex: [0], realtime: false },
{ type: 'inside', yAxisIndex: [0], realtime: false }
],
xAxis: { type: 'category', boundaryGap: false, data: this.xAxis, scale: false },
yAxis: [
{ type: 'value', scale: false, name: this.$t(this.key('current')), axisLabel: { formatter: '{value} mA' } },
{ type: 'value', scale: false, name: this.$t(this.key('voltage')), axisLabel: { formatter: '{value} mV' } },
{ type: 'value', scale: false, name: this.$t(this.key('capacity')), axisLabel: { formatter: '{value} mAH' }, position: 'right', offset: 80 }
],
series: this.seriesData
}
this.chart.setOption(option, true)
},
viewFullTrayCurve () {
if (this.activeRecord.url) window.location.href = this.activeRecord.url
},
async exportAllData () {
if (!this.activeRecord.id) return
const res = await exportBatteryCurveData({
id: this.activeRecord.id,
action: 'export_all_data'
})
const data = this.responseData(res)
if (!data) return
const link = document.createElement('a')
link.href = process.env.VUE_APP_PRO_PUBLIC_URL ? process.env.VUE_APP_PRO_PUBLIC_URL + data : data
link.target = '_blank'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
}
}
</script>
<style lang="scss" scoped>
.search-bar {
margin-bottom: -18px;
}
.curve-page {
display: grid;
grid-template-columns: 260px minmax(0, 1fr);
height: calc(100vh - 170px);
min-height: 560px;
border: 1px solid #ebeef5;
}
.curve-list {
overflow: auto;
border-right: 1px solid #ebeef5;
background: #fff;
}
.curve-list__item {
width: 100%;
overflow: hidden;
line-height: 1.5;
white-space: normal;
word-break: break-all;
}
.curve-list ::v-deep .el-menu-item {
height: auto;
min-height: 86px;
padding: 8px 12px !important;
line-height: 1.5;
}
.curve-content {
min-width: 0;
padding: 12px;
background: #fafafa;
}
.curve-toolbar {
margin-bottom: 12px;
padding-bottom: 10px;
border-bottom: 1px solid #ebeef5;
}
.curve-chart {
height: calc(100% - 64px);
min-height: 430px;
border: 1px solid #ebeef5;
background: #fff;
}
</style>