feat: new api
This commit is contained in:
@@ -5,7 +5,8 @@
|
||||
"Bash(mvn clean package:*)",
|
||||
"Bash(echo:*)",
|
||||
"Bash(git add:*)",
|
||||
"Bash(git commit:*)"
|
||||
"Bash(git commit:*)",
|
||||
"Bash(grep:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
||||
@@ -107,7 +107,13 @@
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="区域" prop="regionId">
|
||||
<el-select v-model="form.regionId" placeholder="请选择区域" filterable style="width: 100%">
|
||||
<el-select
|
||||
v-model="form.regionId"
|
||||
placeholder="请选择任务模板后自动填充"
|
||||
filterable
|
||||
style="width: 100%"
|
||||
:disabled="!!form.taskId && !form.id"
|
||||
>
|
||||
<el-option v-for="region in regionOptions" :key="region.id" :label="region.regionName" :value="region.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@@ -121,7 +127,8 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<!-- 仅编辑时显示状态字段 -->
|
||||
<el-col v-if="form.id" :span="12">
|
||||
<el-form-item label="执行状态" prop="status">
|
||||
<el-select v-model="form.status" placeholder="请选择状态" style="width: 100%">
|
||||
<el-option label="待执行" value="pending" />
|
||||
@@ -134,34 +141,90 @@
|
||||
</el-row>
|
||||
|
||||
<el-divider content-position="left">执行角色</el-divider>
|
||||
|
||||
<!-- 操作人和监护人 -->
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="操作人" prop="operatorName">
|
||||
<el-input v-model="form.operatorName" placeholder="请输入操作人姓名" />
|
||||
<el-input
|
||||
v-model="form.operatorName"
|
||||
placeholder="请选择操作人"
|
||||
readonly
|
||||
style="width: 100%"
|
||||
>
|
||||
<template #append>
|
||||
<el-button icon="User" @click="operatorSelectRef.open()" />
|
||||
<el-button v-if="form.operatorName" icon="Close" @click="clearUser('operator')" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="监护人" prop="custodianName">
|
||||
<el-input v-model="form.custodianName" placeholder="请输入监护人姓名" />
|
||||
<el-input
|
||||
v-model="form.custodianName"
|
||||
placeholder="请选择监护人"
|
||||
readonly
|
||||
style="width: 100%"
|
||||
>
|
||||
<template #append>
|
||||
<el-button icon="User" @click="custodianSelectRef.open()" />
|
||||
<el-button v-if="form.custodianName" icon="Close" @click="clearUser('custodian')" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 送电人和受电人 -->
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="送电人" prop="senderName">
|
||||
<el-input v-model="form.senderName" placeholder="请输入送电人姓名" />
|
||||
<el-input
|
||||
v-model="form.senderName"
|
||||
placeholder="请选择送电人"
|
||||
readonly
|
||||
style="width: 100%"
|
||||
>
|
||||
<template #append>
|
||||
<el-button icon="User" @click="senderSelectRef.open()" />
|
||||
<el-button v-if="form.senderName" icon="Close" @click="clearUser('sender')" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="受电人" prop="recipientName">
|
||||
<el-input v-model="form.recipientName" placeholder="请输入受电人姓名" />
|
||||
<el-input
|
||||
v-model="form.recipientName"
|
||||
placeholder="请选择受电人"
|
||||
readonly
|
||||
style="width: 100%"
|
||||
>
|
||||
<template #append>
|
||||
<el-button icon="User" @click="recipientSelectRef.open()" />
|
||||
<el-button v-if="form.recipientName" icon="Close" @click="clearUser('recipient')" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 指挥人 -->
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="指挥人" prop="commanderName">
|
||||
<el-input v-model="form.commanderName" placeholder="请输入指挥人姓名" />
|
||||
<el-input
|
||||
v-model="form.commanderName"
|
||||
placeholder="请选择指挥人"
|
||||
readonly
|
||||
style="width: 100%"
|
||||
>
|
||||
<template #append>
|
||||
<el-button icon="User" @click="commanderSelectRef.open()" />
|
||||
<el-button v-if="form.commanderName" icon="Close" @click="clearUser('commander')" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -173,18 +236,27 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 用户选择组件 -->
|
||||
<UserSelect ref="operatorSelectRef" :multiple="false" @confirmCallBack="handleOperatorSelect" />
|
||||
<UserSelect ref="custodianSelectRef" :multiple="false" @confirmCallBack="handleCustodianSelect" />
|
||||
<UserSelect ref="senderSelectRef" :multiple="false" @confirmCallBack="handleSenderSelect" />
|
||||
<UserSelect ref="recipientSelectRef" :multiple="false" @confirmCallBack="handleRecipientSelect" />
|
||||
<UserSelect ref="commanderSelectRef" :multiple="false" @confirmCallBack="handleCommanderSelect" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="ArExecution" lang="ts">
|
||||
import { listArExecution, getArExecution, delArExecution, addArExecution, updateArExecution } from '@/api/inspection/execution';
|
||||
import { ArExecutionVO, ArExecutionQuery, ArExecutionForm } from '@/api/inspection/execution/types';
|
||||
import { listArTask } from '@/api/inspection/task';
|
||||
import { listArTask, getArTask } from '@/api/inspection/task';
|
||||
import { ArTaskVO } from '@/api/inspection/task/types';
|
||||
import { listArRegion } from '@/api/inspection/region';
|
||||
import { ArRegionVO } from '@/api/inspection/region/types';
|
||||
import { listArDevice } from '@/api/inspection/device';
|
||||
import { ArDeviceVO } from '@/api/inspection/device/types';
|
||||
import { UserVO } from '@/api/system/user/types';
|
||||
import UserSelect from '@/components/UserSelect/index.vue';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
@@ -203,6 +275,12 @@ const total = ref(0);
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const executionFormRef = ref<ElFormInstance>();
|
||||
|
||||
const operatorSelectRef = ref();
|
||||
const custodianSelectRef = ref();
|
||||
const senderSelectRef = ref();
|
||||
const recipientSelectRef = ref();
|
||||
const commanderSelectRef = ref();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
@@ -369,6 +447,90 @@ const handleExport = () => {
|
||||
);
|
||||
};
|
||||
|
||||
/** 监听任务模板变化,自动填充区域 */
|
||||
watch(() => form.value.taskId, async (newTaskId) => {
|
||||
if (newTaskId && !form.value.id) { // 仅新增时自动填充
|
||||
try {
|
||||
const res = await getArTask(newTaskId);
|
||||
if (res.data && res.data.regionId) {
|
||||
form.value.regionId = res.data.regionId;
|
||||
const region = regionOptions.value.find(r => r.id === res.data.regionId);
|
||||
if (region) {
|
||||
proxy?.$modal.msgSuccess(`已自动填充区域:${region.regionName}`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取任务模板详情失败', error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/** 操作人选择回调 */
|
||||
const handleOperatorSelect = (users: UserVO[]) => {
|
||||
if (users && users.length > 0) {
|
||||
form.value.operatorId = users[0].userId;
|
||||
form.value.operatorName = users[0].nickName;
|
||||
}
|
||||
};
|
||||
|
||||
/** 监护人选择回调 */
|
||||
const handleCustodianSelect = (users: UserVO[]) => {
|
||||
if (users && users.length > 0) {
|
||||
form.value.custodianId = users[0].userId;
|
||||
form.value.custodianName = users[0].nickName;
|
||||
}
|
||||
};
|
||||
|
||||
/** 送电人选择回调 */
|
||||
const handleSenderSelect = (users: UserVO[]) => {
|
||||
if (users && users.length > 0) {
|
||||
form.value.senderId = users[0].userId;
|
||||
form.value.senderName = users[0].nickName;
|
||||
}
|
||||
};
|
||||
|
||||
/** 受电人选择回调 */
|
||||
const handleRecipientSelect = (users: UserVO[]) => {
|
||||
if (users && users.length > 0) {
|
||||
form.value.recipientId = users[0].userId;
|
||||
form.value.recipientName = users[0].nickName;
|
||||
}
|
||||
};
|
||||
|
||||
/** 指挥人选择回调 */
|
||||
const handleCommanderSelect = (users: UserVO[]) => {
|
||||
if (users && users.length > 0) {
|
||||
form.value.commanderId = users[0].userId;
|
||||
form.value.commanderName = users[0].nickName;
|
||||
}
|
||||
};
|
||||
|
||||
/** 清空人员选择 */
|
||||
const clearUser = (role: 'operator' | 'custodian' | 'sender' | 'recipient' | 'commander') => {
|
||||
switch (role) {
|
||||
case 'operator':
|
||||
form.value.operatorId = undefined;
|
||||
form.value.operatorName = undefined;
|
||||
break;
|
||||
case 'custodian':
|
||||
form.value.custodianId = undefined;
|
||||
form.value.custodianName = undefined;
|
||||
break;
|
||||
case 'sender':
|
||||
form.value.senderId = undefined;
|
||||
form.value.senderName = undefined;
|
||||
break;
|
||||
case 'recipient':
|
||||
form.value.recipientId = undefined;
|
||||
form.value.recipientName = undefined;
|
||||
break;
|
||||
case 'commander':
|
||||
form.value.commanderId = undefined;
|
||||
form.value.commanderName = undefined;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getOptions();
|
||||
getList();
|
||||
|
||||
@@ -195,16 +195,16 @@ springdoc:
|
||||
enabled: true
|
||||
info:
|
||||
# 标题
|
||||
title: '标题:RuoYi-Vue-Plus多租户管理系统_接口文档'
|
||||
title: 'AR智能巡检平台-接口文档'
|
||||
# 描述
|
||||
description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...'
|
||||
description: 'AR智能巡检平台 接口文档'
|
||||
# 版本
|
||||
version: '版本号: ${project.version}'
|
||||
# 作者信息
|
||||
contact:
|
||||
name: Lion Li
|
||||
email: crazylionli@163.com
|
||||
url: https://gitee.com/dromara/RuoYi-Vue-Plus
|
||||
name: YANG JIANKUAN
|
||||
email: tim.yee@hotmail.com
|
||||
url: https://www.njcqit.com
|
||||
#这里定义了两个分组,可定义多个,也可以不定义
|
||||
group-configs:
|
||||
- group: 1.演示模块
|
||||
|
||||
@@ -13,6 +13,8 @@ import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.inspection.domain.bo.ArExecutionBo;
|
||||
import org.dromara.inspection.domain.bo.ArExecutionSubmitBo;
|
||||
import org.dromara.inspection.domain.vo.ArExecutionDetailVo;
|
||||
import org.dromara.inspection.domain.vo.ArExecutionVo;
|
||||
import org.dromara.inspection.service.IArExecutionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -61,15 +63,15 @@ public class ArExecutionController extends BaseController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务执行记录详细信息
|
||||
* 获取任务执行记录详细信息(包含关联对象和步骤树)
|
||||
*
|
||||
* @param id 执行ID
|
||||
*/
|
||||
@SaCheckPermission("inspection:execution:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<ArExecutionVo> getInfo(@NotNull(message = "执行ID不能为空")
|
||||
@PathVariable("id") Long id) {
|
||||
return R.ok(arExecutionService.queryById(id));
|
||||
public R<ArExecutionDetailVo> getInfo(@NotNull(message = "执行ID不能为空")
|
||||
@PathVariable("id") Long id) {
|
||||
return R.ok(arExecutionService.queryDetailById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,6 +96,17 @@ public class ArExecutionController extends BaseController {
|
||||
return toAjax(arExecutionService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量提交任务执行结果
|
||||
*/
|
||||
@SaCheckPermission("inspection:execution:submit")
|
||||
@Log(title = "提交任务执行结果", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit
|
||||
@PostMapping("/submit")
|
||||
public R<Void> submit(@Validated @RequestBody ArExecutionSubmitBo bo) {
|
||||
return toAjax(arExecutionService.submitExecution(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除任务执行记录
|
||||
*
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dromara.inspection.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
@@ -40,9 +41,12 @@ public class ArStepRecordController extends BaseController {
|
||||
|
||||
private final IArStepRecordService arStepRecordService;
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* 查询步骤执行记录列表
|
||||
*/
|
||||
|
||||
@SaIgnore
|
||||
@SaCheckPermission("inspection:stepRecord:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<ArStepRecordVo> list(@Validated(QueryGroup.class) ArStepRecordBo bo, PageQuery pageQuery) {
|
||||
@@ -67,6 +71,7 @@ public class ArStepRecordController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("inspection:stepRecord:query")
|
||||
@GetMapping("/{id}")
|
||||
@SaIgnore
|
||||
public R<ArStepRecordVo> getInfo(@NotNull(message = "记录ID不能为空")
|
||||
@PathVariable("id") Long id) {
|
||||
return R.ok(arStepRecordService.queryById(id));
|
||||
@@ -90,6 +95,7 @@ public class ArStepRecordController extends BaseController {
|
||||
@Log(title = "步骤执行记录", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit
|
||||
@PutMapping()
|
||||
@SaIgnore
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ArStepRecordBo bo) {
|
||||
return toAjax(arStepRecordService.updateByBo(bo));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.dromara.inspection.domain.bo;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 任务执行提交业务对象
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-13
|
||||
*/
|
||||
@Data
|
||||
public class ArExecutionSubmitBo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 执行ID
|
||||
*/
|
||||
@NotNull(message = "执行ID不能为空")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 状态(pending/in_progress/completed/cancelled)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
private Date endTime;
|
||||
|
||||
/**
|
||||
* 步骤执行树
|
||||
*/
|
||||
@Valid
|
||||
private List<ArStepRecordTreeBo> stepTree;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package org.dromara.inspection.domain.bo;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 步骤执行记录树形业务对象
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-13
|
||||
*/
|
||||
@Data
|
||||
public class ArStepRecordTreeBo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 步骤ID(仅用于引用)
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 执行记录ID(用于更新现有记录)
|
||||
*/
|
||||
private Long recordId;
|
||||
|
||||
/**
|
||||
* 执行状态(pending/completed/skipped)
|
||||
*/
|
||||
private String recordStatus;
|
||||
|
||||
/**
|
||||
* 是否完成(0否 1是)
|
||||
*/
|
||||
private String isDone;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* 完成时间
|
||||
*/
|
||||
private Date completionTime;
|
||||
|
||||
/**
|
||||
* 耗时(秒)
|
||||
*/
|
||||
private Integer duration;
|
||||
|
||||
/**
|
||||
* 文本反馈
|
||||
*/
|
||||
private String textFeedback;
|
||||
|
||||
/**
|
||||
* 语音识别文本
|
||||
*/
|
||||
private String voiceText;
|
||||
|
||||
/**
|
||||
* AI识别结果(JSON)
|
||||
*/
|
||||
private String aiResult;
|
||||
|
||||
/**
|
||||
* 执行人ID
|
||||
*/
|
||||
private Long executorId;
|
||||
|
||||
/**
|
||||
* 执行人姓名
|
||||
*/
|
||||
private String executorName;
|
||||
|
||||
/**
|
||||
* 子步骤列表
|
||||
*/
|
||||
@Valid
|
||||
private List<ArStepRecordTreeBo> children;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.dromara.inspection.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 任务执行详情视图对象
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-13
|
||||
*/
|
||||
@Data
|
||||
public class ArExecutionDetailVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 执行基本信息
|
||||
*/
|
||||
private ArExecutionVo execution;
|
||||
|
||||
/**
|
||||
* 任务模板信息
|
||||
*/
|
||||
private ArTaskVo task;
|
||||
|
||||
/**
|
||||
* 区域信息
|
||||
*/
|
||||
private ArRegionVo region;
|
||||
|
||||
/**
|
||||
* 设备信息
|
||||
*/
|
||||
private ArDeviceVo device;
|
||||
|
||||
/**
|
||||
* 步骤执行树
|
||||
*/
|
||||
private List<ArStepRecordTreeVo> stepTree;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package org.dromara.inspection.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 步骤执行记录树形视图对象
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-13
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ArStepRecordTreeVo extends ArStepTreeVo {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 执行记录ID
|
||||
*/
|
||||
private Long recordId;
|
||||
|
||||
/**
|
||||
* 执行状态(pending/completed/skipped)
|
||||
*/
|
||||
private String recordStatus;
|
||||
|
||||
/**
|
||||
* 是否完成(0否 1是)
|
||||
*/
|
||||
private String isDone;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* 完成时间
|
||||
*/
|
||||
private Date completionTime;
|
||||
|
||||
/**
|
||||
* 耗时(秒)
|
||||
*/
|
||||
private Integer duration;
|
||||
|
||||
/**
|
||||
* 文本反馈
|
||||
*/
|
||||
private String textFeedback;
|
||||
|
||||
/**
|
||||
* 语音识别文本
|
||||
*/
|
||||
private String voiceText;
|
||||
|
||||
/**
|
||||
* AI识别结果(JSON)
|
||||
*/
|
||||
private String aiResult;
|
||||
|
||||
/**
|
||||
* 执行人ID
|
||||
*/
|
||||
private Long executorId;
|
||||
|
||||
/**
|
||||
* 执行人姓名
|
||||
*/
|
||||
private String executorName;
|
||||
|
||||
/**
|
||||
* 子步骤列表
|
||||
*/
|
||||
private List<ArStepRecordTreeVo> children;
|
||||
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package org.dromara.inspection.service;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.inspection.domain.bo.ArExecutionBo;
|
||||
import org.dromara.inspection.domain.bo.ArExecutionSubmitBo;
|
||||
import org.dromara.inspection.domain.vo.ArExecutionDetailVo;
|
||||
import org.dromara.inspection.domain.vo.ArExecutionVo;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -23,6 +25,22 @@ public interface IArExecutionService {
|
||||
*/
|
||||
ArExecutionVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 查询任务执行详情(包含关联对象和步骤树)
|
||||
*
|
||||
* @param id 执行ID
|
||||
* @return 任务执行详情VO
|
||||
*/
|
||||
ArExecutionDetailVo queryDetailById(Long id);
|
||||
|
||||
/**
|
||||
* 批量提交任务执行结果
|
||||
*
|
||||
* @param bo 提交业务对象
|
||||
* @return 是否成功
|
||||
*/
|
||||
Boolean submitExecution(ArExecutionSubmitBo bo);
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*/
|
||||
|
||||
@@ -10,16 +10,21 @@ import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.inspection.domain.ArExecution;
|
||||
import org.dromara.inspection.domain.ArStep;
|
||||
import org.dromara.inspection.domain.ArStepRecord;
|
||||
import org.dromara.inspection.domain.bo.ArExecutionBo;
|
||||
import org.dromara.inspection.domain.vo.ArExecutionVo;
|
||||
import org.dromara.inspection.mapper.ArExecutionMapper;
|
||||
import org.dromara.inspection.domain.bo.ArExecutionSubmitBo;
|
||||
import org.dromara.inspection.domain.bo.ArStepRecordTreeBo;
|
||||
import org.dromara.inspection.domain.vo.*;
|
||||
import org.dromara.inspection.mapper.*;
|
||||
import org.dromara.inspection.service.IArExecutionService;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 任务执行记录Service业务层处理
|
||||
@@ -32,6 +37,11 @@ import java.util.Map;
|
||||
public class ArExecutionServiceImpl implements IArExecutionService {
|
||||
|
||||
private final ArExecutionMapper baseMapper;
|
||||
private final ArTaskMapper taskMapper;
|
||||
private final ArRegionMapper regionMapper;
|
||||
private final ArDeviceMapper deviceMapper;
|
||||
private final ArStepMapper stepMapper;
|
||||
private final ArStepRecordMapper stepRecordMapper;
|
||||
|
||||
@Override
|
||||
public ArExecutionVo queryById(Long id) {
|
||||
@@ -141,4 +151,253 @@ public class ArExecutionServiceImpl implements IArExecutionService {
|
||||
}
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArExecutionDetailVo queryDetailById(Long id) {
|
||||
// 1. 查询执行记录
|
||||
ArExecutionVo execution = baseMapper.selectVoById(id);
|
||||
if (execution == null) {
|
||||
throw new ServiceException("任务执行记录不存在");
|
||||
}
|
||||
|
||||
// 2. 查询关联对象
|
||||
ArTaskVo task = execution.getTaskId() != null
|
||||
? taskMapper.selectVoById(execution.getTaskId()) : null;
|
||||
ArRegionVo region = execution.getRegionId() != null
|
||||
? regionMapper.selectVoById(execution.getRegionId()) : null;
|
||||
ArDeviceVo device = execution.getDeviceId() != null
|
||||
? deviceMapper.selectVoById(execution.getDeviceId()) : null;
|
||||
|
||||
// 3. 查询步骤模板
|
||||
List<ArStepVo> allSteps = new ArrayList<>();
|
||||
if (execution.getTaskId() != null) {
|
||||
LambdaQueryWrapper<ArStep> stepWrapper = Wrappers.lambdaQuery();
|
||||
stepWrapper.eq(ArStep::getTaskId, execution.getTaskId());
|
||||
stepWrapper.orderByAsc(ArStep::getOrderNum);
|
||||
allSteps = stepMapper.selectVoList(stepWrapper);
|
||||
}
|
||||
|
||||
// 4. 查询执行记录
|
||||
LambdaQueryWrapper<ArStepRecord> recordWrapper = Wrappers.lambdaQuery();
|
||||
recordWrapper.eq(ArStepRecord::getExecutionId, id);
|
||||
List<ArStepRecordVo> allRecords = stepRecordMapper.selectVoList(recordWrapper);
|
||||
|
||||
// 5. 构建步骤记录 Map
|
||||
Map<Long, ArStepRecordVo> recordMap = allRecords.stream()
|
||||
.collect(Collectors.toMap(ArStepRecordVo::getStepId, r -> r, (r1, r2) -> r1));
|
||||
|
||||
// 6. 构建步骤树
|
||||
List<ArStepRecordTreeVo> stepTree = buildStepRecordTree(allSteps, recordMap, 0L);
|
||||
|
||||
// 7. 组装返回对象
|
||||
ArExecutionDetailVo detail = new ArExecutionDetailVo();
|
||||
detail.setExecution(execution);
|
||||
detail.setTask(task);
|
||||
detail.setRegion(region);
|
||||
detail.setDevice(device);
|
||||
detail.setStepTree(stepTree);
|
||||
|
||||
return detail;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归构建步骤执行记录树
|
||||
*
|
||||
* @param allSteps 所有步骤模板
|
||||
* @param recordMap 执行记录Map (stepId -> record)
|
||||
* @param parentId 父步骤ID
|
||||
* @return 树形步骤执行记录列表
|
||||
*/
|
||||
private List<ArStepRecordTreeVo> buildStepRecordTree(
|
||||
List<ArStepVo> allSteps,
|
||||
Map<Long, ArStepRecordVo> recordMap,
|
||||
Long parentId) {
|
||||
|
||||
List<ArStepRecordTreeVo> tree = new ArrayList<>();
|
||||
for (ArStepVo step : allSteps) {
|
||||
if (step.getParentId().equals(parentId)) {
|
||||
ArStepRecordTreeVo treeNode = new ArStepRecordTreeVo();
|
||||
|
||||
// 复制步骤模板信息
|
||||
BeanUtils.copyProperties(step, treeNode);
|
||||
|
||||
// 合并执行记录信息
|
||||
ArStepRecordVo record = recordMap.get(step.getId());
|
||||
if (record != null) {
|
||||
treeNode.setRecordId(record.getId());
|
||||
treeNode.setRecordStatus(record.getStatus());
|
||||
treeNode.setIsDone(record.getIsDone());
|
||||
treeNode.setStartTime(record.getStartTime());
|
||||
treeNode.setCompletionTime(record.getCompletionTime());
|
||||
treeNode.setDuration(record.getDuration());
|
||||
treeNode.setTextFeedback(record.getTextFeedback());
|
||||
treeNode.setVoiceText(record.getVoiceText());
|
||||
treeNode.setAiResult(record.getAiResult());
|
||||
treeNode.setExecutorId(record.getExecutorId());
|
||||
treeNode.setExecutorName(record.getExecutorName());
|
||||
}
|
||||
|
||||
// 递归查找子节点
|
||||
List<ArStepRecordTreeVo> children = buildStepRecordTree(allSteps, recordMap, step.getId());
|
||||
if (!children.isEmpty()) {
|
||||
treeNode.setChildren(children);
|
||||
}
|
||||
|
||||
tree.add(treeNode);
|
||||
}
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean submitExecution(ArExecutionSubmitBo bo) {
|
||||
// 1. 校验执行记录是否存在
|
||||
ArExecution execution = baseMapper.selectById(bo.getId());
|
||||
if (execution == null) {
|
||||
throw new ServiceException("任务执行记录不存在");
|
||||
}
|
||||
|
||||
// 2. 收集所有需要更新的步骤记录
|
||||
List<ArStepRecord> recordsToUpdate = new ArrayList<>();
|
||||
if (bo.getStepTree() != null && !bo.getStepTree().isEmpty()) {
|
||||
collectRecordsToUpdate(bo.getStepTree(), bo.getId(), recordsToUpdate);
|
||||
}
|
||||
|
||||
// 3. 批量更新步骤记录
|
||||
if (!recordsToUpdate.isEmpty()) {
|
||||
boolean updateSuccess = stepRecordMapper.updateBatchById(recordsToUpdate);
|
||||
if (!updateSuccess) {
|
||||
throw new ServiceException("步骤记录更新失败");
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 计算总步骤数和已完成步骤数
|
||||
StepCountResult countResult = countSteps(bo.getStepTree());
|
||||
|
||||
// 5. 更新执行记录
|
||||
ArExecution updateExecution = new ArExecution();
|
||||
updateExecution.setId(bo.getId());
|
||||
|
||||
// 设置状态
|
||||
if (StringUtils.isNotBlank(bo.getStatus())) {
|
||||
updateExecution.setStatus(bo.getStatus());
|
||||
}
|
||||
|
||||
// 设置时间
|
||||
if (bo.getStartTime() != null) {
|
||||
updateExecution.setStartTime(bo.getStartTime());
|
||||
}
|
||||
if (bo.getEndTime() != null) {
|
||||
updateExecution.setEndTime(bo.getEndTime());
|
||||
}
|
||||
|
||||
// 自动设置开始时间
|
||||
if ("in_progress".equals(updateExecution.getStatus()) && execution.getStartTime() == null) {
|
||||
updateExecution.setStartTime(new Date());
|
||||
}
|
||||
|
||||
// 自动设置结束时间
|
||||
if (("completed".equals(updateExecution.getStatus()) || "cancelled".equals(updateExecution.getStatus()))
|
||||
&& execution.getEndTime() == null) {
|
||||
updateExecution.setEndTime(new Date());
|
||||
}
|
||||
|
||||
// 设置步骤统计
|
||||
updateExecution.setTotalSteps(countResult.getTotal());
|
||||
updateExecution.setCompletedSteps(countResult.getCompleted());
|
||||
|
||||
return baseMapper.updateById(updateExecution) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归收集所有需要更新的步骤记录
|
||||
*
|
||||
* @param stepTree 步骤树
|
||||
* @param executionId 执行ID
|
||||
* @param result 结果列表
|
||||
*/
|
||||
private void collectRecordsToUpdate(List<ArStepRecordTreeBo> stepTree, Long executionId, List<ArStepRecord> result) {
|
||||
if (stepTree == null || stepTree.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (ArStepRecordTreeBo stepBo : stepTree) {
|
||||
// 只更新有 recordId 的记录
|
||||
if (stepBo.getRecordId() != null) {
|
||||
ArStepRecord record = new ArStepRecord();
|
||||
record.setId(stepBo.getRecordId());
|
||||
record.setExecutionId(executionId);
|
||||
record.setStepId(stepBo.getId());
|
||||
record.setStatus(stepBo.getRecordStatus());
|
||||
record.setIsDone(stepBo.getIsDone());
|
||||
record.setStartTime(stepBo.getStartTime());
|
||||
record.setCompletionTime(stepBo.getCompletionTime());
|
||||
record.setTextFeedback(stepBo.getTextFeedback());
|
||||
record.setVoiceText(stepBo.getVoiceText());
|
||||
record.setAiResult(stepBo.getAiResult());
|
||||
record.setExecutorId(stepBo.getExecutorId());
|
||||
record.setExecutorName(stepBo.getExecutorName());
|
||||
|
||||
// 自动计算耗时
|
||||
if (stepBo.getStartTime() != null && stepBo.getCompletionTime() != null) {
|
||||
long durationMillis = stepBo.getCompletionTime().getTime() - stepBo.getStartTime().getTime();
|
||||
record.setDuration((int) (durationMillis / 1000));
|
||||
} else if (stepBo.getDuration() != null) {
|
||||
record.setDuration(stepBo.getDuration());
|
||||
}
|
||||
|
||||
result.add(record);
|
||||
}
|
||||
|
||||
// 递归处理子步骤
|
||||
if (stepBo.getChildren() != null && !stepBo.getChildren().isEmpty()) {
|
||||
collectRecordsToUpdate(stepBo.getChildren(), executionId, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归统计步骤数
|
||||
*
|
||||
* @param stepTree 步骤树
|
||||
* @return 统计结果
|
||||
*/
|
||||
private StepCountResult countSteps(List<ArStepRecordTreeBo> stepTree) {
|
||||
int totalCount = 0;
|
||||
int completedCount = 0;
|
||||
|
||||
if (stepTree == null || stepTree.isEmpty()) {
|
||||
return new StepCountResult(totalCount, completedCount);
|
||||
}
|
||||
|
||||
for (ArStepRecordTreeBo stepBo : stepTree) {
|
||||
// 只统计有 recordId 的步骤
|
||||
if (stepBo.getRecordId() != null) {
|
||||
totalCount++;
|
||||
if ("1".equals(stepBo.getIsDone()) || "completed".equals(stepBo.getRecordStatus())) {
|
||||
completedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// 递归统计子步骤
|
||||
if (stepBo.getChildren() != null && !stepBo.getChildren().isEmpty()) {
|
||||
StepCountResult childCounts = countSteps(stepBo.getChildren());
|
||||
totalCount += childCounts.getTotal();
|
||||
completedCount += childCounts.getCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
return new StepCountResult(totalCount, completedCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 步骤统计结果内部类
|
||||
*/
|
||||
@lombok.Data
|
||||
@AllArgsConstructor
|
||||
private static class StepCountResult {
|
||||
private int total;
|
||||
private int completed;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user