yeg
2026-08-30 9c0fd80309b277420c492180ae9f98f779f0f5c8
ruoyi-system/src/main/resources/mapper/system/TTestMapper.xml
@@ -19,6 +19,9 @@
        <result property="startedAtUtc" column="started_at_utc" />
        <result property="endedAtUtc" column="ended_at_utc" />
        <result property="runtimeAttach" column="runtime_attach" />
        <result property="backfillStatus" column="backfill_status" />
        <result property="backfillStartedAtUtc" column="backfill_started_at_utc" />
        <result property="backfillCompletedAtUtc" column="backfill_completed_at_utc" />
        <result property="delFlag" column="del_flag" />
        <result property="createBy" column="create_by" />
        <result property="createTime" column="create_time" />
@@ -108,16 +111,53 @@
        <result property="exceptionInfo" column="exception_info" />
        <result property="delFlag" column="del_flag" />
    </resultMap>
    <resultMap id="TTestCollectorExceptionIntervalResultMap" type="TTestCollectorExceptionInterval">
        <id property="intervalId" column="interval_id" />
        <result property="testId" column="test_id" />
        <result property="batteryRelationId" column="battery_relation_id" />
        <result property="collectorId" column="collector_id" />
        <result property="collectorCode" column="collector_code" />
        <result property="collectorName" column="collector_name" />
        <result property="collectorChannelCode" column="collector_channel_code" />
        <result property="measurementName" column="measurement_name" />
        <result property="exceptionType" column="exception_type" />
        <result property="openedAtUtc" column="opened_at_utc" />
        <result property="missingFromUtc" column="missing_from_utc" />
        <result property="recoveredAtUtc" column="recovered_at_utc" />
        <result property="missingToUtc" column="missing_to_utc" />
        <result property="intervalStatus" column="interval_status" />
        <result property="detail" column="detail" />
    </resultMap>
    <resultMap id="TTestReceptionIntervalResultMap" type="TTestReceptionInterval">
        <id property="intervalId" column="interval_id" />
        <result property="testId" column="test_id" />
        <result property="bindingId" column="binding_id" />
        <result property="sourceType" column="source_type" />
        <result property="sourceId" column="source_id" />
        <result property="sourceChannelCode" column="source_channel_code" />
        <result property="actionAtUtc" column="action_at_utc" />
        <result property="startBoundaryAtUtc" column="start_boundary_at_utc" />
        <result property="endBoundaryAtUtc" column="end_boundary_at_utc" />
        <result property="boundaryNote" column="boundary_note" />
        <result property="intervalStatus" column="interval_status" />
    </resultMap>
    <sql id="selectTestBase">
        select t.test_id, t.test_name, t.creator_id, creator.nick_name creator_name,
               t.principal_id, principal.nick_name principal_name,
               t.test_type_id, ty.test_type_name, t.test_purpose,
               t.test_status, t.reception_status, t.monitor_timeout_minutes,
               case when t.test_status = 'RUNNING'
                         and exists (select 1 from t_test_collector_exception_interval exception_fact
                                     where exception_fact.test_id = t.test_id
                                       and exception_fact.interval_status = 'OPEN')
                    then 'RUNNING_ABNORMAL'
                    else t.test_status end test_status,
               t.reception_status, t.monitor_timeout_minutes,
               t.started_at_utc, t.ended_at_utc, t.del_flag,
               t.create_by, t.create_time, t.update_by, t.update_time, t.remark,
               (select count(1) from t_test_battery b where b.test_id = t.test_id and b.del_flag = 0) battery_count,
               t.runtime_attach runtime_attach
               t.runtime_attach runtime_attach, t.backfill_status, t.backfill_started_at_utc,
               t.backfill_completed_at_utc
        from t_test t
        left join sys_user creator on creator.user_id = t.creator_id and creator.del_flag = '0'
        left join sys_user principal on principal.user_id = t.principal_id and principal.del_flag = '0'
@@ -132,7 +172,18 @@
            <if test="testName != null and testName != ''">and t.test_name like concat('%', #{testName}, '%')</if>
            <if test="testTypeId != null">and t.test_type_id = #{testTypeId}</if>
            <if test="batteryNo != null and batteryNo != ''">and exists (select 1 from t_test_battery fb where fb.test_id = t.test_id and fb.battery_no = #{batteryNo} and fb.del_flag = 0)</if>
            <if test="testStatus != null and testStatus != ''">and t.test_status = #{testStatus}</if>
            <if test="testStatus != null and testStatus != ''">
                and (
                    (#{testStatus} = 'RUNNING_ABNORMAL' and t.test_status = 'RUNNING'
                        and exists (select 1 from t_test_collector_exception_interval exception_fact
                                    where exception_fact.test_id = t.test_id and exception_fact.interval_status = 'OPEN'))
                    or (#{testStatus} = 'RUNNING' and t.test_status = 'RUNNING'
                        and not exists (select 1 from t_test_collector_exception_interval exception_fact
                                        where exception_fact.test_id = t.test_id and exception_fact.interval_status = 'OPEN'))
                    or (#{testStatus} = 'COMPLETED' and t.test_status in ('COMPLETED', 'TERMINATED'))
                    or (#{testStatus} not in ('RUNNING', 'RUNNING_ABNORMAL', 'COMPLETED') and t.test_status = #{testStatus})
                )
            </if>
            <if test="receptionStatus != null and receptionStatus != ''">and t.reception_status = #{receptionStatus}</if>
            <if test="beginCreateTime != null">and t.create_time &gt;= #{beginCreateTime}</if>
            <if test="endCreateTime != null">and t.create_time &lt;= #{endCreateTime}</if>
@@ -269,6 +320,13 @@
        select threshold_id, test_id, metric_code, min_value, max_value, unit, severity, del_flag
        from t_test_warning_threshold where test_id = #{testId} and del_flag = 0 order by threshold_id
    </select>
    <select id="selectTestReceptionIntervals" parameterType="Long" resultMap="TTestReceptionIntervalResultMap">
        select interval_id, test_id, binding_id, source_type, source_id, source_channel_code,
               action_at_utc, start_boundary_at_utc, end_boundary_at_utc, boundary_note, interval_status
        from t_test_reception_interval
        where test_id = #{testId}
        order by source_type, source_id, source_channel_code, start_boundary_at_utc, interval_id
    </select>
    <select id="selectTestResults" parameterType="TTestResult" resultMap="TTestResultResultMap">
        select result.*, battery.test_id from t_test_result result
        join t_test_battery battery on battery.relation_id = result.relation_id
@@ -316,6 +374,9 @@
    </select>
    <select id="selectCollectorChannelCount" resultType="int">
        select channel_count from t_collector where collector_id = #{collectorId} and status = '0' and del_flag = 0
    </select>
    <select id="selectCollectorCode" resultType="string">
        select collector_code from t_collector where collector_id = #{collectorId} and status = '0' and del_flag = 0
    </select>
    <select id="selectEnabledUserOptions" resultType="com.ruoyi.system.domain.vo.TestUserOptionVo">
@@ -376,6 +437,119 @@
          and cabinet.registration_status = 'REGISTERED'
        for update
    </select>
    <select id="selectTestsForNaturalEnd" resultMap="TTestResultMap">
        <include refid="selectTestBase" />
        where t.del_flag = 0 and t.reception_status in ('RECEIVING', 'PAUSED')
        order by t.test_id
    </select>
    <select id="selectTestsForBackfill" resultMap="TTestResultMap">
        <include refid="selectTestBase" />
        where t.del_flag = 0 and t.reception_status = 'ENDED'
          and t.test_status in ('COMPLETION_PENDING', 'COMPLETED')
          and coalesce(t.backfill_status, 'NOT_STARTED') &lt;&gt; 'COMPLETED'
        order by t.ended_at_utc, t.test_id
    </select>
    <resultMap id="TTestBackfillCursorResultMap" type="com.ruoyi.system.domain.TTestBackfillCursor">
        <id property="cursorId" column="cursor_id" />
        <result property="testId" column="test_id" />
        <result property="bindingId" column="binding_id" />
        <result property="sourceType" column="source_type" />
        <result property="sourceId" column="source_id" />
        <result property="sourceChannelCode" column="source_channel_code" />
        <result property="protocolTestId" column="protocol_test_id" />
        <result property="nextPosition" column="next_position" />
        <result property="sourceStatus" column="source_status" />
        <result property="protocolMetadata" column="protocol_metadata" />
        <result property="lastError" column="last_error" />
        <result property="updatedAtUtc" column="updated_at_utc" />
    </resultMap>
    <select id="selectBackfillCursorForUpdate" resultMap="TTestBackfillCursorResultMap">
        select * from t_test_backfill_cursor
        where test_id = #{testId} and binding_id = #{bindingId}
          and source_type = #{sourceType} and source_id = #{sourceId}
          and (source_channel_code = #{sourceChannelCode} or (source_channel_code is null and #{sourceChannelCode} is null))
        for update
    </select>
    <insert id="insertBackfillCursor" parameterType="com.ruoyi.system.domain.TTestBackfillCursor" useGeneratedKeys="true" keyProperty="cursorId">
        insert into t_test_backfill_cursor
        (test_id, binding_id, source_type, source_id, source_channel_code, protocol_test_id,
         next_position, source_status, protocol_metadata, last_error, updated_at_utc)
        values (#{testId}, #{bindingId}, #{sourceType}, #{sourceId}, #{sourceChannelCode}, #{protocolTestId},
                #{nextPosition}, #{sourceStatus}, cast(#{protocolMetadata} as json), #{lastError}, #{updatedAtUtc})
    </insert>
    <update id="updateBackfillCursor" parameterType="com.ruoyi.system.domain.TTestBackfillCursor">
        update t_test_backfill_cursor set protocol_test_id = #{protocolTestId}, next_position = #{nextPosition},
            source_status = #{sourceStatus}, protocol_metadata = cast(#{protocolMetadata} as json),
            last_error = #{lastError}, updated_at_utc = #{updatedAtUtc}
        where cursor_id = #{cursorId}
    </update>
    <update id="updateTestBackfillStarted">
        update t_test set test_status = 'COMPLETION_PENDING', backfill_status = 'RUNNING',
            backfill_started_at_utc = coalesce(backfill_started_at_utc, #{updatedAtUtc}),
            update_time = #{updatedAtUtc} where test_id = #{testId} and reception_status = 'ENDED'
    </update>
    <update id="updateTestBackfillWaiting">
        update t_test set backfill_status = 'WAITING', update_time = #{updatedAtUtc}, remark = #{error}
        where test_id = #{testId} and reception_status = 'ENDED'
    </update>
    <update id="updateTestBackfillCompleted">
        update t_test set backfill_status = 'COMPLETED', backfill_completed_at_utc = #{updatedAtUtc},
            update_time = #{updatedAtUtc} where test_id = #{testId} and reception_status = 'ENDED'
    </update>
    <update id="updateTestNaturallyEnded">
        update t_test set test_status = 'COMPLETION_PENDING', reception_status = 'ENDED',
            ended_at_utc = #{endedAtUtc}, backfill_status = 'NOT_STARTED', update_time = #{endedAtUtc}
        where test_id = #{testId} and reception_status in ('RECEIVING', 'PAUSED')
    </update>
    <select id="selectSampleContentHash" resultType="string">
        select hex(content_sha256) from t_test_sample
        where channel_id = #{channelId} and bts_test_id = #{btsTestId} and seq_id = #{sequenceId}
    </select>
    <insert id="insertBtsSample">
        insert ignore into t_test_sample
        (test_id, binding_id, channel_id, reception_interval_id, bts_test_id, seq_id, device_time_utc,
         device_time_raw, received_at_utc, cycle_no, step_no, step_type, test_time_ms, voltage_v,
         current_a, capacity_ah, energy_wh, content_sha256)
        values (#{testId}, #{bindingId}, #{channelId}, #{intervalId}, #{btsTestId}, #{sequenceId}, #{deviceTimeUtc},
                #{deviceTimeRaw}, #{receivedAtUtc}, #{cycleNo}, #{stepNo}, #{stepType}, #{testTimeMs}, #{voltageV},
                #{currentA}, #{capacityAh}, #{energyWh}, #{contentSha256})
    </insert>
    <insert id="insertBtsMeasurement">
        insert ignore into t_test_sample_measurement
        (sample_id, metric_code, metric_value, unit, source_type)
        values (#{sampleId}, #{metricCode}, #{metricValue}, #{unit}, #{sourceType})
    </insert>
    <select id="selectBtsSampleId" resultType="long">
        select sample_id from t_test_sample
        where channel_id = #{channelId} and bts_test_id = #{btsTestId} and seq_id = #{sequenceId}
    </select>
    <insert id="insertCollectorSample">
        insert ignore into t_test_collector_sample
        (test_id, binding_id, collector_id, collector_channel_code, sequence_id, device_time_utc,
         device_time_raw, server_received_at_utc, metric_code, metric_value, unit, content_sha256)
        values (#{testId}, #{bindingId}, #{collectorId}, #{channelCode}, #{sequenceId}, #{deviceTimeUtc},
                #{deviceTimeRaw}, #{receivedAtUtc}, #{metricCode}, #{metricValue}, #{unit}, #{contentSha256})
    </insert>
    <select id="selectCollectorSampleId" resultType="long">
        select sample_id from t_test_collector_sample
        where collector_id = #{collectorId} and collector_channel_code = #{channelCode}
          and sequence_id = #{sequenceId} and metric_code = #{metricCode}
    </select>
    <select id="selectCollectorSampleContentHash" resultType="string">
        select hex(content_sha256) from t_test_collector_sample
        where collector_id = #{collectorId} and collector_channel_code = #{channelCode}
          and sequence_id = #{sequenceId} and metric_code = #{metricCode}
    </select>
    <insert id="insertBackfillConflict">
        insert into t_test_exception
        (test_id, channel_id, exception_type, exception_status, severity,
         first_occurred_at_utc, last_occurred_at_utc, occurrence_count, detail)
        values (#{testId}, #{channelId}, 'HISTORY_CONTENT_CONFLICT', 'OPEN', 'WARNING', utc_timestamp(3),
                utc_timestamp(3), 1, #{detail})
        on duplicate key update last_occurred_at_utc = utc_timestamp(3), occurrence_count = occurrence_count + 1,
            detail = values(detail)
    </insert>
    <select id="selectChannelLeaseForUpdate" parameterType="Long" resultMap="TTestBindingResultMap">
        select binding.binding_id, binding.test_id, binding.battery_relation_id, binding.channel_id,
               binding.claim_status
@@ -392,6 +566,19 @@
        insert into t_collector_channel_lease(collector_id, channel_code, test_id, binding_id, acquired_by, acquired_at_utc)
        values(#{collectorId}, #{channelCode}, #{testId}, #{bindingId}, #{acquiredBy}, #{acquiredAtUtc})
    </insert>
    <insert id="insertReceptionInterval">
        insert into t_test_reception_interval
        (test_id, binding_id, source_type, source_id, source_channel_code,
         action_at_utc, start_boundary_at_utc, boundary_note, interval_status)
        values(#{testId}, #{bindingId}, #{sourceType}, #{sourceId}, #{sourceChannelCode},
               #{actionAtUtc}, #{actionAtUtc}, #{boundaryNote}, 'OPEN')
    </insert>
    <update id="closeOpenReceptionIntervals">
        update t_test_reception_interval
        set end_boundary_at_utc = #{endBoundaryAtUtc},
            boundary_note = #{boundaryNote}, interval_status = 'CLOSED'
        where test_id = #{testId} and interval_status = 'OPEN'
    </update>
    <delete id="deleteChannelLeasesByTestId">
        delete from t_channel_lease where test_id = #{testId}
    </delete>
@@ -454,8 +641,53 @@
    </update>
    <update id="updateReceptionStopped">
        update t_test
        set test_status = 'TERMINATED', reception_status = 'ENDED', ended_at_utc = #{endedAtUtc},
        set test_status = 'COMPLETED', reception_status = 'ENDED', ended_at_utc = #{endedAtUtc},
            backfill_status = 'NOT_STARTED',
            update_by = #{updateBy}, update_time = #{endedAtUtc}
        where test_id = #{testId} and reception_status in ('RECEIVING', 'PAUSED') and del_flag = 0
    </update>
    <select id="selectReceivingCollectorSources" resultType="com.ruoyi.system.domain.TTestCollectorSource">
        select test_fact.test_id testId, battery.relation_id batteryRelationId, battery.battery_no batteryNo,
               collector.collector_id collectorId, collector.collector_code collectorCode,
               mapping.channel_code channelCode
        from t_test test_fact
        join t_test_battery battery on battery.test_id = test_fact.test_id and battery.del_flag = 0
        join t_collector collector on collector.collector_id = battery.collector_id
            and collector.del_flag = 0
        join t_test_collector_channel mapping on mapping.battery_relation_id = battery.relation_id
            and mapping.test_id = test_fact.test_id
        where test_fact.reception_status = 'RECEIVING' and test_fact.del_flag = 0
        order by test_fact.test_id, battery.relation_id, mapping.mapping_id
    </select>
    <select id="selectOpenCollectorException" resultMap="TTestCollectorExceptionIntervalResultMap">
        select * from t_test_collector_exception_interval
        where test_id = #{testId} and battery_relation_id = #{batteryRelationId}
          and collector_id = #{collectorId} and collector_channel_code = #{channelCode}
          and exception_type = 'COLLECTOR_DISCONNECTED' and interval_status = 'OPEN'
        order by interval_id desc limit 1
    </select>
    <insert id="insertCollectorExceptionInterval" parameterType="TTestCollectorExceptionInterval" useGeneratedKeys="true" keyProperty="intervalId">
        insert into t_test_collector_exception_interval
        (test_id, battery_relation_id, collector_id, collector_channel_code, exception_type,
         opened_at_utc, missing_from_utc, detail)
        values (#{testId}, #{batteryRelationId}, #{collectorId}, #{collectorChannelCode},
                #{exceptionType}, #{openedAtUtc}, #{missingFromUtc}, #{detail})
    </insert>
    <update id="closeCollectorExceptionInterval">
        update t_test_collector_exception_interval
        set recovered_at_utc = #{recoveredAtUtc}, missing_to_utc = #{missingToUtc}, interval_status = 'CLOSED'
        where interval_id = #{intervalId} and interval_status = 'OPEN'
    </update>
    <select id="selectCollectorExceptionIntervals" parameterType="Long" resultMap="TTestCollectorExceptionIntervalResultMap">
        select exception_fact.*, collector.collector_code, collector.collector_name,
               mapping.measurement_name
        from t_test_collector_exception_interval exception_fact
        left join t_collector collector on collector.collector_id = exception_fact.collector_id
        left join t_test_collector_channel mapping on mapping.battery_relation_id = exception_fact.battery_relation_id
            and mapping.collector_id = exception_fact.collector_id
            and mapping.channel_code = exception_fact.collector_channel_code
        where exception_fact.test_id = #{testId} and exception_fact.interval_status = 'OPEN'
        order by exception_fact.opened_at_utc, exception_fact.interval_id
    </select>
</mapper>