From 45dccc43c06c4fe96c406f24a8da331e7c816971 Mon Sep 17 00:00:00 2001
From: 刘帅 <rr.iii@qq.com>
Date: 星期四, 17 九月 2026 17:45:14 +0800
Subject: [PATCH] feat&bug:员工和门店手机号同步
---
cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/system/BallController.java | 187 ++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 184 insertions(+), 3 deletions(-)
diff --git a/cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/system/BallController.java b/cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/system/BallController.java
index 5cfb963..cf2ee0f 100644
--- a/cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/system/BallController.java
+++ b/cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/system/BallController.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.dsh.course.dto.JsDto;
import com.dsh.course.dto.StudentQeryDto;
import com.dsh.course.entity.SiteLock;
@@ -23,12 +24,17 @@
import com.dsh.guns.config.UserExt;
import com.dsh.guns.core.base.controller.BaseController;
import com.dsh.guns.core.util.ToolUtil;
+import com.dsh.guns.modular.system.audit.ManagementAuditWriter;
import com.dsh.guns.modular.system.controller.util.MD5;
import com.dsh.guns.modular.system.model.*;
import com.dsh.guns.modular.system.model.dto.*;
import com.dsh.guns.modular.system.service.*;
import com.dsh.guns.modular.system.util.*;
import org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
@@ -41,8 +47,12 @@
import javax.annotation.Resource;
import javax.imageio.ImageIO;
+import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -90,6 +100,9 @@
@Autowired
private AppUserClient appUserClient;
+ @Resource
+ private ManagementAuditWriter auditWriter;
+
@RequestMapping("/tolist")
public String tolist(Model model) {
List<TCity> list = cityService.list(new LambdaQueryWrapper<TCity>().eq(TCity::getParentId, 0));
@@ -114,15 +127,93 @@
@RequestMapping("/selectJoin")
@ResponseBody
public ResultUtil join(@RequestBody MethodDto method) {
+ if (method == null || method.getId() == null) {
+ return ResultUtil.error("门票记录不能为空");
+ }
+ SiteBooking before = iSiteBookingService.getById(method.getId());
+ if (before == null) {
+ return ResultUtil.error("门票记录不存在");
+ }
+ Integer previousStatus = before.getStatus();
+ if (!Objects.equals(previousStatus, 1) && !Objects.equals(previousStatus, 4)) {
+ return ResultUtil.error("当前门票状态不能确认到店");
+ }
- System.out.println("============" + method);
+ // 待核销正常确认到店;已过期但运营确认用户实际入场时,直接人工完成。
+ Integer targetStatus = Objects.equals(previousStatus, 4) ? 3 : 2;
SiteBooking siteBooking = new SiteBooking();
- siteBooking.setStatus(2);
+ siteBooking.setStatus(targetStatus);
siteBooking.setId(method.getId());
siteBooking.setGoType(method.getMethod());
- iSiteBookingService.updateById(siteBooking);
+ try {
+ // 以修改前状态作为条件,避免并发操作覆盖其他状态变更。
+ boolean updated = iSiteBookingService.update(siteBooking,
+ new LambdaUpdateWrapper<SiteBooking>()
+ .eq(SiteBooking::getId, before.getId())
+ .eq(SiteBooking::getStatus, previousStatus));
+ if (!updated) {
+ appendTicketStatusAudit(before, targetStatus, method.getMethod(), "FAIL", "门票状态更新失败");
+ return ResultUtil.error("确认到店失败");
+ }
+ appendTicketStatusAudit(before, targetStatus, method.getMethod(), "SUCCESS", null);
+ } catch (RuntimeException ex) {
+ appendTicketStatusAudit(before, targetStatus, method.getMethod(), "FAIL", ex.getMessage());
+ throw ex;
+ }
return new ResultUtil<>(0, 0, "到店成功", null, null);
+ }
+
+ /** 记录运营管理员人工确认到店导致的门票状态变更。 */
+ private void appendTicketStatusAudit(SiteBooking before, Integer targetStatus, Integer goType,
+ String result, String errorMessage) {
+ try {
+ Map<String, Object> beforeData = new HashMap<>();
+ beforeData.put("id", before.getId());
+ beforeData.put("orderNo", before.getOrderNo());
+ beforeData.put("status", before.getStatus());
+ beforeData.put("statusName", ticketStatusName(before.getStatus()));
+
+ Map<String, Object> afterData = new HashMap<>(beforeData);
+ afterData.put("status", targetStatus);
+ afterData.put("statusName", ticketStatusName(targetStatus));
+ afterData.put("goType", goType);
+
+ Map<String, Object> audit = new HashMap<>();
+ audit.put("traceId", UUID.randomUUID().toString().replace("-", ""));
+ audit.put("sourceService", "mb-cloud-management");
+ audit.put("sourceType", "HTTP");
+ audit.put("operationType", "STATUS_CHANGE");
+ audit.put("riskLevel", "CRITICAL");
+ audit.put("operationName", "运营管理员人工修改门票状态");
+ audit.put("requestMethod", "POST");
+ audit.put("requestUri", "/ball/selectJoin");
+ audit.put("requestParams", "id=" + before.getId() + ", goType=" + goType + ", targetStatus=" + targetStatus);
+ audit.put("beforeData", com.alibaba.fastjson.JSONObject.toJSONString(beforeData));
+ audit.put("afterData", com.alibaba.fastjson.JSONObject.toJSONString(afterData));
+ audit.put("userId", UserExt.getUser() == null ? null : UserExt.getUser().getId());
+ audit.put("userAccount", UserExt.getUser() == null ? null : UserExt.getUser().getAccount());
+ audit.put("result", result);
+ audit.put("errorMessage", errorMessage);
+ // 审计表的 createdAt 即本次管理员操作时间。
+ audit.put("createdAt", new Date());
+ auditWriter.append(audit);
+ } catch (Exception ignored) {
+ // 审计失败不能阻断实际到店确认,网关日志可作为兜底。
+ }
+ }
+
+ private String ticketStatusName(Integer status) {
+ if (status == null) return "未知";
+ switch (status) {
+ case 0: return "待支付";
+ case 1: return "待核销";
+ case 2: return "已到店";
+ case 3: return "已完成";
+ case 4: return "已过期";
+ case 5: return "已取消";
+ default: return "未知";
+ }
}
@@ -972,6 +1063,7 @@
yuyueTime = strings1.get(0);
}
model.addAttribute("yuyueTime", yuyueTime);
+ model.addAttribute("targetAudience", book.getTargetAudience());
model.addAttribute("city", book.getCity());
model.addAttribute("store", storeService.getById(book.getStoreId()).getName());
model.addAttribute("siteName", siteService.getById(book.getSiteId()).getName());
@@ -1104,6 +1196,67 @@
@RequestMapping("/yuyuelist")
@ResponseBody
public List<Map<String, Object>> yuyuelist(BookingQuery bookingQuery) {
+ return queryBookingOrders(bookingQuery);
+ }
+
+ /**
+ * 导出当前筛选条件下的全部预约记录,不受列表分页影响。
+ */
+ @RequestMapping("/yuyueexport")
+ public void exportYuyue(BookingQuery bookingQuery, HttpServletResponse response) throws IOException {
+ List<Map<String, Object>> orders = queryBookingOrders(bookingQuery);
+ String[] headers = {"序号", "所在省", "所在市", "预约门店", "入场方式", "预约场地", "姓名", "联系电话",
+ "预约时间段", "支付流水号", "支付方式", "金额", "状态"};
+
+ // 线上运行环境使用的是旧版 POI 核心包,使用 HSSF 保持依赖兼容;
+ // 超过单 Sheet 上限的数据拆分到多个工作表,确保导出全部命中记录。
+ HSSFWorkbook workbook = new HSSFWorkbook();
+ try {
+ final int maxDataRowsPerSheet = 60000;
+ int sheetCount = Math.max(1, (orders.size() + maxDataRowsPerSheet - 1) / maxDataRowsPerSheet);
+ for (int sheetIndex = 0; sheetIndex < sheetCount; sheetIndex++) {
+ Sheet sheet = workbook.createSheet(sheetCount == 1 ? "预约管理" : "预约管理" + (sheetIndex + 1));
+ Row header = sheet.createRow(0);
+ for (int i = 0; i < headers.length; i++) {
+ header.createCell(i).setCellValue(headers[i]);
+ sheet.setColumnWidth(i, i == 8 ? 28 * 256 : 18 * 256);
+ }
+ int start = sheetIndex * maxDataRowsPerSheet;
+ int end = Math.min(start + maxDataRowsPerSheet, orders.size());
+ for (int rowIndex = start; rowIndex < end; rowIndex++) {
+ Map<String, Object> order = orders.get(rowIndex);
+ Row row = sheet.createRow(rowIndex - start + 1);
+ String[] values = {
+ valueOf(order.get("id")), valueOf(order.get("province")), valueOf(order.get("city")),
+ valueOf(order.get("name")), targetAudienceName(order.get("targetAudience")),
+ valueOf(order.get("siteName")), valueOf(order.get("booker")), valueOf(order.get("phone")),
+ valueOf(order.get("times")), valueOf(order.get("payOrderNo")), valueOf(order.get("payType")),
+ moneyText(order.get("payType"), order.get("payMoney")), ticketStatusName(toInteger(order.get("status")))
+ };
+ for (int columnIndex = 0; columnIndex < values.length; columnIndex++) {
+ Cell cell = row.createCell(columnIndex);
+ cell.setCellValue(values[columnIndex]);
+ }
+ }
+ }
+
+ String fileName = "预约管理_" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".xls";
+ response.reset();
+ response.setContentType("application/vnd.ms-excel");
+ response.setCharacterEncoding(StandardCharsets.UTF_8.name());
+ response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''"
+ + URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()).replace("+", "%20"));
+ try (OutputStream output = response.getOutputStream()) {
+ workbook.write(output);
+ output.flush();
+ }
+ } finally {
+ // HSSFWorkbook 由旧版 POI 提供,不调用新版 Workbook 的 close API。
+ }
+ }
+
+ /** 列表和导出共用同一查询与数据展示转换,保证权限范围和筛选条件一致。 */
+ private List<Map<String, Object>> queryBookingOrders(BookingQuery bookingQuery) {
Integer objectType = UserExt.getUser().getObjectType();
if (objectType == 2) {
@@ -1156,6 +1309,31 @@
// }
}
return orders;
+ }
+
+ private String targetAudienceName(Object targetAudience) {
+ Integer value = toInteger(targetAudience);
+ if (Objects.equals(value, 1)) return "订场";
+ if (Objects.equals(value, 2)) return "散客";
+ return "";
+ }
+
+ private String moneyText(Object payType, Object payMoney) {
+ if (payMoney == null) return "";
+ return valueOf(payMoney) + ("玩湃币".equals(valueOf(payType)) ? "币" : "元");
+ }
+
+ private Integer toInteger(Object value) {
+ if (value == null || value.toString().trim().isEmpty()) return null;
+ try {
+ return Integer.valueOf(value.toString());
+ } catch (NumberFormatException ignored) {
+ return null;
+ }
+ }
+
+ private String valueOf(Object value) {
+ return value == null ? "" : String.valueOf(value);
}
@@ -1571,6 +1749,9 @@
siteBooking.setCityCode(byId.getCityCode());
}
+ if (siteBooking.getIsHalf()==2){
+ siteBooking.setHalfName(null);
+ }
siteClient.addSiteBooking(siteBooking);
System.out.println("=================" + siteBooking);
return new ResultUtil<>(null, 200, null, null, null);
--
Gitblit v1.7.1