diff --git a/pom.xml b/pom.xml
index f8716c9..a9a1031 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,6 +30,13 @@
spring-boot-starter-web
+
+
+ org.projectlombok
+ lombok
+ true
+
+
org.springframework.boot
@@ -39,10 +46,10 @@
- mysql
- mysql-connector-java
- 8.0.33
+ com.mysql
+ mysql-connector-j
+
org.mybatis.spring.boot
@@ -64,6 +71,14 @@
org.springframework.boot
spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
diff --git a/src/main/java/com/example/mini_program/common/Result.java b/src/main/java/com/example/mini_program/common/Result.java
new file mode 100644
index 0000000..f2f6c0d
--- /dev/null
+++ b/src/main/java/com/example/mini_program/common/Result.java
@@ -0,0 +1,33 @@
+package com.example.mini_program.common;
+
+import lombok.Data;
+
+@Data
+public class Result {
+
+ private int code;
+ private String message;
+ private T data;
+
+ public static Result success(T data) {
+ Result result = new Result<>();
+ result.setCode(0);
+ result.setMessage("success");
+ result.setData(data);
+ return result;
+ }
+
+ public static Result error(String message) {
+ Result result = new Result<>();
+ result.setCode(-1);
+ result.setMessage(message);
+ return result;
+ }
+
+ public static Result error(String code, String message) {
+ Result result = new Result<>();
+ result.setCode(-1);
+ result.setMessage(code + ": " + message);
+ return result;
+ }
+}
diff --git a/src/main/java/com/example/mini_program/config/WxMiniAppConfig.java b/src/main/java/com/example/mini_program/config/WxMiniAppConfig.java
index 1c12774..a6fc3a0 100644
--- a/src/main/java/com/example/mini_program/config/WxMiniAppConfig.java
+++ b/src/main/java/com/example/mini_program/config/WxMiniAppConfig.java
@@ -1,28 +1,14 @@
package com.example.mini_program.config;
+import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
+@Data
@Component
@ConfigurationProperties(prefix = "wx.miniapp")
public class WxMiniAppConfig {
private String appid;
private String secret;
-
- public String getAppid() {
- return appid;
- }
-
- public void setAppid(String appid) {
- this.appid = appid;
- }
-
- public String getSecret() {
- return secret;
- }
-
- public void setSecret(String secret) {
- this.secret = secret;
- }
}
diff --git a/src/main/java/com/example/mini_program/controller/AppointmentController.java b/src/main/java/com/example/mini_program/controller/AppointmentController.java
new file mode 100644
index 0000000..5c59d7a
--- /dev/null
+++ b/src/main/java/com/example/mini_program/controller/AppointmentController.java
@@ -0,0 +1,90 @@
+package com.example.mini_program.controller;
+
+import com.example.mini_program.common.Result;
+import com.example.mini_program.entity.VisitApplication;
+import com.example.mini_program.service.AppointmentService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/wx-mini/appointment")
+@RequiredArgsConstructor
+public class AppointmentController {
+
+ private final AppointmentService appointmentService;
+
+ /**
+ * 根据openid获取最新的一条预约记录
+ */
+ @GetMapping("/latest")
+ public Result getLatest(@RequestParam String openid) {
+ if (openid == null || openid.trim().isEmpty()) {
+ return Result.error("openid不能为空");
+ }
+ return Result.success(appointmentService.getLatest(openid));
+ }
+
+ /**
+ * 获取用户所有预约记录(按创建时间倒序)
+ */
+ @GetMapping("/list")
+ public Result> getList(@RequestParam String openid) {
+ if (openid == null || openid.trim().isEmpty()) {
+ return Result.error("openid不能为空");
+ }
+ return Result.success(appointmentService.getList(openid));
+ }
+
+ /**
+ * 创建预约记录
+ */
+ @PostMapping("/create")
+ public Result create(@RequestBody VisitApplication record) {
+ if (record.getOpenid() == null || record.getOpenid().trim().isEmpty()) {
+ return Result.error("openid不能为空");
+ }
+ if (record.getName() == null || record.getName().trim().isEmpty()) {
+ return Result.error("访客姓名不能为空");
+ }
+ if (record.getPhone() == null || record.getPhone().trim().isEmpty()) {
+ return Result.error("联系电话不能为空");
+ }
+ try {
+ return Result.success(appointmentService.create(record));
+ } catch (Exception e) {
+ return Result.error("创建预约失败: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 取消预约(仅pending状态可取消,需校验openid)
+ */
+ @PutMapping("/cancel")
+ public Result cancel(@RequestParam String id, @RequestParam String openid) {
+ if (id == null || id.trim().isEmpty()) {
+ return Result.error("id不能为空");
+ }
+ if (openid == null || openid.trim().isEmpty()) {
+ return Result.error("openid不能为空");
+ }
+ boolean success = appointmentService.cancel(id, openid);
+ return success ? Result.success(true) : Result.error("取消失败,无权限或状态不允许");
+ }
+
+ /**
+ * 审批预约(通过/拒绝)
+ */
+ @PutMapping("/approve")
+ public Result approve(@RequestParam String id, @RequestParam String status) {
+ if (id == null || id.trim().isEmpty()) {
+ return Result.error("id不能为空");
+ }
+ if (!"approved".equals(status) && !"rejected".equals(status)) {
+ return Result.error("status只能为approved或rejected");
+ }
+ boolean success = appointmentService.approve(id, status);
+ return success ? Result.success(true) : Result.error("审批失败,记录不存在或状态不允许");
+ }
+}
diff --git a/src/main/java/com/example/mini_program/controller/WxLoginController.java b/src/main/java/com/example/mini_program/controller/WxLoginController.java
index e73bcd9..63aed8f 100644
--- a/src/main/java/com/example/mini_program/controller/WxLoginController.java
+++ b/src/main/java/com/example/mini_program/controller/WxLoginController.java
@@ -1,28 +1,20 @@
package com.example.mini_program.controller;
-import com.example.mini_program.entity.VisitApplication;
-import com.example.mini_program.service.AppointmentService;
+import com.example.mini_program.common.Result;
import com.example.mini_program.service.WxLoginService;
+import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/wx-mini")
+@RequiredArgsConstructor
public class WxLoginController {
private final WxLoginService wxLoginService;
- private final AppointmentService appointmentService;
-
- public WxLoginController(WxLoginService wxLoginService, AppointmentService appointmentService) {
- this.wxLoginService = wxLoginService;
- this.appointmentService = appointmentService;
- }
/**
* 微信小程序登录接口
* 接收wx.login的code,换取openid
- *
- * @param code 小程序wx.login获取的code
- * @return openid等信息
*/
@GetMapping("/login")
public Result login(@RequestParam String code) {
@@ -38,74 +30,4 @@ public class WxLoginController {
return Result.error(result.getErrcode(), result.getErrmsg());
}
}
-
- /**
- * 根据openid获取最新的一条预约记录
- *
- * @param openid 微信用户openid
- * @return 最新的一条预约记录
- */
- @GetMapping("/appointment/latest")
- public Result getLatestAppointment(@RequestParam String openid) {
- if (openid == null || openid.trim().isEmpty()) {
- return Result.error("openid不能为空");
- }
- VisitApplication appointment = appointmentService.getLatest(openid);
- return Result.success(appointment);
- }
-
- /**
- * 统一返回结果类
- */
- public static class Result {
- private int code;
- private String message;
- private T data;
-
- public static Result success(T data) {
- Result result = new Result<>();
- result.setCode(0);
- result.setMessage("success");
- result.setData(data);
- return result;
- }
-
- public static Result error(String message) {
- Result result = new Result<>();
- result.setCode(-1);
- result.setMessage(message);
- return result;
- }
-
- public static Result error(String code, String message) {
- Result result = new Result<>();
- result.setCode(-1);
- result.setMessage(code + ": " + message);
- return result;
- }
-
- public int getCode() {
- return code;
- }
-
- public void setCode(int code) {
- this.code = code;
- }
-
- public String getMessage() {
- return message;
- }
-
- public void setMessage(String message) {
- this.message = message;
- }
-
- public T getData() {
- return data;
- }
-
- public void setData(T data) {
- this.data = data;
- }
- }
}
diff --git a/src/main/java/com/example/mini_program/entity/VisitApplication.java b/src/main/java/com/example/mini_program/entity/VisitApplication.java
index 24bbc61..f4191a0 100644
--- a/src/main/java/com/example/mini_program/entity/VisitApplication.java
+++ b/src/main/java/com/example/mini_program/entity/VisitApplication.java
@@ -1,5 +1,9 @@
package com.example.mini_program.entity;
+import com.fasterxml.jackson.annotation.JsonAlias;
+import lombok.Data;
+
+@Data
public class VisitApplication {
private String id;
@@ -7,116 +11,17 @@ public class VisitApplication {
private String phone;
private String company;
private String reason;
+
+ @JsonAlias("date")
private String visitDate;
+
+ @JsonAlias("time")
private String visitTime;
+
private String hostName;
private String area;
private String status;
private String statusText;
private String openid;
private String createTime;
-
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getPhone() {
- return phone;
- }
-
- public void setPhone(String phone) {
- this.phone = phone;
- }
-
- public String getCompany() {
- return company;
- }
-
- public void setCompany(String company) {
- this.company = company;
- }
-
- public String getReason() {
- return reason;
- }
-
- public void setReason(String reason) {
- this.reason = reason;
- }
-
- public String getVisitDate() {
- return visitDate;
- }
-
- public void setVisitDate(String visitDate) {
- this.visitDate = visitDate;
- }
-
- public String getVisitTime() {
- return visitTime;
- }
-
- public void setVisitTime(String visitTime) {
- this.visitTime = visitTime;
- }
-
- public String getHostName() {
- return hostName;
- }
-
- public void setHostName(String hostName) {
- this.hostName = hostName;
- }
-
- public String getArea() {
- return area;
- }
-
- public void setArea(String area) {
- this.area = area;
- }
-
- public String getStatus() {
- return status;
- }
-
- public void setStatus(String status) {
- this.status = status;
- }
-
- public String getStatusText() {
- return statusText;
- }
-
- public void setStatusText(String statusText) {
- this.statusText = statusText;
- }
-
- public String getOpenid() {
- return openid;
- }
-
- public void setOpenid(String openid) {
- this.openid = openid;
- }
-
- public String getCreateTime() {
- return createTime;
- }
-
- public void setCreateTime(String createTime) {
- this.createTime = createTime;
- }
}
diff --git a/src/main/java/com/example/mini_program/mapper/VisitApplicationMapper.java b/src/main/java/com/example/mini_program/mapper/VisitApplicationMapper.java
index fe41ed9..3a0231f 100644
--- a/src/main/java/com/example/mini_program/mapper/VisitApplicationMapper.java
+++ b/src/main/java/com/example/mini_program/mapper/VisitApplicationMapper.java
@@ -4,6 +4,8 @@ import com.example.mini_program.entity.VisitApplication;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
+import java.util.List;
+
@Mapper
public interface VisitApplicationMapper {
@@ -14,4 +16,56 @@ public interface VisitApplicationMapper {
* @return 最新的一条记录,没有则返回null
*/
VisitApplication selectLatestByOpenid(@Param("openid") String openid);
+
+ /**
+ * 根据openid查询所有预约记录(按创建时间倒序)
+ *
+ * @param openid 微信用户openid
+ * @return 预约记录列表
+ */
+ List selectListByOpenid(@Param("openid") String openid);
+
+ /**
+ * 新增预约记录
+ *
+ * @param record 预约记录
+ * @return 影响行数
+ */
+ int insert(VisitApplication record);
+
+ /**
+ * 根据ID和openid取消预约(仅pending状态可取消)
+ *
+ * @param id 记录ID
+ * @param openid 用户openid
+ * @return 影响行数
+ */
+ int updateStatusToCancelled(@Param("id") String id, @Param("openid") String openid);
+
+ /**
+ * 根据ID和openid查询记录(用于权限校验)
+ *
+ * @param id 记录ID
+ * @param openid 用户openid
+ * @return 预约记录
+ */
+ VisitApplication selectByIdAndOpenid(@Param("id") String id, @Param("openid") String openid);
+
+ /**
+ * 根据ID查询记录
+ *
+ * @param id 记录ID
+ * @return 预约记录
+ */
+ VisitApplication selectById(@Param("id") String id);
+
+ /**
+ * 更新审批状态
+ *
+ * @param id 记录ID
+ * @param status 状态值
+ * @param statusText 状态文本
+ * @return 影响行数
+ */
+ int updateStatus(@Param("id") String id, @Param("status") String status, @Param("statusText") String statusText);
}
diff --git a/src/main/java/com/example/mini_program/service/AppointmentService.java b/src/main/java/com/example/mini_program/service/AppointmentService.java
index 25f074c..2140b66 100644
--- a/src/main/java/com/example/mini_program/service/AppointmentService.java
+++ b/src/main/java/com/example/mini_program/service/AppointmentService.java
@@ -2,35 +2,105 @@ package com.example.mini_program.service;
import com.example.mini_program.entity.VisitApplication;
import com.example.mini_program.mapper.VisitApplicationMapper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
-@Service
-public class AppointmentService {
+import java.util.List;
+import java.util.UUID;
- private static final Logger logger = LoggerFactory.getLogger(AppointmentService.class);
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class AppointmentService {
private final VisitApplicationMapper visitApplicationMapper;
- public AppointmentService(VisitApplicationMapper visitApplicationMapper) {
- this.visitApplicationMapper = visitApplicationMapper;
- }
-
/**
* 根据openid获取最新的一条预约记录
- *
- * @param openid 微信用户openid
- * @return 最新的一条预约记录,没有则返回null
*/
public VisitApplication getLatest(String openid) {
- logger.info("查询用户最新预约记录, openid: {}", openid);
+ log.info("查询用户最新预约记录, openid: {}", openid);
VisitApplication result = visitApplicationMapper.selectLatestByOpenid(openid);
if (result != null) {
- logger.info("找到预约记录, id: {}", result.getId());
+ log.info("找到预约记录, id: {}", result.getId());
} else {
- logger.info("未找到预约记录");
+ log.info("未找到预约记录");
}
return result;
}
+
+ /**
+ * 获取用户所有预约记录(按创建时间倒序)
+ */
+ public List getList(String openid) {
+ log.info("查询用户预约列表, openid: {}", openid);
+ List list = visitApplicationMapper.selectListByOpenid(openid);
+ log.info("查询到 {} 条预约记录", list.size());
+ return list;
+ }
+
+ /**
+ * 创建预约记录
+ */
+ public VisitApplication create(VisitApplication record) {
+ record.setId(UUID.randomUUID().toString().replace("-", ""));
+ record.setStatus("pending");
+ record.setStatusText("待审核");
+ visitApplicationMapper.insert(record);
+ log.info("创建预约记录成功, id: {}, openid: {}", record.getId(), record.getOpenid());
+ return record;
+ }
+
+ /**
+ * 取消预约(仅pending状态可取消,需校验openid)
+ */
+ public boolean cancel(String id, String openid) {
+ log.info("取消预约, id: {}, openid: {}", id, openid);
+
+ VisitApplication existing = visitApplicationMapper.selectByIdAndOpenid(id, openid);
+ if (existing == null) {
+ log.warn("预约记录不存在或不属于该用户, id: {}, openid: {}", id, openid);
+ return false;
+ }
+ if (!"pending".equals(existing.getStatus())) {
+ log.warn("预约状态不允许取消, id: {}, status: {}", id, existing.getStatus());
+ return false;
+ }
+
+ int rows = visitApplicationMapper.updateStatusToCancelled(id, openid);
+ if (rows > 0) {
+ log.info("取消预约成功, id: {}", id);
+ return true;
+ }
+ log.warn("取消预约失败, id: {}", id);
+ return false;
+ }
+
+ /**
+ * 审批预约(通过/拒绝)
+ */
+ public boolean approve(String id, String status) {
+ log.info("审批预约, id: {}, status: {}", id, status);
+
+ VisitApplication existing = visitApplicationMapper.selectById(id);
+ if (existing == null) {
+ log.warn("预约记录不存在, id: {}", id);
+ return false;
+ }
+ if (!"pending".equals(existing.getStatus())) {
+ log.warn("预约状态不允许审批, id: {}, currentStatus: {}", id, existing.getStatus());
+ return false;
+ }
+
+ String statusText = "approved".equals(status) ? "已通过" : "已拒绝";
+ int rows = visitApplicationMapper.updateStatus(id, status, statusText);
+ if (rows <= 0) {
+ log.warn("审批更新失败, id: {}", id);
+ return false;
+ }
+
+ log.info("审批成功, id: {}, status: {}", id, statusText);
+ return true;
+ }
}
diff --git a/src/main/java/com/example/mini_program/service/WxLoginService.java b/src/main/java/com/example/mini_program/service/WxLoginService.java
index 969c0b4..3f2cf5c 100644
--- a/src/main/java/com/example/mini_program/service/WxLoginService.java
+++ b/src/main/java/com/example/mini_program/service/WxLoginService.java
@@ -1,6 +1,8 @@
package com.example.mini_program.service;
import com.example.mini_program.config.WxMiniAppConfig;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -11,7 +13,8 @@ import org.springframework.web.client.RestTemplate;
public class WxLoginService {
private static final Logger logger = LoggerFactory.getLogger(WxLoginService.class);
- private static final String JSCODE2SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";
+ private static final String JSCODE2SESSION_URL =
+ "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";
private final WxMiniAppConfig wxMiniAppConfig;
private final RestTemplate restTemplate;
@@ -23,9 +26,6 @@ public class WxLoginService {
/**
* 调用微信接口用code换取openid
- *
- * @param code 小程序调用wx.login获取的code
- * @return 登录结果,包含openid等信息
*/
public WxLoginResult code2Session(String code) {
String url = String.format(JSCODE2SESSION_URL,
@@ -33,17 +33,16 @@ public class WxLoginService {
wxMiniAppConfig.getSecret(),
code);
- logger.info("调用微信jscode2session接口,code: {}", code);
+ logger.info("调用微信jscode2session接口, code: {}", code);
try {
- // 微信返回text/plain,手动解析JSON字符串
String response = restTemplate.getForObject(url, String.class);
logger.info("微信返回原始结果: {}", response);
JSONObject json = new JSONObject(response);
WxLoginResult result = new WxLoginResult();
result.setOpenid(json.optString("openid"));
- result.setSession_key(json.optString("session_key"));
+ result.setSessionKey(json.optString("session_key"));
result.setUnionid(json.optString("unionid"));
result.setErrcode(json.optString("errcode"));
result.setErrmsg(json.optString("errmsg"));
@@ -60,52 +59,15 @@ public class WxLoginService {
}
}
+ @Data
public static class WxLoginResult {
- private String session_key;
+ @JsonProperty("session_key")
+ private String sessionKey;
+
private String unionid;
private String openid;
private String errcode;
private String errmsg;
-
- public String getSession_key() {
- return session_key;
- }
-
- public void setSession_key(String session_key) {
- this.session_key = session_key;
- }
-
- public String getUnionid() {
- return unionid;
- }
-
- public void setUnionid(String unionid) {
- this.unionid = unionid;
- }
-
- public String getOpenid() {
- return openid;
- }
-
- public void setOpenid(String openid) {
- this.openid = openid;
- }
-
- public String getErrcode() {
- return errcode;
- }
-
- public void setErrcode(String errcode) {
- this.errcode = errcode;
- }
-
- public String getErrmsg() {
- return errmsg;
- }
-
- public void setErrmsg(String errmsg) {
- this.errmsg = errmsg;
- }
}
}
diff --git a/src/main/java/com/example/mini_program/service/WxSubscribeMessageService.java b/src/main/java/com/example/mini_program/service/WxSubscribeMessageService.java
new file mode 100644
index 0000000..e69de29
diff --git a/src/main/resources/mapper/VisitApplicationMapper.xml b/src/main/resources/mapper/VisitApplicationMapper.xml
index 789c813..cae9a87 100644
--- a/src/main/resources/mapper/VisitApplicationMapper.xml
+++ b/src/main/resources/mapper/VisitApplicationMapper.xml
@@ -18,16 +18,60 @@
+
+ id, name, phone, company, reason,
+ DATE_FORMAT(visit_date, '%Y-%m-%d') AS visit_date,
+ DATE_FORMAT(visit_time, '%H:%i') AS visit_time,
+ host_name, area, status, status_text, openid,
+ DATE_FORMAT(create_time, '%Y-%m-%dT%H:%i:%s.000+00:00') AS create_time
+
+
+
+
+
+
+
+ INSERT INTO visit_application (id, name, phone, company, reason,
+ visit_date, visit_time, host_name, area,
+ status, status_text, openid, create_time)
+ VALUES (#{id}, #{name}, #{phone}, #{company}, #{reason},
+ #{visitDate}, #{visitTime}, #{hostName}, #{area},
+ #{status}, #{statusText}, #{openid}, NOW())
+
+
+
+ UPDATE visit_application
+ SET status = 'cancelled', status_text = '已取消'
+ WHERE id = #{id} AND openid = #{openid} AND status = 'pending'
+
+
+
+
+
+ UPDATE visit_application
+ SET status = #{status}, status_text = #{statusText}
+ WHERE id = #{id} AND status = 'pending'
+
+