fix: complete appointment management data and filters
| | |
| | | return http.get<PageResult<VerificationRecord>, PageResult<VerificationRecord>>('/api/orders/verifications', { params }) |
| | | } |
| | | |
| | | export function getServiceApplications(params: ServiceApplicationQuery = {}) { |
| | | function serviceApplicationParams(params: ServiceApplicationQuery = {}) { |
| | | const requestParams: Record<string, unknown> = { ...params } |
| | | if (params.talentKeyword && !requestParams.keyword) { |
| | | requestParams.keyword = params.talentKeyword |
| | | } |
| | | if (!requestParams.serviceKeyword) { |
| | | requestParams.serviceKeyword = params.merchantName || params.hospitalName || params.parkingLot |
| | | } |
| | | delete requestParams.talentKeyword |
| | | delete requestParams.merchantName |
| | | delete requestParams.hospitalName |
| | | delete requestParams.parkingLot |
| | | return requestParams |
| | | } |
| | | |
| | | export function getServiceApplications(params: ServiceApplicationQuery = {}) { |
| | | return http.get<PageResult<ServiceApplication>, PageResult<ServiceApplication>>('/api/admin/service-appointment-applications', { |
| | | params: requestParams, |
| | | params: serviceApplicationParams(params), |
| | | }) |
| | | } |
| | | |
| | |
| | | |
| | | export function exportServiceApplications(params: ServiceApplicationQuery = {}) { |
| | | return http.get<Blob, Blob>('/api/admin/service-appointment-applications/export', { |
| | | params, |
| | | params: serviceApplicationParams(params), |
| | | responseType: 'blob', |
| | | }) |
| | | } |
| | |
| | | } |
| | | |
| | | .hotel-voucher-row { |
| | | grid-template-columns: 76px 42px 104px 24px 64px 104px 96px 42px; |
| | | grid-template-columns: 76px 42px 104px 24px 72px 104px 96px 42px; |
| | | } |
| | | |
| | | .hotel-reset-label { |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .hotel-consume-row { |
| | |
| | | size?: number |
| | | applicationType?: ServiceApplicationType |
| | | talentKeyword?: string |
| | | serviceKeyword?: string |
| | | merchantName?: string |
| | | hospitalName?: string |
| | | parkingLot?: string |
| | |
| | | <el-switch v-model="item.freeVoucherEnabled" /> |
| | | <el-input v-model="item.freeVoucherTimes" placeholder="请输入" class="hotel-times-input" /> |
| | | <span>次</span> |
| | | <span class="hotel-margin-left">重置周期</span> |
| | | <span class="hotel-reset-label">重置周期</span> |
| | | <el-select v-model="item.freeVoucherCycle" class="hotel-cycle-select"> |
| | | <el-option label="每天" value="每天" /> |
| | | <el-option label="每周" value="每周" /> |
| | |
| | | @Parameter(description = "联系电话") @RequestParam(required = false) String applicantMobile, |
| | | @Parameter(description = "服务机构关键词") @RequestParam(required = false) String serviceKeyword, |
| | | @Parameter(description = "人才卡等级") @RequestParam(required = false) String cardLevel, |
| | | @Parameter(description = "是否使用补贴:是、否") @RequestParam(required = false) String subsidy, |
| | | @Parameter(description = "提交类型:新增、修改") @RequestParam(required = false) String submissionType, |
| | | @Parameter(description = "处理状态") @RequestParam(required = false) String status, |
| | | @Parameter(description = "提交开始日期,格式yyyy-MM-dd") @RequestParam(required = false) String submittedStart, |
| | | @Parameter(description = "提交结束日期,格式yyyy-MM-dd") @RequestParam(required = false) String submittedEnd, |
| | | @Parameter(description = "页码") @RequestParam(defaultValue = "1") int page, |
| | | @Parameter(description = "每页条数") @RequestParam(defaultValue = "10") int size |
| | | ) { |
| | | return ApiResponse.success(service.page(applicationType, keyword, applicantName, applicantMobile, serviceKeyword, cardLevel, status, submittedStart, submittedEnd, page, size)); |
| | | return ApiResponse.success(service.page(applicationType, keyword, applicantName, applicantMobile, serviceKeyword, cardLevel, subsidy, submissionType, status, submittedStart, submittedEnd, page, size)); |
| | | } |
| | | |
| | | @Operation(summary = "预约申请详情", description = "查看预约申请完整信息,包含服务快照、申请人、配偶或子女信息") |
| | |
| | | @Parameter(description = "联系电话") @RequestParam(required = false) String applicantMobile, |
| | | @Parameter(description = "服务机构关键词") @RequestParam(required = false) String serviceKeyword, |
| | | @Parameter(description = "人才卡等级") @RequestParam(required = false) String cardLevel, |
| | | @Parameter(description = "是否使用补贴:是、否") @RequestParam(required = false) String subsidy, |
| | | @Parameter(description = "提交类型:新增、修改") @RequestParam(required = false) String submissionType, |
| | | @Parameter(description = "处理状态") @RequestParam(required = false) String status, |
| | | @Parameter(description = "提交开始日期,格式yyyy-MM-dd") @RequestParam(required = false) String submittedStart, |
| | | @Parameter(description = "提交结束日期,格式yyyy-MM-dd") @RequestParam(required = false) String submittedEnd, |
| | | HttpServletResponse response |
| | | ) throws IOException { |
| | | byte[] data = service.exportExcel(applicationType, keyword, applicantName, applicantMobile, serviceKeyword, cardLevel, status, submittedStart, submittedEnd); |
| | | byte[] data = service.exportExcel(applicationType, keyword, applicantName, applicantMobile, serviceKeyword, cardLevel, subsidy, submissionType, status, submittedStart, submittedEnd); |
| | | String filename = URLEncoder.encode("预约申请列表.xlsx", StandardCharsets.UTF_8).replace("+", "%20"); |
| | | response.setCharacterEncoding(StandardCharsets.UTF_8.name()); |
| | | response.setContentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet").toString()); |
| | |
| | | response.getOutputStream().write(data); |
| | | response.flushBuffer(); |
| | | } |
| | | } |
| | | } |
| | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.talentcard.server.entity.ServiceApplicationOperationLog; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | import org.apache.ibatis.annotations.Select; |
| | | |
| | | @Mapper |
| | | public interface ServiceApplicationOperationLogMapper extends BaseMapper<ServiceApplicationOperationLog> { |
| | | } |
| | | @Select("select display_name from admin_operator where id = #{operatorId} and deleted = 0 limit 1") |
| | | String selectOperatorName(@Param("operatorId") Long operatorId); |
| | | } |
| | |
| | | @Transactional(readOnly = true) |
| | | public PageResult<Map<String, Object>> page(String applicationType, String keyword, String applicantName, |
| | | String applicantMobile, String serviceKeyword, |
| | | String cardLevel, String status, String submittedStart, |
| | | String cardLevel, String subsidy, String submissionType, String status, String submittedStart, |
| | | String submittedEnd, int page, int size) { |
| | | int safePage = Math.max(page, 1); |
| | | int safeSize = Math.min(Math.max(size, 1), 100); |
| | | QueryWrapper<ServiceApplication> countWrapper = filter(applicationType, keyword, applicantName, applicantMobile, serviceKeyword, cardLevel, status, submittedStart, submittedEnd); |
| | | QueryWrapper<ServiceApplication> countWrapper = filter(applicationType, keyword, applicantName, applicantMobile, serviceKeyword, cardLevel, subsidy, submissionType, status, submittedStart, submittedEnd); |
| | | Long total = applicationMapper.selectCount(countWrapper); |
| | | QueryWrapper<ServiceApplication> pageWrapper = filter(applicationType, keyword, applicantName, applicantMobile, serviceKeyword, cardLevel, status, submittedStart, submittedEnd) |
| | | QueryWrapper<ServiceApplication> pageWrapper = filter(applicationType, keyword, applicantName, applicantMobile, serviceKeyword, cardLevel, subsidy, submissionType, status, submittedStart, submittedEnd) |
| | | .orderByDesc("submitted_at", "id") |
| | | .last("limit " + safeSize + " offset " + ((safePage - 1) * safeSize)); |
| | | List<Map<String, Object>> records = applicationMapper.selectList(pageWrapper).stream() |
| | |
| | | if (REJECTED_STATUSES.contains(nextStatus) && remark.isBlank()) { |
| | | throw new BusinessException(ErrorCode.BAD_REQUEST, "拒绝或驳回时必须填写处理备注"); |
| | | } |
| | | String handlerName = first(request.handlerName(), operatorId == null ? "" : "管理员" + operatorId, "管理员"); |
| | | String handlerName = first(operatorName(operatorId), request.handlerName(), "管理员"); |
| | | LocalDateTime handledAt = PENDING_STATUSES.contains(nextStatus) ? null : LocalDateTime.now(); |
| | | UpdateWrapper<ServiceApplication> update = new UpdateWrapper<ServiceApplication>() |
| | | .set("status", nextStatus) |
| | |
| | | @Transactional(readOnly = true) |
| | | public byte[] exportExcel(String applicationType, String keyword, String applicantName, |
| | | String applicantMobile, String serviceKeyword, |
| | | String cardLevel, String status, String submittedStart, String submittedEnd) { |
| | | QueryWrapper<ServiceApplication> wrapper = filter(applicationType, keyword, applicantName, applicantMobile, serviceKeyword, cardLevel, status, submittedStart, submittedEnd) |
| | | String cardLevel, String subsidy, String submissionType, String status, String submittedStart, String submittedEnd) { |
| | | QueryWrapper<ServiceApplication> wrapper = filter(applicationType, keyword, applicantName, applicantMobile, serviceKeyword, cardLevel, subsidy, submissionType, status, submittedStart, submittedEnd) |
| | | .orderByDesc("submitted_at", "id"); |
| | | List<ServiceApplication> applications = applicationMapper.selectList(wrapper); |
| | | String[] headers = { |
| | |
| | | |
| | | private QueryWrapper<ServiceApplication> filter(String applicationType, String keyword, String applicantName, |
| | | String applicantMobile, String serviceKeyword, |
| | | String cardLevel, String status, String submittedStart, String submittedEnd) { |
| | | String cardLevel, String subsidy, String submissionType, String status, String submittedStart, String submittedEnd) { |
| | | QueryWrapper<ServiceApplication> wrapper = new QueryWrapper<ServiceApplication>().eq("deleted", 0); |
| | | String type = normalizeFilterType(applicationType); |
| | | if (!type.isBlank()) { |
| | |
| | | if (!clean(cardLevel).isBlank()) { |
| | | wrapper.eq("talent_level", clean(cardLevel)); |
| | | } |
| | | String subsidyValue = clean(subsidy); |
| | | if ("是".equals(subsidyValue)) { |
| | | wrapper.eq("subsidy", "是"); |
| | | } else if ("否".equals(subsidyValue)) { |
| | | wrapper.and(query -> query.eq("subsidy", "否").or().isNull("subsidy").or().eq("subsidy", "")); |
| | | } else if (!subsidyValue.isBlank()) { |
| | | wrapper.eq("subsidy", subsidyValue); |
| | | } |
| | | if (!clean(submissionType).isBlank()) { |
| | | wrapper.eq("submission_type", clean(submissionType)); |
| | | } |
| | | if (!clean(status).isBlank()) { |
| | | wrapper.eq("status", clean(status)); |
| | | } |
| | |
| | | result.put("appointmentTime", first(application.getExpectedTime(), "以专员通知为准")); |
| | | result.put("applicantName", participantName(application)); |
| | | result.put("applicantMobile", sensitiveDataCrypto.decrypt(first(application.getApplicantMobile(), application.getSpouseMobile(), application.getTalentMobile()))); |
| | | result.put("guestCount", guestCount(application)); |
| | | if (ServiceAppointmentApplicationService.TYPE_SPOUSE.equals(application.getApplicationType())) { |
| | | result.put("spouseName", first(application.getSpouseName(), application.getApplicantName())); |
| | | result.put("spouseMobile", sensitiveDataCrypto.decrypt(first(application.getSpouseMobile(), application.getApplicantMobile()))); |
| | |
| | | |
| | | private Map<String, Object> detailView(ServiceApplication application) { |
| | | Map<String, Object> result = listView(application); |
| | | result.put("handlerName", handlerName(application)); |
| | | result.put("talentId", application.getTalentId()); |
| | | result.put("cardId", application.getCardId()); |
| | | result.put("merchantId", application.getMerchantId()); |
| | |
| | | result.put("applicantIdCardNo", sensitiveDataCrypto.decrypt(application.getApplicantIdCardNo())); |
| | | result.put("checkInDate", application.getCheckInDate()); |
| | | result.put("checkOutDate", application.getCheckOutDate()); |
| | | result.put("guestCount", application.getGuestCount()); |
| | | result.put("guestCount", guestCount(application)); |
| | | result.put("subsidy", application.getSubsidy()); |
| | | result.put("remark", application.getRejectReason()); |
| | | result.put("estimatedProcessingTime", application.getEstimatedProcessingTime()); |
| | |
| | | return first(application.getApplicantName(), application.getSpouseName(), application.getChildName(), application.getTalentName()); |
| | | } |
| | | |
| | | private Integer guestCount(ServiceApplication application) { |
| | | if (application.getGuestCount() != null) { |
| | | return application.getGuestCount(); |
| | | } |
| | | return ServiceAppointmentApplicationService.TYPE_HOTEL.equals(application.getApplicationType()) ? 1 : null; |
| | | } |
| | | |
| | | private String handlerName(ServiceApplication application) { |
| | | if (application.getHandledAt() == null) { |
| | | return first(application.getHandlerName()); |
| | | } |
| | | ServiceApplicationOperationLog log = operationLogMapper.selectOne( |
| | | new QueryWrapper<ServiceApplicationOperationLog>() |
| | | .eq("application_id", application.getId()) |
| | | .eq("operation_type", "STATUS_UPDATE") |
| | | .eq("after_status", application.getStatus()) |
| | | .orderByDesc("created_at", "id") |
| | | .last("limit 1") |
| | | ); |
| | | return first( |
| | | log == null ? "" : operatorName(log.getOperatorId()), |
| | | log == null ? "" : log.getOperatorName(), |
| | | application.getHandlerName() |
| | | ); |
| | | } |
| | | |
| | | private String operatorName(Long operatorId) { |
| | | return operatorId == null ? "" : first(operationLogMapper.selectOperatorName(operatorId)); |
| | | } |
| | | |
| | | private List<String> proofFileIds(String value) { |
| | | if (value == null || value.isBlank()) { |
| | | return List.of(); |
| | |
| | | applyInstitution(application, merchant, request.merchantName(), request.contactMobile(), false); |
| | | application.setApplicantName(first(clean(request.applicantName()), application.getTalentName())); |
| | | application.setApplicantMobile(first(clean(request.applicantMobile()), application.getTalentMobile())); |
| | | application.setGuestCount(request.guestCount()); |
| | | application.setGuestCount(request.guestCount() == null ? 1 : request.guestCount()); |
| | | application.setSubsidy(blankToNull(clean(request.subsidy()))); |
| | | applyHotelProduct(application, request.productId(), request.productName()); |
| | | LocalDate checkIn = date(request.checkInDate(), "入住日期格式不正确", false); |