From 8bc9027e4614944c6d5ee4fa2d50d01ebb87f3e1 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期四, 27 八月 2026 22:26:51 +0800
Subject: [PATCH] fix: persist battery group batteries through api
---
tests/battery-group-persistence.contract.test.mjs | 31 ++++++
src/api/batteryGroups.ts | 85 ++++++++++++++++
src/api/batteryGroupPayload.ts | 51 ++++++++++
src/views/BatteryGroupForm.vue | 96 ++++++++++--------
src/views/BatteryGroup.vue | 3
5 files changed, 219 insertions(+), 47 deletions(-)
diff --git a/src/api/batteryGroupPayload.ts b/src/api/batteryGroupPayload.ts
new file mode 100644
index 0000000..28014a2
--- /dev/null
+++ b/src/api/batteryGroupPayload.ts
@@ -0,0 +1,51 @@
+export type GroupStatus = '启用' | '禁用'
+
+export interface BatteryGroupPayload {
+ groupName: string
+ model: string
+ purpose: string
+ remark: string
+ status: '0' | '1'
+ z: string
+ h: string
+ f: string
+ a: string
+ b: string
+ batteryNos: string[]
+ templateId: number | null
+ templateFieldRelations?: Array<{ batteryGroupFieldId: number }>
+}
+
+interface BatteryGroupFormPayloadInput {
+ name: string
+ model: string
+ purpose: string
+ remark: string
+ status: GroupStatus
+ specs: Record<string, string>
+ batteries: Array<{ value: string }>
+}
+
+export function buildBatteryGroupPayload(
+ form: BatteryGroupFormPayloadInput,
+ templateId: number | null,
+ templateFieldIds: number[],
+): BatteryGroupPayload {
+ return {
+ groupName: form.name.trim(),
+ model: form.model.trim(),
+ purpose: form.purpose.trim(),
+ remark: form.remark.trim(),
+ status: form.status === '禁用' ? '1' : '0',
+ z: form.specs.z || '',
+ h: form.specs.h || '',
+ f: form.specs.f || '',
+ a: form.specs.a || '',
+ b: form.specs.b || '',
+ batteryNos: form.batteries.map(item => item.value.trim()).filter(Boolean),
+ templateId,
+ templateFieldRelations: templateId
+ ? templateFieldIds.map(batteryGroupFieldId => ({ batteryGroupFieldId }))
+ : undefined,
+ }
+}
diff --git a/src/api/batteryGroups.ts b/src/api/batteryGroups.ts
index 25ea979..3a5de68 100644
--- a/src/api/batteryGroups.ts
+++ b/src/api/batteryGroups.ts
@@ -1,5 +1,7 @@
-import type { GroupStatus } from '@/stores/batteryGroups'
import { request, type ApiResponse } from './request'
+import type { BatteryGroupPayload, GroupStatus } from './batteryGroupPayload'
+
+export type { GroupStatus } from './batteryGroupPayload'
export interface BatteryGroupListParams {
pageNum: number
@@ -13,6 +15,17 @@
endCreateTime?: string
}
+interface BatteryGroupBatteryDto {
+ batteryNo: string | null
+}
+
+interface BatteryGroupTemplateFieldDto {
+ templateId: number | null
+ batteryGroupFieldId: number | null
+ fieldName: string | null
+ fieldType: string | null
+}
+
interface BatteryGroupDto {
groupId: number
groupName: string | null
@@ -22,6 +35,14 @@
createBy: string | null
createTime: string | null
batteryCount: number | null
+ remark?: string | null
+ z?: string | null
+ h?: string | null
+ f?: string | null
+ a?: string | null
+ b?: string | null
+ batteries?: BatteryGroupBatteryDto[] | null
+ templateFields?: BatteryGroupTemplateFieldDto[] | null
}
interface BatteryGroupListResponse extends ApiResponse {
@@ -49,6 +70,10 @@
data: BatteryGroupCreatorDto[]
}
+interface BatteryGroupDetailResponse extends ApiResponse {
+ data: BatteryGroupDto
+}
+
interface BatteryGroupCreatorDto {
userName: string | null
nickName: string | null
@@ -57,6 +82,26 @@
export interface BatteryGroupCreatorOption {
label: string
value: string
+}
+
+export interface BatteryGroupTemplateField {
+ templateId: number
+ batteryGroupFieldId: number
+ fieldName: string
+ fieldType: string
+}
+
+export interface BatteryGroupDetail {
+ id: number
+ name: string
+ model: string
+ purpose: string
+ remark: string
+ status: GroupStatus
+ creator: string
+ specs: Record<'z' | 'h' | 'f' | 'a' | 'b', string>
+ batteries: string[]
+ templateFields: BatteryGroupTemplateField[]
}
function mapBatteryGroup(item: BatteryGroupDto): BatteryGroupListItem {
@@ -96,3 +141,41 @@
})
.filter(item => item.value)
}
+
+export async function getBatteryGroupDetail(groupId: number): Promise<BatteryGroupDetail> {
+ const result = await request<BatteryGroupDetailResponse>(`/system/batteryGroup/${groupId}`)
+ const item = result.data
+ return {
+ id: item.groupId,
+ name: item.groupName || '',
+ model: item.model || '',
+ purpose: item.purpose || '',
+ remark: item.remark || '',
+ status: item.status === '1' ? '禁用' : '启用',
+ creator: item.createBy || '',
+ specs: { z: item.z || '', h: item.h || '', f: item.f || '', a: item.a || '', b: item.b || '' },
+ batteries: (item.batteries || []).map(battery => battery.batteryNo?.trim() || '').filter(Boolean),
+ templateFields: (item.templateFields || [])
+ .filter(field => field.templateId != null && field.batteryGroupFieldId != null)
+ .map(field => ({
+ templateId: Number(field.templateId),
+ batteryGroupFieldId: Number(field.batteryGroupFieldId),
+ fieldName: field.fieldName || '',
+ fieldType: field.fieldType || '文本',
+ })),
+ }
+}
+
+export function createBatteryGroup(payload: BatteryGroupPayload): Promise<ApiResponse> {
+ return request<ApiResponse>('/system/batteryGroup', {
+ method: 'POST',
+ body: JSON.stringify(payload),
+ })
+}
+
+export function updateBatteryGroup(groupId: number, payload: BatteryGroupPayload): Promise<ApiResponse> {
+ return request<ApiResponse>('/system/batteryGroup', {
+ method: 'PUT',
+ body: JSON.stringify({ groupId, ...payload }),
+ })
+}
diff --git a/src/views/BatteryGroup.vue b/src/views/BatteryGroup.vue
index 09eda1f..7ea5942 100644
--- a/src/views/BatteryGroup.vue
+++ b/src/views/BatteryGroup.vue
@@ -2,8 +2,7 @@
import { onMounted, reactive, ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { useRouter } from 'vue-router'
-import { getBatteryGroupCreatorOptions, getBatteryGroupList, type BatteryGroupCreatorOption, type BatteryGroupListItem } from '@/api/batteryGroups'
-import type { GroupStatus } from '@/stores/batteryGroups'
+import { getBatteryGroupCreatorOptions, getBatteryGroupList, type BatteryGroupCreatorOption, type BatteryGroupListItem, type GroupStatus } from '@/api/batteryGroups'
interface Filters {
id: string
diff --git a/src/views/BatteryGroupForm.vue b/src/views/BatteryGroupForm.vue
index d45b38b..5b76108 100644
--- a/src/views/BatteryGroupForm.vue
+++ b/src/views/BatteryGroupForm.vue
@@ -1,8 +1,10 @@
<script setup lang="ts">
-import { computed, reactive, ref } from 'vue'
+import { computed, onMounted, reactive, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useRoute, useRouter } from 'vue-router'
-import { useBatteryGroups, type GroupStatus, type TemplateField } from '@/stores/batteryGroups'
+import { createBatteryGroup, getBatteryGroupDetail, updateBatteryGroup } from '@/api/batteryGroups'
+import { buildBatteryGroupPayload } from '@/api/batteryGroupPayload'
+import type { GroupStatus, TemplateField } from '@/stores/batteryGroups'
import { useBatteryGroupFields, type BatteryGroupField } from '@/stores/batteryGroupFields'
interface FormState {
@@ -20,11 +22,13 @@
const route = useRoute()
const router = useRouter()
-const { groups, createGroup, updateGroup } = useBatteryGroups()
const { fields: managedFields } = useBatteryGroupFields()
const creators = ['张工', '李工', '周工', '王工', '赵工', '陈工']
const templatePanelOpen = ref(false)
+const loading = ref(false)
const saving = ref(false)
+const persistedTemplateId = ref<number | null>(null)
+const persistedTemplateFieldIds = ref<number[]>([])
let batteryKey = 1
const editingId = computed(() => Number(route.params.id) || null)
@@ -74,35 +78,40 @@
.map(field => ({ key: `managed-field-${field.id}`, label: field.name, type: field.type, value: previousValues.get(field.name) || '' }))
}
-function loadEditingGroup() {
+async function loadEditingGroup() {
if (!editingId.value) return
- const target = groups.value.find(item => item.id === editingId.value)
- if (!target) {
- ElMessage.warning('未找到需要编辑的电池组')
- router.replace('/battery-group')
- return
+ loading.value = true
+ try {
+ const target = await getBatteryGroupDetail(editingId.value)
+ const templateFields = target.templateFields.map(field => ({
+ key: `persisted-field-${field.batteryGroupFieldId}`,
+ label: field.fieldName,
+ type: field.fieldType as TemplateField['type'],
+ value: '',
+ }))
+ persistedTemplateId.value = target.templateFields[0]?.templateId || null
+ persistedTemplateFieldIds.value = target.templateFields.map(field => field.batteryGroupFieldId)
+ Object.assign(form, {
+ name: target.name,
+ model: target.model,
+ purpose: target.purpose,
+ remark: target.remark,
+ creator: target.creator,
+ status: target.status,
+ templateName: '自定义',
+ specs: { ...target.specs },
+ customFields: templateFields,
+ batteries: target.batteries.map(value => ({ key: batteryKey++, value })),
+ })
+ if (!form.batteries.length) form.batteries.push({ key: batteryKey++, value: '' })
+ selectedFieldIds.value = [...persistedTemplateFieldIds.value]
+ } catch (error) {
+ ElMessage.error(error instanceof Error ? error.message : '加载电池组失败')
+ await router.replace('/battery-group')
+ } finally {
+ loading.value = false
}
- Object.assign(form, {
- name: target.name,
- model: target.model,
- purpose: target.purpose,
- remark: target.remark,
- creator: target.creator,
- status: target.status,
- templateName: target.templateName,
- specs: { ...target.specs },
- customFields: target.customFields.map(field => {
- const managedField = managedFields.value.find(item => item.name === field.label)
- return { ...field, type: managedField?.type || field.type }
- }),
- batteries: target.batteries.map(value => ({ key: batteryKey++, value })),
- })
- selectedFieldIds.value = target.customFields
- .map(customField => managedFields.value.find(field => field.name === customField.label)?.id)
- .filter((id): id is number => id !== undefined)
}
-
-loadEditingGroup()
function addBattery() {
form.batteries.push({ key: batteryKey++, value: '' })
@@ -155,8 +164,6 @@
if (form.customFields.some(field => !field.label.trim())) return '请填写全部模板字段名称'
const fieldLabels = form.customFields.map(field => field.label.trim().toLowerCase())
if (new Set(fieldLabels).size !== fieldLabels.length) return '模板字段名称不能重复'
- const duplicateGroup = groups.value.some(item => item.id !== editingId.value && item.name.trim().toLowerCase() === form.name.trim().toLowerCase())
- if (duplicateGroup) return '电池组名称已存在'
return ''
}
@@ -167,19 +174,20 @@
return
}
saving.value = true
- await new Promise(resolve => window.setTimeout(resolve, 250))
- const payload = {
- name: form.name.trim(), model: form.model.trim(), purpose: form.purpose.trim(), remark: form.remark.trim(),
- creator: form.creator, status: form.status, templateName: form.templateName, specs: { ...form.specs },
- customFields: form.customFields.map(field => ({ ...field, label: field.label.trim() })),
- batteries: form.batteries.map(item => item.value.trim()).filter(Boolean),
+ try {
+ const payload = buildBatteryGroupPayload(form, persistedTemplateId.value, persistedTemplateFieldIds.value)
+ if (editingId.value) await updateBatteryGroup(editingId.value, payload)
+ else await createBatteryGroup(payload)
+ ElMessage.success(isEditing.value ? '电池组已更新' : '电池组已创建')
+ await router.push('/battery-group')
+ } catch (error) {
+ ElMessage.error(error instanceof Error ? error.message : '保存电池组失败')
+ } finally {
+ saving.value = false
}
- if (editingId.value) updateGroup(editingId.value, payload)
- else createGroup(payload)
- saving.value = false
- ElMessage.success(isEditing.value ? '电池组已更新' : '电池组已创建')
- await router.push('/battery-group')
}
+
+onMounted(loadEditingGroup)
</script>
<template>
@@ -190,7 +198,7 @@
</div>
<div class="form-layout">
- <div class="form-content">
+ <div v-loading="loading" class="form-content">
<section class="detail-panel">
<header class="panel-heading"><div><i></i><strong>样品详情</strong><span>SAMPLE DETAILS</span></div><small><b>*</b> 为必填项</small></header>
<div class="sample-grid">
@@ -221,7 +229,7 @@
<label><span>状态</span><el-radio-group v-model="form.status"><el-radio-button value="启用">启用</el-radio-button><el-radio-button value="禁用">禁用</el-radio-button></el-radio-group></label>
</section>
- <footer class="submit-bar"><button class="secondary-button" type="button" @click="router.push('/battery-group')">取消</button><button class="primary-button submit-button" type="button" :disabled="saving" @click="submit"><el-icon><Check /></el-icon>{{ saving ? '保存中' : `保存${pageTitle}` }}</button></footer>
+ <footer class="submit-bar"><button class="secondary-button" type="button" @click="router.push('/battery-group')">取消</button><button class="primary-button submit-button" type="button" :disabled="loading || saving" @click="submit"><el-icon><Check /></el-icon>{{ saving ? '保存中' : `保存${pageTitle}` }}</button></footer>
</div>
<aside class="template-panel" :aria-hidden="!templatePanelOpen">
diff --git a/tests/battery-group-persistence.contract.test.mjs b/tests/battery-group-persistence.contract.test.mjs
new file mode 100644
index 0000000..d100854
--- /dev/null
+++ b/tests/battery-group-persistence.contract.test.mjs
@@ -0,0 +1,31 @@
+import assert from 'node:assert/strict'
+import test from 'node:test'
+import { buildBatteryGroupPayload } from '../src/api/batteryGroupPayload.ts'
+
+test('battery group payload contains the entered battery numbers', () => {
+ const payload = buildBatteryGroupPayload({
+ name: ' 样品组 ',
+ model: ' M-01 ',
+ purpose: ' 容量验证 ',
+ remark: ' 首批 ',
+ status: '启用',
+ specs: { z: 'Z1', h: '', f: '', a: '', b: '' },
+ batteries: [{ value: ' BAT-01 ' }, { value: '' }, { value: 'BAT-02' }],
+ }, null, [])
+
+ assert.deepEqual(payload, {
+ groupName: '样品组',
+ model: 'M-01',
+ purpose: '容量验证',
+ remark: '首批',
+ status: '0',
+ z: 'Z1',
+ h: '',
+ f: '',
+ a: '',
+ b: '',
+ batteryNos: ['BAT-01', 'BAT-02'],
+ templateId: null,
+ templateFieldRelations: undefined,
+ })
+})
--
Gitblit v1.7.1