yeg
2026-08-27 ebd47e950c8d45f5cc21336f4996857de58e0ea6
fix: persist battery group configuration
2个文件已添加
9个文件已修改
157 ■■■■■ 已修改文件
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/TBatteryGroupFieldController.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/TBatteryGroupTemplateController.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/db/migration/V11__persist_battery_group_field_values.sql 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/test/java/com/ruoyi/config/BatterySelectionMapperContractTest.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/test/java/com/ruoyi/config/FlywayMigrationContractTest.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TBatteryGroupServiceImplTest.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/TBatteryGroupRelationField.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBatteryGroupFieldServiceImpl.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBatteryGroupServiceImpl.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/TBatteryGroupFieldMapper.xml 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/TBatteryGroupMapper.xml 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/TBatteryGroupFieldController.java
@@ -33,7 +33,7 @@
    private ITBatteryGroupFieldService batteryGroupFieldService;
    /** 分页查询电池组字段列表。 */
    @PreAuthorize("@ss.hasPermi('system:batteryGroupField:list')")
    @PreAuthorize("@ss.hasPermi('system:batteryGroup:list')")
    @GetMapping("/list")
    public TableDataInfo list(TBatteryGroupField field)
    {
@@ -43,7 +43,7 @@
    }
    /** 查询电池组字段详情。 */
    @PreAuthorize("@ss.hasPermi('system:batteryGroupField:query')")
    @PreAuthorize("@ss.hasPermi('system:batteryGroup:query')")
    @GetMapping(value = "/{fieldId}")
    public AjaxResult getInfo(@PathVariable Long fieldId)
    {
@@ -51,16 +51,17 @@
    }
    /** 新增电池组字段。 */
    @PreAuthorize("@ss.hasPermi('system:batteryGroupField:add')")
    @PreAuthorize("@ss.hasPermi('system:batteryGroup:add')")
    @Log(title = "电池组字段管理", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@Validated @RequestBody TBatteryGroupField field)
    {
        field.setCreateBy(getUsername());
        return toAjax(batteryGroupFieldService.insertBatteryGroupField(field));
    }
    /** 编辑电池组字段基础资料。 */
    @PreAuthorize("@ss.hasPermi('system:batteryGroupField:edit')")
    @PreAuthorize("@ss.hasPermi('system:batteryGroup:edit')")
    @Log(title = "电池组字段管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@Validated @RequestBody TBatteryGroupField field)
@@ -70,7 +71,7 @@
    }
    /** 启用或禁用电池组字段。 */
    @PreAuthorize("@ss.hasPermi('system:batteryGroupField:edit')")
    @PreAuthorize("@ss.hasPermi('system:batteryGroup:edit')")
    @Log(title = "电池组字段管理", businessType = BusinessType.UPDATE)
    @PutMapping("/changeStatus")
    public AjaxResult changeStatus(@RequestBody TBatteryGroupField field)
@@ -80,7 +81,7 @@
    }
    /** 批量逻辑删除电池组字段。 */
    @PreAuthorize("@ss.hasPermi('system:batteryGroupField:remove')")
    @PreAuthorize("@ss.hasPermi('system:batteryGroup:remove')")
    @Log(title = "电池组字段管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{fieldIds}")
    public AjaxResult remove(@PathVariable Long[] fieldIds)
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/TBatteryGroupTemplateController.java
@@ -31,7 +31,7 @@
    private ITBatteryGroupTemplateService batteryGroupTemplateService;
    /** 查询模板下拉选项。 */
    @PreAuthorize("@ss.hasPermi('system:batteryGroupTemplate:list')")
    @PreAuthorize("@ss.hasPermi('system:batteryGroup:list')")
    @GetMapping("/options")
    public AjaxResult options()
    {
@@ -40,7 +40,7 @@
    }
    /** 查询模板详情及字段关系。 */
    @PreAuthorize("@ss.hasPermi('system:batteryGroupTemplate:query')")
    @PreAuthorize("@ss.hasPermi('system:batteryGroup:list')")
    @GetMapping("/{templateId}")
    public AjaxResult getInfo(@PathVariable Long templateId)
    {
@@ -48,7 +48,7 @@
    }
    /** 新增电池组模板。 */
    @PreAuthorize("@ss.hasPermi('system:batteryGroupTemplate:add')")
    @PreAuthorize("@ss.hasPermi('system:batteryGroup:add')")
    @Log(title = "电池组模板管理", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@Validated @RequestBody TBatteryGroupTemplate template)
@@ -58,7 +58,7 @@
    }
    /** 编辑电池组模板并替换字段关系。 */
    @PreAuthorize("@ss.hasPermi('system:batteryGroupTemplate:edit')")
    @PreAuthorize("@ss.hasPermi('system:batteryGroup:edit')")
    @Log(title = "电池组模板管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@Validated @RequestBody TBatteryGroupTemplate template)
ruoyi-admin/src/main/resources/db/migration/V11__persist_battery_group_field_values.sql
New file
@@ -0,0 +1,2 @@
ALTER TABLE t_battery_group_relation_field
    ADD COLUMN field_value VARCHAR(500) NULL COMMENT '电池组模板字段值' AFTER battery_group_field_id;
ruoyi-admin/src/test/java/com/ruoyi/config/BatterySelectionMapperContractTest.java
New file
@@ -0,0 +1,38 @@
package com.ruoyi.config;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.Test;
/** 电池组写入与测试选项查询的 Mapper 契约。 */
class BatterySelectionMapperContractTest
{
    @Test
    void batteryGroupBatteriesFeedEnabledTestOptions()
    {
        String groupMapper = resource("mapper/system/TBatteryGroupMapper.xml");
        String testMapper = resource("mapper/system/TTestMapper.xml");
        assertTrue(groupMapper.contains("insert into t_battery_group_battery"));
        assertTrue(testMapper.contains("id=\"selectEnabledBatteryOptions\""));
        assertTrue(testMapper.contains("from t_battery_group_battery battery"));
        assertTrue(testMapper.contains("battery_group.status = '0'"));
        assertTrue(testMapper.contains("battery.battery_no batteryNo"));
        assertTrue(groupMapper.contains("t.test_status not in ('COMPLETED', 'TERMINATED')"));
    }
    private static String resource(String path)
    {
        try (InputStream stream = BatterySelectionMapperContractTest.class.getClassLoader().getResourceAsStream(path))
        {
            if (stream == null) throw new AssertionError("缺少资源 " + path);
            return new String(stream.readAllBytes(), StandardCharsets.UTF_8);
        }
        catch (Exception exception)
        {
            throw new AssertionError("无法读取资源 " + path, exception);
        }
    }
}
ruoyi-admin/src/test/java/com/ruoyi/config/FlywayMigrationContractTest.java
@@ -89,6 +89,11 @@
        assertTrue(v10.contains("collector_id"));
        assertTrue(v10.contains("fk_test_battery_collector"));
        assertFalse(v10.matches("(?s).*\\bINSERT\\s+INTO\\b.*"));
        String v11 = resource("db/migration/V11__persist_battery_group_field_values.sql");
        assertTrue(v11.contains("ALTER TABLE t_battery_group_relation_field"));
        assertTrue(v11.contains("field_value VARCHAR(500)"));
        assertFalse(v11.matches("(?s).*\\bINSERT\\s+INTO\\b.*"));
    }
    private static String sha256(String path)
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TBatteryGroupServiceImplTest.java
@@ -9,6 +9,7 @@
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -18,6 +19,7 @@
import org.mockito.junit.jupiter.MockitoExtension;
import com.ruoyi.system.domain.TBatteryGroup;
import com.ruoyi.system.domain.TBatteryGroupBattery;
import com.ruoyi.system.domain.TBatteryGroupRelationField;
import com.ruoyi.system.mapper.TBatteryGroupMapper;
/** 电池组 Service 单元测试。 */
@@ -53,4 +55,40 @@
                .map(TBatteryGroupBattery::getBatteryNo).toList());
        verify(batteryGroupMapper, never()).batchInsertRelationFields(anyList());
    }
    @Test
    void updateShouldPersistStatusAndTemplateFieldValue()
    {
        TBatteryGroup current = new TBatteryGroup();
        current.setGroupId(12L);
        current.setStatus("0");
        TBatteryGroup group = new TBatteryGroup();
        group.setGroupId(12L);
        group.setGroupName("样品组");
        group.setModel("M-01");
        group.setStatus("1");
        group.setBatteryNos(Collections.singletonList("BAT-01"));
        group.setTemplateId(5L);
        TBatteryGroupRelationField relation = new TBatteryGroupRelationField();
        relation.setBatteryGroupFieldId(7L);
        relation.setFieldValue("72Ah");
        group.setTemplateFieldRelations(Collections.singletonList(relation));
        when(batteryGroupMapper.selectBatteryGroupById(12L)).thenReturn(current);
        when(batteryGroupMapper.countTestingByGroupId(12L)).thenReturn(0);
        when(batteryGroupMapper.selectBatteryByNo("BAT-01", 12L)).thenReturn(null);
        when(batteryGroupMapper.selectTemplate(5L)).thenReturn(new TBatteryGroup());
        when(batteryGroupMapper.selectTemplateFieldIds(5L)).thenReturn(Collections.singletonList(7L));
        when(batteryGroupMapper.selectValidTemplateFields(5L, Collections.singletonList(7L)))
                .thenReturn(Collections.singletonList(relation));
        when(batteryGroupMapper.updateBatteryGroup(group)).thenReturn(1);
        assertEquals(1, batteryGroupService.updateBatteryGroup(group));
        verify(batteryGroupMapper).updateBatteryGroup(group);
        ArgumentCaptor<List<TBatteryGroupRelationField>> captor = ArgumentCaptor.forClass(List.class);
        verify(batteryGroupMapper).batchInsertRelationFields(captor.capture());
        assertEquals("72Ah", captor.getValue().get(0).getFieldValue());
        assertEquals("1", group.getStatus());
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/TBatteryGroupRelationField.java
@@ -12,6 +12,7 @@
    private Long batteryGroupFieldId;
    private String fieldName;
    private String fieldType;
    private String fieldValue;
    private String delFlag;
    public Long getRelationId() { return relationId; } public void setRelationId(Long v) { relationId = v; }
    public Long getGroupId() { return groupId; } public void setGroupId(Long v) { groupId = v; }
@@ -19,5 +20,6 @@
    public Long getBatteryGroupFieldId() { return batteryGroupFieldId; } public void setBatteryGroupFieldId(Long v) { batteryGroupFieldId = v; }
    public String getFieldName() { return fieldName; } public void setFieldName(String v) { fieldName = v; }
    public String getFieldType() { return fieldType; } public void setFieldType(String v) { fieldType = v; }
    public String getFieldValue() { return fieldValue; } public void setFieldValue(String v) { fieldValue = v; }
    public String getDelFlag() { return delFlag; } public void setDelFlag(String v) { delFlag = v; }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBatteryGroupFieldServiceImpl.java
@@ -62,7 +62,11 @@
    public int insertBatteryGroupField(TBatteryGroupField field)
    {
        validateField(field, false);
        field.setStatus(NORMAL);
        if (StringUtils.isEmpty(field.getStatus()))
        {
            field.setStatus(NORMAL);
        }
        validateStatus(field.getStatus());
        field.setDelFlag(0L);
        field.setCreateTime(new Date());
        return batteryGroupFieldMapper.insertBatteryGroupField(field);
@@ -73,6 +77,7 @@
    public int updateBatteryGroupField(TBatteryGroupField field)
    {
        validateField(field, true);
        validateStatus(field.getStatus());
        field.setUpdateTime(new Date());
        return batteryGroupFieldMapper.updateBatteryGroupField(field);
    }
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBatteryGroupServiceImpl.java
@@ -22,7 +22,6 @@
public class TBatteryGroupServiceImpl implements ITBatteryGroupService
{
    private static final String ENABLED = "0";
    private static final String TESTING = "1";
    @Autowired
    private TBatteryGroupMapper batteryGroupMapper;
@@ -56,13 +55,13 @@
    @Transactional(rollbackFor = Exception.class)
    public int insertBatteryGroup(TBatteryGroup group)
    {
        validate(group, false);
        group.setGroupName(StringUtils.trim(group.getGroupName()));
        group.setCreateTime(new Date());
        if (StringUtils.isEmpty(group.getStatus()))
        {
            group.setStatus(ENABLED);
        }
        validate(group, false);
        group.setGroupName(StringUtils.trim(group.getGroupName()));
        group.setCreateTime(new Date());
        int rows = batteryGroupMapper.insertBatteryGroup(group);
        replaceRelations(group);
        return rows;
@@ -76,10 +75,16 @@
        {
            throw new ServiceException("电池组ID不能为空");
        }
        if (batteryGroupMapper.selectBatteryGroupById(group.getGroupId()) == null)
        TBatteryGroup current = batteryGroupMapper.selectBatteryGroupById(group.getGroupId());
        if (current == null)
        {
            throw new ServiceException("电池组不存在");
        }
        if (StringUtils.isEmpty(group.getStatus()))
        {
            group.setStatus(current.getStatus());
        }
        validateStatusChange(group, current.getStatus());
        validate(group, true);
        group.setGroupName(StringUtils.trim(group.getGroupName()));
        group.setUpdateTime(new Date());
@@ -100,7 +105,7 @@
        {
            throw new ServiceException("电池组ID和目标状态不能为空");
        }
        if (TESTING.equals(group.getStatus()) || !ENABLED.equals(group.getStatus()) && !"1".equals(group.getStatus()))
        if (!ENABLED.equals(group.getStatus()) && !"1".equals(group.getStatus()))
        {
            throw new ServiceException("电池组状态不正确");
        }
@@ -155,6 +160,10 @@
        {
            throw new ServiceException("电池组型号不能为空");
        }
        if (!ENABLED.equals(group.getStatus()) && !"1".equals(group.getStatus()))
        {
            throw new ServiceException("电池组状态不正确");
        }
        TBatteryGroup existing = batteryGroupMapper.selectBatteryGroupByName(StringUtils.trim(group.getGroupName()));
        if (existing != null && (group.getGroupId() == null || !group.getGroupId().equals(existing.getGroupId())))
        {
@@ -198,6 +207,10 @@
                if (relation == null || relation.getBatteryGroupFieldId() == null || !fieldIds.add(relation.getBatteryGroupFieldId()))
                {
                    throw new ServiceException("模板字段关系不正确");
                }
                if (relation.getFieldValue() != null && relation.getFieldValue().length() > 500)
                {
                    throw new ServiceException("模板字段值长度不能超过500个字符");
                }
            }
        }
@@ -258,4 +271,13 @@
        }
        batteryGroupMapper.batchInsertRelationFields(relations);
    }
    private void validateStatusChange(TBatteryGroup group, String currentStatus)
    {
        if ("1".equals(group.getStatus()) && !"1".equals(currentStatus)
                && batteryGroupMapper.countTestingByGroupId(group.getGroupId()) > 0)
        {
            throw new ServiceException("测试中的电池组不能禁用");
        }
    }
}
ruoyi-system/src/main/resources/mapper/system/TBatteryGroupFieldMapper.xml
@@ -70,6 +70,7 @@
        update t_battery_group_field
        set field_name = #{fieldName},
            field_type = #{fieldType},
            status = #{status},
            remark = #{remark},
            update_by = #{updateBy},
            update_time = #{updateTime}
ruoyi-system/src/main/resources/mapper/system/TBatteryGroupMapper.xml
@@ -22,6 +22,7 @@
        <id property="relationId" column="relation_id" /><result property="groupId" column="group_id" />
        <result property="templateId" column="template_id" /><result property="batteryGroupFieldId" column="battery_group_field_id" />
        <result property="fieldName" column="field_name" /><result property="fieldType" column="field_type" />
        <result property="fieldValue" column="field_value" />
        <result property="delFlag" column="del_flag" />
    </resultMap>
    <sql id="groupColumns">select group_id, group_name, model, purpose, z, h, f, a, b, status, create_by, create_time, update_by, update_time, remark, del_flag from t_battery_group</sql>
@@ -50,18 +51,18 @@
    <select id="selectBatteryGroupById" parameterType="Long" resultMap="TBatteryGroupResult"><include refid="groupColumns"/> where group_id = #{groupId} and del_flag = '0'</select>
    <select id="selectBatteryGroupByName" resultMap="TBatteryGroupResult"> <include refid="groupColumns"/> where group_name = #{groupName} and del_flag = '0' limit 1</select>
    <select id="selectBatteries" parameterType="Long" resultMap="TBatteryGroupBatteryResult">select relation_id, group_id, battery_no, sort_order, del_flag from t_battery_group_battery where group_id = #{groupId} and del_flag = '0' order by sort_order, relation_id</select>
    <select id="selectRelationFields" parameterType="Long" resultMap="TBatteryGroupRelationFieldResult">select r.relation_id, r.group_id, r.template_id, r.battery_group_field_id, f.field_name, f.field_type, r.del_flag from t_battery_group_relation_field r inner join t_battery_group_field f on f.field_id = r.battery_group_field_id and f.del_flag = '0' where r.group_id = #{groupId} and r.del_flag = '0' order by r.relation_id</select>
    <select id="selectRelationFields" parameterType="Long" resultMap="TBatteryGroupRelationFieldResult">select r.relation_id, r.group_id, r.template_id, r.battery_group_field_id, f.field_name, f.field_type, r.field_value, r.del_flag from t_battery_group_relation_field r inner join t_battery_group_field f on f.field_id = r.battery_group_field_id and f.del_flag = '0' where r.group_id = #{groupId} and r.del_flag = '0' order by r.relation_id</select>
    <select id="selectTemplate" resultType="TBatteryGroup">select template_id, template_name from t_battery_group_template where template_id = #{templateId}</select>
    <select id="selectTemplateFieldIds" resultType="Long">select field_id from t_battery_group_template_field where template_id = #{templateId} and del_flag = '0' order by sort_order, relation_id</select>
    <select id="selectValidTemplateFields" resultMap="TBatteryGroupRelationFieldResult">select r.relation_id, r.template_id, r.field_id as battery_group_field_id, f.field_name, f.field_type, '0' as del_flag from t_battery_group_template_field r inner join t_battery_group_field f on f.field_id = r.field_id and f.del_flag = '0' where r.template_id = #{templateId} and r.del_flag = '0' and r.field_id in <foreach collection="fieldIds" item="fieldId" open="(" separator="," close=")">#{fieldId}</foreach></select>
    <select id="selectBatteryByNo" resultMap="TBatteryGroupBatteryResult">select relation_id, group_id, battery_no, sort_order, del_flag from t_battery_group_battery where battery_no = #{batteryNo} and del_flag = '0' limit 1</select>
    <insert id="insertBatteryGroup" parameterType="TBatteryGroup" useGeneratedKeys="true" keyProperty="groupId">insert into t_battery_group (group_name, model, purpose, z, h, f, a, b, status, create_by, create_time, remark, del_flag) values (#{groupName}, #{model}, #{purpose}, #{z}, #{h}, #{f}, #{a}, #{b}, #{status}, #{createBy}, sysdate(), #{remark}, '0')</insert>
    <update id="updateBatteryGroup" parameterType="TBatteryGroup">update t_battery_group set group_name=#{groupName}, model=#{model}, purpose=#{purpose}, z=#{z}, h=#{h}, f=#{f}, a=#{a}, b=#{b}, update_by=#{updateBy}, update_time=sysdate(), remark=#{remark} where group_id=#{groupId} and del_flag='0'</update>
    <update id="updateBatteryGroup" parameterType="TBatteryGroup">update t_battery_group set group_name=#{groupName}, model=#{model}, purpose=#{purpose}, z=#{z}, h=#{h}, f=#{f}, a=#{a}, b=#{b}, status=#{status}, update_by=#{updateBy}, update_time=sysdate(), remark=#{remark} where group_id=#{groupId} and del_flag='0'</update>
    <update id="updateBatteryGroupStatus" parameterType="TBatteryGroup">update t_battery_group set status=#{status}, update_by=#{updateBy}, update_time=sysdate() where group_id=#{groupId} and del_flag='0'</update>
    <update id="deleteBatteryGroup">update t_battery_group set del_flag=cast(group_id as char), update_by=#{updateBy}, update_time=sysdate() where group_id=#{groupId} and del_flag='0'</update>
    <update id="deleteBatteries">update t_battery_group_battery set del_flag=cast(relation_id as char) where group_id=#{groupId} and del_flag='0'</update>
    <update id="deleteRelationFields">update t_battery_group_relation_field set del_flag=cast(relation_id as char) where group_id=#{groupId} and del_flag='0'</update>
    <insert id="batchInsertBatteries">insert into t_battery_group_battery (group_id,battery_no,sort_order,del_flag) values <foreach collection="items" item="item" separator=",">(#{item.groupId},#{item.batteryNo},#{item.sortOrder},#{item.delFlag})</foreach></insert>
    <insert id="batchInsertRelationFields">insert into t_battery_group_relation_field (group_id,template_id,battery_group_field_id,del_flag) values <foreach collection="items" item="item" separator=",">(#{item.groupId},#{item.templateId},#{item.batteryGroupFieldId},#{item.delFlag})</foreach></insert>
    <select id="countTestingByGroupId" resultType="int">select count(1) from t_test_battery b inner join t_test t on t.test_id = b.test_id and t.del_flag = '0' where b.group_id=#{groupId} and b.del_flag='0' and t.status='1'</select>
    <insert id="batchInsertRelationFields">insert into t_battery_group_relation_field (group_id,template_id,battery_group_field_id,field_value,del_flag) values <foreach collection="items" item="item" separator=",">(#{item.groupId},#{item.templateId},#{item.batteryGroupFieldId},#{item.fieldValue},#{item.delFlag})</foreach></insert>
    <select id="countTestingByGroupId" resultType="int">select count(1) from t_test_battery b inner join t_test t on t.test_id = b.test_id and t.del_flag = 0 where b.group_id=#{groupId} and b.del_flag=0 and t.test_status not in ('COMPLETED', 'TERMINATED')</select>
</mapper>