| | |
| | | *.log |
| | | .env |
| | | .env.local |
| | | .codegraph/ |
| | | **/.codegraph/ |
| | |
| | | |
| | | @ExceptionHandler(SaTokenException.class) |
| | | public Result<Void> handleSaToken(SaTokenException e) { |
| | | log.error("satoken error", e); |
| | | if (e instanceof NotPermissionException){ |
| | | log.warn("satoken forbidden: {}", safeMessage(e)); |
| | | return ResultUtil.error(HttpBizCode.FORBIDDEN, "无权限访问"); |
| | | } |
| | | if (e instanceof NotLoginException notLogin |
| | | && NotLoginException.KICK_OUT.equals(notLogin.getType())) { |
| | | log.warn("satoken unauthorized: type={} message={}", notLogin.getType(), safeMessage(e)); |
| | | return ResultUtil.error(HttpBizCode.UNAUTHORIZED, "账号已被禁用,请重新登录"); |
| | | } |
| | | if (e instanceof NotLoginException notLogin) { |
| | | log.warn("satoken unauthorized: type={} message={}", notLogin.getType(), safeMessage(e)); |
| | | return ResultUtil.error(HttpBizCode.UNAUTHORIZED, "账号信息已过期,请重新登录"); |
| | | } |
| | | log.warn("satoken error: {} message={}", e.getClass().getSimpleName(), safeMessage(e)); |
| | | return ResultUtil.error(HttpBizCode.UNAUTHORIZED, "账号信息已过期,请重新登录"); |
| | | } |
| | | |
| | | private String safeMessage(Exception e) { |
| | | String message = e.getMessage(); |
| | | return message == null || message.isBlank() ? "-" : message; |
| | | } |
| | | |
| | | @ExceptionHandler(Exception.class) |
| | | public Result<Void> handleOther(Exception e) { |
| | | log.error("Unhandled error", e); |
| | |
| | | import com.sinata.appointment.service.AppointmentApplicationService; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import jakarta.validation.constraints.NotBlank; |
| | | import java.io.IOException; |
| | | import lombok.RequiredArgsConstructor; |
| | | import java.time.LocalDate; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | import org.springframework.http.HttpHeaders; |
| | | import org.springframework.http.MediaType; |
| | | import org.springframework.http.ResponseEntity; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PathVariable; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | |
| | | @Operation(summary = "导出 Excel") |
| | | @GetMapping("/export") |
| | | @SaCheckPermission("appointments:export") |
| | | public ResponseEntity<byte[]> export( |
| | | public void export( |
| | | HttpServletResponse response, |
| | | @RequestParam(required = false) String visitedUserName, |
| | | @RequestParam(required = false) Long visitedDeptId, |
| | | @RequestParam(required = false) Long accessAreaId, |
| | |
| | | @RequestParam(required = false) String displayStatus, |
| | | @RequestParam(required = false) String approvalStatus, |
| | | @RequestParam(required = false) String visitorKeyword, |
| | | @RequestParam(required = false) String visitReasonCode) { |
| | | byte[] body = |
| | | appointmentApplicationService.exportExcel( |
| | | visitedUserName, |
| | | visitedDeptId, |
| | | accessAreaId, |
| | | accessArea, |
| | | localUnit, |
| | | visitDateStart, |
| | | visitDateEnd, |
| | | displayStatus, |
| | | approvalStatus, |
| | | visitorKeyword, |
| | | visitReasonCode); |
| | | return ResponseEntity.ok() |
| | | .contentType( |
| | | MediaType.parseMediaType( |
| | | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) |
| | | .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"appointments.xlsx\"") |
| | | .body(body); |
| | | @RequestParam(required = false) String visitReasonCode) |
| | | throws IOException { |
| | | appointmentApplicationService.exportExcel( |
| | | response, |
| | | visitedUserName, |
| | | visitedDeptId, |
| | | accessAreaId, |
| | | accessArea, |
| | | localUnit, |
| | | visitDateStart, |
| | | visitDateEnd, |
| | | displayStatus, |
| | | approvalStatus, |
| | | visitorKeyword, |
| | | visitReasonCode); |
| | | } |
| | | |
| | | @Operation(summary = "详情含访客") |
| | |
| | | import com.sinata.appointment.service.VisitorUserManageApplicationService; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import jakarta.validation.Valid; |
| | | import jakarta.validation.constraints.NotBlank; |
| | | import java.io.IOException; |
| | | import java.time.LocalDate; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.http.HttpHeaders; |
| | | import org.springframework.http.MediaType; |
| | | import org.springframework.http.ResponseEntity; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.DeleteMapping; |
| | |
| | | @Operation(summary = "导出 Excel") |
| | | @GetMapping("/export") |
| | | @SaCheckPermission("sys:visitor-users:export") |
| | | public ResponseEntity<byte[]> export( |
| | | public void export( |
| | | HttpServletResponse response, |
| | | @RequestParam(required = false) String userName, |
| | | @RequestParam(required = false) String mobile, |
| | | @RequestParam(required = false) String companyName, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate registerStartDate, |
| | | @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate registerEndDate, |
| | | @RequestParam(required = false) Integer status) { |
| | | byte[] body = |
| | | visitorUserManageApplicationService.exportExcel( |
| | | userName, mobile, companyName, registerStartDate, registerEndDate, status); |
| | | return ResponseEntity.ok() |
| | | .contentType( |
| | | MediaType.parseMediaType( |
| | | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) |
| | | .header( |
| | | HttpHeaders.CONTENT_DISPOSITION, |
| | | "attachment; filename=\"visitor-users.xlsx\"") |
| | | .body(body); |
| | | @RequestParam(required = false) Integer status) |
| | | throws IOException { |
| | | visitorUserManageApplicationService.exportExcel( |
| | | response, userName, mobile, companyName, registerStartDate, registerEndDate, status); |
| | | } |
| | | |
| | | @Operation(summary = "详情") |
| | |
| | | import com.sinata.appointment.util.MobileMaskUtil; |
| | | import com.sinata.appointment.util.SensitiveDataUtil; |
| | | import com.sinata.appointment.util.UuidAssert; |
| | | import java.io.ByteArrayOutputStream; |
| | | import com.alibaba.excel.ExcelWriter; |
| | | import com.alibaba.excel.write.metadata.WriteSheet; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import java.io.IOException; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | |
| | | return buildAdminPage(pagedOrders); |
| | | } |
| | | |
| | | public byte[] exportExcel( |
| | | public void exportExcel( |
| | | HttpServletResponse response, |
| | | String visitedUserName, |
| | | Long visitedDeptId, |
| | | Long accessAreaId, |
| | |
| | | String displayStatus, |
| | | String approvalStatus, |
| | | String visitorKeyword, |
| | | String visitReasonCode) { |
| | | String visitReasonCode) |
| | | throws IOException { |
| | | prepareExcelResponse(response, "appointments.xlsx"); |
| | | List<Long> accessAreaIds = resolveAccessAreaFilterIds(accessAreaId); |
| | | long pageNo = 1L; |
| | | long pageSize = 200L; |
| | | List<AppointmentAdminExportRow> rows = new ArrayList<>(); |
| | | while (true) { |
| | | Page<AppointmentOrder> orderPage = new Page<>(pageNo, pageSize); |
| | | IPage<AppointmentOrder> pagedOrders = |
| | | appointmentOrderMapper.pageAdminOrders( |
| | | orderPage, |
| | | trimToNull(visitedUserName), |
| | | visitedDeptId, |
| | | accessAreaIds, |
| | | trimToNull(accessArea), |
| | | trimToNull(localUnit), |
| | | visitDateStart, |
| | | visitDateEnd, |
| | | trimToNull(displayStatus), |
| | | trimToNull(approvalStatus), |
| | | trimToNull(visitorKeyword), |
| | | trimToNull(visitReasonCode)); |
| | | List<AppointmentOrder> orders = pagedOrders.getRecords(); |
| | | if (orders == null || orders.isEmpty()) { |
| | | break; |
| | | boolean wroteAnyPage = false; |
| | | try (ExcelWriter writer = |
| | | EasyExcel.write(response.getOutputStream(), AppointmentAdminExportRow.class).build()) { |
| | | WriteSheet sheet = EasyExcel.writerSheet("预约记录").build(); |
| | | while (true) { |
| | | Page<AppointmentOrder> orderPage = new Page<>(pageNo, pageSize); |
| | | IPage<AppointmentOrder> pagedOrders = |
| | | appointmentOrderMapper.pageAdminOrders( |
| | | orderPage, |
| | | trimToNull(visitedUserName), |
| | | visitedDeptId, |
| | | accessAreaIds, |
| | | trimToNull(accessArea), |
| | | trimToNull(localUnit), |
| | | visitDateStart, |
| | | visitDateEnd, |
| | | trimToNull(displayStatus), |
| | | trimToNull(approvalStatus), |
| | | trimToNull(visitorKeyword), |
| | | trimToNull(visitReasonCode)); |
| | | List<AppointmentOrder> orders = pagedOrders.getRecords(); |
| | | if (orders == null || orders.isEmpty()) { |
| | | break; |
| | | } |
| | | AdminPageData pageData = loadAdminPageData(orders); |
| | | writer.write( |
| | | buildExportRows( |
| | | orders, |
| | | pageData.visitorRowsMap(), |
| | | pageData.approvalInstanceMap(), |
| | | pageData.reasonNameMap()), |
| | | sheet); |
| | | wroteAnyPage = true; |
| | | if (pageNo * pageSize >= pagedOrders.getTotal()) { |
| | | break; |
| | | } |
| | | pageNo++; |
| | | } |
| | | AdminPageData pageData = loadAdminPageData(orders); |
| | | rows.addAll( |
| | | buildExportRows( |
| | | orders, |
| | | pageData.visitorRowsMap(), |
| | | pageData.approvalInstanceMap(), |
| | | pageData.reasonNameMap())); |
| | | if (pageNo * pageSize >= pagedOrders.getTotal()) { |
| | | break; |
| | | if (!wroteAnyPage) { |
| | | writer.write(List.of(), sheet); |
| | | } |
| | | pageNo++; |
| | | } |
| | | try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { |
| | | EasyExcel.write(bos, AppointmentAdminExportRow.class).sheet("预约记录").doWrite(rows); |
| | | return bos.toByteArray(); |
| | | } catch (Exception e) { |
| | | return new byte[0]; |
| | | } |
| | | } |
| | | |
| | | private void prepareExcelResponse(HttpServletResponse response, String filename) { |
| | | response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); |
| | | response.setCharacterEncoding("UTF-8"); |
| | | response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\""); |
| | | } |
| | | |
| | | public AppointmentOrder getById(Long id, String uuid) { |
| | |
| | | payload.put("workUnit", firstNonBlank(valueOf(visitorProfile, MpVisitor::getVisitorCompany), order.getVisitorOrg())); |
| | | payload.put("carNumber", trimToEmpty(visitor.getPlateNo())); |
| | | payload.put("visitPurpose", trimToEmpty(visitPurpose)); |
| | | payload.put("jobNo", valueOf(visitedUser, MpUser::getStaffNo)); |
| | | payload.put("beVisitorPhone", valueOf(visitedUser, MpUser::getMobile)); |
| | | payload.put("startTime", formatDateTime(startTime, QR_TIME_FORMATTER)); |
| | | payload.put("endTime", formatDateTime(endTime, QR_TIME_FORMATTER)); |
| | |
| | | payload.put("date", formatDateTime(qrGenerateTime, QR_DATE_FORMATTER)); |
| | | payload.put("validTime", VALID_TIME_PREFIX + Math.max(validMinutes, 1)); |
| | | payload.put("codeId", trimToEmpty(codeId)); |
| | | payload.put("customa", EMPTY); |
| | | payload.put("customb", EMPTY); |
| | | payload.put("customc", EMPTY); |
| | | try { |
| | | String json = objectMapper.writeValueAsString(payload); |
| | | log.info( |
| | |
| | | import com.sinata.appointment.constants.BizErrorCode; |
| | | import com.sinata.appointment.exception.BizException; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.nio.file.Files; |
| | | import java.nio.file.Path; |
| | | import java.nio.file.StandardCopyOption; |
| | |
| | | if (!target.getParent().equals(uploadDir)) { |
| | | throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "图片上传路径非法"); |
| | | } |
| | | try { |
| | | try (InputStream in = file.getInputStream()) { |
| | | Files.createDirectories(uploadDir); |
| | | Files.copy(file.getInputStream(), target, StandardCopyOption.REPLACE_EXISTING); |
| | | Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING); |
| | | } catch (IOException ex) { |
| | | throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "图片上传失败"); |
| | | } |
| | |
| | | visitor.setPlateNo(driverPlateMap.get(visitor.getMpVisitorId())); |
| | | String ticketUuid = UUID.randomUUID().toString().replace("-", ""); |
| | | String visitorIdCardPlain = resolveVisitorIdCardPlain(visitor, visitorProfile); |
| | | QrcodeTicket ticket = new QrcodeTicket(); |
| | | ticket.setUuid(ticketUuid); |
| | | ticket.setOrderId(order.getId()); |
| | | ticket.setMpVisitorId(visitor.getMpVisitorId()); |
| | | ticket.setPayload("{}"); |
| | | ticket.setTicketStatus(QrcodeTicketStatus.UNUSED); |
| | | ticket.setGenerateTime(generateTime); |
| | | ticket.setExpireTime(expireTime); |
| | | qrcodeTicketMapper.insert(ticket); |
| | | String payload = |
| | | integrationHikvisionService.requestQrcodePayload( |
| | | order, |
| | |
| | | generateTime, |
| | | expireTime, |
| | | validMinutes, |
| | | ticketUuid, |
| | | String.valueOf(ticket.getId()), |
| | | visitorIdCardPlain); |
| | | QrcodeTicket ticket = new QrcodeTicket(); |
| | | ticket.setUuid(ticketUuid); |
| | | ticket.setOrderId(order.getId()); |
| | | ticket.setMpVisitorId(visitor.getMpVisitorId()); |
| | | ticket.setPayload(payload); |
| | | ticket.setTicketStatus(QrcodeTicketStatus.UNUSED); |
| | | ticket.setGenerateTime(generateTime); |
| | | ticket.setExpireTime(expireTime); |
| | | qrcodeTicketMapper.insert(ticket); |
| | | qrcodeTicketMapper.updateById(ticket); |
| | | existingTicketMap.put(visitor.getMpVisitorId(), ticket); |
| | | createdCount++; |
| | | log.info( |
| | | "{} raw-payload orderId={} mpVisitorId={} ticketUuid={} payloadLength={}", |
| | | "{} raw-payload orderId={} mpVisitorId={} ticketId={} ticketUuid={} payloadLength={}", |
| | | IntegrationConstant.HIKVISION_QRCODE_EVENT, |
| | | order.getId(), |
| | | visitor.getMpVisitorId(), |
| | | ticket.getId(), |
| | | ticketUuid, |
| | | payload == null ? 0 : payload.length()); |
| | | } |
| | |
| | | Path dir = resolveAvatarUploadDir(); |
| | | String fileName = UUID.randomUUID().toString().replace("-", "") + ext; |
| | | Path target = dir.resolve(fileName); |
| | | try { |
| | | try (InputStream in = file.getInputStream()) { |
| | | Files.createDirectories(dir); |
| | | Files.copy(file.getInputStream(), target, StandardCopyOption.REPLACE_EXISTING); |
| | | Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING); |
| | | } catch (IOException ex) { |
| | | throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "头像上传失败"); |
| | | } |
| | |
| | | q.notIn(MpUser::getId, inGroup); |
| | | } |
| | | } |
| | | q.orderByDesc(MpUser::getCreateTime); |
| | | q.orderByAsc(MpUser::getNickName).orderByAsc(MpUser::getId); |
| | | Page<MpUser> p = mpUserMapper.selectPage(new Page<>(page, size), q); |
| | | Set<Long> deptIds = new HashSet<>(); |
| | | Set<Long> userIds = new HashSet<>(); |
| | |
| | | package com.sinata.appointment.service; |
| | | |
| | | import com.alibaba.excel.ExcelWriter; |
| | | import com.alibaba.excel.EasyExcel; |
| | | import com.alibaba.excel.write.metadata.WriteSheet; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | |
| | | import com.sinata.appointment.util.MobileMaskUtil; |
| | | import com.sinata.appointment.util.PhoneNormalize; |
| | | import com.sinata.appointment.util.UuidAssert; |
| | | import java.io.ByteArrayOutputStream; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import java.io.IOException; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | |
| | | return result.convert(user -> toListVo(user, bookingCountMap)); |
| | | } |
| | | |
| | | public byte[] exportExcel( |
| | | public void exportExcel( |
| | | HttpServletResponse response, |
| | | String userName, |
| | | String mobile, |
| | | String companyName, |
| | | LocalDate registerStartDate, |
| | | LocalDate registerEndDate, |
| | | Integer status) { |
| | | List<MpUser> users = |
| | | mpUserMapper.selectList( |
| | | buildVisitorQuery( |
| | | userName, mobile, companyName, registerStartDate, registerEndDate, status)); |
| | | List<Long> userIds = users.stream().map(MpUser::getId).filter(Objects::nonNull).toList(); |
| | | Map<Long, Long> bookingCountMap = loadBookingCountMap(userIds); |
| | | List<VisitorUserExportRow> rows = |
| | | users.stream().map(user -> toExportRow(user, bookingCountMap)).toList(); |
| | | try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { |
| | | EasyExcel.write(bos, VisitorUserExportRow.class).sheet("访客信息").doWrite(rows); |
| | | return bos.toByteArray(); |
| | | } catch (Exception e) { |
| | | return new byte[0]; |
| | | Integer status) |
| | | throws IOException { |
| | | prepareExcelResponse(response, "visitor-users.xlsx"); |
| | | long pageNo = 1L; |
| | | long pageSize = 500L; |
| | | boolean wroteAnyPage = false; |
| | | try (ExcelWriter writer = |
| | | EasyExcel.write(response.getOutputStream(), VisitorUserExportRow.class).build()) { |
| | | WriteSheet sheet = EasyExcel.writerSheet("访客信息").build(); |
| | | while (true) { |
| | | IPage<MpUser> page = |
| | | mpUserMapper.selectPage( |
| | | new Page<>(pageNo, pageSize), |
| | | buildVisitorQuery( |
| | | userName, |
| | | mobile, |
| | | companyName, |
| | | registerStartDate, |
| | | registerEndDate, |
| | | status)); |
| | | List<MpUser> users = page.getRecords(); |
| | | if (users == null || users.isEmpty()) { |
| | | break; |
| | | } |
| | | List<Long> userIds = users.stream().map(MpUser::getId).filter(Objects::nonNull).toList(); |
| | | Map<Long, Long> bookingCountMap = loadBookingCountMap(userIds); |
| | | List<VisitorUserExportRow> rows = |
| | | users.stream().map(user -> toExportRow(user, bookingCountMap)).toList(); |
| | | writer.write(rows, sheet); |
| | | wroteAnyPage = true; |
| | | if (pageNo * pageSize >= page.getTotal()) { |
| | | break; |
| | | } |
| | | pageNo++; |
| | | } |
| | | if (!wroteAnyPage) { |
| | | writer.write(List.of(), sheet); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void prepareExcelResponse(HttpServletResponse response, String filename) { |
| | | response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); |
| | | response.setCharacterEncoding("UTF-8"); |
| | | response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\""); |
| | | } |
| | | |
| | | public VisitorUserDetailVo detail(Long id, String uuid) { |
| | | MpUser user = loadVisitorUserWithUuid(id, uuid); |
| | | VisitorUserDetailVo vo = new VisitorUserDetailVo(); |
| | |
| | | <view v-if="formData.vehicleEntry" class="w-[16rpx] h-[16rpx] rounded-full bg-[#1677FF]"> |
| | | </view> |
| | | </view> |
| | | <text class="ml-[12rpx] text-[28rpx]" :class="formData.vehicleEntry ? 'text-[#333333]' : 'text-[#999999]'">车辆进场</text> |
| | | <text class="ml-[12rpx] text-[28rpx]" :class="formData.vehicleEntry ? 'text-[#333333]' : 'text-[#999999]'">接送货</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | qrCodes: VisitorCodeDisplayTicket[] |
| | | } |
| | | |
| | | function wait(ms: number) { |
| | | return new Promise(resolve => setTimeout(resolve, ms)) |
| | | } |
| | | |
| | | const systemInfo = uni.getSystemInfoSync() |
| | | const { safeAreaInsets } = systemInfo |
| | | const parkFlowBottomPx = Math.max(24, Math.round(systemInfo.windowHeight / 8)) |
| | |
| | | ) |
| | | const visitorCodeCardMinHeightClass = computed(() => { |
| | | if (hasLongAccessAreaText.value) { |
| | | return currentOrderHasMultipleTickets.value ? 'min-h-[900rpx]' : 'min-h-[860rpx]' |
| | | return currentOrderHasMultipleTickets.value ? 'min-h-[940rpx]' : 'min-h-[900rpx]' |
| | | } |
| | | return currentOrderHasMultipleTickets.value ? 'min-h-[804rpx]' : 'min-h-[760rpx]' |
| | | return currentOrderHasMultipleTickets.value ? 'min-h-[844rpx]' : 'min-h-[800rpx]' |
| | | }) |
| | | const currentTicket = computed(() => { |
| | | if (!currentOrder.value) { |
| | |
| | | errorCorrectionLevel: 'M', |
| | | margin: 1, |
| | | }) |
| | | const size = 300 |
| | | const size = 400 |
| | | const moduleCount = qr.modules.size |
| | | const tileSize = size / moduleCount |
| | | const canvasId = 'visitorQrCanvas' |
| | |
| | | } |
| | | |
| | | context.draw(false, () => { |
| | | uni.canvasToTempFilePath({ |
| | | canvasId, |
| | | width: size, |
| | | height: size, |
| | | destWidth: size * 2, |
| | | destHeight: size * 2, |
| | | success: res => resolve(res.tempFilePath), |
| | | fail: reject, |
| | | void wait(500).then(() => { |
| | | uni.canvasToTempFilePath({ |
| | | canvasId, |
| | | width: size, |
| | | height: size, |
| | | destWidth: size * 2, |
| | | destHeight: size * 2, |
| | | success: res => resolve(res.tempFilePath), |
| | | fail: reject, |
| | | }) |
| | | }) |
| | | }) |
| | | }) |
| | |
| | | /> |
| | | <image |
| | | :src="currentOrder?.orderId === order.orderId ? currentTicket?.qrCode : order.qrCodes[0]?.qrCode" |
| | | class="h-[360rpx] w-[360rpx]" |
| | | class="h-[400rpx] w-[400rpx]" |
| | | mode="aspectFit" |
| | | /> |
| | | <image |
| | |
| | | position: fixed; |
| | | left: -9999px; |
| | | top: -9999px; |
| | | width: 300px; |
| | | height: 300px; |
| | | width: 400px; |
| | | height: 400px; |
| | | pointer-events: none; |
| | | } |
| | | </style> |
| | |
| | | qrCode: string |
| | | } |
| | | |
| | | function wait(ms: number) { |
| | | return new Promise(resolve => setTimeout(resolve, ms)) |
| | | } |
| | | |
| | | definePage({ |
| | | name: 'visitorCode', |
| | | layout: 'default', |
| | |
| | | errorCorrectionLevel: 'M', |
| | | margin: 1, |
| | | }) |
| | | const size = 400 |
| | | const size = 448 |
| | | const moduleCount = qr.modules.size |
| | | const tileSize = size / moduleCount |
| | | const canvasId = 'sharedVisitorQrCanvas' |
| | |
| | | } |
| | | |
| | | context.draw(false, () => { |
| | | uni.canvasToTempFilePath({ |
| | | canvasId, |
| | | width: size, |
| | | height: size, |
| | | destWidth: size * 2, |
| | | destHeight: size * 2, |
| | | success: res => resolve(res.tempFilePath), |
| | | fail: reject, |
| | | void wait(500).then(() => { |
| | | uni.canvasToTempFilePath({ |
| | | canvasId, |
| | | width: size, |
| | | height: size, |
| | | destWidth: size * 2, |
| | | destHeight: size * 2, |
| | | success: res => resolve(res.tempFilePath), |
| | | fail: reject, |
| | | }) |
| | | }) |
| | | }) |
| | | }) |
| | |
| | | position: fixed; |
| | | left: -9999px; |
| | | top: -9999px; |
| | | width: 400px; |
| | | height: 400px; |
| | | width: 448px; |
| | | height: 448px; |
| | | opacity: 0; |
| | | pointer-events: none; |
| | | } |
| | |
| | | qrCode: string |
| | | } |
| | | |
| | | function wait(ms: number) { |
| | | return new Promise(resolve => setTimeout(resolve, ms)) |
| | | } |
| | | |
| | | interface VisitorCodeDisplayOrder extends Omit<MiniMyVisitorCodeOrderItem, 'qrCodes'> { |
| | | qrCodes: VisitorCodeDisplayTicket[] |
| | | } |
| | |
| | | }, |
| | | }) |
| | | |
| | | const router = useRouter() |
| | | const sysInfo = uni.getSystemInfoSync() |
| | | const statusBarHeight = sysInfo.statusBarHeight || 0 |
| | | const navBarHeight = 44 |
| | |
| | | const currentTicket = computed(() => order.value?.qrCodes?.[0] || null) |
| | | |
| | | function handleBack() { |
| | | router.back() |
| | | const pages = getCurrentPages() |
| | | if (pages.length > 1) { |
| | | uni.navigateBack({ |
| | | delta: 1, |
| | | fail: () => { |
| | | uni.switchTab({ url: '/pages/index/index' }) |
| | | }, |
| | | }) |
| | | return |
| | | } |
| | | uni.switchTab({ |
| | | url: '/pages/index/index', |
| | | fail: () => { |
| | | uni.reLaunch({ url: '/pages/index/index' }) |
| | | }, |
| | | }) |
| | | } |
| | | |
| | | function ticketTimeText() { |
| | |
| | | errorCorrectionLevel: 'M', |
| | | margin: 1, |
| | | }) |
| | | const size = 400 |
| | | const size = 448 |
| | | const moduleCount = qr.modules.size |
| | | const tileSize = size / moduleCount |
| | | const canvasId = 'sharedSingleVisitorQrCanvas' |
| | |
| | | } |
| | | |
| | | context.draw(false, () => { |
| | | uni.canvasToTempFilePath({ |
| | | canvasId, |
| | | width: size, |
| | | height: size, |
| | | destWidth: size * 2, |
| | | destHeight: size * 2, |
| | | success: res => resolve(res.tempFilePath), |
| | | fail: reject, |
| | | void wait(500).then(() => { |
| | | uni.canvasToTempFilePath({ |
| | | canvasId, |
| | | width: size, |
| | | height: size, |
| | | destWidth: size * 2, |
| | | destHeight: size * 2, |
| | | success: res => resolve(res.tempFilePath), |
| | | fail: reject, |
| | | }) |
| | | }) |
| | | }) |
| | | }) |
| | |
| | | position: fixed; |
| | | left: -9999px; |
| | | top: -9999px; |
| | | width: 400px; |
| | | height: 400px; |
| | | width: 448px; |
| | | height: 448px; |
| | | opacity: 0; |
| | | pointer-events: none; |
| | | } |