Bladeren bron

增加与ai大模型对话

wwh 2 weken geleden
bovenliggende
commit
6f158d6010
13 gewijzigde bestanden met toevoegingen van 1163 en 4 verwijderingen
  1. 58 0
      huimv-employment/fe-api/src/main/java/com/huimv/employment/controller/mp/RegistrationBatchController.java
  2. 95 0
      huimv-employment/fe-dao/src/main/java/com/huimv/employment/dao/entity/FeWorkflowDefinition.java
  3. 95 0
      huimv-employment/fe-dao/src/main/java/com/huimv/employment/dao/entity/FeWorkflowStep.java
  4. 9 0
      huimv-employment/fe-dao/src/main/java/com/huimv/employment/dao/mapper/FeWorkflowDefinitionMapper.java
  5. 9 0
      huimv-employment/fe-dao/src/main/java/com/huimv/employment/dao/mapper/FeWorkflowStepMapper.java
  6. 1 0
      huimv-employment/fe-service/src/main/java/com/huimv/employment/service/order/McpOrderService.java
  7. 13 0
      huimv-employment/fe-service/src/main/java/com/huimv/employment/service/order/dto/McpOrderCloneResponse.java
  8. 374 4
      huimv-employment/fe-service/src/main/java/com/huimv/employment/service/registration/RegistrationBatchService.java
  9. 207 0
      huimv-employment/fe-service/src/main/java/com/huimv/employment/service/registration/dto/RegistrationBatchDetailResponse.java
  10. 40 0
      huimv-employment/fe-service/src/main/java/com/huimv/employment/service/registration/dto/RegistrationBatchProgressResponse.java
  11. 80 0
      huimv-employment/fe-service/src/main/java/com/huimv/employment/service/registration/dto/RegistrationBatchStatsResponse.java
  12. 64 0
      huimv-employment/fe-service/src/main/java/com/huimv/employment/service/registration/dto/RegistrationBatchStepResponse.java
  13. 118 0
      huimv-employment/fe-service/src/main/java/com/huimv/employment/service/registration/dto/RegistrationBatchWorkerItemResponse.java

+ 58 - 0
huimv-employment/fe-api/src/main/java/com/huimv/employment/controller/mp/RegistrationBatchController.java

@@ -0,0 +1,58 @@
1
+package com.huimv.employment.controller.mp;
2
+
3
+import com.huimv.employment.common.exception.BizException;
4
+import com.huimv.employment.common.exception.ErrorCode;
5
+import com.huimv.employment.common.web.R;
6
+import com.huimv.employment.security.LoginUser;
7
+import com.huimv.employment.security.LoginUserHolder;
8
+import com.huimv.employment.service.registration.RegistrationBatchService;
9
+import com.huimv.employment.service.registration.dto.RegistrationBatchDetailResponse;
10
+import io.swagger.v3.oas.annotations.Operation;
11
+import io.swagger.v3.oas.annotations.Parameter;
12
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
13
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
14
+import io.swagger.v3.oas.annotations.tags.Tag;
15
+import org.springframework.web.bind.annotation.GetMapping;
16
+import org.springframework.web.bind.annotation.RequestMapping;
17
+import org.springframework.web.bind.annotation.RequestParam;
18
+import org.springframework.web.bind.annotation.RestController;
19
+
20
+/**
21
+ * 临时工扫码登记批次(企业主进度管理)。
22
+ */
23
+@RestController
24
+@RequestMapping("/api/v1/mp/registration-batches")
25
+@Tag(name = "登记批次", description = "企业主查看扫码登记进度详情,需企业端 JWT")
26
+@SecurityRequirement(name = "Authorization")
27
+public class RegistrationBatchController {
28
+
29
+    private static final String USER_TYPE_ENTERPRISE = "enterprise";
30
+
31
+    private final RegistrationBatchService registrationBatchService;
32
+
33
+    public RegistrationBatchController(RegistrationBatchService registrationBatchService) {
34
+        this.registrationBatchService = registrationBatchService;
35
+    }
36
+
37
+    @GetMapping
38
+    @Operation(summary = "查询登记批次详情",
39
+            description = "按草稿 ID 查询进度管理页数据:人数统计、登记进度条、办理流程步骤、人员列表。"
40
+                    + "路径:草稿 → 订单 → 登记批次。仅可查询本企业草稿。",
41
+            parameters = {
42
+                    @Parameter(name = "draft_id", in = ParameterIn.QUERY, required = true,
43
+                            description = "用工草稿 ID(generate / confirm 返回的 draft_id)")
44
+            })
45
+    public R<RegistrationBatchDetailResponse> getDetail(
46
+            @RequestParam("draft_id") Long draftId) {
47
+        LoginUser loginUser = requireEnterprise();
48
+        return R.ok(registrationBatchService.getDetailByDraftId(loginUser.getUserId(), draftId));
49
+    }
50
+
51
+    private static LoginUser requireEnterprise() {
52
+        LoginUser loginUser = LoginUserHolder.require();
53
+        if (!USER_TYPE_ENTERPRISE.equals(loginUser.getUserType())) {
54
+            throw new BizException(ErrorCode.ENTERPRISE_ONLY);
55
+        }
56
+        return loginUser;
57
+    }
58
+}

+ 95 - 0
huimv-employment/fe-dao/src/main/java/com/huimv/employment/dao/entity/FeWorkflowDefinition.java

@@ -0,0 +1,95 @@
1
+package com.huimv.employment.dao.entity;
2
+
3
+import com.baomidou.mybatisplus.annotation.IdType;
4
+import com.baomidou.mybatisplus.annotation.TableId;
5
+import com.baomidou.mybatisplus.annotation.TableName;
6
+
7
+import java.time.LocalDateTime;
8
+
9
+/**
10
+ * 合规流程定义 {@code fe_workflow_definition} 实体。
11
+ */
12
+@TableName("fe_workflow_definition")
13
+public class FeWorkflowDefinition {
14
+
15
+    @TableId(type = IdType.AUTO)
16
+    private Long id;
17
+
18
+    private String workflowCode;
19
+
20
+    private String workflowName;
21
+
22
+    private String description;
23
+
24
+    private Integer version;
25
+
26
+    private Boolean isActive;
27
+
28
+    private LocalDateTime createTime;
29
+
30
+    private LocalDateTime updateTime;
31
+
32
+    public Long getId() {
33
+        return id;
34
+    }
35
+
36
+    public void setId(Long id) {
37
+        this.id = id;
38
+    }
39
+
40
+    public String getWorkflowCode() {
41
+        return workflowCode;
42
+    }
43
+
44
+    public void setWorkflowCode(String workflowCode) {
45
+        this.workflowCode = workflowCode;
46
+    }
47
+
48
+    public String getWorkflowName() {
49
+        return workflowName;
50
+    }
51
+
52
+    public void setWorkflowName(String workflowName) {
53
+        this.workflowName = workflowName;
54
+    }
55
+
56
+    public String getDescription() {
57
+        return description;
58
+    }
59
+
60
+    public void setDescription(String description) {
61
+        this.description = description;
62
+    }
63
+
64
+    public Integer getVersion() {
65
+        return version;
66
+    }
67
+
68
+    public void setVersion(Integer version) {
69
+        this.version = version;
70
+    }
71
+
72
+    public Boolean getIsActive() {
73
+        return isActive;
74
+    }
75
+
76
+    public void setIsActive(Boolean active) {
77
+        isActive = active;
78
+    }
79
+
80
+    public LocalDateTime getCreateTime() {
81
+        return createTime;
82
+    }
83
+
84
+    public void setCreateTime(LocalDateTime createTime) {
85
+        this.createTime = createTime;
86
+    }
87
+
88
+    public LocalDateTime getUpdateTime() {
89
+        return updateTime;
90
+    }
91
+
92
+    public void setUpdateTime(LocalDateTime updateTime) {
93
+        this.updateTime = updateTime;
94
+    }
95
+}

+ 95 - 0
huimv-employment/fe-dao/src/main/java/com/huimv/employment/dao/entity/FeWorkflowStep.java

@@ -0,0 +1,95 @@
1
+package com.huimv.employment.dao.entity;
2
+
3
+import com.baomidou.mybatisplus.annotation.IdType;
4
+import com.baomidou.mybatisplus.annotation.TableId;
5
+import com.baomidou.mybatisplus.annotation.TableName;
6
+
7
+import java.time.LocalDateTime;
8
+
9
+/**
10
+ * 合规流程步骤 {@code fe_workflow_step} 实体。
11
+ */
12
+@TableName("fe_workflow_step")
13
+public class FeWorkflowStep {
14
+
15
+    @TableId(type = IdType.AUTO)
16
+    private Long id;
17
+
18
+    private Long workflowId;
19
+
20
+    private String stepCode;
21
+
22
+    private String stepName;
23
+
24
+    private Integer stepOrder;
25
+
26
+    private Boolean required;
27
+
28
+    private Boolean autoAdvance;
29
+
30
+    private LocalDateTime createTime;
31
+
32
+    public Long getId() {
33
+        return id;
34
+    }
35
+
36
+    public void setId(Long id) {
37
+        this.id = id;
38
+    }
39
+
40
+    public Long getWorkflowId() {
41
+        return workflowId;
42
+    }
43
+
44
+    public void setWorkflowId(Long workflowId) {
45
+        this.workflowId = workflowId;
46
+    }
47
+
48
+    public String getStepCode() {
49
+        return stepCode;
50
+    }
51
+
52
+    public void setStepCode(String stepCode) {
53
+        this.stepCode = stepCode;
54
+    }
55
+
56
+    public String getStepName() {
57
+        return stepName;
58
+    }
59
+
60
+    public void setStepName(String stepName) {
61
+        this.stepName = stepName;
62
+    }
63
+
64
+    public Integer getStepOrder() {
65
+        return stepOrder;
66
+    }
67
+
68
+    public void setStepOrder(Integer stepOrder) {
69
+        this.stepOrder = stepOrder;
70
+    }
71
+
72
+    public Boolean getRequired() {
73
+        return required;
74
+    }
75
+
76
+    public void setRequired(Boolean required) {
77
+        this.required = required;
78
+    }
79
+
80
+    public Boolean getAutoAdvance() {
81
+        return autoAdvance;
82
+    }
83
+
84
+    public void setAutoAdvance(Boolean autoAdvance) {
85
+        this.autoAdvance = autoAdvance;
86
+    }
87
+
88
+    public LocalDateTime getCreateTime() {
89
+        return createTime;
90
+    }
91
+
92
+    public void setCreateTime(LocalDateTime createTime) {
93
+        this.createTime = createTime;
94
+    }
95
+}

+ 9 - 0
huimv-employment/fe-dao/src/main/java/com/huimv/employment/dao/mapper/FeWorkflowDefinitionMapper.java

@@ -0,0 +1,9 @@
1
+package com.huimv.employment.dao.mapper;
2
+
3
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4
+import com.huimv.employment.dao.entity.FeWorkflowDefinition;
5
+import org.apache.ibatis.annotations.Mapper;
6
+
7
+@Mapper
8
+public interface FeWorkflowDefinitionMapper extends BaseMapper<FeWorkflowDefinition> {
9
+}

+ 9 - 0
huimv-employment/fe-dao/src/main/java/com/huimv/employment/dao/mapper/FeWorkflowStepMapper.java

@@ -0,0 +1,9 @@
1
+package com.huimv.employment.dao.mapper;
2
+
3
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4
+import com.huimv.employment.dao.entity.FeWorkflowStep;
5
+import org.apache.ibatis.annotations.Mapper;
6
+
7
+@Mapper
8
+public interface FeWorkflowStepMapper extends BaseMapper<FeWorkflowStep> {
9
+}

+ 1 - 0
huimv-employment/fe-service/src/main/java/com/huimv/employment/service/order/McpOrderService.java

@@ -112,6 +112,7 @@ public class McpOrderService {
112 112
 
113 113
         McpOrderCloneResponse response = new McpOrderCloneResponse();
114 114
         response.setStatus(STATUS_SUCCESS);
115
+        response.setDraftId(draft.getId());
115 116
         return response;
116 117
     }
117 118
 

+ 13 - 0
huimv-employment/fe-service/src/main/java/com/huimv/employment/service/order/dto/McpOrderCloneResponse.java

@@ -1,5 +1,6 @@
1 1
 package com.huimv.employment.service.order.dto;
2 2
 
3
+import com.fasterxml.jackson.annotation.JsonProperty;
3 4
 import io.swagger.v3.oas.annotations.media.Schema;
4 5
 
5 6
 @Schema(description = "MCP 克隆订单至草稿响应(v2 §6.3.7)")
@@ -8,6 +9,10 @@ public class McpOrderCloneResponse {
8 9
     @Schema(description = "克隆结果", example = "success")
9 10
     private String status;
10 11
 
12
+    @JsonProperty("draft_id")
13
+    @Schema(description = "新生成的草稿 ID")
14
+    private Long draftId;
15
+
11 16
     public String getStatus() {
12 17
         return status;
13 18
     }
@@ -15,4 +20,12 @@ public class McpOrderCloneResponse {
15 20
     public void setStatus(String status) {
16 21
         this.status = status;
17 22
     }
23
+
24
+    public Long getDraftId() {
25
+        return draftId;
26
+    }
27
+
28
+    public void setDraftId(Long draftId) {
29
+        this.draftId = draftId;
30
+    }
18 31
 }

+ 374 - 4
huimv-employment/fe-service/src/main/java/com/huimv/employment/service/registration/RegistrationBatchService.java

@@ -1,13 +1,28 @@
1 1
 package com.huimv.employment.service.registration;
2 2
 
3
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
3 4
 import com.huimv.employment.common.exception.BizException;
4 5
 import com.huimv.employment.common.exception.ErrorCode;
5 6
 import com.huimv.employment.dao.entity.FeEmploymentDraft;
6 7
 import com.huimv.employment.dao.entity.FeEmploymentOrder;
8
+import com.huimv.employment.dao.entity.FeEnterprise;
7 9
 import com.huimv.employment.dao.entity.FeRegistrationBatch;
10
+import com.huimv.employment.dao.entity.FeWorkerRegistration;
11
+import com.huimv.employment.dao.entity.FeWorkflowDefinition;
12
+import com.huimv.employment.dao.entity.FeWorkflowStep;
13
+import com.huimv.employment.dao.mapper.FeEmploymentDraftMapper;
8 14
 import com.huimv.employment.dao.mapper.FeEmploymentOrderMapper;
9 15
 import com.huimv.employment.dao.mapper.FeRegistrationBatchMapper;
16
+import com.huimv.employment.dao.mapper.FeWorkerRegistrationMapper;
17
+import com.huimv.employment.dao.mapper.FeWorkflowDefinitionMapper;
18
+import com.huimv.employment.dao.mapper.FeWorkflowStepMapper;
10 19
 import com.huimv.employment.service.config.RegistrationQrProperties;
20
+import com.huimv.employment.service.enterprise.EnterpriseService;
21
+import com.huimv.employment.service.registration.dto.RegistrationBatchDetailResponse;
22
+import com.huimv.employment.service.registration.dto.RegistrationBatchProgressResponse;
23
+import com.huimv.employment.service.registration.dto.RegistrationBatchStatsResponse;
24
+import com.huimv.employment.service.registration.dto.RegistrationBatchStepResponse;
25
+import com.huimv.employment.service.registration.dto.RegistrationBatchWorkerItemResponse;
11 26
 import com.huimv.employment.service.wechat.WeChatMiniAppService;
12 27
 import org.slf4j.Logger;
13 28
 import org.slf4j.LoggerFactory;
@@ -20,11 +35,15 @@ import java.nio.file.Files;
20 35
 import java.nio.file.Path;
21 36
 import java.nio.file.Paths;
22 37
 import java.time.LocalDateTime;
38
+import java.time.format.DateTimeFormatter;
39
+import java.util.ArrayList;
40
+import java.util.Collections;
41
+import java.util.List;
23 42
 import java.util.regex.Pattern;
24 43
 
25 44
 /**
26
- * 方案确认后创建登记批次,并立刻生成小程序码写入 {@code fe_registration_batch.qr_code_url}。
27
- * <p>小程序码 scene = 订单编号,page = pages/worker/job-offer(见微信 getwxacodeunlimit)。</p>
45
+ * 登记批次:确认方案后创建批次与小程序码;企业端查询进度详情
46
+ * <p>办理流程步骤来自启用中的 {@code fe_workflow_definition} + {@code fe_workflow_step}。</p>
28 47
  */
29 48
 @Service
30 49
 public class RegistrationBatchService {
@@ -34,20 +53,48 @@ public class RegistrationBatchService {
34 53
     private static final String STATUS_ACTIVE = "active";
35 54
     private static final String STEP_REGISTRATION = "registration";
36 55
     private static final String PUBLIC_PATH_TEMPLATE = "/api/v1/public/registration-qr/%s.png";
37
-    /** 订单编号 / 文件名安全字符 */
38 56
     private static final Pattern SAFE_SCENE = Pattern.compile("^[A-Za-z0-9_-]{1,32}$");
57
+    private static final Pattern NUMERIC_ID = Pattern.compile("^\\d+$");
58
+    private static final DateTimeFormatter STEP_TIME_FMT = DateTimeFormatter.ofPattern("MM-dd HH:mm");
59
+
60
+    private static final String STEP_STATUS_DONE = "done";
61
+    private static final String STEP_STATUS_ACTIVE = "active";
62
+    private static final String STEP_STATUS_PENDING = "pending";
63
+
64
+    private static final String REG_PENDING = "pending";
65
+    private static final String REG_REGISTERING = "registering";
66
+    private static final String REG_UNDER_REVIEW = "under_review";
67
+    private static final String REG_COMPLETED = "completed";
68
+    private static final String REG_VERIFY_FAILED = "verify_failed";
69
+
70
+    private static final String WORKFLOW_CODE_EMPLOYMENT = "employment_compliance";
39 71
 
40 72
     private final FeRegistrationBatchMapper feRegistrationBatchMapper;
41 73
     private final FeEmploymentOrderMapper feEmploymentOrderMapper;
74
+    private final FeEmploymentDraftMapper feEmploymentDraftMapper;
75
+    private final FeWorkerRegistrationMapper feWorkerRegistrationMapper;
76
+    private final FeWorkflowDefinitionMapper feWorkflowDefinitionMapper;
77
+    private final FeWorkflowStepMapper feWorkflowStepMapper;
78
+    private final EnterpriseService enterpriseService;
42 79
     private final WeChatMiniAppService weChatMiniAppService;
43 80
     private final RegistrationQrProperties qrProperties;
44 81
 
45 82
     public RegistrationBatchService(FeRegistrationBatchMapper feRegistrationBatchMapper,
46 83
                                     FeEmploymentOrderMapper feEmploymentOrderMapper,
84
+                                    FeEmploymentDraftMapper feEmploymentDraftMapper,
85
+                                    FeWorkerRegistrationMapper feWorkerRegistrationMapper,
86
+                                    FeWorkflowDefinitionMapper feWorkflowDefinitionMapper,
87
+                                    FeWorkflowStepMapper feWorkflowStepMapper,
88
+                                    EnterpriseService enterpriseService,
47 89
                                     WeChatMiniAppService weChatMiniAppService,
48 90
                                     RegistrationQrProperties qrProperties) {
49 91
         this.feRegistrationBatchMapper = feRegistrationBatchMapper;
50 92
         this.feEmploymentOrderMapper = feEmploymentOrderMapper;
93
+        this.feEmploymentDraftMapper = feEmploymentDraftMapper;
94
+        this.feWorkerRegistrationMapper = feWorkerRegistrationMapper;
95
+        this.feWorkflowDefinitionMapper = feWorkflowDefinitionMapper;
96
+        this.feWorkflowStepMapper = feWorkflowStepMapper;
97
+        this.enterpriseService = enterpriseService;
51 98
         this.weChatMiniAppService = weChatMiniAppService;
52 99
         this.qrProperties = qrProperties;
53 100
     }
@@ -62,7 +109,6 @@ public class RegistrationBatchService {
62 109
         if (!StringUtils.hasText(order.getOrderNo()) || !SAFE_SCENE.matcher(order.getOrderNo().trim()).matches()) {
63 110
             throw new BizException(ErrorCode.BAD_REQUEST, "订单编号无效,无法作为小程序码 scene");
64 111
         }
65
-        // getwxacodeunlimit.scene = 订单编号(≤32)
66 112
         String scene = order.getOrderNo().trim();
67 113
         int validDays = resolveValidDays(draft);
68 114
         String page = normalizePage(qrProperties.getPage());
@@ -102,6 +148,93 @@ public class RegistrationBatchService {
102 148
         return feRegistrationBatchMapper.selectById(batch.getId());
103 149
     }
104 150
 
151
+    /**
152
+     * 企业端登记进度详情:按草稿 ID 定位订单 → 登记批次。
153
+     */
154
+    public RegistrationBatchDetailResponse getDetailByDraftId(Long userId, Long draftId) {
155
+        FeEnterprise enterprise = enterpriseService.findEnterpriseByUserId(userId);
156
+        if (enterprise == null) {
157
+            throw new BizException(ErrorCode.NOT_FOUND, "企业信息不存在");
158
+        }
159
+        if (draftId == null) {
160
+            throw new BizException(ErrorCode.BAD_REQUEST, "draft_id 不能为空");
161
+        }
162
+        FeEmploymentDraft draft = feEmploymentDraftMapper.selectById(draftId);
163
+        if (draft == null || !enterprise.getId().equals(draft.getEnterpriseId())) {
164
+            throw new BizException(ErrorCode.NOT_FOUND, "草稿不存在");
165
+        }
166
+        FeEmploymentOrder order = feEmploymentOrderMapper.selectOne(new LambdaQueryWrapper<FeEmploymentOrder>()
167
+                .eq(FeEmploymentOrder::getDraftId, draftId)
168
+                .orderByDesc(FeEmploymentOrder::getId)
169
+                .last("LIMIT 1"));
170
+        if (order == null) {
171
+            throw new BizException(ErrorCode.NOT_FOUND, "尚未确认方案,暂无登记批次");
172
+        }
173
+        FeRegistrationBatch batch = feRegistrationBatchMapper.selectOne(new LambdaQueryWrapper<FeRegistrationBatch>()
174
+                .eq(FeRegistrationBatch::getOrderId, order.getId())
175
+                .orderByDesc(FeRegistrationBatch::getId)
176
+                .last("LIMIT 1"));
177
+        if (batch == null || !enterprise.getId().equals(batch.getEnterpriseId())) {
178
+            throw new BizException(ErrorCode.NOT_FOUND, "登记批次不存在");
179
+        }
180
+        return toDetailResponse(batch, order, draft);
181
+    }
182
+
183
+    /**
184
+     * 企业端登记进度详情:按批次主键 ID 或业务编号(如 bat_1)。
185
+     */
186
+    public RegistrationBatchDetailResponse getDetail(Long userId, String batchKey) {
187
+        FeEnterprise enterprise = enterpriseService.findEnterpriseByUserId(userId);
188
+        if (enterprise == null) {
189
+            throw new BizException(ErrorCode.NOT_FOUND, "企业信息不存在");
190
+        }
191
+        FeRegistrationBatch batch = requireOwnedBatch(enterprise.getId(), batchKey);
192
+        FeEmploymentOrder order = feEmploymentOrderMapper.selectById(batch.getOrderId());
193
+        if (order == null) {
194
+            throw new BizException(ErrorCode.NOT_FOUND, "用工订单不存在");
195
+        }
196
+        FeEmploymentDraft draft = order.getDraftId() != null
197
+                ? feEmploymentDraftMapper.selectById(order.getDraftId()) : null;
198
+        return toDetailResponse(batch, order, draft);
199
+    }
200
+
201
+    private RegistrationBatchDetailResponse toDetailResponse(FeRegistrationBatch batch,
202
+                                                             FeEmploymentOrder order,
203
+                                                             FeEmploymentDraft draft) {
204
+        List<FeWorkerRegistration> registrations = feWorkerRegistrationMapper.selectList(
205
+                new LambdaQueryWrapper<FeWorkerRegistration>()
206
+                        .eq(FeWorkerRegistration::getBatchId, batch.getId())
207
+                        .orderByAsc(FeWorkerRegistration::getId));
208
+
209
+        RegistrationBatchStatsResponse stats = buildStats(batch, registrations);
210
+        RegistrationBatchProgressResponse progress = buildProgress(stats);
211
+        List<RegistrationBatchStepResponse> steps = buildSteps(order, draft, progress);
212
+        List<RegistrationBatchWorkerItemResponse> workers = buildWorkers(registrations);
213
+
214
+        String title = StringUtils.hasText(order.getTitle()) ? order.getTitle().trim() : "用工批次";
215
+        String batchNo = batch.getBatchNo();
216
+
217
+        RegistrationBatchDetailResponse response = new RegistrationBatchDetailResponse();
218
+        response.setBatchId(batch.getId());
219
+        response.setBatchNo(batchNo);
220
+        response.setTitle(title);
221
+        response.setSubtitle(title + (StringUtils.hasText(batchNo) ? " " + batchNo : ""));
222
+        response.setOrderId(order.getId());
223
+        response.setOrderNo(order.getOrderNo());
224
+        response.setStatus(batch.getStatus());
225
+        response.setQrCodeUrl(batch.getQrCodeUrl());
226
+        response.setRegistrationUrl(batch.getRegistrationUrl());
227
+        response.setQrToken(batch.getQrToken());
228
+        response.setValidFrom(batch.getValidFrom());
229
+        response.setValidUntil(batch.getValidUntil());
230
+        response.setCurrentStepCode(order.getCurrentStepCode());
231
+        response.setStats(stats);
232
+        response.setProgress(progress);
233
+        response.setSteps(steps);
234
+        response.setWorkers(workers);
235
+        return response;
236
+    }
237
+
105 238
     /** 按订单编号(scene)读取本地小程序码 PNG;不存在返回 null。 */
106 239
     public byte[] readQrPng(String scene) {
107 240
         if (!StringUtils.hasText(scene) || !SAFE_SCENE.matcher(scene.trim()).matches()) {
@@ -119,6 +252,243 @@ public class RegistrationBatchService {
119 252
         }
120 253
     }
121 254
 
255
+    private FeRegistrationBatch requireOwnedBatch(Long enterpriseId, String batchKey) {
256
+        if (!StringUtils.hasText(batchKey)) {
257
+            throw new BizException(ErrorCode.BAD_REQUEST, "batch_id 不能为空");
258
+        }
259
+        String key = batchKey.trim();
260
+        FeRegistrationBatch batch = null;
261
+        if (NUMERIC_ID.matcher(key).matches()) {
262
+            try {
263
+                batch = feRegistrationBatchMapper.selectById(Long.parseLong(key));
264
+            } catch (NumberFormatException ignored) {
265
+                batch = null;
266
+            }
267
+        }
268
+        if (batch == null) {
269
+            batch = feRegistrationBatchMapper.selectOne(new LambdaQueryWrapper<FeRegistrationBatch>()
270
+                    .eq(FeRegistrationBatch::getBatchNo, key)
271
+                    .orderByDesc(FeRegistrationBatch::getId)
272
+                    .last("LIMIT 1"));
273
+        }
274
+        if (batch == null || !enterpriseId.equals(batch.getEnterpriseId())) {
275
+            throw new BizException(ErrorCode.NOT_FOUND, "登记批次不存在");
276
+        }
277
+        return batch;
278
+    }
279
+
280
+    private RegistrationBatchStatsResponse buildStats(FeRegistrationBatch batch,
281
+                                                      List<FeWorkerRegistration> registrations) {
282
+        int expected = batch.getExpectedCount() != null ? batch.getExpectedCount() : 0;
283
+        int completed = 0;
284
+        int inProgress = 0;
285
+        int abnormal = 0;
286
+        int appliedPending = 0;
287
+        if (registrations != null) {
288
+            for (FeWorkerRegistration reg : registrations) {
289
+                String status = reg.getRegStatus();
290
+                if (REG_COMPLETED.equals(status)) {
291
+                    completed++;
292
+                } else if (REG_VERIFY_FAILED.equals(status)) {
293
+                    abnormal++;
294
+                } else if (REG_PENDING.equals(status)) {
295
+                    appliedPending++;
296
+                } else {
297
+                    inProgress++;
298
+                }
299
+            }
300
+        }
301
+        int applied = registrations != null ? registrations.size() : 0;
302
+        int pending = Math.max(0, expected - applied) + appliedPending;
303
+        inProgress = inProgress + abnormal;
304
+        if (expected <= 0) {
305
+            expected = pending + inProgress + completed;
306
+        }
307
+        int registered = Math.max(0, expected - pending);
308
+
309
+        RegistrationBatchStatsResponse stats = new RegistrationBatchStatsResponse();
310
+        stats.setPendingCount(pending);
311
+        stats.setInProgressCount(inProgress);
312
+        stats.setCompletedCount(completed);
313
+        stats.setAbnormalCount(abnormal);
314
+        stats.setExpectedCount(expected);
315
+        stats.setRegisteredCount(registered);
316
+        return stats;
317
+    }
318
+
319
+    private RegistrationBatchProgressResponse buildProgress(RegistrationBatchStatsResponse stats) {
320
+        int total = stats.getExpectedCount() != null ? stats.getExpectedCount() : 0;
321
+        int current = stats.getRegisteredCount() != null ? stats.getRegisteredCount() : 0;
322
+        int percent = total > 0 ? (int) Math.round(current * 100.0 / total) : 0;
323
+        if (percent > 100) {
324
+            percent = 100;
325
+        }
326
+        RegistrationBatchProgressResponse progress = new RegistrationBatchProgressResponse();
327
+        progress.setCurrent(current);
328
+        progress.setTotal(total);
329
+        progress.setPercent(percent);
330
+        return progress;
331
+    }
332
+
333
+    private List<RegistrationBatchStepResponse> buildSteps(FeEmploymentOrder order,
334
+                                                           FeEmploymentDraft draft,
335
+                                                           RegistrationBatchProgressResponse progress) {
336
+        List<FeWorkflowStep> flowSteps = listActiveWorkflowSteps();
337
+        if (flowSteps.isEmpty()) {
338
+            log.warn("未配置启用的 fe_workflow_step,进度页办理流程为空");
339
+            return Collections.emptyList();
340
+        }
341
+
342
+        String currentCode = StringUtils.hasText(order.getCurrentStepCode())
343
+                ? order.getCurrentStepCode().trim() : STEP_REGISTRATION;
344
+        int currentIndex = indexOfStep(flowSteps, currentCode);
345
+        if (currentIndex < 0) {
346
+            currentIndex = indexOfStep(flowSteps, STEP_REGISTRATION);
347
+        }
348
+        if (currentIndex < 0) {
349
+            currentIndex = 0;
350
+        }
351
+
352
+        List<RegistrationBatchStepResponse> steps = new ArrayList<>();
353
+        for (int i = 0; i < flowSteps.size(); i++) {
354
+            FeWorkflowStep def = flowSteps.get(i);
355
+            String code = def.getStepCode();
356
+            RegistrationBatchStepResponse step = new RegistrationBatchStepResponse();
357
+            step.setStepCode(code);
358
+            step.setTitle(def.getStepName());
359
+            if (i < currentIndex) {
360
+                step.setStatus(STEP_STATUS_DONE);
361
+                step.setTime(resolveStepTime(code, draft, order));
362
+            } else if (i == currentIndex) {
363
+                step.setStatus(STEP_STATUS_ACTIVE);
364
+                if (STEP_REGISTRATION.equals(code) && progress != null) {
365
+                    step.setHighlight(String.format("进行中 %d/%d",
366
+                            progress.getCurrent() != null ? progress.getCurrent() : 0,
367
+                            progress.getTotal() != null ? progress.getTotal() : 0));
368
+                }
369
+            } else {
370
+                step.setStatus(STEP_STATUS_PENDING);
371
+            }
372
+            steps.add(step);
373
+        }
374
+        return steps;
375
+    }
376
+
377
+    /**
378
+     * 读取当前启用合规流程下的步骤定义(按 step_order 升序)。
379
+     */
380
+    private List<FeWorkflowStep> listActiveWorkflowSteps() {
381
+        FeWorkflowDefinition definition = feWorkflowDefinitionMapper.selectOne(
382
+                new LambdaQueryWrapper<FeWorkflowDefinition>()
383
+                        .eq(FeWorkflowDefinition::getWorkflowCode, WORKFLOW_CODE_EMPLOYMENT)
384
+                        .eq(FeWorkflowDefinition::getIsActive, Boolean.TRUE)
385
+                        .orderByDesc(FeWorkflowDefinition::getVersion)
386
+                        .last("LIMIT 1"));
387
+        if (definition == null) {
388
+            // 兼容初始化脚本未显式筛选时:取 employment_compliance 最新版
389
+            definition = feWorkflowDefinitionMapper.selectOne(
390
+                    new LambdaQueryWrapper<FeWorkflowDefinition>()
391
+                            .eq(FeWorkflowDefinition::getWorkflowCode, WORKFLOW_CODE_EMPLOYMENT)
392
+                            .orderByDesc(FeWorkflowDefinition::getVersion)
393
+                            .last("LIMIT 1"));
394
+        }
395
+        if (definition == null) {
396
+            definition = feWorkflowDefinitionMapper.selectOne(
397
+                    new LambdaQueryWrapper<FeWorkflowDefinition>()
398
+                            .eq(FeWorkflowDefinition::getIsActive, Boolean.TRUE)
399
+                            .orderByDesc(FeWorkflowDefinition::getVersion)
400
+                            .last("LIMIT 1"));
401
+        }
402
+        if (definition == null) {
403
+            return Collections.emptyList();
404
+        }
405
+        List<FeWorkflowStep> steps = feWorkflowStepMapper.selectList(
406
+                new LambdaQueryWrapper<FeWorkflowStep>()
407
+                        .eq(FeWorkflowStep::getWorkflowId, definition.getId())
408
+                        .orderByAsc(FeWorkflowStep::getStepOrder)
409
+                        .orderByAsc(FeWorkflowStep::getId));
410
+        return steps != null ? steps : Collections.<FeWorkflowStep>emptyList();
411
+    }
412
+
413
+    private static int indexOfStep(List<FeWorkflowStep> flowSteps, String stepCode) {
414
+        if (!StringUtils.hasText(stepCode) || flowSteps == null) {
415
+            return -1;
416
+        }
417
+        for (int i = 0; i < flowSteps.size(); i++) {
418
+            if (stepCode.equals(flowSteps.get(i).getStepCode())) {
419
+                return i;
420
+            }
421
+        }
422
+        return -1;
423
+    }
424
+
425
+    private static String resolveStepTime(String stepCode, FeEmploymentDraft draft, FeEmploymentOrder order) {
426
+        LocalDateTime time = null;
427
+        if ("draft_created".equals(stepCode) && draft != null) {
428
+            time = draft.getCreateTime();
429
+        } else if ("plan_confirmed".equals(stepCode)) {
430
+            if (draft != null && draft.getConfirmedAt() != null) {
431
+                time = draft.getConfirmedAt();
432
+            } else if (order != null) {
433
+                time = order.getCreateTime();
434
+            }
435
+        }
436
+        return time != null ? STEP_TIME_FMT.format(time) : null;
437
+    }
438
+
439
+    private List<RegistrationBatchWorkerItemResponse> buildWorkers(List<FeWorkerRegistration> registrations) {
440
+        List<RegistrationBatchWorkerItemResponse> workers = new ArrayList<>();
441
+        if (registrations == null) {
442
+            return workers;
443
+        }
444
+        for (FeWorkerRegistration reg : registrations) {
445
+            RegistrationBatchWorkerItemResponse item = new RegistrationBatchWorkerItemResponse();
446
+            item.setRegistrationId(reg.getId());
447
+            item.setWorkerId(reg.getWorkerId());
448
+            item.setRealName(reg.getRealName());
449
+            item.setMobileMask(reg.getMobileMask());
450
+            item.setRegStatus(reg.getRegStatus());
451
+            item.setStatusTag(toStatusTag(reg.getRegStatus()));
452
+            item.setStatusText(toStatusText(reg.getRegStatus()));
453
+            item.setFailReason(reg.getFailReason());
454
+            item.setSubmittedAt(reg.getSubmittedAt());
455
+            workers.add(item);
456
+        }
457
+        return workers;
458
+    }
459
+
460
+    private static String toStatusTag(String regStatus) {
461
+        if (REG_COMPLETED.equals(regStatus)) {
462
+            return "done";
463
+        }
464
+        if (REG_VERIFY_FAILED.equals(regStatus)) {
465
+            return "fail";
466
+        }
467
+        if (REG_UNDER_REVIEW.equals(regStatus)) {
468
+            return "review";
469
+        }
470
+        if (REG_REGISTERING.equals(regStatus)) {
471
+            return "registering";
472
+        }
473
+        return "pending";
474
+    }
475
+
476
+    private static String toStatusText(String regStatus) {
477
+        if (REG_COMPLETED.equals(regStatus)) {
478
+            return "已完成";
479
+        }
480
+        if (REG_VERIFY_FAILED.equals(regStatus)) {
481
+            return "核验失败";
482
+        }
483
+        if (REG_UNDER_REVIEW.equals(regStatus)) {
484
+            return "审核中";
485
+        }
486
+        if (REG_REGISTERING.equals(regStatus)) {
487
+            return "登记中";
488
+        }
489
+        return "待登记";
490
+    }
491
+
122 492
     private void attachQrCode(FeRegistrationBatch batch, String scene, LocalDateTime now) {
123 493
         try {
124 494
             byte[] png;

+ 207 - 0
huimv-employment/fe-service/src/main/java/com/huimv/employment/service/registration/dto/RegistrationBatchDetailResponse.java

@@ -0,0 +1,207 @@
1
+package com.huimv.employment.service.registration.dto;
2
+
3
+import com.fasterxml.jackson.annotation.JsonProperty;
4
+import io.swagger.v3.oas.annotations.media.Schema;
5
+
6
+import java.time.LocalDateTime;
7
+import java.util.ArrayList;
8
+import java.util.List;
9
+
10
+@Schema(description = "登记批次详情(进度管理)")
11
+public class RegistrationBatchDetailResponse {
12
+
13
+    @JsonProperty("batch_id")
14
+    @Schema(description = "批次主键 ID")
15
+    private Long batchId;
16
+
17
+    @JsonProperty("batch_no")
18
+    @Schema(description = "批次业务编号", example = "bat_1")
19
+    private String batchNo;
20
+
21
+    @Schema(description = "批次/订单标题", example = "浦东仓库搬运")
22
+    private String title;
23
+
24
+    @Schema(description = "页头副标题:标题 + 批次号", example = "浦东仓库搬运 bat_1")
25
+    private String subtitle;
26
+
27
+    @JsonProperty("order_id")
28
+    @Schema(description = "订单主键 ID")
29
+    private Long orderId;
30
+
31
+    @JsonProperty("order_no")
32
+    @Schema(description = "订单编号")
33
+    private String orderNo;
34
+
35
+    @Schema(description = "批次状态:active / expired / closed")
36
+    private String status;
37
+
38
+    @JsonProperty("qr_code_url")
39
+    @Schema(description = "小程序码图片 URL")
40
+    private String qrCodeUrl;
41
+
42
+    @JsonProperty("registration_url")
43
+    @Schema(description = "临时工登记页 path")
44
+    private String registrationUrl;
45
+
46
+    @JsonProperty("qr_token")
47
+    @Schema(description = "扫码 scene / token")
48
+    private String qrToken;
49
+
50
+    @JsonProperty("valid_from")
51
+    private LocalDateTime validFrom;
52
+
53
+    @JsonProperty("valid_until")
54
+    private LocalDateTime validUntil;
55
+
56
+    @JsonProperty("current_step_code")
57
+    @Schema(description = "订单当前流程步骤编码")
58
+    private String currentStepCode;
59
+
60
+    @Schema(description = "人数统计(待登记 / 登记中 / 已完成 / 总计)")
61
+    private RegistrationBatchStatsResponse stats;
62
+
63
+    @Schema(description = "登记进度条")
64
+    private RegistrationBatchProgressResponse progress;
65
+
66
+    @Schema(description = "办理流程步骤")
67
+    private List<RegistrationBatchStepResponse> steps = new ArrayList<>();
68
+
69
+    @Schema(description = "人员列表")
70
+    private List<RegistrationBatchWorkerItemResponse> workers = new ArrayList<>();
71
+
72
+    public Long getBatchId() {
73
+        return batchId;
74
+    }
75
+
76
+    public void setBatchId(Long batchId) {
77
+        this.batchId = batchId;
78
+    }
79
+
80
+    public String getBatchNo() {
81
+        return batchNo;
82
+    }
83
+
84
+    public void setBatchNo(String batchNo) {
85
+        this.batchNo = batchNo;
86
+    }
87
+
88
+    public String getTitle() {
89
+        return title;
90
+    }
91
+
92
+    public void setTitle(String title) {
93
+        this.title = title;
94
+    }
95
+
96
+    public String getSubtitle() {
97
+        return subtitle;
98
+    }
99
+
100
+    public void setSubtitle(String subtitle) {
101
+        this.subtitle = subtitle;
102
+    }
103
+
104
+    public Long getOrderId() {
105
+        return orderId;
106
+    }
107
+
108
+    public void setOrderId(Long orderId) {
109
+        this.orderId = orderId;
110
+    }
111
+
112
+    public String getOrderNo() {
113
+        return orderNo;
114
+    }
115
+
116
+    public void setOrderNo(String orderNo) {
117
+        this.orderNo = orderNo;
118
+    }
119
+
120
+    public String getStatus() {
121
+        return status;
122
+    }
123
+
124
+    public void setStatus(String status) {
125
+        this.status = status;
126
+    }
127
+
128
+    public String getQrCodeUrl() {
129
+        return qrCodeUrl;
130
+    }
131
+
132
+    public void setQrCodeUrl(String qrCodeUrl) {
133
+        this.qrCodeUrl = qrCodeUrl;
134
+    }
135
+
136
+    public String getRegistrationUrl() {
137
+        return registrationUrl;
138
+    }
139
+
140
+    public void setRegistrationUrl(String registrationUrl) {
141
+        this.registrationUrl = registrationUrl;
142
+    }
143
+
144
+    public String getQrToken() {
145
+        return qrToken;
146
+    }
147
+
148
+    public void setQrToken(String qrToken) {
149
+        this.qrToken = qrToken;
150
+    }
151
+
152
+    public LocalDateTime getValidFrom() {
153
+        return validFrom;
154
+    }
155
+
156
+    public void setValidFrom(LocalDateTime validFrom) {
157
+        this.validFrom = validFrom;
158
+    }
159
+
160
+    public LocalDateTime getValidUntil() {
161
+        return validUntil;
162
+    }
163
+
164
+    public void setValidUntil(LocalDateTime validUntil) {
165
+        this.validUntil = validUntil;
166
+    }
167
+
168
+    public String getCurrentStepCode() {
169
+        return currentStepCode;
170
+    }
171
+
172
+    public void setCurrentStepCode(String currentStepCode) {
173
+        this.currentStepCode = currentStepCode;
174
+    }
175
+
176
+    public RegistrationBatchStatsResponse getStats() {
177
+        return stats;
178
+    }
179
+
180
+    public void setStats(RegistrationBatchStatsResponse stats) {
181
+        this.stats = stats;
182
+    }
183
+
184
+    public RegistrationBatchProgressResponse getProgress() {
185
+        return progress;
186
+    }
187
+
188
+    public void setProgress(RegistrationBatchProgressResponse progress) {
189
+        this.progress = progress;
190
+    }
191
+
192
+    public List<RegistrationBatchStepResponse> getSteps() {
193
+        return steps;
194
+    }
195
+
196
+    public void setSteps(List<RegistrationBatchStepResponse> steps) {
197
+        this.steps = steps;
198
+    }
199
+
200
+    public List<RegistrationBatchWorkerItemResponse> getWorkers() {
201
+        return workers;
202
+    }
203
+
204
+    public void setWorkers(List<RegistrationBatchWorkerItemResponse> workers) {
205
+        this.workers = workers;
206
+    }
207
+}

+ 40 - 0
huimv-employment/fe-service/src/main/java/com/huimv/employment/service/registration/dto/RegistrationBatchProgressResponse.java

@@ -0,0 +1,40 @@
1
+package com.huimv.employment.service.registration.dto;
2
+
3
+import io.swagger.v3.oas.annotations.media.Schema;
4
+
5
+@Schema(description = "登记进度(进度条)")
6
+public class RegistrationBatchProgressResponse {
7
+
8
+    @Schema(description = "已进入登记流程人数")
9
+    private Integer current;
10
+
11
+    @Schema(description = "计划总人数")
12
+    private Integer total;
13
+
14
+    @Schema(description = "进度百分比 0-100")
15
+    private Integer percent;
16
+
17
+    public Integer getCurrent() {
18
+        return current;
19
+    }
20
+
21
+    public void setCurrent(Integer current) {
22
+        this.current = current;
23
+    }
24
+
25
+    public Integer getTotal() {
26
+        return total;
27
+    }
28
+
29
+    public void setTotal(Integer total) {
30
+        this.total = total;
31
+    }
32
+
33
+    public Integer getPercent() {
34
+        return percent;
35
+    }
36
+
37
+    public void setPercent(Integer percent) {
38
+        this.percent = percent;
39
+    }
40
+}

+ 80 - 0
huimv-employment/fe-service/src/main/java/com/huimv/employment/service/registration/dto/RegistrationBatchStatsResponse.java

@@ -0,0 +1,80 @@
1
+package com.huimv.employment.service.registration.dto;
2
+
3
+import com.fasterxml.jackson.annotation.JsonProperty;
4
+import io.swagger.v3.oas.annotations.media.Schema;
5
+
6
+@Schema(description = "登记批次人数统计")
7
+public class RegistrationBatchStatsResponse {
8
+
9
+    @JsonProperty("pending_count")
10
+    @Schema(description = "待登记人数")
11
+    private Integer pendingCount;
12
+
13
+    @JsonProperty("in_progress_count")
14
+    @Schema(description = "登记中人数(填写中 / 审核中等)")
15
+    private Integer inProgressCount;
16
+
17
+    @JsonProperty("completed_count")
18
+    @Schema(description = "已完成人数")
19
+    private Integer completedCount;
20
+
21
+    @JsonProperty("abnormal_count")
22
+    @Schema(description = "异常人数(如核验失败)")
23
+    private Integer abnormalCount;
24
+
25
+    @JsonProperty("expected_count")
26
+    @Schema(description = "计划总人数")
27
+    private Integer expectedCount;
28
+
29
+    @JsonProperty("registered_count")
30
+    @Schema(description = "已进入登记流程人数(总计 - 待登记)")
31
+    private Integer registeredCount;
32
+
33
+    public Integer getPendingCount() {
34
+        return pendingCount;
35
+    }
36
+
37
+    public void setPendingCount(Integer pendingCount) {
38
+        this.pendingCount = pendingCount;
39
+    }
40
+
41
+    public Integer getInProgressCount() {
42
+        return inProgressCount;
43
+    }
44
+
45
+    public void setInProgressCount(Integer inProgressCount) {
46
+        this.inProgressCount = inProgressCount;
47
+    }
48
+
49
+    public Integer getCompletedCount() {
50
+        return completedCount;
51
+    }
52
+
53
+    public void setCompletedCount(Integer completedCount) {
54
+        this.completedCount = completedCount;
55
+    }
56
+
57
+    public Integer getAbnormalCount() {
58
+        return abnormalCount;
59
+    }
60
+
61
+    public void setAbnormalCount(Integer abnormalCount) {
62
+        this.abnormalCount = abnormalCount;
63
+    }
64
+
65
+    public Integer getExpectedCount() {
66
+        return expectedCount;
67
+    }
68
+
69
+    public void setExpectedCount(Integer expectedCount) {
70
+        this.expectedCount = expectedCount;
71
+    }
72
+
73
+    public Integer getRegisteredCount() {
74
+        return registeredCount;
75
+    }
76
+
77
+    public void setRegisteredCount(Integer registeredCount) {
78
+        this.registeredCount = registeredCount;
79
+    }
80
+}

+ 64 - 0
huimv-employment/fe-service/src/main/java/com/huimv/employment/service/registration/dto/RegistrationBatchStepResponse.java

@@ -0,0 +1,64 @@
1
+package com.huimv.employment.service.registration.dto;
2
+
3
+import com.fasterxml.jackson.annotation.JsonProperty;
4
+import io.swagger.v3.oas.annotations.media.Schema;
5
+
6
+@Schema(description = "办理流程步骤")
7
+public class RegistrationBatchStepResponse {
8
+
9
+    @JsonProperty("step_code")
10
+    @Schema(description = "步骤编码", example = "registration")
11
+    private String stepCode;
12
+
13
+    @Schema(description = "步骤标题", example = "扫码登记")
14
+    private String title;
15
+
16
+    @Schema(description = "步骤状态:done / active / pending", example = "active")
17
+    private String status;
18
+
19
+    @Schema(description = "完成时间展示(MM-dd HH:mm),未完成可为空", example = "01-15 14:30")
20
+    private String time;
21
+
22
+    @Schema(description = "进行中高亮文案,如「进行中 7/10」")
23
+    private String highlight;
24
+
25
+    public String getStepCode() {
26
+        return stepCode;
27
+    }
28
+
29
+    public void setStepCode(String stepCode) {
30
+        this.stepCode = stepCode;
31
+    }
32
+
33
+    public String getTitle() {
34
+        return title;
35
+    }
36
+
37
+    public void setTitle(String title) {
38
+        this.title = title;
39
+    }
40
+
41
+    public String getStatus() {
42
+        return status;
43
+    }
44
+
45
+    public void setStatus(String status) {
46
+        this.status = status;
47
+    }
48
+
49
+    public String getTime() {
50
+        return time;
51
+    }
52
+
53
+    public void setTime(String time) {
54
+        this.time = time;
55
+    }
56
+
57
+    public String getHighlight() {
58
+        return highlight;
59
+    }
60
+
61
+    public void setHighlight(String highlight) {
62
+        this.highlight = highlight;
63
+    }
64
+}

+ 118 - 0
huimv-employment/fe-service/src/main/java/com/huimv/employment/service/registration/dto/RegistrationBatchWorkerItemResponse.java

@@ -0,0 +1,118 @@
1
+package com.huimv.employment.service.registration.dto;
2
+
3
+import com.fasterxml.jackson.annotation.JsonProperty;
4
+import io.swagger.v3.oas.annotations.media.Schema;
5
+
6
+import java.time.LocalDateTime;
7
+
8
+@Schema(description = "批次登记人员条目")
9
+public class RegistrationBatchWorkerItemResponse {
10
+
11
+    @JsonProperty("registration_id")
12
+    @Schema(description = "登记记录 ID")
13
+    private Long registrationId;
14
+
15
+    @JsonProperty("worker_id")
16
+    @Schema(description = "临时工档案 ID")
17
+    private Long workerId;
18
+
19
+    @JsonProperty("real_name")
20
+    @Schema(description = "姓名")
21
+    private String realName;
22
+
23
+    @JsonProperty("mobile_mask")
24
+    @Schema(description = "脱敏手机号", example = "138****1234")
25
+    private String mobileMask;
26
+
27
+    @JsonProperty("reg_status")
28
+    @Schema(description = "登记状态:pending / registering / under_review / completed / verify_failed")
29
+    private String regStatus;
30
+
31
+    @JsonProperty("status_tag")
32
+    @Schema(description = "前端状态样式标签:pending / registering / review / done / fail")
33
+    private String statusTag;
34
+
35
+    @JsonProperty("status_text")
36
+    @Schema(description = "状态中文", example = "已完成")
37
+    private String statusText;
38
+
39
+    @JsonProperty("fail_reason")
40
+    @Schema(description = "失败原因(核验失败时)")
41
+    private String failReason;
42
+
43
+    @JsonProperty("submitted_at")
44
+    @Schema(description = "提交时间")
45
+    private LocalDateTime submittedAt;
46
+
47
+    public Long getRegistrationId() {
48
+        return registrationId;
49
+    }
50
+
51
+    public void setRegistrationId(Long registrationId) {
52
+        this.registrationId = registrationId;
53
+    }
54
+
55
+    public Long getWorkerId() {
56
+        return workerId;
57
+    }
58
+
59
+    public void setWorkerId(Long workerId) {
60
+        this.workerId = workerId;
61
+    }
62
+
63
+    public String getRealName() {
64
+        return realName;
65
+    }
66
+
67
+    public void setRealName(String realName) {
68
+        this.realName = realName;
69
+    }
70
+
71
+    public String getMobileMask() {
72
+        return mobileMask;
73
+    }
74
+
75
+    public void setMobileMask(String mobileMask) {
76
+        this.mobileMask = mobileMask;
77
+    }
78
+
79
+    public String getRegStatus() {
80
+        return regStatus;
81
+    }
82
+
83
+    public void setRegStatus(String regStatus) {
84
+        this.regStatus = regStatus;
85
+    }
86
+
87
+    public String getStatusTag() {
88
+        return statusTag;
89
+    }
90
+
91
+    public void setStatusTag(String statusTag) {
92
+        this.statusTag = statusTag;
93
+    }
94
+
95
+    public String getStatusText() {
96
+        return statusText;
97
+    }
98
+
99
+    public void setStatusText(String statusText) {
100
+        this.statusText = statusText;
101
+    }
102
+
103
+    public String getFailReason() {
104
+        return failReason;
105
+    }
106
+
107
+    public void setFailReason(String failReason) {
108
+        this.failReason = failReason;
109
+    }
110
+
111
+    public LocalDateTime getSubmittedAt() {
112
+        return submittedAt;
113
+    }
114
+
115
+    public void setSubmittedAt(LocalDateTime submittedAt) {
116
+        this.submittedAt = submittedAt;
117
+    }
118
+}